NOTICE: This website will be shut down in the near future. Product content has moved to nxp.com. Forum content and FAQs have been moved to community.nxp.com. We encourage you to create a user account on nxp.com to use the new community forums and access NXP microcontroller content. We greatly appreciate your contributions and look forward to seeing you at our new web location.

 

LPC43xx dual core notes

Introduction

This page provides some basic information on using the dual core feature of the LPC43xx devices. The information and topics on this page are demonstrated with the use of the dual core project for use with the Keil uVision4 tools. The project initializes both cores to run FreeRTOS and uses the tri-color LED to indicate operation of the M0 and M4 cores and the interprocessor communication between both cores. The project is meant to be basic and simple to focus more on the details of a dual core project.

  • Executable image layout and memory usage
  • Sharing peripheral and memory resources
  • Driver initialization code
  • Interprocessor communications via shared memory and interrupt events
  • Dual core debugging
  • Potential pitfalls and things to watch out for

What this project does

This project creates a bootable image for the M4 core that loads, sets up, and boots the M0 core (with an image embedded in the M4 binary image or from a location in memory). Both cores run FreeRTOS, with the M4 core using the Cortex M4 system tick for its RTOS tick and the M0 core using timer 0. The M4 core initializes most of the needed chip peripherals - including timer 0 for the M0 core. Both cores use a tick rate of 1KHz for FreeRTOS.

The project can be configured in 1 of 2 ways:

  • As an event driver without queues and feedback for the M0 cores (int mode)
  • As an event driver with queues and feedback between the M4 and M0 core

When operating without queues, the M4 core provides interrupts at a varying time to the M0 core. On each interrupt, the M0 core will toggle the green color component of the tri-color LED. When the M4 core is stopped, the green LED will immediately quit blinking.

When operating with queues, the M4 core provides the green color component of the tri-color LED in a queue with a time. The queue is filled up to completion (as fast as possible) on the M4 core's side, while the M0 core consumes queue entries based on the times in each ueue entry. When the M0 core consumes an entry, it signals the M4 core that the entry is free and the M4 core will re-fill the entry. If the M4 core is stopped, the green LED will continue blinking at the rates defined in the queue until the queue is empty.

To help determine that the cores are running, the M4 core blinks the red LED at about 0.5Hz and the M0 core blinks the blue LED at about 1Hz.

When everything is running, the red, blue, and green components of the tri-color LED are all simulatenously toggling at different rates. Stoping or starting a core (via JTAG) will immedaitely halt the red or blue LED from toggling. Restarting either core will continue the process of queue management. When using the queue, the queue is shared between both cores at location 0x10080000 in IRAM. As the system is running, you can peek at the shared memory queue to see it being updated by both cores.

Configuration options for the project are located in the shmem.h file.


Where to get the code

CAUTION: Stick some tape or paper over the tri-color LED on the Hitex 4350 board to dull the LED intensity. It's quite bright! Don't stare at the LEDs for too long!

The code can be download from the project cotribution area at http://www.lpcware.com/content/contribproj/lpc43xx-dual-core-freertosx2-...

Detailed procedures of how to build, load, and run the project are location at http://www.lpcware.com/content/project/lpc43xx-dual-core-notes/lpc43xx-d...

Configuration options for the project are located in the shmem.h file.


Code overview

The project consists of 2 Keil uVision4 projects - one for the M0 core and the other for the M4 core. For this project, the M4 core embeds the M0 image into it's executable, although this doesn't have to be done with way.

M4 code sequence

M4 initialization

The code for the M4 core initializes the system as follows:

  • system clocking and configuration (CGU)
  • pin muxing (tri-color LED)
  • debug frame work
  • Sets up timer 0 for a 1KHz rate. Timer 0 can be setup as part of the M0 core's initialization sequence, but adding the timer driver makes the M0 image larger. The timer driver also depends on the CGU driver (and possibly other drivers), so adding a simple driver like this may significantly increase image size as both cores now have copies of the driver. Another thing to consider is how the drivers initialize hardware. As the timer driver requires the CGU driver and the CGU driver has some data that is initialized at run-time (ie, via cgu_init()), re-initializing the CGU driver on the M0 core after it's been executed on the M4 core may alter system CGU settings - the state of the data for the CGU in the M4 core may not be accurate.
  • Starts FreeRTOS with the system tick at 1KHz, will kick off initial task

M4 initial task

