STM32: 通过ST-LINK/V2-1+OpenOCD更新GD32F150C6T6固件

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;
        }
  • 注意事项
  1. 清除读保护之后flash上的所有的数据会清空(变为0xff)
  2. GD32F150C6T6掉电之后flash会重新上锁,不知道是个体问题、硬件电路导致还是本身特有的属性,手头上只对一片MCU进行操作。

发表评论

电子邮件地址不会被公开。 必填项已用*标注