Saravana Pandian Annamalai
25. April 2019 · Write a comment · Categories: ARM, Embedded Software · Tags: , , ,

In our earlier blogs on ARM Interrupt architectures, we explored the ARM exception models and registers. Also, we went through different kinds of Interrupt controllers being used. In the upcoming blogs, we will primarily see ARM Interrupt handling from the firmware/software perspective including operating systems like FreeRTOS, Linux and WinCE. To being with, this blog will discuss interrupt handling in ARM Cortex M MCUs.

Cortex M Vector Table

As discussed earlier, the ARM Cortex M series of MCUs typically carters to lower end application with the core running between a few MHz to a maximum 150MHz. To target low cost tools and ease of development, the interrupt architecture is designed to be simpler and straight forward. The vector table in ARM Cortex M series looks like:

Cortex M Vector Table

Typically, on power-on reset, the Vector table base address is defined to be at 0. The ARM core, up on boot up, loads the stack pointer with the value stored at offset 0. And then it loads the Program counter with the address available at offset 4 and starts executing the same.

Thus, the vector table design is such that the stack is operational before the core starts executing thereby eliminating the need for an assembly code to set things up for calling functions. In the firmware perspective, this is a major advantage. There is no need to write any assembly code.

Following these 2 words, the table should hold the addresses of the exception handlers. The first 14 of them are pre-defined ad reserved for handling specific to the core and its execution. From offset, 0x40, the SoC specific interrupt handlers are defined and can be customized by the silicon vendor.

It can also be noted that there is a priority associated with each of these exceptions. Lower the number the higher the priority. Some of the major exceptions defined by ARM are

Reset Handler

At the highest priority of -3, this is the entry point of execution. Loaded to PC on power on reset, this is responsible for initializing the system peripherals and start executing the firmware/OS.

NMI Handler

At a priority only next to Reset Handler (-2), as the name suggests this cannot be masked by software. It is typically triggered by a specialized peripheral unit that can be connected to a critical functionality.

HardFault Handler

This exception is caused when there is an error during exception processing. At a higher priority of -1 than other exception, this can be used to recover from issues during exception handling.

MemManage Handler

Caused due to memory protection faults, the priority level can be configured by the firmware.

BusFault Handler

Caused during to memory access – either during instruction fetch or data access, the priority level can be configured by the firmware

UsageFault Handler

Caused during to instruction executing, the priority level can be configured by the firmware. The handler is called when one of the following errors occurs

  • Presence of an undefined instruction
  • Performing an illegal unaligned access
  • Core in invalid state on instruction execution
  • An error occurring on exception return.
  • Doing an unaligned address on word and halfword memory access
  • Performing division by zero

SVCall Handler

Known as the Supervisor Call, this handler is called up on the core executing a SVC instruction. This is typically used in OS environments to execute system services.

PendSV Handler

This is typically used in OS environments to perform context switching.

SysTick Handler

The ARM Cortex M core defines a specialize timer module to keep track of the System time. This handler is executed once this timer value reaches 0.

With this understanding of Cortex M vector table, now we will see how the firmware handles exceptions in software.

Cortex M Vector Table

To practically understand Cortex M Interrupt handling, we will take an example of software implementation of FreeRTOS running on NXP K66 MCU compiled using GCC tool chain. The first and foremost step is to define the vector table and place it in the Vector base location. The vector table for the device looks like this:

__attribute__ ((used, section(“.isr_vector”)))

