+ All Categories
Home > Documents > Microcomputer Interfacing Lab 3 ARM - University of...

Microcomputer Interfacing Lab 3 ARM - University of...

Date post: 12-May-2018
Category:
Upload: leminh
View: 219 times
Download: 2 times
Share this document with a friend
26
Microcomputer Interfacing Lab 3 – Interrupts in ARM ANGUS GALLOWAY
Transcript

MicrocomputerInterfacingLab 3 –Interrupts in ARMANGUS GALLOWAY

The Goal:

Convert a KSDK project with interrupts into ARM assembly

FOR THE ARMASM ASSEMBLER USED BY KEIL

Why learn ARM?

ARM doesn’t build anything, they license IP designs

In 2010, ~6 Billion ARM devices shipped. Today, 50 Billion.

95% of smartphones = ARM

Cortex-M4 based MCUs are made by Atmel, Freescale, Nordic, NXP, Texas Instruments, Silicon Labs, ST Microelectronics, and more!

BBC Microbit – This year, every grade 7+ student in the UK will receive the free ARM based development platform to learn on.

Other ARM based products:

GameBoy, Apple Ipod, Tablets, Xbox 360, Thalmic Myo, Nest, Garmin

Prerequisites

▪ TWR-K60D100M

▪ Keil uVision 5

▪ Freescale Kinetis SDK

▪ Patience

▪ ENGG3640 Laboratory Manual, Radu Muresan - August 2015

▪ Cortex-M4 Technical Reference Manual (DDI0439B)

▪ Can google “cortex m4 reference manual”

▪ Side note, Kinetis Design Studio is a free eclipse IDE, uses a different assembler GNU ASM – GAS, and compiler GCC for ARM. When you move to C based labs this difference becomes irrelevant, might be a superior IDE to develop with.

Today vs. Your Textbook

Cortex-M3 is much more similar to Cortex-M4 in the K60D100M.

We no longer talk about FIQs, we can have hundreds of nested interrupts with variable priorities. Nested

Just means that you don’t disable interrupts if you are in the middle of processing one, the CPU can handle

several levels of interruption. NMI = Non maskable interrupt.

Source: http://electronics.stackexchange.com/questions/15359/which-family-of-arm-processors-should-i-learn-arm7tdmi-or-cortex-m3

How I would approach this task (1)

▪ The KSDK helps with productivity for developing a complicated application as it is very high level, unfortunately for you, this makes porting to assembly a bit tricky.

▪ You will need to step through several levels of function calls to begin seeing code that looks like register writes

▪ I recommend you download this sample code which has an lptmrexample, and is MUCH closer to assembly form.

http://www.freescale.com/webapp/sps/download/license.jsp?colCode=KINETIS512_V2_SC&location=null&Parent_nodeId=1333141411984714199192&Parent_pageType=product

How I would approach this task (2)

▪ I assumed hardware_init(), which enables the UART (for printf) and clocks to the ports.

▪ Import global variable into assembly code, increment it in the ISR.

▪ Retain similar main loop that checks the value of lptmrCounterand toggles an LED.

▪ All initialization of interrupts and LPTMR module is done in assembly as well as the ISR.

Traditional vs. KSDK

▪ Basically,

/* Set up LPTMR to use 1kHz LPO with no prescaler as its clock source */

LPTMR0_PSR = LPTMR_PSR_PCS(1)|LPTMR_PSR_PBYP_MASK; //Easier for convert to assembly

Instead of:

// Initialize LPTMR

LPTMR_DRV_Init(LPTMR_INSTANCE, &lptmrState, &lptmrUserConfig);

Extremely useful…things

▪ I very seldomly just flash the board, use the Debug button in Keil!

▪ Run at full speed if you want to

▪ F10 to step over a function

▪ F11 to step into a function

▪ CTRL + F10 to run to cursor

▪ Put breakpoints in your ISR!

▪ Use the peripherals tab to access the state of …peripherals!

▪ Such as the NVIC, LPTMR – Displays all bit values (live) and what their states mean

▪ You can even change bits in a register from the IDE for troubleshooting

Sample Layout of Your Assembly File

▪ Enable clock to LPTMR

▪ Disable LPTMR

▪ Set up compare value

▪ Select clock source for timer, can bypass prescaler

▪ (optional) – interrupt priority

▪ Enable LPTMR and interrupt (TEN, TIE)

▪ Enable LPTMR interrupt in NVIC

▪ Do something in a loop, or branch back to a c function

There are two different types of clocks you need to be concerned with. There is a clock gate to simply

enable the peripheral (SIM_SCGC5), and then for the LPTMR you get to choose (MUX) which clock it draws

from as its source for counting. The LPO is 1kHz and is fast enough for the delays we are talking about

which are on the order of seconds. It also has the added bonus that it still runs when the chip is in very low

power modes (you aren’t concerned about this for lab3), and makes the math easy as you can simply

divide the compare value (ticks) by 1000 to get the period in seconds of the delay. This calculation

assumes the prescaler is bypassed, otherwise the clock is divided by 2 at a minimum, and 32K at the max.