The FreeRTOS initial task on the M4 core performs the following:

  • clears the shared memory queue
  • creates a synchronization semqphaore for use with interrupt events from the M0 core
  • Prepares and boots the M0 core
    • Places the M0 core in reset
    • Enables the clock for the M0 core (at M4 core speed)
    • Sets the M0APPMEMMAP register to point to the base of the M0 code
    • Release reset for the M0 core
  • Sets up and enables the M0->M4 core event interrupt
  • Creates and starts the Interprocess communication task
  • Endlessly toggles the red color component of the tri-color LED at about 0.5Hz

M4 interprocess communication task

The FreeRTOS Interprocess communication task on the M4 core performs the following:

  • When not built with queue mode, repeats the following sequence
    • Generates an interrupt event to the M0 core
    • Waits for .333 seconds
  • When built with queue mode, repeats the following sequence
    • Pushes events into the shared memory queue until full
    • Waits for an event from the M0 core, signalling at least 1 queue entry is free

The M4 core uses a binary semaphore for kicking off the interprocess communication task from the M0->M4 interrupt event. On each event, the queue entries re relcaimed and re-filled as needed. Note that a counting semaphore could be used to count events, but if the M0 issues several fast events to the M4 core and the M4 core is too busy to handle both events, it may preceive 1 event causing the counting semaphore to lose values over time. For example, if the M4 core is processing the timer interrupt and M0->M4 core interrupt is pending, but pre-empted by a higher priority interrupt, and the M0 core issues anther event before the M4 core can handle it, both events from the M0 core will be seem as 1 event on the M4 core.

M0 code sequence

M0 Initialization

The M0 core doesn't do any initialization, as it's all done by the M4 core! It directly starts FreeRTOS and kicks off the initial task.

M0 initial task

The FreeRTOS initial task on the M0 core performs the following:

  • Enables the timer 0 interrupt (already started from the M4 core) for the FreeRTOS tick
  • creates a synchronization semqphaore for use with interrupt events from the M4 core
  • Creates and starts the Interprocess communication task
  • Endlessly toggles the blue color component of the tri-color LED at about 1Hz

M0 interprocess communication task

The FreeRTOS Interprocess communication task on the M0 core performs the following:

  • When not built with queue mode, repeats the following sequence
    • Waits for an event from the M4 core
    • Toggles the state of the green LED
    • Waits for .333 seconds
  • When built with queue mode, repeats the following sequence
    • Waits for an event from the M4 core
    • Pops the event from the queue
    • Sets green LED state based on event
    • Delays task based on event
    • Signals M4 core that it's done with the event

 


JTAG setup for dual core debugging

The Keil uVision4 IDE was used with a Keil Ulink2 JTAG debugger on the Hitex LPC4350 board. The 10-pin JTAG connector was used on the board. When the IDE scans the JTAG bus via Ulink2, it will detect 2 cores. For each core's project, the JTAG needs to be setup for the core it will use. Each core can be indepdently debugged using it's uVision4 session.

For the M0 project, the JTAG should be configured as is shown in the following 2 images. The M0 debug sessions will always attempt to attach to the running image without altering the system or core context.

For the M4 project, the JTAG should be configured as is shown in the following 2 images.

 JTAG image setup scripts

When loading images to the M4 core to run no both the M0 and M4 core, the M0 core should be held in reset prior to the download. This can be done in the JTAG initialization script prior to download. The M0 and M4 core inetrrupts should also be disabled in the CREG M0TXEVENT and M4TXEVENT registers to prevent spurious interrupts when the program is starting.

Executable image layout and memory usage - IRAM variant

The M0 core has restrictions on it's boot address. When the system first starts up after a reset, the M0 core is idle. The M4 core boots first and in turn sets up the M0APPMEMMAP register - which points to the base addresses of the M0 boot code - and then boots the M0 core. Because bits 11..0 in the M0APPMEMMAP register must be 0, the M0 core can only boot from code that's aligned on a 4K boundary.

The table below shows the layout used for IRAM based projects. IRAM based projects can be loaded and started via JTAG or DFU boot.

Region Core Address range Notes
M4 code/data region M4 0x10000000 - 0x1000FFFF  Includes code and data up to 64K
M0 code/data region M0 0x10010000 - 0x10017FFF  Includes code and data up to 32K.
Extra IRAM/free   0x10018000 - 0x1001FFFF  
Shared memory region M0/M4 0x10080000 - 0x10083FFF Shared memory region between M0 and M4 core, used for queue

One of the nice features about the M0 core is that it can have the same memory mapping (well, mostly) as the M4 core. So you can link the M0 image to run out of SPI FLASH or NOR FLASH at the system's FLASH address. When you use the M0APPMEMMAPregister to map address 0x00000000 to the location i FLASH, the M0 core only needs to use address 0x00000000 for the load of the iniial stack value and PC counter, with the PC counter poining to an address in FLASH (ie, 0x1Cxxxxxx).