void (* const g_pfnVectors[])(void) = {

// Core Level – CM4

&_vStackTop,                            // The initial stack pointer

ResetISR,                                   // The reset handler

NMI_Handler,                           // The NMI handler

HardFault_Handler,                   // The hard fault handler

MemManage_Handler,              // The MPU fault handler

BusFault_Handler,                     // The bus fault handler

UsageFault_Handler,                 // The usage fault handler

0,                                                // Reserved

0,                                                // Reserved

0,                                                // Reserved

0,                                                // Reserved

SVC_Handler,                           // SVCall handler

DebugMon_Handler,                // Debug monitor handler

0,                                               // Reserved

PendSV_Handler,                     // The PendSV handler

SysTick_Handler,                     // The SysTick handler

 

// Chip Level – MK66F18

DMA0_DMA16_IRQHandler,       // 16 : DMA Channel 0, 16 Transfer Complete

DMA1_DMA17_IRQHandler,       // 17 : DMA Channel 1, 17 Transfer Complete

DMA2_DMA18_IRQHandler,       // 18 : DMA Channel 2, 18 Transfer Complete

:

:

UART0_RX_TX_IRQHandler,      // 47 : UART0 Receive/Transmit interrupt

:

:

CAN1_Tx_Warning_IRQHandler,  // 113: CAN1 Tx warning interrupt

CAN1_Rx_Warning_IRQHandler,  // 114: CAN1 Rx warning interrupt

CAN1_Wake_Up_IRQHandler,      // 115: CAN1 wake up interrupt

 

}; /* End of g_pfnVectors */

As it can be seen, the interrupt handlers are clubbed together as an array with the address to the top of the stack (lowest address as it grows towards higher address) as the first element. This array is placed in address 0, via linker script mechanism. In this example, using the section (.isr_vector) keyword, the location of the vector table is set to 0.

Also, it can be noted that there are hundreds of interrupt handlers supported. Even this example has close to 115 handlers. Obviously, a firmware system will not have all these implemented, hardly 20-30 interrupts will be used in a system. Instead of asking the user to define handlers, the start-up code provided by the silicon vendors, will have dummy functions (a while (1) loop) defined with weak reference.

weak void NMI_Handler(void)

{ while(1) {}

}

WEAK_AV void SVC_Handler(void)

{ while(1) {}

}

So, when the developer defines an interrupt handler with the same name in his code, this weak function will be discarded and user-defined function linked against instead.

Cortex M Interrupt Handling

With the vector table installed, the functions that are needed can be added one by one in the firmware. As a first step, the Reset Handler has to be created. At typical, reset handler will look like as below.

void ResetISR(void) {

// Disable interrupts

__asm volatile (cpsid i”);

// If __USE_CMSIS defined, then call CMSIS SystemInit code

SystemInit();

//

// Copy the data sections from flash to SRAM.

//

unsigned int LoadAddr, ExeAddr, SectionLen;

unsigned int *SectionTableAddr;

// Load base address of Global Section Table

SectionTableAddr = &__data_section_table;

// Copy the data sections from flash to SRAM.

while (SectionTableAddr < &__data_section_table_end) {

LoadAddr = *SectionTableAddr++;

ExeAddr = *SectionTableAddr++;

SectionLen = *SectionTableAddr++;

data_init(LoadAddr, ExeAddr, SectionLen);

}

// At this point, SectionTableAddr = &__bss_section_table;

// Zero fill the bss segment

while (SectionTableAddr < &__bss_section_table_end) {

ExeAddr = *SectionTableAddr++;

SectionLen = *SectionTableAddr++;

bss_init(ExeAddr, SectionLen);

}

// Reenable interrupts

__asm volatile (cpsie i”);

main();

//

// main() shouldn’t return, but if it does, we’ll just enter an infinite loop

//

while (1) {

;

}

}

This minimalistic handler, disables all interrupts up on entry, configures the core and major peripherals via SystemInit function. Then it initializes the data and bss sections. Finally, it enables the interrupts before jumping to the main function.

Now we will see how a peripheral is configured for interrupt operation based on the Systick unit.

uint32_t SysTick_Config(uint32_t ticks)

{

if ((ticks – 1UL) > SysTick_LOAD_RELOAD_Msk)

{

return (1UL); /* Reload value impossible */

}

SysTick->LOAD = (uint32_t)(ticks – 1UL); /* set reload register */

NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) – 1UL); /* set Priority for Systick Interrupt */

