piątek, 22 kwietnia 2022

STM32 - Startup File w C

Ten post jest kontynuacją poprzedniego dotyczącego pliku startup w mikrokontrolerze STM32F4. W tym poście przygotuję ten plik w języku C. 


[Źródło: http://www.st.com/en/evaluation-tools/stm32f4discovery.html]

Poniżej przejdę przez poszczególne elementy jakie musiały zostać przygotowane aby plik startup w języku C działał poprawnie.

Na samym początku należy dołączyć biblioteki jakie będą obsługiwane przez ten plik:

  1. #include "stdint.h"
  2. #include "system_stm32f4xx.h"
  3. #include "stm32f4xx.h"

Następnie informujemy o adresach danych w pamięci mikrokontrolera. Musi być ona zdefiniowana jako extern. Ponieważ wszystkie adresy w pamięci zostały opisane w pliku STM32f407vgtx_flash.ld:

  1. /* start address for the initialization values of the .data section. defined in linker script */
  2. extern uint32_t _sidata;
  3. /* start address for the .data section. defined in linker script */  
  4. extern uint32_t _sdata;
  5. /* end address for the .data section. defined in linker script */
  6. extern uint32_t _edata;
  7. /* start address for the .bss section. defined in linker script */
  8. extern uint32_t _sbss;
  9. /* end address for the .bss section. defined in linker script */
  10. extern uint32_t _ebss;
  11. /* stack used for SystemInit_ExtMemCtl; always internal RAM used */
  12. extern uint32_t _estack;

Dalej należy umieścić deklarację zewnętrznych funkcji:

  1. extern void __libc_init_array();
  2. extern int main();

Kolejnym elementem jest zdefiniowanie funkcji Reset_Handler() oraz Default_Handler().

Druga z nich jest prosta w implementacji, wymaga jedynie umieszczenia pętli nieskończonej tak aby w przypadku wygenerowania nieobsługiwanego przerwania program zakończył w niej działanie. 

  1. void Default_Handler(void) {
  2.     while(1) {
  3.     }
  4. }

W przypadku pierwszej z wymienionych funkcji należy się nieco bardziej wysilić. 

  1.     .section  .text.Reset_Handler
  2.   .weak  Reset_Handler
  3.   .type  Reset_Handler, %function
  4. Reset_Handler:  
  5.   ldr   sp, =_estack     /* set stack pointer */
  6.  
  7. /* Copy the data segment initializers from flash to SRAM */  
  8.   ldr r0, =_sdata
  9.   ldr r1, =_edata
  10.   ldr r2, =_sidata
  11.   movs r3, #0
  12.   b LoopCopyDataInit
  13.  
  14. CopyDataInit:
  15.   ldr r4, [r2, r3]
  16.   str r4, [r0, r3]
  17.   adds r3, r3, #4
  18.  
  19. LoopCopyDataInit:
  20.   adds r4, r0, r3
  21.   cmp r4, r1
  22.   bcc CopyDataInit
  23.  
  24. /* Zero fill the bss segment. */
  25.   ldr r2, =_sbss
  26.   ldr r4, =_ebss
  27.   movs r3, #0
  28.   b LoopFillZerobss
  29.  
  30. FillZerobss:
  31.   str  r3, [r2]
  32.   adds r2, r2, #4
  33.  
  34. LoopFillZerobss:
  35.   cmp r2, r4
  36.   bcc FillZerobss
  37.  
  38. /* Call the clock system intitialization function.*/
  39.   bl  SystemInit  
  40. /* Call static constructors */
  41.     bl __libc_init_array
  42. /* Call the application's entry point.*/
  43.   bl  main
  44.   bx  lr    
  45. .size  Reset_Handler, .-Reset_Handler

Powyższa funkcja wykonuje następujące elementy:

  • ustawia wskaźnik pamięci na adres stosu,
  • kopiuje dane z flash do SRAM,
  • wprowadza wartości 0 do segmentu bss,
  • wywołanie funkcji inicjalizującej FPU, dane w pamięci zewnętrznej (DataInExtSRAM / SDRAM) czy tablicę wektorów (USER_VECT_TAB_ADDRESS). W zależności od konfiguracji.
  • wywołanie funkcji __libc_init_array(), która pozwala na inicjalizację podstawowych bibliotek języka C.
  • ostatnim elementem jest wywołanie funkcji main(), czyli początku aplikacji.

Poniżej implementacja funkcji Reset_Handler() w języku C:

  1. void Reset_Handler() {
  2.     __asm("ldr   sp, =_estack");
  3.  
  4.     // Initialize data segment
  5.     volatile uint32_t *dataInit = &_sidata;
  6.     volatile uint32_t *data = &_sdata;
  7.  
  8.     /* Copy the data segment initializers from flash to SRAM */
  9.     while(data < &_edata) {
  10.         *data++ = *dataInit++;
  11.     }
  12.  
  13.     /* Zero fill the bss segment. */
  14.     volatile uint32_t *bss = &_sbss;
  15.     while(bss < &_ebss) {
  16.         *bss++ = 0;
  17.     }
  18.  
  19.     /* Call the clock system intitialization function.*/
  20.     SystemInit();
  21.  
  22.     /* Call static constructors */
  23.     __libc_init_array();
  24.  
  25.     /* Call the application's entry point.*/
  26.     main();
  27. }
  28.  

Następnie należy wprowadzić deklarację funkcji obsługującej przerwania. Są one zdefiniowane jako __weak, czyli w przypadku wpisaniu innej funkcji zostanie ona nadpisana. Jeśli nie zostanie ona zastąpiona inną obsługą przerwania to wywołanie zostanie wykonane przez funkcję Default_Hander();

  1. __weak void NMI_Handler(void)                   { Default_Handler(); }
  2. __weak void HardFault_Handler(void)             { Default_Handler(); }
  3. __weak void MemManage_Handler(void)             { Default_Handler(); }
  4. __weak void BusFault_Handler(void)              { Default_Handler(); }
  5. __weak void UsageFault_Handler(void)            { Default_Handler(); }
  6. __weak void SVC_Handler(void)                   { Default_Handler(); }
  7. __weak void DebugMon_Handler(void)              { Default_Handler(); }
  8. __weak void PendSV_Handler(void)                { Default_Handler(); }
  9. __weak void SysTick_Handler(void)               { Default_Handler(); }
  10. __weak void WWDG_IRQHandler(void)               { Default_Handler(); }
  11. __weak void PVD_IRQHandler(void)                { Default_Handler(); }
  12. __weak void TAMP_STAMP_IRQHandler(void)         { Default_Handler(); }
  13. __weak void RTC_WKUP_IRQHandler(void)           { Default_Handler(); }
  14. __weak void FLASH_IRQHandler(void)              { Default_Handler(); }
  15. __weak void RCC_IRQHandler(void)                { Default_Handler(); }
  16. __weak void EXTI0_IRQHandler(void)              { Default_Handler(); }
  17. __weak void EXTI1_IRQHandler(void)              { Default_Handler(); }
  18. __weak void EXTI2_IRQHandler(void)              { Default_Handler(); }
  19. __weak void EXTI3_IRQHandler(void)              { Default_Handler(); }
  20. __weak void EXTI4_IRQHandler(void)              { Default_Handler(); }
  21. __weak void DMA1_Stream0_IRQHandler(void)       { Default_Handler(); }
  22. __weak void DMA1_Stream1_IRQHandler(void)       { Default_Handler(); }
  23. __weak void DMA1_Stream2_IRQHandler(void)       { Default_Handler(); }
  24. __weak void DMA1_Stream3_IRQHandler(void)       { Default_Handler(); }
  25. __weak void DMA1_Stream4_IRQHandler(void)       { Default_Handler(); }
  26. __weak void DMA1_Stream5_IRQHandler(void)       { Default_Handler(); }
  27. __weak void DMA1_Stream6_IRQHandler(void)       { Default_Handler(); }
  28. __weak void ADC_IRQHandler(void)                { Default_Handler(); }
  29. __weak void CAN1_TX_IRQHandler(void)            { Default_Handler(); }
  30. __weak void CAN1_RX0_IRQHandler(void)           { Default_Handler(); }
  31. __weak void CAN1_RX1_IRQHandler(void)           { Default_Handler(); }
  32. __weak void CAN1_SCE_IRQHandler(void)           { Default_Handler(); }
  33. __weak void EXTI9_5_IRQHandler(void)            { Default_Handler(); }
  34. __weak void TIM1_BRK_TIM9_IRQHandler(void)      { Default_Handler(); }
  35. __weak void TIM1_UP_TIM10_IRQHandler(void)      { Default_Handler(); }
  36. __weak void TIM1_TRG_COM_TIM11_IRQHandler(void) { Default_Handler(); }
  37. __weak void TIM1_CC_IRQHandler(void)            { Default_Handler(); }
  38. __weak void TIM2_IRQHandler(void)               { Default_Handler(); }
  39. __weak void TIM3_IRQHandler(void)               { Default_Handler(); }
  40. __weak void TIM4_IRQHandler(void)               { Default_Handler(); }
  41. __weak void I2C1_EV_IRQHandler(void)            { Default_Handler(); }
  42. __weak void I2C1_ER_IRQHandler(void)            { Default_Handler(); }
  43. __weak void I2C2_EV_IRQHandler(void)            { Default_Handler(); }
  44. __weak void I2C2_ER_IRQHandler(void)            { Default_Handler(); }
  45. __weak void SPI1_IRQHandler(void)               { Default_Handler(); }
  46. __weak void SPI2_IRQHandler(void)               { Default_Handler(); }
  47. __weak void USART1_IRQHandler(void)             { Default_Handler(); }
  48. __weak void USART2_IRQHandler(void)             { Default_Handler(); }
  49. __weak void USART3_IRQHandler(void)             { Default_Handler(); }
  50. __weak void EXTI15_10_IRQHandler(void)          { Default_Handler(); }
  51. __weak void RTC_Alarm_IRQHandler(void)          { Default_Handler(); }
  52. __weak void OTG_FS_WKUP_IRQHandler(void)        { Default_Handler(); }
  53. __weak void TIM8_BRK_TIM12_IRQHandler(void)     { Default_Handler(); }
  54. __weak void TIM8_UP_TIM13_IRQHandler(void)      { Default_Handler(); }
  55. __weak void TIM8_TRG_COM_TIM14_IRQHandler(void) { Default_Handler(); }
  56. __weak void TIM8_CC_IRQHandler(void)            { Default_Handler(); }
  57. __weak void DMA1_Stream7_IRQHandler(void)       { Default_Handler(); }
  58. __weak void FSMC_IRQHandler(void)               { Default_Handler(); }
  59. __weak void SDIO_IRQHandler(void)               { Default_Handler(); }
  60. __weak void TIM5_IRQHandler(void)               { Default_Handler(); }
  61. __weak void SPI3_IRQHandler(void)               { Default_Handler(); }
  62. __weak void UART4_IRQHandler(void)              { Default_Handler(); }
  63. __weak void UART5_IRQHandler(void)              { Default_Handler(); }
  64. __weak void TIM6_DAC_IRQHandler(void)           { Default_Handler(); }
  65. __weak void TIM7_IRQHandler(void)               { Default_Handler(); }
  66. __weak void DMA2_Stream0_IRQHandler(void)       { Default_Handler(); }
  67. __weak void DMA2_Stream1_IRQHandler(void)       { Default_Handler(); }
  68. __weak void DMA2_Stream2_IRQHandler(void)       { Default_Handler(); }
  69. __weak void DMA2_Stream3_IRQHandler(void)       { Default_Handler(); }
  70. __weak void DMA2_Stream4_IRQHandler(void)       { Default_Handler(); }
  71. __weak void ETH_IRQHandler(void)                { Default_Handler(); }
  72. __weak void ETH_WKUP_IRQHandler(void)           { Default_Handler(); }
  73. __weak void CAN2_TX_IRQHandler(void)            { Default_Handler(); }
  74. __weak void CAN2_RX0_IRQHandler(void)           { Default_Handler(); }
  75. __weak void CAN2_RX1_IRQHandler(void)           { Default_Handler(); }
  76. __weak void CAN2_SCE_IRQHandler(void)           { Default_Handler(); }
  77. __weak void OTG_FS_IRQHandler(void)             { Default_Handler(); }
  78. __weak void DMA2_Stream5_IRQHandler(void)       { Default_Handler(); }
  79. __weak void DMA2_Stream6_IRQHandler(void)       { Default_Handler(); }
  80. __weak void DMA2_Stream7_IRQHandler(void)       { Default_Handler(); }
  81. __weak void USART6_IRQHandler(void)             { Default_Handler(); }
  82. __weak void I2C3_EV_IRQHandler(void)            { Default_Handler(); }
  83. __weak void I2C3_ER_IRQHandler(void)            { Default_Handler(); }
  84. __weak void OTG_HS_EP1_OUT_IRQHandler(void)     { Default_Handler(); }
  85. __weak void OTG_HS_EP1_IN_IRQHandler(void)      { Default_Handler(); }
  86. __weak void OTG_HS_WKUP_IRQHandler(void)        { Default_Handler(); }
  87. __weak void OTG_HS_IRQHandler(void)             { Default_Handler(); }
  88. __weak void DCMI_IRQHandler(void)               { Default_Handler(); }
  89. __weak void CRYP_IRQHandler(void)               { Default_Handler(); }
  90. __weak void HASH_RNG_IRQHandler(void)           { Default_Handler(); }
  91. __weak void FPU_IRQHandler(void)                { Default_Handler(); }

Podstawowe funkcje obsługujące przerwania systemowe została zdefiniowana w pliku stm32f4xx_it.c. Do niej trafiają także wygenerowane przez CubeMx funkcje obsługujące przerwania zewnętrzne:

  1. void NMI_Handler(void) { while (1) {  } }
  2. void HardFault_Handler(void) { while (1) {  } }
  3. void MemManage_Handler(void)  { while (1) {  } }
  4. void BusFault_Handler(void)  { while (1) {  } }
  5. void UsageFault_Handler(void)  { while (1) {  } }
  6. void SVC_Handler(void)  { while (1) {  } }
  7. void DebugMon_Handler(void)  { while (1) {  } }
  8. void PendSV_Handler(void)  { while (1) {  } }
  9. void SysTick_Handler(void)  { while (1) {  } }

Ostatnim elementem w pliku jest tablica wektorów zawierająca informację z wartością początkową wskaźnika stosu, adresem startowym oraz wektorami przerwań dla wszystkich funkcji obsługi przerwania:

  1. __attribute__((section(".isr_vector")))
  2. const void (*VectorTable[])(void) = {
  3.     (const void (*)(void))&_estack,
  4.     Reset_Handler,
  5.     NMI_Handler,
  6.     HardFault_Handler,
  7.     MemManage_Handler,
  8.     BusFault_Handler,
  9.     UsageFault_Handler,
  10.     0, 0, 0, 0, //Reserved
  11.     SVC_Handler,
  12.     DebugMon_Handler,
  13.     0,
  14.     PendSV_Handler,
  15.     SysTick_Handler,
  16.  
  17.     /* External Interrupts */
  18.     WWDG_IRQHandler,                   /* Window WatchDog              */
  19.     PVD_IRQHandler,                    /* PVD through EXTI Line detection */
  20.     TAMP_STAMP_IRQHandler,             /* Tamper and TimeStamps through the EXTI line */
  21.     RTC_WKUP_IRQHandler,               /* RTC Wakeup through the EXTI line */
  22.     FLASH_IRQHandler,                  /* FLASH                        */
  23.     RCC_IRQHandler,                    /* RCC                          */
  24.     EXTI0_IRQHandler,                  /* EXTI Line0                   */
  25.     EXTI1_IRQHandler ,                 /* EXTI Line1                   */
  26.     EXTI2_IRQHandler,                  /* EXTI Line2                   */
  27.     EXTI3_IRQHandler,                  /* EXTI Line3                   */
  28.     EXTI4_IRQHandler,                  /* EXTI Line4                   */
  29.     DMA1_Stream0_IRQHandler,           /* DMA1 Stream 0                */
  30.     DMA1_Stream1_IRQHandler,           /* DMA1 Stream 1                */
  31.     DMA1_Stream2_IRQHandler,           /* DMA1 Stream 2                */
  32.     DMA1_Stream3_IRQHandler,           /* DMA1 Stream 3                */
  33.     DMA1_Stream4_IRQHandler,           /* DMA1 Stream 4                */
  34.     DMA1_Stream5_IRQHandler,           /* DMA1 Stream 5                */
  35.     DMA1_Stream6_IRQHandler,           /* DMA1 Stream 6                */
  36.     ADC_IRQHandler,                    /* ADC1, ADC2 and ADC3s         */
  37.     CAN1_TX_IRQHandler,               /* CAN1 TX                      */
  38.     CAN1_RX0_IRQHandler,              /* CAN1 RX0                     */
  39.     CAN1_RX1_IRQHandler,               /* CAN1 RX1                     */
  40.     CAN1_SCE_IRQHandler,              /* CAN1 SCE                     */
  41.     EXTI9_5_IRQHandler,                /* External Line[9:5]s          */
  42.     TIM1_BRK_TIM9_IRQHandler,          /* TIM1 Break and TIM9          */
  43.     TIM1_UP_TIM10_IRQHandler,          /* TIM1 Update and TIM10        */
  44.     TIM1_TRG_COM_TIM11_IRQHandler,     /* TIM1 Trigger and Commutation and TIM11 */
  45.     TIM1_CC_IRQHandler,                /* TIM1 Capture Compare         */
  46.     TIM2_IRQHandler,                   /* TIM2                         */
  47.     TIM3_IRQHandler,                   /* TIM3                         */
  48.     TIM4_IRQHandler,                   /* TIM4                         */
  49.     I2C1_EV_IRQHandler,                /* I2C1 Event                   */
  50.     I2C1_ER_IRQHandler,                /* I2C1 Error                   */
  51.     I2C2_EV_IRQHandler,                /* I2C2 Event                   */
  52.     I2C2_ER_IRQHandler,                /* I2C2 Error                   */
  53.     SPI1_IRQHandler,                  /* SPI1                         */
  54.     SPI2_IRQHandler,                  /* SPI2                         */
  55.     USART1_IRQHandler,                 /* USART1                       */
  56.     USART2_IRQHandler,                 /* USART2                       */
  57.     USART3_IRQHandler,                 /* USART3                       */
  58.     EXTI15_10_IRQHandler,              /* External Line[15:10]s        */
  59.     RTC_Alarm_IRQHandler,              /* RTC Alarm (A and B) through EXTI Line */
  60.     OTG_FS_WKUP_IRQHandler,            /* USB OTG FS Wakeup through EXTI line */
  61.     TIM8_BRK_TIM12_IRQHandler,         /* TIM8 Break and TIM12         */
  62.     TIM8_UP_TIM13_IRQHandler,          /* TIM8 Update and TIM13        */
  63.     TIM8_TRG_COM_TIM14_IRQHandler,     /* TIM8 Trigger and Commutation and TIM14 */
  64.     TIM8_CC_IRQHandler,                /* TIM8 Capture Compare         */
  65.     DMA1_Stream7_IRQHandler,           /* DMA1 Stream7                 */
  66.     FSMC_IRQHandler,                   /* FSMC                         */
  67.     SDIO_IRQHandler,                   /* SDIO                         */
  68.     TIM5_IRQHandler,                   /* TIM5                         */
  69.     SPI3_IRQHandler,                   /* SPI3                         */
  70.     UART4_IRQHandler,                  /* UART4                        */
  71.     UART5_IRQHandler,                  /* UART5                        */
  72.     TIM6_DAC_IRQHandler,               /* TIM6 and DAC1&2 underrun errors */
  73.     TIM7_IRQHandler,                   /* TIM7                         */
  74.     DMA2_Stream0_IRQHandler,           /* DMA2 Stream 0                */
  75.     DMA2_Stream1_IRQHandler,           /* DMA2 Stream 1                */
  76.     DMA2_Stream2_IRQHandler,           /* DMA2 Stream 2                */
  77.     DMA2_Stream3_IRQHandler,           /* DMA2 Stream 3                */
  78.     DMA2_Stream4_IRQHandler,           /* DMA2 Stream 4                */
  79.     ETH_IRQHandler,                    /* Ethernet                     */
  80.     ETH_WKUP_IRQHandler,               /* Ethernet Wakeup through EXTI line */
  81.     CAN2_TX_IRQHandler,               /* CAN2 TX                      */
  82.     CAN2_RX0_IRQHandler,               /* CAN2 RX0                     */
  83.     CAN2_RX1_IRQHandler,               /* CAN2 RX1                     */
  84.     CAN2_SCE_IRQHandler,               /* CAN2 SCE                     */
  85.     OTG_FS_IRQHandler,                 /* USB OTG FS                   */
  86.     DMA2_Stream5_IRQHandler,           /* DMA2 Stream 5                */
  87.     DMA2_Stream6_IRQHandler,           /* DMA2 Stream 6                */
  88.     DMA2_Stream7_IRQHandler,           /* DMA2 Stream 7                */
  89.     USART6_IRQHandler,                 /* USART6                       */
  90.     I2C3_EV_IRQHandler,                /* I2C3 event                   */
  91.     I2C3_ER_IRQHandler,                /* I2C3 error                   */
  92.     OTG_HS_EP1_OUT_IRQHandler,         /* USB OTG HS End Point 1 Out   */
  93.     OTG_HS_EP1_IN_IRQHandler,          /* USB OTG HS End Point 1 In    */
  94.     OTG_HS_WKUP_IRQHandler,            /* USB OTG HS Wakeup through EXTI */
  95.     OTG_HS_IRQHandler,                 /* USB OTG HS                   */
  96.     DCMI_IRQHandler,                   /* DCMI                         */
  97.     CRYP_IRQHandler,                   /* CRYP crypto                  */
  98.     HASH_RNG_IRQHandler,               /* Hash and Rng                 */
  99.     FPU_IRQHandler                     /* FPU                          */
  100. };

Plik startup do pobrania z dysku Google pod tym linkiem.