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:
- #include "stdint.h"
- #include "system_stm32f4xx.h"
- #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:
- /* start address for the initialization values of the .data section. defined in linker script */
- extern uint32_t _sidata;
- /* start address for the .data section. defined in linker script */
- extern uint32_t _sdata;
- /* end address for the .data section. defined in linker script */
- extern uint32_t _edata;
- /* start address for the .bss section. defined in linker script */
- extern uint32_t _sbss;
- /* end address for the .bss section. defined in linker script */
- extern uint32_t _ebss;
- /* stack used for SystemInit_ExtMemCtl; always internal RAM used */
- extern uint32_t _estack;
Dalej należy umieścić deklarację zewnętrznych funkcji:
- extern void __libc_init_array();
- 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.
- void Default_Handler(void) {
- while(1) {
- }
- }
W przypadku pierwszej z wymienionych funkcji należy się nieco bardziej wysilić.
- .section .text.Reset_Handler
- .weak Reset_Handler
- .type Reset_Handler, %function
- Reset_Handler:
- ldr sp, =_estack /* set stack pointer */
- /* Copy the data segment initializers from flash to SRAM */
- ldr r0, =_sdata
- ldr r1, =_edata
- ldr r2, =_sidata
- movs r3, #0
- b LoopCopyDataInit
- CopyDataInit:
- ldr r4, [r2, r3]
- str r4, [r0, r3]
- adds r3, r3, #4
- LoopCopyDataInit:
- adds r4, r0, r3
- cmp r4, r1
- bcc CopyDataInit
- /* Zero fill the bss segment. */
- ldr r2, =_sbss
- ldr r4, =_ebss
- movs r3, #0
- b LoopFillZerobss
- FillZerobss:
- str r3, [r2]
- adds r2, r2, #4
- LoopFillZerobss:
- cmp r2, r4
- bcc FillZerobss
- /* Call the clock system intitialization function.*/
- bl SystemInit
- /* Call static constructors */
- bl __libc_init_array
- /* Call the application's entry point.*/
- bl main
- bx lr
- .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:
- void Reset_Handler() {
- __asm("ldr sp, =_estack");
- // Initialize data segment
- volatile uint32_t *dataInit = &_sidata;
- volatile uint32_t *data = &_sdata;
- /* Copy the data segment initializers from flash to SRAM */
- while(data < &_edata) {
- *data++ = *dataInit++;
- }
- /* Zero fill the bss segment. */
- volatile uint32_t *bss = &_sbss;
- while(bss < &_ebss) {
- *bss++ = 0;
- }
- /* Call the clock system intitialization function.*/
- SystemInit();
- /* Call static constructors */
- __libc_init_array();
- /* Call the application's entry point.*/
- main();
- }
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();
- __weak void NMI_Handler(void) { Default_Handler(); }
- __weak void HardFault_Handler(void) { Default_Handler(); }
- __weak void MemManage_Handler(void) { Default_Handler(); }
- __weak void BusFault_Handler(void) { Default_Handler(); }
- __weak void UsageFault_Handler(void) { Default_Handler(); }
- __weak void SVC_Handler(void) { Default_Handler(); }
- __weak void DebugMon_Handler(void) { Default_Handler(); }
- __weak void PendSV_Handler(void) { Default_Handler(); }
- __weak void SysTick_Handler(void) { Default_Handler(); }
- __weak void WWDG_IRQHandler(void) { Default_Handler(); }
- __weak void PVD_IRQHandler(void) { Default_Handler(); }
- __weak void TAMP_STAMP_IRQHandler(void) { Default_Handler(); }
- __weak void RTC_WKUP_IRQHandler(void) { Default_Handler(); }
- __weak void FLASH_IRQHandler(void) { Default_Handler(); }
- __weak void RCC_IRQHandler(void) { Default_Handler(); }
- __weak void EXTI0_IRQHandler(void) { Default_Handler(); }
- __weak void EXTI1_IRQHandler(void) { Default_Handler(); }
- __weak void EXTI2_IRQHandler(void) { Default_Handler(); }
- __weak void EXTI3_IRQHandler(void) { Default_Handler(); }
- __weak void EXTI4_IRQHandler(void) { Default_Handler(); }
- __weak void DMA1_Stream0_IRQHandler(void) { Default_Handler(); }
- __weak void DMA1_Stream1_IRQHandler(void) { Default_Handler(); }
- __weak void DMA1_Stream2_IRQHandler(void) { Default_Handler(); }
- __weak void DMA1_Stream3_IRQHandler(void) { Default_Handler(); }
- __weak void DMA1_Stream4_IRQHandler(void) { Default_Handler(); }
- __weak void DMA1_Stream5_IRQHandler(void) { Default_Handler(); }
- __weak void DMA1_Stream6_IRQHandler(void) { Default_Handler(); }
- __weak void ADC_IRQHandler(void) { Default_Handler(); }
- __weak void CAN1_TX_IRQHandler(void) { Default_Handler(); }
- __weak void CAN1_RX0_IRQHandler(void) { Default_Handler(); }
- __weak void CAN1_RX1_IRQHandler(void) { Default_Handler(); }
- __weak void CAN1_SCE_IRQHandler(void) { Default_Handler(); }
- __weak void EXTI9_5_IRQHandler(void) { Default_Handler(); }
- __weak void TIM1_BRK_TIM9_IRQHandler(void) { Default_Handler(); }
- __weak void TIM1_UP_TIM10_IRQHandler(void) { Default_Handler(); }
- __weak void TIM1_TRG_COM_TIM11_IRQHandler(void) { Default_Handler(); }
- __weak void TIM1_CC_IRQHandler(void) { Default_Handler(); }
- __weak void TIM2_IRQHandler(void) { Default_Handler(); }
- __weak void TIM3_IRQHandler(void) { Default_Handler(); }
- __weak void TIM4_IRQHandler(void) { Default_Handler(); }
- __weak void I2C1_EV_IRQHandler(void) { Default_Handler(); }
- __weak void I2C1_ER_IRQHandler(void) { Default_Handler(); }
- __weak void I2C2_EV_IRQHandler(void) { Default_Handler(); }
- __weak void I2C2_ER_IRQHandler(void) { Default_Handler(); }
- __weak void SPI1_IRQHandler(void) { Default_Handler(); }
- __weak void SPI2_IRQHandler(void) { Default_Handler(); }
- __weak void USART1_IRQHandler(void) { Default_Handler(); }
- __weak void USART2_IRQHandler(void) { Default_Handler(); }
- __weak void USART3_IRQHandler(void) { Default_Handler(); }
- __weak void EXTI15_10_IRQHandler(void) { Default_Handler(); }
- __weak void RTC_Alarm_IRQHandler(void) { Default_Handler(); }
- __weak void OTG_FS_WKUP_IRQHandler(void) { Default_Handler(); }
- __weak void TIM8_BRK_TIM12_IRQHandler(void) { Default_Handler(); }
- __weak void TIM8_UP_TIM13_IRQHandler(void) { Default_Handler(); }
- __weak void TIM8_TRG_COM_TIM14_IRQHandler(void) { Default_Handler(); }
- __weak void TIM8_CC_IRQHandler(void) { Default_Handler(); }
- __weak void DMA1_Stream7_IRQHandler(void) { Default_Handler(); }
- __weak void FSMC_IRQHandler(void) { Default_Handler(); }
- __weak void SDIO_IRQHandler(void) { Default_Handler(); }
- __weak void TIM5_IRQHandler(void) { Default_Handler(); }
- __weak void SPI3_IRQHandler(void) { Default_Handler(); }
- __weak void UART4_IRQHandler(void) { Default_Handler(); }
- __weak void UART5_IRQHandler(void) { Default_Handler(); }
- __weak void TIM6_DAC_IRQHandler(void) { Default_Handler(); }
- __weak void TIM7_IRQHandler(void) { Default_Handler(); }
- __weak void DMA2_Stream0_IRQHandler(void) { Default_Handler(); }
- __weak void DMA2_Stream1_IRQHandler(void) { Default_Handler(); }
- __weak void DMA2_Stream2_IRQHandler(void) { Default_Handler(); }
- __weak void DMA2_Stream3_IRQHandler(void) { Default_Handler(); }
- __weak void DMA2_Stream4_IRQHandler(void) { Default_Handler(); }
- __weak void ETH_IRQHandler(void) { Default_Handler(); }
- __weak void ETH_WKUP_IRQHandler(void) { Default_Handler(); }
- __weak void CAN2_TX_IRQHandler(void) { Default_Handler(); }
- __weak void CAN2_RX0_IRQHandler(void) { Default_Handler(); }
- __weak void CAN2_RX1_IRQHandler(void) { Default_Handler(); }
- __weak void CAN2_SCE_IRQHandler(void) { Default_Handler(); }
- __weak void OTG_FS_IRQHandler(void) { Default_Handler(); }
- __weak void DMA2_Stream5_IRQHandler(void) { Default_Handler(); }
- __weak void DMA2_Stream6_IRQHandler(void) { Default_Handler(); }
- __weak void DMA2_Stream7_IRQHandler(void) { Default_Handler(); }
- __weak void USART6_IRQHandler(void) { Default_Handler(); }
- __weak void I2C3_EV_IRQHandler(void) { Default_Handler(); }
- __weak void I2C3_ER_IRQHandler(void) { Default_Handler(); }
- __weak void OTG_HS_EP1_OUT_IRQHandler(void) { Default_Handler(); }
- __weak void OTG_HS_EP1_IN_IRQHandler(void) { Default_Handler(); }
- __weak void OTG_HS_WKUP_IRQHandler(void) { Default_Handler(); }
- __weak void OTG_HS_IRQHandler(void) { Default_Handler(); }
- __weak void DCMI_IRQHandler(void) { Default_Handler(); }
- __weak void CRYP_IRQHandler(void) { Default_Handler(); }
- __weak void HASH_RNG_IRQHandler(void) { Default_Handler(); }
- __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:
- void NMI_Handler(void) { while (1) { } }
- void HardFault_Handler(void) { while (1) { } }
- void MemManage_Handler(void) { while (1) { } }
- void BusFault_Handler(void) { while (1) { } }
- void UsageFault_Handler(void) { while (1) { } }
- void SVC_Handler(void) { while (1) { } }
- void DebugMon_Handler(void) { while (1) { } }
- void PendSV_Handler(void) { while (1) { } }
- 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:
- __attribute__((section(".isr_vector")))
- const void (*VectorTable[])(void) = {
- (const void (*)(void))&_estack,
- Reset_Handler,
- NMI_Handler,
- HardFault_Handler,
- MemManage_Handler,
- BusFault_Handler,
- UsageFault_Handler,
- 0, 0, 0, 0, //Reserved
- SVC_Handler,
- DebugMon_Handler,
- 0,
- PendSV_Handler,
- SysTick_Handler,
- /* External Interrupts */
- WWDG_IRQHandler, /* Window WatchDog */
- PVD_IRQHandler, /* PVD through EXTI Line detection */
- TAMP_STAMP_IRQHandler, /* Tamper and TimeStamps through the EXTI line */
- RTC_WKUP_IRQHandler, /* RTC Wakeup through the EXTI line */
- FLASH_IRQHandler, /* FLASH */
- RCC_IRQHandler, /* RCC */
- EXTI0_IRQHandler, /* EXTI Line0 */
- EXTI1_IRQHandler , /* EXTI Line1 */
- EXTI2_IRQHandler, /* EXTI Line2 */
- EXTI3_IRQHandler, /* EXTI Line3 */
- EXTI4_IRQHandler, /* EXTI Line4 */
- DMA1_Stream0_IRQHandler, /* DMA1 Stream 0 */
- DMA1_Stream1_IRQHandler, /* DMA1 Stream 1 */
- DMA1_Stream2_IRQHandler, /* DMA1 Stream 2 */
- DMA1_Stream3_IRQHandler, /* DMA1 Stream 3 */
- DMA1_Stream4_IRQHandler, /* DMA1 Stream 4 */
- DMA1_Stream5_IRQHandler, /* DMA1 Stream 5 */
- DMA1_Stream6_IRQHandler, /* DMA1 Stream 6 */
- ADC_IRQHandler, /* ADC1, ADC2 and ADC3s */
- CAN1_TX_IRQHandler, /* CAN1 TX */
- CAN1_RX0_IRQHandler, /* CAN1 RX0 */
- CAN1_RX1_IRQHandler, /* CAN1 RX1 */
- CAN1_SCE_IRQHandler, /* CAN1 SCE */
- EXTI9_5_IRQHandler, /* External Line[9:5]s */
- TIM1_BRK_TIM9_IRQHandler, /* TIM1 Break and TIM9 */
- TIM1_UP_TIM10_IRQHandler, /* TIM1 Update and TIM10 */
- TIM1_TRG_COM_TIM11_IRQHandler, /* TIM1 Trigger and Commutation and TIM11 */
- TIM1_CC_IRQHandler, /* TIM1 Capture Compare */
- TIM2_IRQHandler, /* TIM2 */
- TIM3_IRQHandler, /* TIM3 */
- TIM4_IRQHandler, /* TIM4 */
- I2C1_EV_IRQHandler, /* I2C1 Event */
- I2C1_ER_IRQHandler, /* I2C1 Error */
- I2C2_EV_IRQHandler, /* I2C2 Event */
- I2C2_ER_IRQHandler, /* I2C2 Error */
- SPI1_IRQHandler, /* SPI1 */
- SPI2_IRQHandler, /* SPI2 */
- USART1_IRQHandler, /* USART1 */
- USART2_IRQHandler, /* USART2 */
- USART3_IRQHandler, /* USART3 */
- EXTI15_10_IRQHandler, /* External Line[15:10]s */
- RTC_Alarm_IRQHandler, /* RTC Alarm (A and B) through EXTI Line */
- OTG_FS_WKUP_IRQHandler, /* USB OTG FS Wakeup through EXTI line */
- TIM8_BRK_TIM12_IRQHandler, /* TIM8 Break and TIM12 */
- TIM8_UP_TIM13_IRQHandler, /* TIM8 Update and TIM13 */
- TIM8_TRG_COM_TIM14_IRQHandler, /* TIM8 Trigger and Commutation and TIM14 */
- TIM8_CC_IRQHandler, /* TIM8 Capture Compare */
- DMA1_Stream7_IRQHandler, /* DMA1 Stream7 */
- FSMC_IRQHandler, /* FSMC */
- SDIO_IRQHandler, /* SDIO */
- TIM5_IRQHandler, /* TIM5 */
- SPI3_IRQHandler, /* SPI3 */
- UART4_IRQHandler, /* UART4 */
- UART5_IRQHandler, /* UART5 */
- TIM6_DAC_IRQHandler, /* TIM6 and DAC1&2 underrun errors */
- TIM7_IRQHandler, /* TIM7 */
- DMA2_Stream0_IRQHandler, /* DMA2 Stream 0 */
- DMA2_Stream1_IRQHandler, /* DMA2 Stream 1 */
- DMA2_Stream2_IRQHandler, /* DMA2 Stream 2 */
- DMA2_Stream3_IRQHandler, /* DMA2 Stream 3 */
- DMA2_Stream4_IRQHandler, /* DMA2 Stream 4 */
- ETH_IRQHandler, /* Ethernet */
- ETH_WKUP_IRQHandler, /* Ethernet Wakeup through EXTI line */
- CAN2_TX_IRQHandler, /* CAN2 TX */
- CAN2_RX0_IRQHandler, /* CAN2 RX0 */
- CAN2_RX1_IRQHandler, /* CAN2 RX1 */
- CAN2_SCE_IRQHandler, /* CAN2 SCE */
- OTG_FS_IRQHandler, /* USB OTG FS */
- DMA2_Stream5_IRQHandler, /* DMA2 Stream 5 */
- DMA2_Stream6_IRQHandler, /* DMA2 Stream 6 */
- DMA2_Stream7_IRQHandler, /* DMA2 Stream 7 */
- USART6_IRQHandler, /* USART6 */
- I2C3_EV_IRQHandler, /* I2C3 event */
- I2C3_ER_IRQHandler, /* I2C3 error */
- OTG_HS_EP1_OUT_IRQHandler, /* USB OTG HS End Point 1 Out */
- OTG_HS_EP1_IN_IRQHandler, /* USB OTG HS End Point 1 In */
- OTG_HS_WKUP_IRQHandler, /* USB OTG HS Wakeup through EXTI */
- OTG_HS_IRQHandler, /* USB OTG HS */
- DCMI_IRQHandler, /* DCMI */
- CRYP_IRQHandler, /* CRYP crypto */
- HASH_RNG_IRQHandler, /* Hash and Rng */
- FPU_IRQHandler /* FPU */
- };
Plik startup do pobrania z dysku Google pod tym linkiem.