SysTick->VAL = 0UL; /* Load the SysTick Counter Value */

SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |

SysTick_CTRL_TICKINT_Msk |

SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */

return (0UL); /* Function successful */

}

As the code listing shows, the function configures various registers needed for proper operation of the Systick interrupt such as LOAD, VAL, CTRL etc. IT=t also configures the priority of the interrupt. As mentioned earlier, in Cortex M architecture, each of the interrupts has an associated priority. Depending on the implementation, there could be n number of bits corresponding to each interrupt number. Lower the number, higher the priority/urgency and can be set via the NVIC_SetPriority CMSIS API. With this mechanism, it is possible for the interrupts to be prioritized and only the higher priority one will be serviced if more than one interrupt is pending at the same time.

Typical handler for SysTick looks like:

void SysTickHandler( void )

{

/* The SysTick runs at the lowest interrupt priority, so when this interrupt

executes all interrupts must be unmasked. There is therefore no need to

save and then restore the interrupt mask value as its value is already

known. */

         portDISABLE_INTERRUPTS();

         {

                    /* Increment the RTOS tick. */

                    if( xTaskIncrementTick() != pdFALSE )

                   {

                                  /* A context switch is required. Context switching is performed in the PendSV interrupt. Pend the PendSV interrupt. */

                            portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;

                  }

         }

     portENABLE_INTERRUPTS();

}

Cortex M Interrupt Handling via Assembly

So far, we have not writing a single line of assembly code and still able to do all the required functionality in software. In some cases, there will be a need to do assembly code. In these cases, the handler can be defined as naked function (Which will not generate any stack push/pop and return codes) and implement them in assembly.

For example, in FreeRTOS, the SVC Handler implementation is as below:

void vPortSVCHandler( void ) __attribute__ (( naked ));

void vPortSVCHandler( void )

{

     __asm volatile (

     ldr r3, pxCurrentTCBConst2 \n” /* Restore the context. */

     ldr r1, [r3] \n” /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */

     ldr r0, [r1] \n” /* The first item in pxCurrentTCB is the task top of stack. */

     ldmia r0!, {r4-r11, r14} \n” /* Pop the registers that are not automatically saved on exception entry and the critical nesting count. */

     msr psp, r0 \n” /* Restore the task stack pointer. */

     isb \n”

     mov r0, #0 \n”

     msr basepri, r0 \n”

     bx r14 \n”

     ” \n”

     ” .align 4 \n”

     “pxCurrentTCBConst2: .word pxCurrentTCB \n”

     );

}

Thus with compiler extensions, it is possible to include assembly based interrupt handling as well.

Switching Vector tables

In the above examples, we have noted that the vector table is located at address 0. But there are cases, where we will need to place it at a different location. For example, the flash location could be at address 0, and the RAM, where the user wants to place the vector table could be elsewhere. Or it could be a dual A/B firmware or a bootloader/application firmware each sitting at a different location. So, based on the current code being executed, the vector table location differs.

ARM provides a simple mechanism to switch the base address of the vector table. It provides a Vector table offset register at address 0xE000ED08 in the NVIC group, where the base address can be programmed. For example, to switch the vector location to address 0x20000000, following lines will suffice.

With deployment of IoT is spreading across various domains and applications, the requirements of the underlying communication mechanism varies. There is no one-size-fill-all solution as the needs are different in case of throughput, range, power consumption etc. There are many wireless communication technologies, such as Short-range wireless, Cellular, LPWAN etc.

LPWAN stands for Low Power Wide Area Network, designed for sending small data packages over long distances. While short range technologies like Bluetooth, Wi-Fi, Zigbee are cheap, it is limited by distance, cellular technologies like 3G, 4G and 5G have more transmission rate and range but are more costly and high power consuming. LPWAN has overcome the cons of existing wireless technology by compromising on the data rate and featuring the long-range data transmission, low power consumption and being economical. Some of the technologies that comes under LPWAN includes Narrowband IoT (NB-IoT), Sigfox, LoRa and others.