NVICNESTED VECTORED INTERRUPT CONTROLLER

To confirm p.79, Search “NVIC” in system_MK60D10.c

NVIC_EnableIRQ( IRQn );

▪ NVIC->ISER[(uint32_t) ((int32_t)IRQn) >> 5] = (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F));

▪ /* enable interrupt */

If IRQ = 85

▪ 85 = 0x55

▪ 0x55 >> 5 = 0x10 = 2

▪ 0x55 & 1F = 0x15 = 21

What you need to know from p.79

▪ You don’t need to write to ALL of those registers, they just want you to know they are available.

▪ All you really need is NVICISER2, ISER = Interrupt Set Enable Reg.

▪ NVICIABR2 is set by hardware when an interrupt happens, not by you! Confirm with NVIC peripheral view when in ISR.

▪ Setting the interrupt priority is optional (and pointless if you only have one). The highest priority is 0 (default).

Calculate NVIC addresses

NVIC_ISER2 = 0xE00E1008

// Set LPTMR interrupt priority NVIC_IPR21

LDR R1, =0xE000E415 ; Get NVIC interrupt enable location

LDR R0, [R1]

MOV R0, #0x10 ; Set priority

STR R0, [R1] ; Write

IPR0-3 because a peripheral could generate interrupts on multiple

channels, but LPTMR only has 1. On p75-76 in ref man,

The IPR is repeated 4 times.

If you look at NVIC documentation, it says 256 interrupt

P priorities available. The manufacturer (Freescale)

chose to implement less than ARM’s full spec,

but obviously can’t exceed it.

Context Switch – The part your code doesn’t have to manage

What should your ISR do?

1. Clear the flag that triggered it in the first place (hint: TCF)

2. Do some work (Generally like to keep brief) – I simply incremented a global variable

3. Call BX LR! (Branch Indirect to Link Register) The Cortex-M4 uses a special instruction 0xFFFF_FFF9 which you should see in the LR if you pause execution at any point in the ISR. This pops registers including the PC from the stack. Remember, we have no idea what the CPU was doing when it got interrupted, unlike humans, computers always remember this as the PC was pushed to the stack in the context switch.

Part of the architecture of the NVIC is that every possible interrupting signal is mapped to a vector. You don’t have control over this, but you can control what the vector points to. The vector table can be relocated (i.e to SRAM), but no need for this lab.

Hint, there’s a special shortcut if you give it a very specific name…. CTRL+F “LPTMR” in startup_MK60D10.s

Make sure you comment out the code in fsl_lptmr_irq.c to avoid conflicts.

More ISR tips

1. Use the assembler keyword “EXPORT <name_of_your_isr>

2. Put the code that enables the interrupts in the NVIC as close to the end as possible of your asmMain to prevent from interrupting before you complete all the setup. (This might not matter depending on how your code is setup, I branched back to a C function after the setup). This caused a problem initially because I was checking to see if the TCF was initially set correctly when doing the LPTMR initialization. Interrupt too early and you’ll get an infinite loop! (You probably don’t need to check the TCF).

3. To work with globals, you need their address,

1. i.e LDR R5, =lptmrCounter

2. Add AREA globals to assembly header

3. Store result back in same memory location to make change persistent (i.e STR R0, [R5])

APPENDIXTHE STUFF YOU SHOULD READ, BUT NEVER DO

Definitions

Vector number = Number stored on stack when switching to a particular interrupt

IRQ number = The vector number offset by the number of core-interrupts. IRQ = Vector – 16.

The vector table is just memory! (FLASH)

▪ Hit Debug, check memory contents at 0x0000_0194, then hover over your ISR name in the .S file, the addresses should match.

▪ You will see that many of the addresses near by all have the same value, this is because they have been un-initialized and are set to a default handler. Some near addr 0x0 will be set to 0, this should jive with un-implemented vectors on p. 75

▪ Little endian = least significant byte at lowest memory location.

▪ Cortex-M4 is actually bi-endian, it can do both.

Bit-band mappings

This is a simple concept so don’t be confused.

For the sake of speed, we map every bit in a register

To have its own dedicated alias register.

So 1MB of space represented in 32MB.

Write a value to position 0 of the alias register to set a bit

In the original register.

Load and write instead of read, modify, write.

For the interested reader – Reserved Bits

This is a classic embedded world problem as to what to do with reserved bits! First, you

should NOT write randomly into it [a register with reserved bits] lest your code becomes un-

portable. What happens when the architecture assigns a new meaning to the reserved bits in

future? Your code will break.

So the best mantra when dealing with registers having reserved bits is Read-Modify-Write. i.e read the

register contents, modify only the bits you want and then write back the value so that reserved

bits are untouched ( untouched, does not mean we dont write into them, but in the sense, that we

wrote that which was there before ) For example, say there is a register in which only the LSBit has

meaning and all others are reserved. I would do this

ldr r0,=memoryAddressldr r1,[r0] orr r1,r1,#1str r1,[r0]

Taken from StackOverflow user:

Pavan Manjunath - http://stackoverflow.com/questions/9681615/dealing-with-reserved-register-bits-of-an-arm-chip


Recommended