I have created and published on GitHub a new component ‘CriticalSection’:
This component is a wrapper between my components and the problematic current implementation in Processor Expert (see EnterCritical()
and ExitCritical()
: Why Things are Failing Badly). It uses a flexible approach and uses macros to either use my modified version of EnterCritical()
and ExitCritical()
, or simply defaults to the original implementation.
Implementation
The driver source code is available on GitHub here.
For ARM Cortex, the implementation is as below:
#define CS1_CriticalVariable() \ uint8_t cpuSR; /* variable to store current status */ /* ** =================================================================== ** Method : CS1_CriticalVariable (component CriticalSection) ** Description : ** Defines a variable if necessary. This is a macro. ** Parameters : None ** Returns : Nothing ** =================================================================== */ #define CS1_EnterCritical() \ do { \ asm ( \ "MRS R0, PRIMASK\n\t" \ "CPSID I\n\t" \ "STRB R0, %[output]" \ : [output] "=m" (cpuSR) :: "r0"); \ } while(0) /* ** =================================================================== ** Method : CS1_EnterCritical (component CriticalSection) ** Description : ** Enters a critical section ** Parameters : None ** Returns : Nothing ** =================================================================== */ #define CS1_ExitCritical() \ do{ \ asm ( \ "ldrb r0, %[input]\n\t" \ "msr PRIMASK,r0;\n\t" \ ::[input] "m" (cpuSR) : "r0"); \ } while(0) /* ** =================================================================== ** Method : CS1_ExitCritical (component CriticalSection) ** Description : ** Exits a critical section ** Parameters : None ** Returns : Nothing ** =================================================================== */Usage
The component source implements three macros:
CriticalVariable()
is a macro who declares and defines a local variable to store the current interrupt state.EnterCritical()
is a macro to create a critical section.ExitCritical()
leaves the critical section.Below shows how I used it: it defines the local critical variable, and uses
EnterCritical()
andExitCritical()
to protect a critical section:void TMOUT1_LeaveCounter(TMOUT1_CounterHandle handle) { CS1_CriticalVariable() if (handle==TMOUT1_OUT_OF_HANDLE) { return; } CS1_EnterCritical(); TMOUT1_Counters[handle] = 0; TMOUT1_FreeCounters[handle]=TRUE; CS1_ExitCritical(); }Upgrading
Several components have now added an extra interface to the new Critical Section component. Components include the Shell, RingBuffer, Trigger, Timeout and SimpleEvent components.
Upgrading is easy: simply select to add the new component (or use the already added one):
That’s it :-).
Summary
I have created that new CriticalSection component to avoid an obvious problem with the default Processor Expert implementation. While this solves the problem for all my components, the problem still exists where the Freescale provided components are using
EnterCritical()
andExitCritical()
: as these components are not open, I cannot change the sources of them. Until Freescale fixes that problem, I have it at least solved on my side. I plan to check the Processor Expert version number in my CriticalSection component, so I can revert back to a fixed Processor Expert implementation as needed.❗ The Freescale provided Processor Expert SPI and UART drivers are still using the problematic versions of
EnterCritical()
andExitCritical()
. I need to see how I can deal with that situation.I have updated the many example projects on my GitHub. If I missed something, simply post a comment ;-).
Happy Sectioning 🙂
Excellent article. I’m using Enter/ExitCritical to protect some atomic variables in a current engine ECU design. an Interrupt saves off some tick counts between external real world trigger pulses and then main line code (protected by Enter/ExitCritical) grabs a copy of the tick count for further processing.
From my understanding of Enter/Exit Critical, I thought I was protected & I haven’t seen any issues yet, but I’m going to look further now as I see how this could easily corrupt my tick count.
LikeLike
thanks :-). The occurrence of the problem depends on the interrupt load and interrupt sequence. I only saw the issue rarely, but can be easily reproduced with high interrupt load.
LikeLike
Hi Erich,
When i set the rtos support enable in CS component, the ldd driver in PE can use taskEnterCritical() from freeRTOS automaticlly, but the high level driver components such as AsynchroSerial… still not using it taskEntercritical(), how we can set both high level component and LDD component using it ?
LikeLike
Can just replace the PE default EnterCritica with freertos’s taskEnterCritical directly in PE_Tyes.h file?
LikeLike
Yes, that’s the only way at least with MCU10.5. Or try out MCU10.6 (just released) which seems to have this fixed.
LikeLike
Unfortunately, the built-in Processor Expert components are encrypted and I cannot change it. But you could change the default implementation of Processor Expert in Cpu.h. Just make sure you disable code generation (see https://mcuoneclipse.com/2012/03/23/disable-my-code-generation/) otherwise you change will be overwritten.
LikeLike
Hi Erich
I follow your post mostly for my KL25z.
very good work it gives us direction thank you for such detailed posts
I am facing while compiling this CS1 used in USB_MSD post of yours.
it shows compile time error around this macro precisely the error looks something like this
”
Invoking: Cross ARM C Compiler
arm-none-eabi-gcc -mcpu=cortex-m0plus -mthumb -O0 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -g3 -I”C:\Program Files\eclipse\eclipse\ProcessorExpert/lib/Kinetis/pdd/inc” -I”C:\Program Files\eclipse\eclipse\ProcessorExpert/lib/Kinetis/iofiles” -I”C:/Freescale/workspace/PE_Blinky/Sources” -I”C:/Freescale/workspace/PE_Blinky/Generated_Code” -std=c99 -MMD -MP -MF”Generated_Code/CLS1.d” -MT”Generated_Code/CLS1.o” -c -o “Generated_Code/CLS1.o” “../Generated_Code/CLS1.c”
../Generated_Code/CLS1.c: In function ‘CLS1_ReadChar’:
../Generated_Code/CLS1.c:704:3: warning: implicit declaration of function ‘asm’ [-Wimplicit-function-declaration]
CS1_EnterCriticalDrv();
^
In file included from ../Generated_Code/CLS1.c:87:0:
../Generated_Code/CS1.h:81:5: error: expected ‘)’ before ‘:’ token
: [output] “=m” (cpuSR) :: “r0″); \
^
../Generated_Code/CS1.h:58:3: note: in expansion of macro ‘CS1_EnterCritical’
CS1_EnterCritical()
”
Please let me know how to tackle this issue.
LikeLike
Hi Devidas,
can you confirm that you have loaded my latest *.PEupd files from GitHub (see https://mcuoneclipse.com/2013/05/09/processor-expert-component-peupd-files-on-github/)? I ask as I have replaced asm() with __asm() as if you enable ‘strict’ ANSI options, then the compiler expects __asm.
Otherwise, you should be able to change the compiler settings. In the project properties (C/C++ Build > Settings > Tool Settings > Cross ARM C Compiler > Optimization) set the language standard to ‘GNU ISO C90’ (toolchain default).
I hope this helps?
LikeLike
hi Erich
this is very good thing i experienced about this site
thank you for such quick reply
and by the way GNU ISO C90′ (toolchain default) did work with me
and one good thing happen
as I am exposed to this thing i researched bit about extended assembly
so that is positive side of this
Thanx again for this help
LikeLike