Heterogeneous Wireless communication Technologies

Of these LPWAN, LoRa has a significant market share and finds application across use cases.

Following are key features of LoRa Technology,

  • It has very wide coverage range about 5 km in urban areas and 15 km in suburban areas
  • Battery lifetime up to 15 years
  • One LoRa gateway takes care of thousands of nodes.
  • Easy to deploy and low cost.
  • Enhanced the secure data transmission by embedded end-to-end AES128 encryption

In this blog, we will cover the underlying technology behind LoRa and its network topology.

LoRa Technology

LoRa is a long range, low power, inexpensive technology for Internet of Things (IoT) developed by a company called Cycleo, France in 2009, later acquired by Semtech in 2012. The LoRa radio and modulation part is patented and its source is closed. Semtech has licensed its LoRa intellectual property to other chip manufacturers. The LoRa Alliance, an open, non-profit association has been formed to promote the adoption of this technology and has grown to more than 500 members since its inception in March 2015.

The most important aspect of the LoRa is that it uses license-free sub-gigahertz radio frequency ISM bands in the deployed region such as 868 MHz in Europe and 915MHz in North America. Thus, there is no need for a separate licensing for using LoRa in any country.

Usually in digital communication, there are three types of basic modulation techniques such as

Amplitude Shift Keying, Frequency Shift Keying and Phase Shift Keying, in which either amplitude or frequency or phase of the carrier varies according to the digital signal changes. The short coming with these approaches is that since the bandwidth is quiet limited the signal is quiet prone to interference and could be easily jammed. To over come this, spread spectrum techniques are being used where by the signal is modulated such that it is spread across the entire bandwidth. There are many spread spectrum techniques such as DSSS, FHSS, THSS, CSS etc.

Chirp Spread Spectrum

LoRa is a proprietary spread spectrum modulation scheme that is based on Chirp Spread Spectrum modulation (CSS). Chirp Spread Spectrum is a spread spectrum technique that uses wideband linear frequency modulated chirp pulses to encode information.A chirp is a sinusoidal signal whose frequency increases(up chirp) or decreases(down chirp) over time across the entire bandwidth. This signal is used as the carrier and is modulated according to the data to be transmitted.

LoRa uses three bandwidths: 125kHz, 250kHz and 500kHz. The chirp uses the entire bandwidth and the spreading factors are – in short – the duration of the chirp. LoRa operates with spread factors from 7 to 12. This delivers orthogonal transmissions at different data rates. Moreover it provides processing gain and hence transmitter output power can be reduced with same RF link budget and hence will increase battery life.

LoRa WAN

While LoRa is the underlying physical part, LoRaWAN is the network on which that LoRa operates. It is a media access control (MAC) in the data link layer that is maintained by the LoRa Alliance. LoRaWAN defines a set of rules and software that ensures data arrives with an acknowledgement and does not have duplicate packets. It is a network architecture that is deployed in a star topology and so the communication between the end node and gateway is bidirectional.

LoRaWAN defines role of end points and gateway. End points or End nodes are the remote nodes typically housing the sensors/actuators. Gateways or Concentrators forms the heart of the star topology, to which the end points communicate to.

Lora WAN Network Architecture

When an end node transmits data to the gateway, it is called an uplink. When the gateway transmits data to the end node, it is called a downlink. The gateways forward this packet to the network server. The network server collects the messages from all gateways and filters out the duplicate data and determines the gateway that has the best reception. The network server forwards the packet to the correct application server where the end user can process the sensor data. Optionally the application server can send a response back to the end node. When a response is sent, the network server receives the response and determines which gateway to use to broadcast the response back to the end node.

