Skip to main content
Franzi.Edo
Senior
April 15, 2017
Question

stm32L476 buggy package

  • April 15, 2017
  • 6 replies
  • 933 views
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

    This topic has been closed for replies.

    6 replies

    Tesla DeLorean
    Guru
    April 15, 2017
    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 (See Profile) Up vote any posts that you find helpful, it shows what's working..
    Franzi.Edo
    Senior
    April 15, 2017
    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.

    Jan Waclawek
    Visitor II
    April 15, 2017
    Posted on April 15, 2017 at 23:59

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

    JW

    Franzi.Edo
    Senior
    April 17, 2017
    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

       );

    }

    waclawek.jan
    Super User
    April 17, 2017
    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.