M0 project - IRAM version

In the M0 IRAM version of project, the code is built to run at address 0x10010000 with a maxmum total size (code, data, stacks, and heap) of 32K. If the memory usage exceeds 32K in total for the M0 run-time image, the link step will fail. When running from IRAM, this places the image at a 64K boundary into the 128K IRAM memory range. The 64K before the M0 image and the 32K after the M0 image are usable for the M4 core. Here is the link script setup for the M0 code and data - this includes the stack and heap - all code, data, heap allocations, and the stack will be located within this range.

  ER_RO 0x10010000 NOCOMPRESS 0x8000 {
    startup_LPC43xx_M0.o (RESET, +FIRST)
    *.o (+RO)
    *.o (+RW, +ZI)
  }

Note the use of the NOCOMPRESS attribute. If the M0 image is embedded into the M4 image and does not have a static size, the data section may be compressed in the linked image and then decompressed at run-time. If the M4 code or data is located directly after the embedded M0 image, the M4 code might be overwritten on decompression. The NOCOMPRESS attribute prevents this by storing the pre-initialized data uncompressed.

M4 project - IRAM version

In the M4 IRAM version, the code is built to load and boot from address 0x10000000 with a maxmimum total size of 64K. The M0 image is placed at address 0x10010000 (matching the address the M0 image is linked at) with a maximum size of 32K and 64K alignment. By pre-placing the image at the linked M0 boot address, the image doesn't need to be copied by the M4 core to the right location at run-time and M0APPMEMMAP can be pointed directly to where the image is located in memory.

The M4 link script is below. Note that the M4 image is padded with 0x0's - this helps when making a binary image by keeping the M0 image data aligned in the correct place - this isn't an issue when creating a hex file...except to make the file bigger. Also note that the M0 image is padded - this isn't needed in this setup, but if data or code was palced directly after the M0 image, this would guarantee that data wasn't inside the M0 memory region.

  ER_RO 0x10000000 PADVALUE 0x0 0x10000 {
    startup_lpc43xx.o (RESET, +FIRST)
    *.o (+RO)
    *.o (+RW, +ZI)
  }
  ER_RO2 0x10010000 FIXED PADVALUE 0x0 0x8000 {
    incm0.o (+RO)
  }

M0/M4 shared memory region

The IRAM at address 0x10080000 is used for the shared memory queue. Although both the M0 and M4 read and write from the queue in this region, neither has both read and write access to the same part of the queue. Data values altered by the M4 core are only readable by the M0 core, while data values altered by the M0 core are only readable by the M4 core. Using this approach, the shared data region doesn't need to be managed as a critical region.

Executable image layout and memory usage - FLASH variant

The FLASH variant of the projects is similar to the IRAM version, except with the following differences:

  • the code and read-only data portions of the image are stored and executed in FLASH for both cores
  • The pre-initialized data regions must be copied to IRAM before use

 The table below shows the layout used for FLASH based projects. Data segments will be copied or initialized at run-time, but both cores will executes code out of FLASH.

Region Core Address range Notes
M4 code region M4 0x1C000000 - 0x1C00FFFF  Includes code and data up to 64K
M0 code region M0 0x1C010000 - 0x10007FFF  Includes code and data up to 32K.
M4 data region M4 0x10000000 - 0x1000FFFF  pre-initialized RW data, ZI data, heap, stack, 64K max
M0 data region M0 0x10001000 - 0x10017FFF  pre-initialized RW data, ZI data, heap, stack, 32K max
Extra IRAM/free   0x10018000 - 0x1001FFFF  
Shared memory region M0/M4 0x10080000 - 0x10083FFF Shared memory region between M0 and M4 core, used for queue

 


 

Sharing peripheral and memory resources

The M0 and M4 core share the same memory map and can access most of the same system resources. The following guidelines regarding memory access and event sharing may be helpful.

  • Avoid using the interprocessor interrupt event to generate count events. If the processor receiving the event is busy (ie, processing a higher priority interrupt) and can't handle the interrupt from the core right away, it will pend the event until it can handle it. In that time, the other core may have generated another event causing the original event to be lost.
  • When building images for each core to a specific memory layout, make sure the linker script monitors the sizes of the images - code and data - to prevent code/data overlap at run-time. Just because an image links in the necessary space doesn't mean it will run within that same region! Using the linker script with the NOCOMPRESS, PADVALUE/FILL, and section size attributes will help enforce layout and notify you at link time of any possible memory clashes.
  • Consider minimal driver usage for one of the cores. A driver that seems simple may depend on other drivers and can increase the image size considerably.
  • Mind driver initialization when using a driver on both cores. For example, if you use the CGU driver on both cores, the driver that calls CGU_init() last will override the CGU configuration setup by the other core.
  • If you really needed a shared memory region that is protected with a critical region lock, you can use the Cortex atomic 'exclusive load and store (LDREX, STREX) instructions' to test and set a shared memory lock. The M0 and M4 will not interleave the access to the shared location. Optionally, bit banding can be used.

