I decided to do some experiments with STM32. So I bought cheapest STM32F103C8T6 board for about $5 (ebay). The chip has some nice features, e.g. dozens of GPIOs, AD converter, timers, USB full-speed interface etc., full specs here.
The board has JTAG programming/debug interface header so I also needed some JTAG interface. I decided to buy some Chinese j-link clone for about $12 (ebay).
When I had the hardware at home, I started to find some know-how on the internet. My requirement was, that the software has to work under Linux.
On the beginning, I’ve found this article, which talks about running STM32F4 discovery under Linux. It gave me some ideas where to start and what should I look for, so I knew I need some example code with makefile, compiler and debug/flash tool.
Installing compiler was the easiest part, the article suggested downloading a package and uncompressing it, but I used another way, simple package installation:
apt-get install gcc-arm-none-eabi
Next step was to get some example code, I searched for blinking LED and after some googling I found this page. With this zip containing sample LED blinking project. It’s not avaiIable now so I reuploaded this file here STM32F103VHB6_RevZ_Demo1_Lanchon_20080210.
dano@u430:~$ unzip STM32F103VHB6_RevZ_Demo1_Lanchon_20080210.zip Archive: STM32F103VHB6_RevZ_Demo1_Lanchon_20080210.zip inflating: STM32F103VHB6_RevZ_Demo1/jtag/flash.cfg inflating: STM32F103VHB6_RevZ_Demo1/jtag/flash.script inflating: STM32F103VHB6_RevZ_Demo1/jtag/openocd.cfg inflating: STM32F103VHB6_RevZ_Demo1/jtag/target.ini inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/cortexm3_macro.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_adc.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_bkp.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_can.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_dma.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_exti.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_flash.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_gpio.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_i2c.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_iwdg.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_lib.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_map.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_nvic.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_pwr.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_rcc.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_rtc.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_spi.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_systick.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_tim.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_tim1.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_type.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_usart.h inflating: STM32F103VHB6_RevZ_Demo1/lib/inc/stm32f10x_wwdg.h inflating: STM32F103VHB6_RevZ_Demo1/lib/src/cortexm3_macro.s inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_adc.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_bkp.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_can.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_dma.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_exti.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_flash.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_gpio.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_i2c.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_iwdg.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_lib.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_nvic.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_pwr.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_rcc.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_rtc.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_spi.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_systick.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_tim.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_tim1.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_usart.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_vector.c inflating: STM32F103VHB6_RevZ_Demo1/lib/src/stm32f10x_wwdg.c inflating: STM32F103VHB6_RevZ_Demo1/lib/STM32_128K_20K_FLASH.ld inflating: STM32F103VHB6_RevZ_Demo1/lib/STM32_COMMON.ld inflating: STM32F103VHB6_RevZ_Demo1/lib/STM32_SEC_EXT.ld inflating: STM32F103VHB6_RevZ_Demo1/lib/STM32_SEC_FLASH.ld inflating: STM32F103VHB6_RevZ_Demo1/lib/STM32_SEC_RAM.ld inflating: STM32F103VHB6_RevZ_Demo1/lib/STM32_SEC_RAMonly.ld extracting: STM32F103VHB6_RevZ_Demo1/lib/version-ld.txt inflating: STM32F103VHB6_RevZ_Demo1/lib/version-lib.txt inflating: STM32F103VHB6_RevZ_Demo1/clean-main.c inflating: STM32F103VHB6_RevZ_Demo1/main.c inflating: STM32F103VHB6_RevZ_Demo1/makefile inflating: STM32F103VHB6_RevZ_Demo1/readme.txt inflating: STM32F103VHB6_RevZ_Demo1/stm32.ld inflating: STM32F103VHB6_RevZ_Demo1/stm32f10x_conf.h inflating: STM32F103VHB6_RevZ_Demo1/stm32f10x_it.c inflating: STM32F103VHB6_RevZ_Demo1/stm32f10x_it.h dano@u430:~$ cd STM32F103VHB6_RevZ_Demo1/ dano@u430:~/STM32F103VHB6_RevZ_Demo1$ make arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o main.o main.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o stm32f10x_it.o stm32f10x_it.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_adc.o lib/src/stm32f10x_adc.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_bkp.o lib/src/stm32f10x_bkp.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_can.o lib/src/stm32f10x_can.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_dma.o lib/src/stm32f10x_dma.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_exti.o lib/src/stm32f10x_exti.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_flash.o lib/src/stm32f10x_flash.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_gpio.o lib/src/stm32f10x_gpio.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_i2c.o lib/src/stm32f10x_i2c.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_iwdg.o lib/src/stm32f10x_iwdg.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_lib.o lib/src/stm32f10x_lib.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_nvic.o lib/src/stm32f10x_nvic.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_pwr.o lib/src/stm32f10x_pwr.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_rcc.o lib/src/stm32f10x_rcc.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_rtc.o lib/src/stm32f10x_rtc.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_spi.o lib/src/stm32f10x_spi.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_systick.o lib/src/stm32f10x_systick.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_tim.o lib/src/stm32f10x_tim.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_tim1.o lib/src/stm32f10x_tim1.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_usart.o lib/src/stm32f10x_usart.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_wwdg.o lib/src/stm32f10x_wwdg.c arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -c -o lib/src/cortexm3_macro.o lib/src/cortexm3_macro.s arm-none-eabi-gcc -mcpu=cortex-m3 -mthumb -Wall -g -O0 -I . -I lib/inc -c -o lib/src/stm32f10x_vector.o lib/src/stm32f10x_vector.c lib/src/stm32f10x_vector.c:111:3: warning: taking address of expression of type 'void' [enabled by default] &_estack, // The initial stack pointer ^ lib/src/stm32f10x_vector.c:175:1: warning: initialization makes pointer from integer without a cast [enabled by default] }; ^ lib/src/stm32f10x_vector.c:175:1: warning: (near initialization for 'g_pfnVectors[66]') [enabled by default] arm-none-eabi-ar cr lib/libstm32.a lib/src/stm32f10x_adc.o lib/src/stm32f10x_bkp.o lib/src/stm32f10x_can.o lib/src/stm32f10x_dma.o lib/src/stm32f10x_exti.o lib/src/stm32f10x_flash.o lib/src/stm32f10x_gpio.o lib/src/stm32f10x_i2c.o lib/src/stm32f10x_iwdg.o lib/src/stm32f10x_lib.o lib/src/stm32f10x_nvic.o lib/src/stm32f10x_pwr.o lib/src/stm32f10x_rcc.o lib/src/stm32f10x_rtc.o lib/src/stm32f10x_spi.o lib/src/stm32f10x_systick.o lib/src/stm32f10x_tim.o lib/src/stm32f10x_tim1.o lib/src/stm32f10x_usart.o lib/src/stm32f10x_wwdg.o lib/src/cortexm3_macro.o lib/src/stm32f10x_vector.o arm-none-eabi-gcc -Wl,--gc-sections,-Map=main.elf.map,-cref,-u,Reset_Handler -I . -I lib/inc -L lib -T stm32.ld main.o stm32f10x_it.o lib/libstm32.a --output main.elf arm-none-eabi-objcopy -O binary main.elf main.bin
Compilation worked like a charm and at the end I was left with a binary (main.bin) to put into flash.
The code originally used PC1 pin which is not populated in my board so I did a small change into the code to use PB0 and recompiled:
@@ -50,23 +50,23 @@ NVIC_Configuration(); /* Enable GPIOC clock */ - RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); + RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); /* Configure PC.4 as Output push-pull */ - GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; + GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; - GPIO_Init(GPIOC, &GPIO_InitStructure); + GPIO_Init(GPIOB, &GPIO_InitStructure); while (1) { /* Turn on led connected to PC.4 pin */ - GPIO_SetBits(GPIOC, GPIO_Pin_4); + GPIO_SetBits(GPIOB, GPIO_Pin_0); /* Insert delay */ Delay(0xAFFFF); /* Turn off led connected to PC.4 pin */ - GPIO_ResetBits(GPIOC, GPIO_Pin_4); + GPIO_ResetBits(GPIOB, GPIO_Pin_0); /* Insert delay */ Delay(0xAFFFF); }
Ok, now I needed to flash the binary. So I downloaded original J-Link tools which in turn made my j-link clone unusable (they probably try to fight counterfeits) :(.
[53331.986830] usb 1-3: new full-speed USB device number 53 using xhci_hcd [53331.987000] usb 1-3: Device not responding to setup address. [53332.190955] usb 1-3: Device not responding to setup address. [53332.394579] usb 1-3: device not accepting address 53, error -71 [53332.506592] usb 1-3: new full-speed USB device number 54 using xhci_hcd [53332.506799] usb 1-3: Device not responding to setup address. [53332.710690] usb 1-3: Device not responding to setup address. [53332.914295] usb 1-3: device not accepting address 54, error -71
I didn’t give up and googled how to unbrick it. Fortunately, chip used in j-link is atmel AT91SAM7S64 which supports uploading firmware via USB when put into recovery mode. Full manual is available here. Atmel SAM-BA utility can be also found here: sam-ba_2.12.zip. Using this, I successfully bring my debugger back to life.
So I had to find another utilty for programming. OpenOCD is what I’ve found. Some pages mentioned it as working option so I installed it from repository:
sudo apt-get install openocd
OpenOCD needs a config to know which chip and debugger is used. I easilly found an example here. It mentions ft2232 device as debugger but only a simple change was enough to make it work:
#daemon configuration telnet_port 4444 gdb_port 3333 #interface interface jlink # The chip has 64KB sram set WORKAREASIZE 0x10000 source [find target/stm32f1x.cfg] #adapter_khz 100 gdb_breakpoint_override hard #daemon configuration telnet_port 4444 gdb_port 3333 #interface interface jlink # The chip has 64KB sram set WORKAREASIZE 0x10000 source [find target/stm32f1x.cfg] #adapter_khz 100 gdb_breakpoint_override hard
After this, my chip was successfully detected:
dano@u430:~/stm32$ openocd -f stm32f103.cfg Open On-Chip Debugger 0.8.0 (2014-10-25-15:24) Licensed under GNU GPL v2 For bug reports, read http://openocd.sourceforge.net/doc/doxygen/bugs.html Info : only one transport option; autoselect 'jtag' adapter speed: 1000 kHz adapter_nsrst_delay: 100 jtag_ntrst_delay: 100 cortex_m reset_config sysresetreq force hard breakpoints Info : J-Link initialization started / target CPU reset initiated Info : J-Link ARM V8 compiled May 27 2009 17:31:22 Info : J-Link caps 0xb9ff7bbf Info : J-Link hw version 80000 Info : J-Link hw type J-Link Info : J-Link max mem block 9752 Info : J-Link configuration Info : USB-Address: 0xff Info : Kickstart power on JTAG-pin 19: 0xffffffff Info : Vref = 3.287 TCK = 1 TDI = 0 TDO = 1 TMS = 0 SRST = 0 TRST = 0 Info : J-Link JTAG Interface ready Info : clock speed 1000 kHz Info : JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3) Info : JTAG tap: stm32f1x.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1) Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints Error: stm32f1x.cpu -- clearing lockup after double fault Polling target stm32f1x.cpu failed, GDB will be halted. Polling again in 100ms Polling target stm32f1x.cpu succeeded again
After some fiddling in debug shell and thanks to this note, I found a way how to successfully flash my binary:
telnet localhost 4444 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. Open On-Chip Debugger > halt target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x21000000 pc: 0x080001fc msp: 0x20004fd0 > stm32f1x mass_erase 0 stm32x mass erase complete > flash erase_check 0 successfully checked erase state # 0: 0x00000000 (0x400 1kB) erased # 1: 0x00000400 (0x400 1kB) erased # 2: 0x00000800 (0x400 1kB) erased # 3: 0x00000c00 (0x400 1kB) erased # 4: 0x00001000 (0x400 1kB) erased # 5: 0x00001400 (0x400 1kB) erased # 6: 0x00001800 (0x400 1kB) erased # 7: 0x00001c00 (0x400 1kB) erased # 8: 0x00002000 (0x400 1kB) erased # 9: 0x00002400 (0x400 1kB) erased # 10: 0x00002800 (0x400 1kB) erased # 11: 0x00002c00 (0x400 1kB) erased # 12: 0x00003000 (0x400 1kB) erased # 13: 0x00003400 (0x400 1kB) erased # 14: 0x00003800 (0x400 1kB) erased # 15: 0x00003c00 (0x400 1kB) erased # 16: 0x00004000 (0x400 1kB) erased # 17: 0x00004400 (0x400 1kB) erased # 18: 0x00004800 (0x400 1kB) erased # 19: 0x00004c00 (0x400 1kB) erased # 20: 0x00005000 (0x400 1kB) erased # 21: 0x00005400 (0x400 1kB) erased # 22: 0x00005800 (0x400 1kB) erased # 23: 0x00005c00 (0x400 1kB) erased # 24: 0x00006000 (0x400 1kB) erased # 25: 0x00006400 (0x400 1kB) erased # 26: 0x00006800 (0x400 1kB) erased # 27: 0x00006c00 (0x400 1kB) erased # 28: 0x00007000 (0x400 1kB) erased # 29: 0x00007400 (0x400 1kB) erased # 30: 0x00007800 (0x400 1kB) erased # 31: 0x00007c00 (0x400 1kB) erased # 32: 0x00008000 (0x400 1kB) erased # 33: 0x00008400 (0x400 1kB) erased # 34: 0x00008800 (0x400 1kB) erased # 35: 0x00008c00 (0x400 1kB) erased # 36: 0x00009000 (0x400 1kB) erased # 37: 0x00009400 (0x400 1kB) erased # 38: 0x00009800 (0x400 1kB) erased # 39: 0x00009c00 (0x400 1kB) erased # 40: 0x0000a000 (0x400 1kB) erased # 41: 0x0000a400 (0x400 1kB) erased # 42: 0x0000a800 (0x400 1kB) erased # 43: 0x0000ac00 (0x400 1kB) erased # 44: 0x0000b000 (0x400 1kB) erased # 45: 0x0000b400 (0x400 1kB) erased # 46: 0x0000b800 (0x400 1kB) erased # 47: 0x0000bc00 (0x400 1kB) erased # 48: 0x0000c000 (0x400 1kB) erased # 49: 0x0000c400 (0x400 1kB) erased # 50: 0x0000c800 (0x400 1kB) erased # 51: 0x0000cc00 (0x400 1kB) erased # 52: 0x0000d000 (0x400 1kB) erased # 53: 0x0000d400 (0x400 1kB) erased # 54: 0x0000d800 (0x400 1kB) erased # 55: 0x0000dc00 (0x400 1kB) erased # 56: 0x0000e000 (0x400 1kB) erased # 57: 0x0000e400 (0x400 1kB) erased # 58: 0x0000e800 (0x400 1kB) erased # 59: 0x0000ec00 (0x400 1kB) erased # 60: 0x0000f000 (0x400 1kB) erased # 61: 0x0000f400 (0x400 1kB) erased # 62: 0x0000f800 (0x400 1kB) erased # 63: 0x0000fc00 (0x400 1kB) erased > flash write_bank 0 main.bin 0 wrote 6840 bytes from file main.bin to flash bank 0 at offset 0x00000000 in 0.331746s (20.135 KiB/s) > reset run JTAG tap: stm32f1x.cpu tap/device found: 0x3ba00477 (mfg: 0x23b, part: 0xba00, ver: 0x3) JTAG tap: stm32f1x.bs tap/device found: 0x16410041 (mfg: 0x020, part: 0x6410, ver: 0x1) > telnet> q Connection closed.
And voila! Blinking LED. This whole took me about 5 hours also with this blog writing. Next time I hope I’ll post some more interesting usage of this devel board. Stay tuned.
Hay,
Do you stil have this zip somewhere? Original page is down and a’m unable to find this zip anywhere.
No, I’m sorry, I accidentally deleted it.
Ok, I have found it now 🙂
@Mateusz Wojcik – good to know, maybe paste a link then? Or you just wanted as to enjoy your success on finding it?:>
Please see updated link in article.