The LoRaWAN protocol defines the Adaptive Data Rate (ADR) scheme to control the uplink transmission parameters of LoRa devices. Whether the ADR functionality will be used is requested by the end nodes by setting the ADR flag in the uplink message. If the ADR flag is set, the network server can control the end node’s transmission parameters. ADR should only be used in stable Radio Frequency (RF) situations where end nodes do not move. Mobile end nodes which are stationary for longer times can enable ADR during those times.

This blog introduced the basics behind LoRa technology including the underlying communication techniques and network topology. In the next blog, we will cover the communication model in more detail including the classes, bands and also the typical configuration available in a gateway.

About Embien: Embien Technologies is a proven enabler in adoption of IoT. We have been working with different communication technologies such as ZigBee, BLE, SigFox, LoRa, NB-IoT and have designed gateways to inter-operate between them. Our services include end device development, gateways design, cloud application development and analytics.

In the last blog, we have covered the basics of CAN communication. Now, we will see about some of the advanced concepts involved such as Bit Stuffing, frame types, error types, Synchronization etc. We will also look into some of the non-standard extensions available in modern CAN controllers.

Generally, all CAN modules support the classical CAN protocol. It can receive and transmit both CAN base and the CAN extended frames. The transmission and reception of CAN FD frames is optional. Classical CAN Implementation do not support 29-bit identifiers. CAN 2.0B passive nodes were compliant with ISO 11898-1:2003, but it used very rarely. In this context, let us explore some of other concepts in detail.

Bit Stuffing

Bit Stuffing is used to ensure the synchronization of all nodes even when transmitting consecutive information with same value either 1 or 0.
During the transmission of message, a maximum of five consecutive bits may have the same polarity. In this case, the transmitter will insert the one additional bit of opposite polarity into the bit stream before transmitting the further bits. This will ensure that there is always some activity in the bus with in 6-bit intervals and hence avoid DC Voltage build up as well as being in sync with the transmitter.

Stuffing and De-stuffing

On the receiving end, similarly the receiver also checks the number of bits of same polarity and removes the stuffed bits again from the bit stream in a process called de-stuffing.

CAN Frame Types

There are 5 types of frames in CAN protocol;

Data Frame (DF):

Carries Data from transmitting node to receiving node.

Remote Frame (RF):

Some times, a node might want to request some data from another which is made possible by Remote frame.
There are two differences between data and Remote frames.
RTR field of a data frame is dominant and RTR field of remote frame is recessive.
In data frame format data field is present, whereas in Remote frame format data field is absent.

The receiver will understand that transmitter is requesting some date and then prepares and sends the Data frame based on the protocol.

Error Frame (EF):

This type of frame is transmitted by any node to signal error.
The error frame consists of two different fields in CAN.
superposition of ERROR FLAGS (6–12 dominant/recessive bits)
ERROR DELIMITER (8 recessive bits).
There are two types of error flags:

Active Error Flag

When the Transmitting node transmitted six dominant bits, the error will be detected in network and the error sate called active error flag.

Passive Error Flag

When the Transmitting node transmitted six recessive bits, the error will be detected in network and the error sate called passive error flag.

Now let us see, how the CAN manages error states. In every CAN node, there are 2 error counters – Transmit Error Counter (TEC) and Receive Error Counter (REC). When the transmitter detects an error in the transmitted frame, it increments the TEC by 8. A receiver detecting an error will increment its REC by 1. On successful transmission/reception the error counters are reduced by 1.
Based on the error counts, the node behavior varies.

  • By default, the Active Error frame will be transmitted on the bus, when TEC and REC < 128. Thus, it will invalidate the frame globally.
  • But when 127 < TEC \ REC > 255, the passive Error frame will be transmitted on the bus, without affecting the bus traffic.
  • Finally, the node enters into the Bus off state, when TEC > 255. If node enters into the bus off state then no frames will be transmitted.

In any case, both transmitter and receiver reject the erroneous frames completely and do not process it any further.

