Okay three big topics here: crt0 (also known as c0), crt1 (also known as c1), and the linking scripts. crt0 is the code that needs to run before your main, it sets up things like the stack. crt1 is the low level stuff that would normally be OS calls. I sorta simulate an OS because we don’t have one, so I simulate a heap and malloc, etc. The linking scripts tell the linker where to put things in the address space.
crt0
This is the code that executes before your main function gets called. Execution starts at 0000h (actually it may be a pointer on this implementation). But before one can actually run any C one has to do some set-up stuff. Traditionally one writes crt0 in assembly and indeed my original was in assembly. If your careful and don’t use certain C constructs you can write crt0 in c itself. There is heavy interaction with the linker script as we need to prepare things like the BSS, EBSS, stack etc. Remember C is gonna need to know where in the address space (which changes from implementation to implementation) things like RAM(rw), flash(ro) and heap are.
crt0.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
#include <stdlib.h> #include <string.h> #include <stm32f10x_conf.h> #include "irq.h" extern int main(); extern void* _estack; extern void* _sdata; extern void* _edata; extern void* _sidata; extern void* _sbss; extern void* _ebss; extern void* _eusrstack; void _start(); extern void _init_crt1(); /* IRQ vector table */ __attribute__ ((section(".isr_vector"))) struct configword_struct { const void* stackpointer; void (* const vectors[165])(void); } configword = { &_estack, { _start, NMIException, HardFaultException, MemManageException, BusFaultException, UsageFaultException, NULL, NULL, NULL, NULL, SVC_Handler, DebugMon_Handler, NULL, PendSV_Handler, SysTick_Handler, WWDG_IRQHandler, PVD_IRQHandler, TAMPER_IRQHandler, RTC_IRQHandler, FLASH_IRQHandler, RCC_IRQHandler, EXTI0_IRQHandler, EXTI1_IRQHandler, EXTI2_IRQHandler, EXTI3_IRQHandler, EXTI4_IRQHandler, DMA1_Channel1_IRQHandler, DMA1_Channel2_IRQHandler, DMA1_Channel3_IRQHandler, DMA1_Channel4_IRQHandler, DMA1_Channel5_IRQHandler, DMA1_Channel6_IRQHandler, DMA1_Channel7_IRQHandler, ADC1_2_IRQHandler, USB_HP_CAN1_TX_IRQHandler, USB_LP_CAN1_RX0_IRQHandler, CAN1_RX1_IRQHandler, CAN1_SCE_IRQHandler, EXTI9_5_IRQHandler, TIM1_BRK_IRQHandler, TIM1_UP_IRQHandler, TIM1_TRG_COM_IRQHandler, TIM1_CC_IRQHandler, TIM2_IRQHandler, TIM3_IRQHandler, TIM4_IRQHandler, I2C1_EV_IRQHandler, I2C1_ER_IRQHandler, I2C2_EV_IRQHandler, I2C2_ER_IRQHandler, SPI1_IRQHandler, SPI2_IRQHandler, USART1_IRQHandler, USART2_IRQHandler, USART3_IRQHandler, EXTI15_10_IRQHandler, RTCAlarm_IRQHandler, USBWakeUp_IRQHandler, TIM8_BRK_IRQHandler, TIM8_UP_IRQHandler, TIM8_TRG_COM_IRQHandler, TIM8_CC_IRQHandler, ADC3_IRQHandler, FSMC_IRQHandler, SDIO_IRQHandler, TIM5_IRQHandler, SPI3_IRQHandler, UART4_IRQHandler, UART5_IRQHandler, TIM6_IRQHandler, TIM7_IRQHandler, DMA2_Channel1_IRQHandler, DMA2_Channel2_IRQHandler, DMA2_Channel3_IRQHandler, DMA2_Channel4_5_IRQHandler, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; void null_driver_reset() { } void _start() { /* copy data segment from flash to ram */ { const size_t datalen = (size_t) &_edata - (unsigned int) &_sdata; memcpy(&_sdata, &_sidata, datalen); } /* zero out bss segment */ { const size_t bsslen = (size_t) &_ebss - (unsigned int) &_sbss; memset(&_sbss, 0x0, bsslen); } SystemInit(); /* set process stack */ __set_PSP((uint32_t) &_eusrstack); (void) _init_crt1(); (void) main(); } |
crt1
This is the low level operating system type stuff. Well, we don’t have one, but we’d still like things like printf and malloc to work or at least not crash. Remember after you call printf, somewhere down the pike some ascii (or unicode) has to go somewhere. In our case we’re going to output it to one of the UARTs. This is very convenient when debugging! This code took a long time to sort out and is incomplete. I got some of the stubs from the manufacturer. Recall that in a unix OS we would be opening files (in dev), reading from and writing to them but here we don’t have an OS or a file-system so we make some assumptions, lots of assumptions.
crt1.h
1 2 3 4 5 6 |
#ifndef __CRT1_H__ #define __CRT1_H__ void _init_crt1(); #endif /* __CRT1_H__ */ |
crt1.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
#include <stdint.h> #include <string.h> #include <errno.h> #include <sys/stat.h> #include "stm32f10x_usart.h" #include "irq.h" extern int8_t _sheap; extern int8_t _eheap; static const int8_t* eheap_p = &_eheap; static const int8_t* sheap_p = &_sheap; static intptr_t heap_ptr; size_t heap_peak = 0x0; long _write_r(struct _reent *_r, int fd, const void *buf, int cnt) { int n; const char *ptr = buf; for (n = 0; n < cnt; n++) { while ((USART2->SR & USART_FLAG_TC) == 0x0000); USART2->DR = (*ptr++ & 0x01FF); } return cnt; } long _read_r(struct _reent *_r, int fd, char *ptr, int len ) { while ((USART2->SR & USART_FLAG_RXNE) == 0x0000); *ptr = (char) (USART2->DR & 0x01FF); return 1; } off_t _lseek_r( struct _reent *_r, int fd, off_t pos, int whence ) { return 0; } int _isatty( struct _reent *_r, int fd) { return 1; } int _fstat_r ( struct _reent *_r, int fd, struct stat *pstat) { pstat->st_mode = S_IFCHR; return 0; } long _close_r(struct _reent *_r, int fd) { _r->_errno = EBADF; return -1; } /* int _open_r (struct _reent *_r, const char *file, int flags, int mode) { _r->_errno = ENODEV; return -1; } */ void *_sbrk_r(struct _reent *r, intptr_t incr) { void* retval = 0; intptr_t newbrk = (intptr_t)((size_t)heap_ptr + (size_t)incr); if(newbrk >= (intptr_t)eheap_p) { r->_errno = ENOMEM; retval = (void *)-1; } else { const size_t new_size = ((size_t)newbrk) - ((size_t)sheap_p); heap_peak = (heap_peak < new_size) ? new_size : heap_peak; retval = (void*)heap_ptr; heap_ptr = newbrk; } return retval; } void _init_crt1() { /* set the heap with 0xff */ { const size_t heapsize = ((size_t)(eheap_p)) - ((size_t)sheap_p); memset(&_sheap, 0xff, heapsize); heap_ptr = (const intptr_t)sheap_p; } } void _exit(int i) { while(1); } |
linker script
We need to tell the linker where to put things. What addresses correspond to RAM? What addresses correspond to ROM(flash)? Where’s the “heap”, how big is it.
stm32.ld
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
/* default stack sizes. These are used by the startup in order to allocate stacks for the different modes. */ ENTRY(_start) __Stack_Size = 1024 ; PROVIDE ( _Stack_Size = __Stack_Size ) ; __Stack_Init = _estack - __Stack_Size ; /*"PROVIDE" allows to easily override these values from an object file or the commmand line.*/ PROVIDE ( _Stack_Init = __Stack_Init ) ; _Heap_Size = 0x10000; /* There will be a link error if there is not this amount of RAM free at the end. */ _Minimum_Stack_Size = 0x100 ; /* include the memory spaces definitions sub-script */ /* Linker subscript for STM32F10x definitions with 512K Flash and 1024K RAM */ /* Memory Spaces Definitions */ MEMORY { RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0 EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0 EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0 EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0 } /* higher address of the user mode stack */ _estack = 0x20017fff; /* include the sections management sub-script for FLASH mode */ /* Sections Definitions */ SECTIONS { /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */ .isr_vector : { . = ALIGN(4); KEEP(*(.isr_vector)) /* Startup code */ . = ALIGN(4); } >FLASH /* the program code is stored in the .text section, which goes to Flash */ .text : { . = ALIGN(4); *(.text) /* remaining code */ *(.text.*) /* remaining code */ *(.rodata) /* read-only data (constants) */ *(.rodata*) *(.glue_7) *(.glue_7t) . = ALIGN(4); _etext = .; /* This is used by the startup in order to initialize the .data secion */ _sidata = _etext; } >FLASH /* This is the initialized data section The program executes knowing that the data is in the RAM but the loader puts the initial values in the FLASH (inidata). It is one task of the startup to copy the initial values from FLASH to RAM. */ .data : AT ( _sidata ) { . = ALIGN(4); /* This is used by the startup in order to initialize the .data secion */ _sdata = . ; *(.data) *(.data.*) . = ALIGN(4); /* This is used by the startup in order to initialize the .data secion */ _edata = . ; } >RAM /* This is the uninitialized data section */ .bss : { . = ALIGN(4); /* This is used by the startup in order to initialize the .bss secion */ _sbss = .; *(.bss) *(COMMON) . = ALIGN(4); /* This is used by the startup in order to initialize the .bss secion */ _ebss = . ; } >RAM PROVIDE ( end = _ebss ); PROVIDE ( _end = _ebss ); ._usrheap : { _sheap = .; . = . + _Heap_Size; _eheap = .; } >RAM /* This is the user stack section This is just to check that there is enough RAM left for the User mode stack It should generate an error if it's full. */ ._usrstack : { . = ALIGN(4); _susrstack = . ; . = . + _Minimum_Stack_Size ; . = ALIGN(4); _eusrstack = . ; } >RAM /* this is the FLASH Bank1 */ /* the C or assembly source must explicitly place the code or data there using the "section" attribute */ .b1text : { *(.b1text) /* remaining code */ *(.b1rodata) /* read-only data (constants) */ *(.b1rodata*) } >FLASHB1 /* this is the EXTMEM */ /* the C or assembly source must explicitly place the code or data there using the "section" attribute */ /* EXTMEM Bank0 */ .eb0text : { *(.eb0text) /* remaining code */ *(.eb0rodata) /* read-only data (constants) */ *(.eb0rodata*) } >EXTMEMB0 /* EXTMEM Bank1 */ .eb1text : { *(.eb1text) /* remaining code */ *(.eb1rodata) /* read-only data (constants) */ *(.eb1rodata*) } >EXTMEMB1 /* EXTMEM Bank2 */ .eb2text : { *(.eb2text) /* remaining code */ *(.eb2rodata) /* read-only data (constants) */ *(.eb2rodata*) } >EXTMEMB2 /* EXTMEM Bank0 */ .eb3text : { *(.eb3text) /* remaining code */ *(.eb3rodata) /* read-only data (constants) */ *(.eb3rodata*) } >EXTMEMB3 /* after that it's only debugging information. */ /* remove the debugging information from the standard libraries */ DISCARD : { libc.a ( * ) libm.a ( * ) libgcc.a ( * ) } /* Stabs debugging sections. */ .stab 0 : { *(.stab) } .stabstr 0 : { *(.stabstr) } .stab.excl 0 : { *(.stab.excl) } .stab.exclstr 0 : { *(.stab.exclstr) } .stab.index 0 : { *(.stab.index) } .stab.indexstr 0 : { *(.stab.indexstr) } .comment 0 : { *(.comment) } /* DWARF debug sections. Symbols in the DWARF debugging sections are relative to the beginning of the section so we begin them at 0. */ /* DWARF 1 */ .debug 0 : { *(.debug) } .line 0 : { *(.line) } /* GNU DWARF 1 extensions */ .debug_srcinfo 0 : { *(.debug_srcinfo) } .debug_sfnames 0 : { *(.debug_sfnames) } /* DWARF 1.1 and DWARF 2 */ .debug_aranges 0 : { *(.debug_aranges) } .debug_pubnames 0 : { *(.debug_pubnames) } /* DWARF 2 */ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } .debug_abbrev 0 : { *(.debug_abbrev) } .debug_line 0 : { *(.debug_line) } .debug_frame 0 : { *(.debug_frame) } .debug_str 0 : { *(.debug_str) } .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } /* SGI/MIPS DWARF 2 extensions */ .debug_weaknames 0 : { *(.debug_weaknames) } .debug_funcnames 0 : { *(.debug_funcnames) } .debug_typenames 0 : { *(.debug_typenames) } .debug_varnames 0 : { *(.debug_varnames) } } |
IRQ handlers
Lastly we have the irq handlers. We mostly just go into an infinite loop. Naturally we really should do better than this but I never got round to it.
irq.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
#ifndef IRQ_H__ #define IRQ_H__ void IRQHandler(void); void NMIException(void); void HardFaultException(void); void MemManageException(void); void BusFaultException(void); void UsageFaultException(void); void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); void WWDG_IRQHandler(void); void PVD_IRQHandler(void); void TAMPER_IRQHandler(void); void RTC_IRQHandler(void); void FLASH_IRQHandler(void); void RCC_IRQHandler(void); void EXTI0_IRQHandler(void); void EXTI1_IRQHandler(void); void EXTI2_IRQHandler(void); void EXTI3_IRQHandler(void); void EXTI4_IRQHandler(void); void DMA1_Channel1_IRQHandler(void); void DMA1_Channel2_IRQHandler(void); void DMA1_Channel3_IRQHandler(void); void DMA1_Channel4_IRQHandler(void); void DMA1_Channel5_IRQHandler(void); void DMA1_Channel6_IRQHandler(void); void DMA1_Channel7_IRQHandler(void); void ADC1_2_IRQHandler(void); void USB_HP_CAN1_TX_IRQHandler(void); void USB_LP_CAN1_RX0_IRQHandler(void); void CAN1_RX1_IRQHandler(void); void CAN1_SCE_IRQHandler(void); void EXTI9_5_IRQHandler(void); void TIM1_BRK_IRQHandler(void); void TIM1_UP_IRQHandler(void); void TIM1_TRG_COM_IRQHandler(void); void TIM1_CC_IRQHandler(void); void TIM2_IRQHandler(void); void TIM3_IRQHandler(void); void TIM4_IRQHandler(void); void I2C1_EV_IRQHandler(void); void I2C1_ER_IRQHandler(void); void I2C2_EV_IRQHandler(void); void I2C2_ER_IRQHandler(void); void SPI1_IRQHandler(void); void SPI2_IRQHandler(void); void USART1_IRQHandler(void); void USART2_IRQHandler(void); void USART3_IRQHandler(void); void EXTI15_10_IRQHandler(void); void RTCAlarm_IRQHandler(void); void USBWakeUp_IRQHandler(void); void TIM8_BRK_IRQHandler(void); void TIM8_UP_IRQHandler(void); void TIM8_TRG_COM_IRQHandler(void); void TIM8_CC_IRQHandler(void); void ADC3_IRQHandler(void); void FSMC_IRQHandler(void); void SDIO_IRQHandler(void); void TIM5_IRQHandler(void); void SPI3_IRQHandler(void); void UART4_IRQHandler(void); void UART5_IRQHandler(void); void TIM6_IRQHandler(void); void TIM7_IRQHandler(void); void DMA2_Channel1_IRQHandler(void); void DMA2_Channel2_IRQHandler(void); void DMA2_Channel3_IRQHandler(void); void DMA2_Channel4_5_IRQHandler(void); #endif // IRQ_H__ |
irq.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
#include <stdint.h> #include <stdio.h> #include "irq.h" extern void _start(); void SVC_Handler_main(uint32_t* svc_args) { uint32_t svc_number; svc_number = ((char *) svc_args[6])[-2]; switch (svc_number) { case 0: break; default: break; } } void NMIException(void) { for (;;) ; } void HardFaultException(void) { for (;;) ; } void MemManageException(void) { for (;;) ; } void BusFaultException(void) { for (;;) ; } void UsageFaultException(void) { for (;;) ; } void DebugMon_Handler(void) { for (;;) ; } void PendSV_Handler(void) { for (;;) ; } void SysTick_Handler(void) { for (;;) ; } void WWDG_IRQHandler(void) { for (;;) ; } void PVD_IRQHandler(void) { for (;;) ; } void TAMPER_IRQHandler(void) { for (;;) ; } void RTC_IRQHandler(void) { for (;;) ; } void FLASH_IRQHandler(void) { for (;;) ; } void RCC_IRQHandler(void) { for (;;) ; } void EXTI0_IRQHandler(void) { for (;;) ; } void EXTI1_IRQHandler(void) { for (;;) ; } void EXTI2_IRQHandler(void) { for (;;) ; } void EXTI3_IRQHandler(void) { for (;;) ; } void EXTI4_IRQHandler(void) { for (;;) ; } void DMA1_Channel1_IRQHandler(void) { for (;;) ; } void DMA1_Channel2_IRQHandler(void) { for (;;) ; } void DMA1_Channel3_IRQHandler(void) { for (;;) ; } void DMA1_Channel4_IRQHandler(void) { for (;;) ; } void DMA1_Channel5_IRQHandler(void) { for (;;) ; } void DMA1_Channel6_IRQHandler(void) { for (;;) ; } void DMA1_Channel7_IRQHandler(void) { for (;;) ; } void ADC1_2_IRQHandler(void) { for (;;) ; } void USB_HP_CAN1_TX_IRQHandler(void) { for (;;) ; } void USB_LP_CAN1_RX0_IRQHandler(void) { for (;;) ; } void CAN1_RX1_IRQHandler(void) { for (;;) ; } void CAN1_SCE_IRQHandler(void) { for (;;) ; } void EXTI9_5_IRQHandler(void) { for (;;) ; } void TIM1_BRK_IRQHandler(void) { for (;;) ; } void TIM1_UP_IRQHandler(void) { for (;;) ; } void TIM1_TRG_COM_IRQHandler(void) { for (;;) ; } void TIM1_CC_IRQHandler(void) { for (;;) ; } void TIM2_IRQHandler(void) { for (;;) ; } void TIM3_IRQHandler(void) { for (;;) ; } void TIM4_IRQHandler(void) { for (;;) ; } void I2C1_EV_IRQHandler(void) { for (;;) ; } void I2C1_ER_IRQHandler(void) { for (;;) ; } void I2C2_EV_IRQHandler(void) { for (;;) ; } void I2C2_ER_IRQHandler(void) { for (;;) ; } void SPI1_IRQHandler(void) { for (;;) ; } void SPI2_IRQHandler(void) { for (;;) ; } void USART1_IRQHandler(void) { for (;;) ; } void USART2_IRQHandler(void) { } void USART3_IRQHandler(void) { for (;;) ; } void EXTI15_10_IRQHandler(void) { for (;;) ; } void RTCAlarm_IRQHandler(void) { for (;;) ; } void USBWakeUp_IRQHandler(void) { for (;;) ; } void TIM8_BRK_IRQHandler(void) { for (;;) ; } void TIM8_UP_IRQHandler(void) { for (;;) ; } void TIM8_TRG_COM_IRQHandler(void) { for (;;) ; } void TIM8_CC_IRQHandler(void) { for (;;) ; } void ADC3_IRQHandler(void) { for (;;) ; } void FSMC_IRQHandler(void) { for (;;) ; } void SDIO_IRQHandler(void) { for (;;) ; } void TIM5_IRQHandler(void) { for (;;) ; } void SPI3_IRQHandler(void) { for (;;) ; } void UART4_IRQHandler(void) { for (;;) ; } void UART5_IRQHandler(void) { for (;;) ; } void TIM6_IRQHandler(void) { for (;;) ; } void TIM7_IRQHandler(void) { for (;;) ; } void DMA2_Channel1_IRQHandler(void) { for (;;) ; } void DMA2_Channel2_IRQHandler(void) { for (;;) ; } void DMA2_Channel3_IRQHandler(void) { for (;;) ; } void DMA2_Channel4_5_IRQHandler(void) { for (;;) ; } |