cancel
Showing results for 
Search instead for 
Did you mean: 

stm32L476 buggy package

Franzi.Edo
Senior
Posted on April 15, 2017 at 18:36

Dear all,

During a porting of an RTOS on a Discovery 476 board I discovered a serious problem with the stm32l476xx.h file provided by ST. All the elements of timers structure are defined as a 32-bits. So, after having spent a couple of hours in debugging my porting I discovered that some elements HAVE to be accessed in a

16-bits

and not in a

32-bits

. In particular, the SR register accessed in 32-bits crashe my system with an 'Hard Fault Exception'. In the documentation the SR register is described to be 16-bits. So, I modified the original structure of the package and now everything work as expected. Here is my modification.

The original package (that crash the interruption acknowledge)

typedef struct {

   ...

   volatile

uint32_t

SR;

   ...

} TIM_TypeDef;

The modified package (that works)

typedef struct {

   ...

   volatile

uint16_t

SR;

   volatile

uint16_t

RESERVED0;

   ...

} TIM_TypeDef;

I pointed different peripheral structures and I discovered that potentially I can have the same problem (of course, this depends on how the silicon supports the 32-bit accesses for 16-bit wide registers).

Now I have serious doubts regarding the quality of the packages provided by ST!

Regards

   Edo

6 REPLIES 6
Posted on April 15, 2017 at 20:37

I'm not using the L4's, but can't say I've seen the other STM32 parts being that sensitive.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on April 15, 2017 at 21:01

I have just tried on a stm32F777 and stm32F429 targets and those SoC seem to work fine with 32-bits and 16-bits accesses. For the moment only the stm32L476 seems to be sensitive to this problem.

Posted on April 15, 2017 at 23:59

Show us a minimal but complete compilable code exhibiting the problem.

JW

Posted on April 16, 2017 at 18:45

The stated issue as framed should be easy enough to replicate. I'd need to dig up a STM32L476G-DISCO

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Franzi.Edo
Senior
Posted on April 17, 2017 at 11:08

Hi Jan and Clive,

Not easy to debug. The problem is more nasty than expected. The crash occurs inside a software interruption responsible to pass parameters to a µKernel. It cannot be easily isolated. Here is the µKernel routine (in red the instructions that generate the Hard Fault Exception if the SR is accessed as 32-bit and not as 16-bits as reported in the documentation). The disassembled code do not emphasise possible problems.

Of course, you can download the entire package for testing at this location

http://www.ukos.ch

Thank you for your suggestions

Edo

/*!

* \brief EXTI3_IRQHandler

*

* - TRAP

* - Save the context

* - Save the context stack

* - Process the message sent

* - Change the context

* - Give another timeout to the process

* - Recover another context

*

* - Save the full stack frame (uKOS like)

*

* Normal stack frame Stack frame with fpu

* IOFF IOFF

*

* -> Message +36 +108

* -> Message +32 +104

*

* -> FPSCR

* -> S15..S0

* -> xPSR xPSR

* -> PC PC

* -> LR(R14) LR(R14)

* -> R12 R12

* -> R3..R0 R3..R0 Block stacked by an exception

*

* -> R11..R4 R11..R4

* -> BASEPRI BASEPRI

* -> S31..S16

* -> LR(R14) LR(R14) Block stacked manually

*

* !!! Do not generate prologue/epilogue sequences

*

*/

void EXTI3_IRQHandler(void) __attribute__ ((naked)) __attribute__ ((optimize('Os')));

void EXTI3_IRQHandler(void) {

// Interruption ACK

   EXTI->PR1 |= (1<<BKERNSWIMSG);

// Recover the swi message

// r0 contains the stack

   __asm__ volatile (

      'cpsid i              \n' //

      'mrs r0,psp           \n' // r0 = stack

      'add r1,r0,#36        \n' // r1 = message address (normal stack frame)

      'tst r14,#0x10        \n' //

      'it eq                \n' //

      'addeq r1,r0,#(36+72) \n' // r1 = message address (stack frame with fpu regs)

      'ldr r1,[r1]          \n' // r1 = message

      'str r1,%0            \n' // Save the message on the vKern_message location

      :

      : 'm' (vKern_message)

      : KSAVEREGISTERS

      );

// Save the registers r4..r11 and the basepri

// r0 contains the stack

   __asm__ volatile (

      'mrs r1,basepri         \n' // r1 = basepri

      'stmdb r0!,{r1,r4-r11}  \n' // Save the register list

      'tst r14,#0x10          \n' //

      'it eq                  \n' //

      'vstmdbeq r0!,{s16-s31} \n' // If used, save the fp registers

      'stmdb r0!,{r14}        \n' // Save the EXCEPTION return

      'msr psp,r0             \n' //

      'str r0,%0              \n' // Save the stack of the old process

      'cpsie i                \n' //

      :

      : 'm' (vKern_stackProcess)

      : KSAVEREGISTERS

   );

// INT acknowledge and new time for the next process

// Change the context and prepare the next process

// - Stop time of the process

// - Clear the interruption

// - Disable the timer

// - Change the context

// - Start time of the process

   _timeStop();

   if (TIM2->SR & TIM_SR_UIF) {

      TIM2->SR &= ~TIM_SR_UIF;

   

}

   TIM2->CR1 &= ~TIM_CR1_CEN;

   sche_callBackTrap(vKern_message);

   _timeStart();

   #if (defined(__WITHSTAT__))

   stat_statistic(vKern_backwardProcess, \

                  vTimeStart, vTimeStop, vTimeLastStart, vTimeException);

   vTimeException = 0;

   #endif

// Restore the registers r4..r11 and the basepri

   __asm__ volatile (

      'cpsid i                \n' //

      'ldr r0,%0              \n' // Recover the stack of the new process

      'ldmia r0!,{r14}        \n' // Recover the EXCEPTION return

      'tst r14,#0x10          \n' //

      'it eq                  \n' //

      'vldmiaeq r0!,{s16-s31} \n' // If used, restore the fp registers

      'ldmia r0!,{r1,r4-r11}  \n' // Restore the register list

      'msr psp,r0             \n' // New stack

      'msr basepri,r1         \n' // Restore the basepri

      :

      : 'm' (vKern_stackProcess)

      : KSAVEREGISTERS

   );

// Return

   __asm__ volatile (

      'cpsie I    \n' //

      'dmb        \n' //

      'dsb        \n' //

      'isb        \n' //

      'bx lr      \n' // Return

   );

}

Posted on April 18, 2017 at 01:56

I just tried to add

   if (TIM3->SR & TIM_SR_UIF) {

      TIM3->SR &= ~TIM_SR_UIF;

   

}

into while(1) loop in main() in the 'breathing blinky' for the 'L476 DISCO on www.efton.sk/STM32 . No change in behaviour, no hardfault.

I believe the change in behaviour after changing the access width is coincidental and the bug is elsewhere in your code. While TIMx_SR is indeed 16-bit, as are most of the TIM registers, RM0351 allows to access using 32-bit access (e.g. in 27.4, 'The peripheral registers can be accessed by half-words (16-bit) or words (32-bit).')

I recommend you to check the SCB's fault-related registers and properly track back the stack to the crash origin when the fault happens.

JW

PS. Not a problem here, but generally, don't RMW TIMx_SR to avoid risk of loss of a flag being set by HW during the RMW - just write a mask to clear the bits you want, they are deliberately of rc_w0 type.