Can I share code between the 2 cores?

Interprocessor communications via shared memory and interrupt events

Each core has an interrupt associated with it that can be triggered from the other core (or it's own core). On both cores, this is NVIC interrupt number 1. To generate an interrupt to the other core, you can use 1 of 2 methods.

Method 1: SEV instruction

The Set Event instruction will generate an interrupt to the other core. If the instruction is executed on the M4 core, it will generate an interrupt on the M0 core. M0 core execution will generate an interrupt on the M4 core.

void signal_other_core(void)
{
    __DSB();
    __sev();
}

Method 2: Invocation via CREG

The CREG M0TXEVENT and M4TXEVENT registers can be used to directly geenrate the event. Unlike the SEV instruction, they can be used to generate an interrupt to the other core or it's own core.

To generate an interrupt on the M0 core (from either core), use

LPC_CREG->M4TXEVENT = 0x1;

To generate an interrupt on the M4 core (from either core), use

LPC_CREG->M0TXEVENT = 0x1;


On either core, the interrupt event is cleared by setting M0TXEVENT or M4TXEVENT  to 0.

On the M0 core,

LPC_CREG->M4TXEVENT = 0x0;

On the M4 core,

LPC_CREG->M0TXEVENT = 0x0;
0
Your rating: None

hello I am a beginner in

hello
I am a beginner in lpc4337 and trying to make a project by this processor...
I want to blink the LEDs connected to P6.9 & P6.10 with core M0 and blink the other tow LEDs connected to P6.11 & P6.12 with coreM4.
I am working by keil 5 and registers without using of CMSIS standard function. my programmer is j_link and I have work on OPEN18xx/43xxB1 training board(fabricated by Wave Share).
by using your post and others I don't understand how to configure my program Sad(
I write this code for core M0 :

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include

void delay_ms(int Del)
{
long int i;
for(i=0;iSFSP6_9=0x00000028;
LPC_GPIO_PORT->DIR[3] |= (1 <<5);
//LED3 P6.10 GPIO3[6] FUNC0
LPC_SCU->SFSP6_10=0x00000028;
LPC_GPIO_PORT->DIR[3] |= (1 <<6);
while (1)
{
LPC_GPIO_PORT->SET[3]=1<<5; // GPIO3[5] : (LED D4)
delay_ms(500);
LPC_GPIO_PORT->SET[3]=1<<6; // GPIO3[6] : (LED D3)
delay_ms(500);
LPC_GPIO_PORT->CLR[3]=1<<5; // GPIO3[5] : (LED D4)
delay_ms(500);
LPC_GPIO_PORT->CLR[3]=1<<6; // GPIO3[6] : (LED D3)
delay_ms(500);
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
and setting for M0 core like this:

image1

image2

image3

image4

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

and this code for core M4 in the other project:

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include

void delay_ms(int Del)
{
long int i;
for(i=0;iRESET_CTRL1 = (1 << 24);
}

int main(void)
{

//LED2 P6.11 GPIO3[7] FUNC0
LPC_SCU->SFSP6_11=0x00000028;
LPC_GPIO_PORT->DIR[3] |= (1 <<7);
//LED1 P6.12 GPIO2[8] FUNC0
LPC_SCU->SFSP6_12=0x00000028;
LPC_GPIO_PORT->DIR[2] |= (1 <<8);

while (1)
{
LPC_GPIO_PORT->SET[3]=1<<7; // GPIO3[7] : (LED D2)
delay_ms(1000);
LPC_GPIO_PORT->SET[2]=1<<8; // GPIO2[8] : (LED D1)
delay_ms(1000);
LPC_GPIO_PORT->CLR[3]=1<<7; // GPIO3[7] : (LED D2)
delay_ms(1000);
LPC_GPIO_PORT->CLR[2]=1<<8; // GPIO2[8] : (LED D1)
delay_ms(1000);

}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
and setting for M0 core like this:

image5

image6

image7

image8

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
i should say that i use wizard project in keil 5 to make these tow project & i want to run all of these project by using any new heeder file or lib Puzzled
i want to do all the necessary work like releasing M0 core from reset just by basic registers.
i read all of corresponsive post in this site and in internet, but i just confused !!!
thank you for attention

feedback