Hello All,
my goal is to use the OpenBLT Bootloader on a STM32F103C6 to flash and later update a Keil RTX project.
The bootloader part (OpenBLT with UART Interface) is using the space between 0x08000000 to 0x08001800 on ROM and 0x20000000 to 0x20000C00 on RAM.
The RTX Application is unsing a scatter-file to create the file for flashing with the OpenBLT:
; ************************************************************* ; *** Scatter-Loading Description File for OpenBLT *** ; ************************************************************* LR_IROM1 0x08001800 0x00005800 { ; load region size_region ER_IROM1 0x08001800 0x00005800 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x20000C00 0x00001C00 { ; RW data .ANY (+RW +ZI) } }
As described in the OpenBLT guide, the "Checksum placeholder" is placed at the end of the vector table of the RTX Project (startup_stm32f10x_ld.s):
... DCD 0 ; Reserved DCD EXTI15_10_IRQHandler ; EXTI Line 15..10 DCD RTCAlarm_IRQHandler ; RTC Alarm through EXTI Line DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend DCD 0x55AA11EE ; OpenBLT Checksum Reserved place __Vectors_End
The BOOT_FLASH_VECTOR_TABLE_CS_OFFSET is set to 0x130 in the flash.c file.
When I try to flash an RTX-like Project, the application is calling immediately the _sys_exit() function. (I'm using the
#pragma import(__use_no_semihosting)
and have implemented the function to get over the BKPT 0xAB).
When I try to flash an non-RTX Project, the application is running fine.
I think, that the problem is somewhere in the initializing code of the RTX kernel, maybe some Stack or Heap related part, but I really don't know where to start, because debugging is only possible when running the OpenBLT application and then following the program in the disassembly window...
Unfortunately I havent found a OpenBLT example who includes an Keil RTX program to run, only non-RTX examples.
Thanks
Alain
Hello again,
thanks for your answers. Truly there must be something wrong with this scatterload function, but I've never seen/used it (and also questionned this basic functionality because it has always worked)...
Just to get this correctly and understand the functionality: the function call to the __scatterload is made to initialize variables with pre-defined values including zeroing some variables. As far as I understand, there is a __scatterload_copy and a __scatterload_zeroinit function to do exactly this.
The copy function is loading the variables with the pre-defined values and the zeroinit is filling other variables with zeroes.
Unfortunately I haven't found the "source code" of the __scatterload functions but with the *.map file I could set breakpoints where those functions are called. Or do you have a Idea of how to get to the source of this?
So I've changed back the __I definition and removed the call to the "ClearSpecial" function to get to the "basic", failing rtx application.
So here is the assembler code from the disassembly view:
__scatterload_copy: 0x0800192C 3A10 SUBS r2,r2,#0x10 0x0800192E BF24 ITT CS 0x08001930 371A ADDCS r7,r7,#0x1A 0x08001932 AFFF ADDCS r7,sp,#0x3FC 0x08001934 D8FA BHI __scatterload_copy (0x0800192C) 0x08001936 0752 LSLS r2,r2,#29 0x08001938 BF24 ITT CS 0x0800193A C830 LDMCS r0!,{r4-r5} 0x0800193C C130 STMCS r1!,{r4-r5} 0x0800193E BF44 ITT MI 0x08001940 6804 LDRMI r4,[r0,#0x00] 0x08001942 600C STRMI r4,[r1,#0x00] 0x08001944 4770 BX lr 0x08001946 0000 MOVS r0,r0 __scatterload_zeroinit: 0x08001948 2300 MOVS r3,#0x00 0x0800194A 2400 MOVS r4,#0x00 0x0800194C 2500 MOVS r5,#0x00 0x0800194E 2600 MOVS r6,#0x00 0x08001950 3A10 SUBS r2,r2,#0x10 0x08001952 BF28 IT CS 0x08001954 C178 STMCS r1!,{r3-r6} 0x08001956 D8FB BHI 0x08001950 0x08001958 0752 LSLS r2,r2,#29 0x0800195A BF28 IT CS 0x0800195C C130 STMCS r1!,{r4-r5} 0x0800195E BF48 IT MI 0x08001960 600B STRMI r3,[r1,#0x00] 0x08001962 4770 BX lr
I've added a breakpoint on the line 0x0800192C and 0x08001948. So when entering the __scatterload_copy I have:
R0 = 0x08006E9C R1 = 0x20000C00 R2 = 0x00000114 R3 = 0x0800192D R4 = 0x08001AE1 R5 = 0x20000504 R6 = 0x00000000 R7 = 0x08006E7B R8 = 0x00000000 R9 = 0x20000160 R10 = 0x08006E8C R11 = 0x08006E9C R12 = 0x00000008 R13(SP) = 0x20002750 R14(LR) = 0x08001907 R15(PC) = 0c0800192C
and when entering the __scatterload_zeroinit:
R0 = 0x08006FB0 R1 = 0x20000D14 R2 = 0x00001A3C R3 = 0x08001949 R4 = 0x00000100 R5 = 0x20000504 R6 = 0x00000000 R7 = 0x20002B4C R8 = 0x00000000 R9 = 0x20000160 R10 = 0x08006E9C R11 = 0x08006E9C R12 = 0x00000008 R13(SP) = 0x20002750 R14(LR) = 0x08001907 R15(PC) = 0c08001948
I'm a bit overwhelmed with the assembler code, but I saw there two addresses: 0x20000C00 in the copy function (R1) and 0x20000D14 in the zeroinit. Considering the *.map file I found that from 0x20000C00 to 0x20000D14 are .data variables located and from 0x20000D14 upwards .bss variables. For the note: the APBAHBPrescTable is located at 0x20000CD8 and the os_initialized and os_running at 0x20000CEC / 0x20000CED = in the .data section.
However, I think that the __scatterload_copy is using the wrong address to copy the initialization values and thus creating those problems, so I'm starting now to research those assembler commands to get the logic of the copy function and to get the address of the initialization values who should be stored in the ROM section I think...
What you have shown looks very correct. A basic project would have 1 copy section and 1 zero init section. The compiler will compress the copy data stored in flash if the total size of the compressed data and the code to decompress it is less then the total size of the uncompressed init data. (my guess is your data is compressed)
what values does os_initialized and os_running have immediately after calling the __scatterload_copy? If these are zero, are either of them non-zero at the osKernelInitialize call?
You should be able to tell if __scatterload_copy was sucessful as after it is run, ANY variable that is initialized you should be able to find it's address in the map file and then do a view memory in the debugger. If you think scatterloading is happening to/from a wrong address, provide more information on that.
There is not yet any indication that __scatterload_copy or __scatter_load_zeroinit is bad so no need to get the source for it. (the zero_init is extreamly simple to analyze for correctness in assembly language as well as copy for sections that are not compressed.)
It might be helpful if you can extract a few 32-bit values fro the Application code.
You should have a variable in the map file called Region$$Table$$Base. The next 8 32-bit values may be helpful, though it really appears as if scatterload is setup properly. This should tell us if a wrong address is being used to copy from scatter loading wise.
Hi Robert,
thanks for your message. So I've stepped through the __scatterload_copy and the os_initialized and os_running are 1 when I get to the __scatterload_copy, after it, they were also 1 and even after the __scatterload_zeroinit they were 1. For fun, I've set them to a value of 120 at the beginning of the __main call and they were untouched until the osKernelInitialize call, where they were set to 1, but because of the "non zero" value the memory don't gets allocated and so on... On the other hand, when I set a variable who is in the zeroinit section to non-zero values at the beginning of the __main, the variable get's correctly set to zero, so I think we're on the right track here.
The variable Region$$Table$$Base is in my case located at 0x08006E7C and the Region$$Table$$Limit is located at 0x08006E9C.
The memory values are (hex from the memory window):
Address = Hexhexhexhex = converted -> my guess, what this number means 0x08006E7C = 9C 6E 00 08 = 0x08006E9C -> end of this array 0x08006E80 = 00 0C 00 20 = 0x20000C00 -> scatterload starting address for initializing 0x08006E84 = 14 01 00 00 = 0x00000114 -> size for initializing 0x08006E88 = 2C 19 00 08 = 0x0800192C -> address of the copy function __scatterload_copy 0x08006E8C = B0 6F 00 08 = 0x08006FB0 -> special memory address?!? 0x08006E90 = 14 0D 00 20 = 0x20000D14 -> scatterload starting address for zeroing 0x08006E94 = 3C 1A 00 00 = 0x00001A3C -> size for zeroing 0x08006E98 = 48 19 00 08 = 0x08001948 -> address of the zero function __scatterload_zeroinit 0x08006E9C = 00 01 00 00 = 0x00000100 -> special size?!?
Can someone see some hint in the numbers? The "special memory address" seems suspicious to me but maybe that is just the "decompress" function...
No hint in the numbers. These are 4 parameters passed into the function call (that is also one of the parameters). 1st is the starting point in flash used in the copy. This value is not used for zeroinit so is usually just the last value it was (0x08006E9C + 0x0114) so I don't beleive there is anything "special" about "special memory address?!?". The "special size?!?" is past the end of the table so not related to scatterloading.
As I think Robert #1 pointed out, it seemed very likely that the initialization of some variables was not correct - most likely the os_initialized. It must be 0 for the os to initialize the memory boxes for the TCB and stacks. If they are not the stack allocation for the idle task fails (but this one does have a valid TCB because it is static) as well as every TCB allocation for threadcreate.
It concerns me that other parameters might not be initialized properly that are not so obvious, but maybe just as damaging at the point they are needed. This is why clearing these values individually just does not seem to be a good idea. The scatter loading should have you set up properly and if it is not, you need to understand why.
What address is os_initialized at?
Is this address within the range of one of the scatter load sections? Which one. I might be interesting to know if it is in the rw section or the zero_init. The scatter load table looks just fine. It seems to be calling the proper functions with valid parameters.
maybe you can put an write access break point at the address of os_initialized. Does it every get zeroed. Who is setting it to 1?
thanks for your message. The os_initialized is at the address 0x20000CEC and so within the __scatterload_copy section (0x20000C00 - 0x20000D14) what is shown in the map file as ".data".
I've added the access breakpoint to the os_initialized and the only point, where this breakpoint is triggered, is at the end of the function svcKernelInitialize():
osStatus svcKernelInitialize (void) { uint32_t ret; if (os_initialized == 0U) { // Init Thread Stack Memory (must be 8-byte aligned) if (((uint32_t)os_stack_mem & 7U) != 0U) { return osErrorNoMemory; } ret = rt_init_mem(os_stack_mem, os_stack_sz); if (ret != 0U) { return osErrorNoMemory; } rt_sys_init(); // RTX System Initialization } os_tsk.run->prio = 255U; // Highest priority if (os_initialized == 0U) { // Create OS Timers resources (Message Queue & Thread) osMessageQId_osTimerMessageQ = svcMessageCreate (&os_messageQ_def_osTimerMessageQ, NULL); osThreadId_osTimerThread = svcThreadCreate(&os_thread_def_osTimerThread, NULL); } sysThreadError(osOK); os_initialized = 1U; // <- here os_running = 0U; return osOK; }
That is all correct EXCEPT there should be an access break during the scatter_copy when os_initialize gets initialized to the value 0.
I think you are going to need to remove the bootloader. Build your application to run from 0x08000000 and 0x20000000. Load and run it. Does it work properly. If it does not, you likely need to upgrade your MDK version. It looks like your current code size is small enough that a trial license would be fine at least to test that it works.
If it does work, then you will have to find out why when you combine this with the bootloader it fails.
thanks for your message. So I've downloaded the newest MDK, the 5.26.2.0 and the result was always the same: no initialization of the non-zero variables, when using the bootloader. I've even tried different compiler versions, and updated the CMSIS Core but no success.
But what I've found while compiling and updating to the "new" MDK version were some differences in the __scatterload_copy function:
without bootloader part (initialization working):
__scatterload_copy: 0x0800012C 3A10 SUBS r2,r2,#0x10 0x0800012E BF24 ITT CS 0x08000130 C878 LDMCS r0!,{r3-r6} 0x08000132 C178 STMCS r1!,{r3-r6} 0x08000134 D8FA BHI __scatterload_copy (0x0800012C) 0x08000136 0752 LSLS r2,r2,#29 0x08000138 BF24 ITT CS 0x0800013A C830 LDMCS r0!,{r4-r5} 0x0800013C C130 STMCS r1!,{r4-r5} 0x0800013E BF44 ITT MI 0x08000140 6804 LDRMI r4,[r0,#0x00] 0x08000142 600C STRMI r4,[r1,#0x00] 0x08000144 4770 BX lr 0x08000146 0000 MOVS r0,r0
with bootloader (no initialization):
__scatterload_copy: 0x0800192C 3A10 SUBS r2,r2,#0x10 0x0800192E BF24 ITT CS 0x08001930 3AE2 SUBCS r2,r2,#0xE2 0x08001932 AFFF ADDCS r7,sp,#0x3FC 0x08001934 D8FA BHI __scatterload_copy (0x0800192C) 0x08001936 0752 LSLS r2,r2,#29 0x08001938 BF24 ITT CS 0x0800193A C830 LDMCS r0!,{r4-r5} 0x0800193C C130 STMCS r1!,{r4-r5} 0x0800193E BF44 ITT MI 0x08001940 6804 LDRMI r4,[r0,#0x00] 0x08001942 600C STRMI r4,[r1,#0x00] 0x08001944 4770 BX lr 0x08001946 0000 MOVS r0,r0
So there are differences depending only on the different start address. But I'm a bit lost here...
I am not seeing anything different in the scatterloading code based on Load address. IF it is calling that code it certainly will not initialize the rw data.
Can you build the "offset" file (your app) and generate a binary file from it. Can you see if the bytes at the same offset in the binary file and see if 0x1930 and 0x1932 have proper files. Is it possible that your bootloader is actually changing this offset file before it gets into the flash (either on the host or as it is copied/burned to the flash the flash)
__scatterload_copy: 0x0800192C 3A10 SUBS r2,r2,#0x10 0x0800192E BF24 ITT CS 0x08001930 3AE2 SUBCS r2,r2,#0xE2 ; <<< here. is it C878 or 3AE2 0x08001932 AFFF ADDCS r7,sp,#0x3FC ; <<< here. is it AFFF or C178 0x08001934 D8FA BHI __scatterload_copy (0x0800192C)
I have no experience with OpenBLT, So I am not sure what the chances are that it is changing the file/data, but that does look to be bad scatterloading code and it seems more likley to me that something has changed it rather then it being generated wrong.
Actually maybe a good test would be to remove the bootloader. Build the app for 0x08001800. Flash the app. Go into the debugger and see the dissasembly at 0x08001800 (actually 0x0800192C forward if it is the same build as above).
thanks for your hint! Actually I think I found the problem to all this, It's the wrong vector table offset for the OpenBLT checksum (bummer!), but here are the steps of what I've done:
As you said, I've loaded the "offset" binary to the microcontroller and started the debugger. Obviously the programm was waiting in the OpenBLT bootloader because the needed checksum was not there. So I've stopped the target and went to the scatterload function:
__scatterload_copy: 0x0800192C 3A10 SUBS r2,r2,#0x10 0x0800192E BF24 ITT CS 0x08001930 C878 LDMCS r0!,{r3-r6} 0x08001932 C178 STMCS r1!,{r3-r6} 0x08001934 D8FA BHI __scatterload_copy (0x0800192C) 0x08001936 0752 LSLS r2,r2,#29 0x08001938 BF24 ITT CS 0x0800193A C830 LDMCS r0!,{r4-r5} 0x0800193C C130 STMCS r1!,{r4-r5} 0x0800193E BF44 ITT MI 0x08001940 6804 LDRMI r4,[r0,#0x00] 0x08001942 600C STRMI r4,[r1,#0x00] 0x08001944 4770 BX lr 0x08001946 0000 MOVS r0,r0
I thaught: perfect, so the reason of my problems were that the openblt is messing with my code so the whole thing is unusable...
Anyway I went back to the bootloader application (this wasn't touched because I didn't changed this) and stepped through the code. Somewhere there was this BOOT_FLASH_VECTOR_TABLE_CS_OFFSET who I set to 0x130. Reviewing once again the *.map file of the rtx application I found a symbol called __Vectors_Size with a value of 0xF0. Well if the vectorsize is 0xF0, why do I offset the checksum to 0x130? Because I've used the reference manual where the vector table for "other STM32F10xx devices" ended at 0x12C, so the next word address would be 0x130. But considering the startup file, the interrupts after USBWakeUp_IRQHandler were inexistent (at address 0x0E8) and so the CORRECT place for the checksum offset is 0xEC and not 0x130.
So guess what lies at the position of 0x08001800 + 0x130? Right, its the address 0x08001930 where the two instructions for the __scatterload_copy functions are located. This is so fun, I mean what the heck ;-)
Changed the checksum offset to the right value and everything works as expected! No change on libraries or special initializations.
So finally I have to thank you all to stay with me in this special case! I've learned very much about the basic functionality, scatter files and the fascination information of a map file ;-) and could finally solve it.
To round things up I would like to ask you a last question: why are there no "hints" or informations about the different vector tables on the STM32F103C6? Because I've just used the "regular" reference manual: www.st.com/.../cd00171190.pdf
Or is this a "special" one because normally you don't go into the startup file and do stuff there.
Many thanks!
Good job! Suggesting that 2 instructions were being overwritten (and JUST those 2) seemed very odd, but the instructions provided no useful algorithm that I could identify as if they were almost random bytes and certainly were not what I have ALWAYS seen when I have looked at the __scatter_copy function (which is almost never because, why would anyone EVER need to look at the __scatter_copy code. It just "works" and you just use it - usually without even knowing you're using it.)
I understand your pain here. The "regular" reference manual you reference above is the specific reference manual for the STM32F103C6 as well as the entire STM32F1xx line of chips.
They really did leave "hints" and even some information. A lot of hints.
Section 1 show what is implemented in each different variation of the chips. The Low Density does not support as many devices and therefore does not need to support as many interrupt vectors. There would have been no harm to have unusable vectors in your table so you could have used offset 0x130, but you did need to let OpenBLT know what location you were using.
Also looking at the specific stm32f10x.h would have given you a nice hint. Below is the part for Low Density Chips. The big "hint" in this file is that the last entry is USBWakeUp_IRQn at "index 42"
typedef enum IRQn { /****** Cortex-M3 Processor Exceptions Numbers ***************************************************/ NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */ BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */ UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */ SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */ DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */ PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */ SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */ /****** STM32 specific Interrupt Numbers *********************************************************/ WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ TAMPER_IRQn = 2, /*!< Tamper Interrupt */ RTC_IRQn = 3, /*!< RTC global Interrupt */ FLASH_IRQn = 4, /*!< FLASH global Interrupt */ RCC_IRQn = 5, /*!< RCC global Interrupt */ EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ DMA1_Channel1_IRQn = 11, /*!< DMA1 Channel 1 global Interrupt */ DMA1_Channel2_IRQn = 12, /*!< DMA1 Channel 2 global Interrupt */ DMA1_Channel3_IRQn = 13, /*!< DMA1 Channel 3 global Interrupt */ DMA1_Channel4_IRQn = 14, /*!< DMA1 Channel 4 global Interrupt */ DMA1_Channel5_IRQn = 15, /*!< DMA1 Channel 5 global Interrupt */ DMA1_Channel6_IRQn = 16, /*!< DMA1 Channel 6 global Interrupt */ DMA1_Channel7_IRQn = 17, /*!< DMA1 Channel 7 global Interrupt */ #ifdef STM32F10X_LD ADC1_2_IRQn = 18, /*!< ADC1 and ADC2 global Interrupt */ USB_HP_CAN1_TX_IRQn = 19, /*!< USB Device High Priority or CAN1 TX Interrupts */ USB_LP_CAN1_RX0_IRQn = 20, /*!< USB Device Low Priority or CAN1 RX0 Interrupts */ CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ TIM1_BRK_IRQn = 24, /*!< TIM1 Break Interrupt */ TIM1_UP_IRQn = 25, /*!< TIM1 Update Interrupt */ TIM1_TRG_COM_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt */ TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ USART1_IRQn = 37, /*!< USART1 global Interrupt */ USART2_IRQn = 38, /*!< USART2 global Interrupt */ EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */ USBWakeUp_IRQn = 42 /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */ #endif /* STM32F10X_LD */ } IRQn_Type;
Many manufactures will include a count item at the end of this (I usually add it if they don't), something like
PERIPH_COUNT_IRQn = 43
It is not easy not being overwhelmed by all the information. More information often can lead to more confusion rather then more clarity.