2012-05-27 07:44 PM
Hi, I have just received a new Mini-STM32 board from here:
I put together some sample code to, basically, flash an LED, tested it on a local debugger, no problems, ran it in the Keil uVision simulator software, all good, burned the binary to the chip using ST's Flash Loader demo, all was well, the light flashed normally; however, when I clicked the ''Reset'' button on the board, the app did not come back into operation (no activity at all on the board.)
So, basically, if I re-burn the app and choose the ''Jump to User Program'' option in Flash Loader Demo, the app will run, upon clicking Reset it will not.
I originally compiled this with the Code Sourcery Lite tools and the startup code from ST's Standard Periph. Lib. I then built a fresh project in Keil uVision and rebuilt from scratch using their supplied startup code - same result in either case.
Now, I had saved a binary of the demo app running on the board before I overwrote it. If I reload that binary, the board functions normally even after Reset; so I kind of think it's user error (me being the user :) I'm an experienced programmer but completely new to Arm.
(Also, I only have USB access to the board so no way to see what it's actually doing...) Any help would be greatly appreciated! I can't figure out what could be different between the Boot Loader's reset and the hardware Reset... #stm32-startup #stm32-bootloader #stm32-bootloader-flash-loader2012-05-28 05:52 AM
Whoah - good price. With all the money you saved you can splurge on a JTAG interface. :)
The first (little-endian) word loaded at 0x0800.0000 needs to be your stack pointer, and the next one needs to be the address of** your Reset_Handler. You can look at your .bin or .hex file along-side your map file and maybe get a clue what to look at next. **The address vectors need to have the LSB set when they're pointing to Thumb code. For example, if the Reset_Handler is at 0x08000bfc, the vector in the table should be 08000bfd. I've read accounts of some tool chains / setups not setting the LSB, but have not experienced the problem myself.2012-05-28 12:49 PM
08003c80 <Reset_Handler>:
8003c80: 2100 movs r1, #0 8003c82: e003 b.n 8003c8c <LoopCopyDataInit>08003c84 <CopyDataInit>:
8003c84: 4b0a ldr r3, [pc, #40] ; (8003cb0 <LoopFillZerobss+0x10>) 8003c86: 585b ldr r3, [r3, r1] 8003c88: 5043 str r3, [r0, r1] 8003c8a: 3104 adds r1, #408003c8c <LoopCopyDataInit>:
8003c8c: 4809 ldr r0, [pc, #36] ; (8003cb4 <LoopFillZerobss+0x14>) 8003c8e: 4b0a ldr r3, [pc, #40] ; (8003cb8 <LoopFillZerobss+0x18>) 8003c90: 1842 adds r2, r0, r1 8003c92: 429a cmp r2, r3 8003c94: d3f6 bcc.n 8003c84 <CopyDataInit> 8003c96: 4a09 ldr r2, [pc, #36] ; (8003cbc <LoopFillZerobss+0x1c>) 8003c98: e002 b.n 8003ca0 <LoopFillZerobss>08003c9a <FillZerobss>:
8003c9a: 2300 movs r3, #0 8003c9c: f842 3b04 str.w r3, [r2], #408003ca0 <LoopFillZerobss>:
8003ca0: 4b07 ldr r3, [pc, #28] ; (8003cc0 <LoopFillZerobss+0x20>) 8003ca2: 429a cmp r2, r3 8003ca4: d3f9 bcc.n 8003c9a <FillZerobss> 8003ca6: f7ff fcad bl 8003604 <SystemInit> 8003caa: f7ff febf bl 8003a2c <main> 8003cae: 4770 bx lr So it looks like it ''should be'' calling SystemInit() and then main(). Maybe I'm setting this up wrong... I'm including these startup files from ST's Std Periph lib: startup_stm32f10x_md.S system_stm32f10x.c (contains SystemInit()) stm32_flash.ld (found at STM32F10x_StdPeriph_Template\TrueSTUDIO\STM3210B-EVAL) I can get some of the examples that came with the board to work correctly (even after Reset) so I guess I'm doing something wrong. I am just trying to set up a ''correct'' minimal template by including only files from CMSIS and the ST Periph library and it's just not starting after Reset. Probably getting the JTAG wire is definitely not a bad idea :)2012-05-28 02:37 PM
Well life certainly will be hard without some debug connectivity, be it JTAG/SWD or serial output.
You could check the .MAP file, and make sure the FLASH and RAM addresses are correct. With a more complete disassembly you could walk through the code. The listing provided doesn't seem to be a problem. You could make sure main() does not return, this will certainly crash. You could make sure the HSE_VALUE and PLL settings are suitable for the hardware on the board. If the clocks are mismatched it could get stuck in System_Init() bringing them up. A simple implementation could just run off HSI directly.2012-05-28 03:41 PM
Everything there looks exactly right. My best guess now is that you're not getting a mode register or some such set up quite right. Maybe in some cases you get a ''left over'' desired setup from the previous program until you reset. Although a SystemInit() issue is another possibility.
The .._md.S file looks right. The system_stm32f10x.c should be fine as long as you #define the HSE clock somewhere. (I assume you #defined STM32F10X_MD already to get this far.) I don't know about the .ld file but it appears that the linker put everything in the right place. I confess I bought a very similar board a while back (at a higher price). Here is an almost minimal blinky that doesn't use the StdPeriphLib (in case one of those calls is part of your problem). LEDs might be on different pins. #include ''stm32f10x.h'' __IO uint16_t ticks; int main(void){ RCC->APB2ENR = RCC_APB2ENR_IOPBEN; GPIOB->CRL = 0x00000022; /* PB.0,1 2MHz out */ SysTick_Config((SysTick->CALIB) & SysTick_LOAD_RELOAD_Msk); /* 1 msec */ while (1) { GPIOB->ODR = (ticks >> 12); } } void SysTick_Handler(void){ ticks++; } If you can just get the serial port working, you can use that for debug. For simple stuff anyway...2012-05-29 01:01 PM
Hm, thanks for all the help! It's definitely very useful. In fact, this code works perfectly once I update the port and pin info, even on Reset. The only obvious difference (to me) is that you call SysTick_Config() and I don't. I am using TIM2 which fires an interrupt to toggle the LED. I kind of borrowed the code from here:
https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/STM32f100 how start TIM1 interrupt handler&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=915
Here's my code in case anything is obvious: int main(void){ outpin_init(); timer_init(1); while(1) { } } void outpin_init(){ GPIO_InitTypeDef gpio; gpio.GPIO_Pin = GPIO_Pin_2; gpio.GPIO_Mode = GPIO_Mode_Out_PP; gpio.GPIO_Speed = GPIO_Speed_2MHz; GPIO_Init(GPIOA, &gpio); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); } void togglePin(){ GPIOA->ODR ^= GPIO_Pin_2; }void timer_init(uint tickFrequency){
TIM_TimeBaseInitTypeDef timebase; NVIC_InitTypeDef nvic; nvic.NVIC_IRQChannel = TIM2_IRQn; nvic.NVIC_IRQChannelPreemptionPriority = 0; nvic.NVIC_IRQChannelSubPriority = 1; nvic.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&nvic); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); SetPeriod(tickFrequency, &timebase); TIM_TimeBaseInit(TIM2, &timebase); if (timebase.TIM_Prescaler == 0) throw(''Overload xxyyzz''); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE); } void SetPeriod(uint tickFrequency, TIM_TimeBaseInitTypeDef* timebase){ uint prescale = SystemCoreClock / tickFrequency; uint period = 0; #ifdef KEILC uint shifter = __clz(__rbit(prescale)); //count trailing zeros int leftPusher = 16 - (_clz(prescale >> shifter)); //ensure none of the 1st 16 bits are used #else uint shifter = __builtin_ctz(prescale); int leftPusher = 16 - (__builtin_clz(prescale >> shifter)); #endif if (leftPusher>0) shifter += leftPusher; if (shifter > 0xF) shifter = 0xF; prescale = (prescale >> shifter) - 1; period = (1 << shifter) - 1; timebase->TIM_Period = period; timebase->TIM_Prescaler = prescale; timebase->TIM_CounterMode = TIM_CounterMode_Up; timebase->TIM_ClockDivision = 0; }void TIM2_IRQHandler(void){
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == RESET) return; TIM_ClearITPendingBit(TIM2, TIM_IT_Update); togglePin(); } } I checked the HSE_VALUE setting and it was supplied correctly in the library headers. I guess I'm probably getting something wrong with setting up the interrupt or the timer. Is calling Systick_Config() a requirement? I notice the Chinese code that came with the board (and works) calls it too but the sample timer code with the interrupts did not.2012-05-29 02:26 PM
You must enable the clock before configuring the peripheral
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
before GPIO_Init();2012-05-29 02:49 PM
Awesome, you hit the nail on the head. Thank you!
2012-05-29 07:34 PM
Systick etc. absolutely not a requirement. That was just some code I had lying around. I should have taken 5 minutes to chop out the non-essentials. Anyway, sounds like you're up and running!
2012-05-29 09:44 PM
Yeah, well it was a great help because I was thinking it had to do with startup code 'til I saw I was actually getting to main(). Plus, you forced me to actually go read all the bit configurations on setting up the IO port... yuck!