Overload Frame (OF):

Overload frame contains two fields such as Overload flag and Overload Delimiter.
The over load frame will be generated, when the receiving node is overloaded – i.e. it is not able to detect and receive the incoming messages. The format is very similar to Error Frame but without the error counters incrementing. An Overload frame indicates that its transmitter require delay before receiving next data or remote frame and is mostly not used in modern CAN controllers.

Inter Frame Space (IFS):

Data frames and remote frames are separated from preceding frames and succeeding frame by a bit field called interframe space. It consists of three consecutive recessive bits. Following that, if a dominant bit is detected, it will be regarded as the “Start of frame” bit of the next frame.

Frame on CAN BUS

Error Types

There are 5 types of error in CAN protocol.

Bit error:

Every node reads back, bit by bit from the bus during transmitting the message and then compares the transmitted bit value with received bit value. If bit received does not match with bit sent, then Bit error is said to be occurred.

Stuff error:

Set when more than five consecutive bits of same polarity are received in receiving node.

CRC error:

A transmitted always transmits the CRC value in the CRC field of CAN frame. The receiving node also calculates the CRC value using same formula and compares with received CRC value. If receiving node detects mismatch between calculated CRC values and received CRC value then it is called CRC error.

ACK error:

Occurs when no acknowledgment is sent by receiving node or no acknowledgment received in transmitting node.

Form error:

Set when fixed format fields in receive frame is violated. No dominant bits are allowed in CRC delimiter, ACK delimiter, EOF and IFS.

Synchronization and Re-synchronization

As there is no separate clock signal on the CAN bus, the node itself need to synchronize on the bus. For that reason, the underlying transmission format is NRZ-5 coding.
When the transmitting node sends CAN frame it consists the first bit of SOF (start of frame). All the receivers align themselves to this falling edge (recessive to dominant) after the period of bus idle. This mechanism is called hard synchronization.
After subsequent falling edges on the CAN frame are used to re-synchronize the nodes on bus and it is called soft synchronization. This resynchronization happens continuously at every falling edge (recessive to dominant transition) to ensure transmitting and receiving nodes stay in sync.

Additional functions

Some CAN protocol implementations offer optional functions that may or may not be a part of CAN specification. These include, for example, the single-shot transmission of data frames. This means that the automatic re-transmission in case of detected errors is disabled. This is useful for TTCAN add-ons and some tool applications.
Another option generally available is the bus-monitoring mode. The node can receive data and remote frames, but doesn’t acknowledge them and also doesn’t send error and overload flags. Nevertheless, these dominant bits are communicated internally in the CAN module.
In another optional restricted operation mode, the CAN module behaves equally, but it acknowledges received data and remote frames. The error counters are not incremented and decremented in this mode. If a node is the TTCAN time master, it must be able to transmit the time-reference message; other frames must not be transmitted.
For some applications, message time stamping is required. ISO 11898-1:2015 specifies that the optional time-stamp function features resolutions of 8-bit, 16-bit, or 32-bit. The time-base value is captured at the reference point of each data frame and it is readable after EOF (end-of-frame). Other (not standardized) optional functions include readable error counters, configurable warning limits, interrupt request generation, and arbitration lost capture.
If the CAN implementation allows changing the configuration of a node by software, the configuration data (e.g. bit-time configuration or operating mode) needs to be locked against changes while CAN communication is ongoing.

Armed with details of CAN communication, we will now attempt to understand general configuration of a CAN node for transmission and reception with examples from a real controller.

About Embien

Embien Technologies is a leading provider of product engineering services for the Automotive, Semi-conductor, Industrial, Consumer and Health Care segments. Working with OEMs in Industrial segments, we have developed numerous gateways, sensory modes on top of CAN network and protocols such as DeviceNet, CANOpen etc. Our Automotive experience enabled us develop Telematic units and In-vehicle Infotainment systems, Instrument clusters with CAN interfaces.