GD32F150C6T6基于ARM Cortex-M3 内核的MCU:Core frequency 72MHz, Flash 32KiB, RAM 6KiB。
GD32系列MCU由于价格便宜(相对于STM32)?与STM32系列P2P兼容并且外设所使用的寄存器也基本一致使得原来在STM32上运行的程序可以直接在其上面运行?
- 关于GD32F150C6T6
官网:http://www.gigadevice.com/index.html?locale=en_US
GD32F150相关的介绍:http://www.gigadevice.com/product-series/16.html?locale=en_US
Firmware Library相关的下载页面:http://www.gigadevice.com/product-downloadmcu.html?locale=en_US (没有下载地址?)
相关文档的下载页面:http://gd32mcu.21ic.com/documents
GD32F1x0用户手册:
- EN: http://gd32mcu.21ic.com/documents/down/document_id/82/path_type/1
- CN: http://gd32mcu.21ic.com/documents/down/document_id/82/path_type/2
Programming Flash Memory Manual:
- http://gd32mcu.21ic.com/documents/down/document_id/9/path_type/1
GD32F1x0 Firmware Library下载地址:
- http://gd32mcu.21ic.com/data/documents/yingyongruanjian/GD32F1x0_Firmware_Library_V1.0.1.rar
GD32F1x0 USB Device Library下载地址:
- http://gd32mcu.21ic.com/data/documents/yingyongruanjian/GD32F1x0_USB_FS_Device_Lib_V1.0.0.rar
- 固件更新方法
这里我们使用的是ST-LINK/V2-1调试器,通过SWD接口进行固件更新,所以我们只需要连接SWDIO, SWCLK, GND这三根线,而软件上使用的是OpenOCD工具,需要说明的是当前的OpenOCD版本还不支持GD32系列MCU,但由于GD32与STM32高度匹配,用更新STM32F10x的方法先试试看。
首先看一下option byte的相关信息:
$ /usr/local/bin/openocd -f interface/stlink-v2-1.cfg -f target/stm32f1x.cfg -c init -c 'reset halt' -c 'stm32f1x options_read 0' -c shutdown Open On-Chip Debugger 0.10.0-dev-00288-g060e9c3 (2016-05-14-22:52) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'. Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD adapter speed: 4000 kHz adapter_nsrst_delay: 100 none separate Info : clock speed 4000 kHz Info : STLINK v2 JTAG v27 API v2 SWIM v15 VID 0x0483 PID 0x374B Info : using stlink api v2 Info : Target voltage: 0.007879 Error: target voltage may be too low for reliable debugging Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints stm32f1x.cpu: target state: halted target halted due to debug-request, current mode: Thread xPSR: 00000000 pc: 00000000 msp: 00000000 Info : device id = 0x13030410 Info : flash size = 32kbytes Option Byte: 0xffffff02 Readout Protection On Hardware Watchdog Stop: Reset generated Standby: Reset generated User Option0: 0xff User Option1: 0xff shutdown command invoked
这里我们可以看到ST-LINK/V2-1能够正常识别这个MCU(device id = 0x13030410),flash size为32KiB,并且是处于Readout Protection On的状态。
通过GD32F1x0手册我们可以知道与Readout Protection On的状态可以通过读取0x1ffff800 (OB_RDPT)来获取,我们先将这12字节的option byte读取出来:
$ /usr/local/bin/openocd -f interface/stlink-v2-1.cfg -f target/stm32f1x.cfg -c init -c 'reset halt' -c 'mdb phys 0x1ffff800 12' -c shutdown Open On-Chip Debugger 0.10.0-dev-00288-g060e9c3 (2016-05-14-22:52) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'. Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD adapter speed: 4000 kHz adapter_nsrst_delay: 100 none separate Info : clock speed 4000 kHz Info : STLINK v2 JTAG v27 API v2 SWIM v15 VID 0x0483 PID 0x374B Info : using stlink api v2 Info : Target voltage: 0.006303 Error: target voltage may be too low for reliable debugging Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints stm32f1x.cpu: target state: halted target halted due to debug-request, current mode: Thread xPSR: 00000000 pc: 00000000 msp: 00000000 0x1ffff800: ff ff ff ff ff ff ff ff ff 00 ff 00 shutdown command invoked
这时,我们可以看到OB_RDPT的值为0xff, 属于Protection level low的状态。
GD32F1x0具有3种protection level(详见UM v2.0_201601115 P67):
There are 3 levels for protecting:
- No protection: when setting OB_RDPT byte and its complement value to 0xA55A, no protection performed. The main flash and option bytes block are accessible by all operations.
- Protection level low: when setting OB_RDPT byte and its complement value to any value except 0xA55A or 0xCC33, protection level low performed. The main flash can only be accessed by user code. In debug mode, boot from SRAM or boot from boot loader mode, all operations to main flash is forbidden. If a read operation is executed to main flash in debug mode, boot from SRAM or boot from boot loader mode, a bus error will be generated. If a program/erase operation is executed to main flash in debug mode, boot from SRAM or boot from boot loader mode, the PGEF bit in FMC_CSR register will be set. At protection level low, option bytes block are accessible by all operations. If program back to no protection level by setting OB_RDPT byte and its complement value to 0xA55A, a mass erase for main flash will be performed.
- Protection level high: when set OB_RDPT byte and its complement value to 0xCC33, protection level high performed. When this level is programmed in debug mode, boot from SRAM or boot from boot loader mode is disabled. All operations are from user code. The main flash block is accessible by all operations. The option byte cannot be erased, and the OB_RDPT byte and its complement value cannot be reprogrammed. So, if protection level high is programmed, it cannot move back to protection level low or no protection level.
关闭Read out protection:
#! /bin/bash set -x OCD=/usr/local/bin/openocd ${OCD} -f interface/stlink-v2-1.cfg -f target/stm32f1x.cfg -c init -c 'reset halt' \ -c 'mdb 0x1ffff800 12' -c 'sleep 100' \ -c 'mww 0x40022004 0x45670123' -c 'sleep 100' -c 'mww 0x40022004 0xcdef89ab' -c 'sleep 100' \ -c 'mww 0x40022008 0x45670123' -c 'sleep 100' -c 'mww 0x40022008 0xcdef89ab' -c 'sleep 100' \ -c 'mww 0x40022010 0x00000260' -c 'sleep 100' \ -c 'mww 0x40022010 0x00000210' -c 'sleep 100' \ -c 'mwh 0x1ffff800 0x5aa5' -c 'sleep 100' -c 'shutdown'
关闭page write protection:
${OCD} -f interface/stlink-v2-1.cfg -f target/stm32f1x.cfg -c init -c 'reset halt' \ -c 'mdb 0x1ffff800 12' -c 'sleep 100' \ -c 'mww 0x40022004 0x45670123' -c 'sleep 100' -c 'mww 0x40022004 0xcdef89ab' -c 'sleep 100' \ -c 'mww 0x40022008 0x45670123' -c 'sleep 100' -c 'mww 0x40022008 0xcdef89ab' -c 'sleep 100' \ -c 'mww 0x40022010 0x00000210' -c 'sleep 100' \ \ -c 'mwh 0x1ffff802 0xff00' -c 'sleep 100' \ -c 'mwh 0x1ffff804 0xff00' -c 'sleep 100' -c 'mwh 0x1ffff806 0xff00' -c 'sleep 100' \ -c 'mwh 0x1ffff808 0x00ff' -c 'sleep 100' -c 'mwh 0x1ffff80a 0x00ff' -c 'sleep 100' \ -c 'mww 0x40022010 0x00000080' -c 'sleep 100' \ -c 'mdb 0x1ffff800 12' \ -c 'mdw 0x4002201c 1' -c 'shutdown'
执行之后,可以看到如下log:
+ /usr/local/bin/openocd -f interface/stlink-v2-1.cfg -f target/stm32f1x.cfg -c init -c 'reset halt' -c 'mdb 0x1ffff800 12' -c 'sleep 100' -c 'mww 0x40022004 0x45670123' -c 'sleep 100' -c 'mww 0x40022004 0xcdef89ab' -c 'sleep 100' -c 'mww 0x40022008 0x45670123' -c 'sleep 100' -c 'mww 0x40022008 0xcdef89ab' -c 'sleep 100' -c 'mww 0x40022010 0x00000210' -c 'sleep 100' -c 'mwh 0x1ffff802 0xff00' -c 'sleep 100' -c 'mwh 0x1ffff804 0xff00' -c 'sleep 100' -c 'mwh 0x1ffff806 0xff00' -c 'sleep 100' -c 'mwh 0x1ffff808 0x00ff' -c 'sleep 100' -c 'mwh 0x1ffff80a 0x00ff' -c 'sleep 100' -c 'mww 0x40022010 0x00000080' -c 'sleep 100' -c 'mdb 0x1ffff800 12' -c 'mdw 0x4002201c 1' -c shutdown Open On-Chip Debugger 0.10.0-dev-00288-g060e9c3 (2016-05-14-22:52) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'. Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD adapter speed: 4000 kHz adapter_nsrst_delay: 100 none separate Info : clock speed 4000 kHz Info : STLINK v2 JTAG v27 API v2 SWIM v15 VID 0x0483 PID 0x374B Info : using stlink api v2 Info : Target voltage: 0.011016 Error: target voltage may be too low for reliable debugging Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints stm32f1x.cpu: target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc 0x1ffff800: a5 5a ff ff ff ff ff ff ff ff ff ff 0x1ffff800: a5 5a 00 ff 00 ff 00 ff ff 00 ff 00 0x4002201c: ffffff00 shutdown command invoked
将整块flash擦除:
$ /usr/local/bin/openocd -f interface/stlink-v2-1.cfg -f target/stm32f1x.cfg -c init -c 'reset halt' -c 'flash erase_sector 0 0 31' -c shutdown Open On-Chip Debugger 0.10.0-dev-00288-g060e9c3 (2016-05-14-22:52) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'. Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD adapter speed: 4000 kHz adapter_nsrst_delay: 100 none separate Info : clock speed 4000 kHz Info : STLINK v2 JTAG v27 API v2 SWIM v15 VID 0x0483 PID 0x374B Info : using stlink api v2 Info : Target voltage: 0.004721 Error: target voltage may be too low for reliable debugging Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints stm32f1x.cpu: target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0xfffffffe msp: 0xfffffffc Info : device id = 0x13030410 Info : flash size = 32kbytes erased sectors 0 through 31 on flash bank 0 in 0.058463s shutdown command invoked
更新固件,UM V2.0_20160115.pdf中提到对main flash编程(P64),一次可以写入32-bit word或者是16-bit half word,但实际上只能一次写入32-bit word:
The FMC provides a 32-bit word/16-bit half word programming function which is used to modify the Main Flash memory contents. The following steps show the word programming operation register access sequence.
Unlock the FMC_CMR register if necessary. Check the BUSY bit in FMC_CSR register to confirm that no Flash memory operation is in progress (BUSY equal to 0). Otherwise, wait until the operation has been finished.
Write the word program command into the PG bit in FMC_CMR register.
A 32-bit word/16-bit half word write at desired address by DBUS.
WaituntilalltheoperationshavebeencompletedbycheckingthevalueoftheBUSYbit in FMC_CSR register.
Read and verify the Flash memory if required using a DBUS access.
这个需要修改OpenOCD的代码了,后续看看能不能通过black magic probe写入。
OpenOCD写flash的代码在这里:
- http://repo.or.cz/openocd.git/blob/1edc019f0226fceba7a58b35551adee57a9c6eac:/src/flash/nor/stm32f1x.c#l693
693 static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, 694 uint32_t offset, uint32_t count) 695 { // ... 739 /* try using a block write */ 740 retval = stm32x_write_block(bank, buffer, offset, words_remaining); 741 742 if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { 743 /* if block write failed (no sufficient working area), 744 * we use normal (slow) single halfword accesses */ 745 LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); 746 747 while (words_remaining > 0) { 748 uint16_t value; 749 memcpy(&value, buffer, sizeof(uint16_t)); 750 751 retval = target_write_u16(target, bank->base + offset, value); 752 if (retval != ERROR_OK) 753 goto reset_pg_and_lock; 754 755 retval = stm32x_wait_status_busy(bank, 5); 756 if (retval != ERROR_OK) 757 goto reset_pg_and_lock; 758 759 words_remaining--; 760 buffer += 2; 761 offset += 2; 762 } 763 } 764 765 reset_pg_and_lock: 766 retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); 767 if (retval == ERROR_OK) 768 retval = retval2; 769 770 cleanup: 771 if (new_buffer) 772 free(new_buffer); 773 774 return retval; 775 }
从这里可以看到OpenOCD会先使用 block write (async)的方法写入数据,对于GD32F150C6T6写入时会失败(不支持这种操作?)。失败之后会使用normal(slow) single halfword accesses的方式写入,看起来使用这种方式写入数据也会失败。看起来这种方式下,一次需要写入word (4 bytes)才不会有问题,需要修改这里的代码:
while (words_remaining > 0) { uint32_t value; memcpy(&value, buffer, sizeof(uint32_t)); retval = target_write_u32(target, bank->base + offset, value); if (retval != ERROR_OK) { goto reset_pg_and_lock; } retval = stm32x_wait_status_busy(bank, 100); if (retval != ERROR_OK) { goto reset_pg_and_lock; } words_remaining -= 2; buffer += 4; offset += 4; }
- 注意事项
- 清除读保护之后flash上的所有的数据会清空(变为0xff)
- GD32F150C6T6掉电之后flash会重新上锁,不知道是个体问题、硬件电路导致还是本身特有的属性,手头上只对一片MCU进行操作。