0%

STM32与RTOS实实践

开发板简介

  • The STM32 Nucleo-144 F767ZI boards offer combinations of performance and power that provide an affordable and flexible
    way for users to build prototypes and try out new concepts. For compatible boards, the SMPS significantly reduces power
    consumption in Run mode.
  • The Arduino-compatible ST Zio connector expands functionality of the Nucleo open development platform, with a wide choice
    of specialized Arduino* Uno V3 shields.
  • The STM32 Nucleo-144 board does not require any separate probe as it integrates the ST-LINK/V2-1 debugger/programmer.
  • The STM32 Nucleo-144 board comes with the STM32 comprehensive free software libraries and examples available with the
    STM32Cube MCU Package.
  • Key Features
    • STM32 microcontroller in LQFP144 package
    • Ethernet compliant with IEEE-802.3-2002 (depending on STM32 support)
    • USB OTG or full-speed device (depending on STM32 support)
    • 3 user LEDs
    • 2 user and reset push-buttons
    • 32.768 kHz crystal oscillator
    • Board connectors:
      • USB with Micro-AB
      • SWD
      • Ethernet RJ45 (depending on STM32 support)
      • ST Zio connector including Arduino* Uno V3
      • ST morpho
    • Flexible power-supply options: ST-LINK USB VBUS or external sources.
    • On-board ST-LINK/V2-1 debugger/programmer with USB re-enumeration
    • capability: mass storage, virtual COM port and debug port.
    • Comprehensive free software libraries and examples available with the STM32Cube MCU package.
  • 根据文档The Cortex ® -M7 with FPU core is binary compatible with the Cortex ® -M4 core.说明 ,Cortex-M7内核比M4性更
    高,且二进制兼容.

Zephyr

系统简介

  • Zephyr 内核是一个内存占用极低的内核,它主要设计用于资源受限系统:从简单的嵌入式环境传感器、LED 可穿戴设备,到复杂的智能手表、IoT 无线网关.Zephyr 在被设计时就支持多架构,包括ARM Cortex-M,Intel x86,ARC,NIOS IIRISC V.使用Zephyr的一大优点是操作系统(OS)和软件开发工具包(SDK)可支持数百个开发板.

安装Zephyr环境

初始化工程

1
2
3
4
5
~$ pip3 install west
~$ west init ~/zephyrproject
~$ cd zephyrproject
~$ west update # 这里会通过west,同步大量的git库.
~$ west zephyr-export
  • 更新后的目录结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
~ zephyrproject$ tree -L 2
.
├── bootloader
│ └── mcuboot
├── modules
│ ├── bsim_hw_models
│ ├── crypto
│ ├── debug
│ ├── fs
│ ├── hal
│ ├── lib
│ └── tee
├── tools
│ ├── ci-tools
│ ├── edtt
│ └── net-tools
└── zephyr
├── arch
├── boards
├── cmake
├── CMakeLists.txt
├── CODE_OF_CONDUCT.md
├── CODEOWNERS
├── CONTRIBUTING.rst
├── doc
├── drivers
├── dts
├── include
├── Kconfig
├── Kconfig.zephyr
├── kernel
├── lib
├── LICENSE
├── MAINTAINERS.yml
├── Makefile
├── misc
├── modules
├── README.rst
├── samples
├── scripts
├── share
├── soc
├── subsys
├── tests
├── VERSION
├── version.h.in
├── west.yml
├── zephyr-env.cmd
└── zephyr-env.sh

32 directories, 15 files
  • 安装大量的Python依赖库
    1
    ~ zephyrproject$  pip install -r ./zephyr/scripts/requirements.txt

安装工具链

1
2
3
~$ wget https://github.com/zephyrproject-rtos/sdk-ng/releases/download/v0.11.4/zephyr-sdk-0.11.4-setup.run
~$ chmod +x zephyr-sdk-0.11.4-setup.run
~$ ./zephyr-sdk-0.11.4-setup.run -- -d ~/zephyr-sdk-0.11.4
  • 解压安装完成后,会有一个~/.zephyrrc的环境变量文件.下面安装udev文件.
    1
    2
    ~$ sudo cp ~/zephyr-sdk-0.11.4/sysroots/x86_64-pokysdk-linux/usr/share/openocd/contrib/60-openocd.rules  /etc/udev/rules.d/
    ~$ sudo udevadm control --reload

板级示例程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
~$  west build -p auto  -b nucleo_f767zi samples/hello_world
[......]
-- west build: building application
[1/131] Preparing syscall dependency handling

[126/131] Linking C executable zephyr/zephyr_prebuilt.elf
Memory region Used Size Region Size %age Used
FLASH: 13448 B 2 MB 0.64%
DTCM: 0 GB 128 KB 0.00%
SRAM: 4432 B 384 KB 1.13%
IDT_LIST: 200 B 2 KB 9.77%
[131/131] Linking C executable zephyr/zephyr.elf
# 查看编译目录的文件结构.
~$ ls build/zephyr/
arch drivers kconfig linker.cmd.dep nucleo_f767zi.dts.pre.d zephyr.bin zephyr.map
boards edt.pickle kernel linker_pass_final.cmd nucleo_f767zi.dts.pre.tmp zephyr.dts zephyr_prebuilt.elf
cmake include lib linker_pass_final.cmd.dep runners.yaml zephyr.elf zephyr_prebuilt.map
CMakeFiles isrList.bin libzephyr.a misc soc zephyr.hex zephyr.stat
cmake_install.cmake isr_tables.c linker.cmd nucleo_f767zi.dts_compiled subsys zephyr.lst
  • 连接到目标板子的USB,使用下面命令烧写入示例.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
~$ west flash
Open On-Chip Debugger 0.10.0+dev-01341-g580d06d9d-dirty (2020-06-25-12:07)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : clock speed 2000 kHz
Info : STLINK V2J23M7 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.245850
Info : stm32f7x.cpu: hardware has 8 breakpoints, 4 watchpoints
Info : Listening on port 3333 for gdb connections
TargetName Type Endian TapName State
-- ------------------ ---------- ------ ------------------ ------------
0* stm32f7x.cpu hla_target little stm32f7x.cpu running

Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08000268 msp: 0x20020e8c
Info : device id = 0x10006451
Info : flash size = 2048 kbytes
Info : Single Bank 2048 kiB STM32F76x/77x found
auto erase enabled
wrote 32768 bytes from file /fullpath/zephyrproject/zephyr/build/zephyr/zephyr.hex in 1.283166s (24.938 KiB/s)
  • 通过USB连接的/dev/ttyACM0会看到如下输出.
1
2
3
~$ sudo minicom -o -b 115200 -D /dev/ttyACM0
*** Booting Zephyr OS build v2.4.0-rc3-10-g0a0cb52fb229 ***
Hello World! nucleo_f767zi

板级调试

1
2
3
4
5
6
7
~$ west debug
-- west debug: rebuilding
[0/1] cd /fullpath/zephyrproject/zephyr/build/zephyr/cmake/flash && /usr/bin/cmake -E echo

-- west debug: using runner openocd
/fullpath/zephyr-sdk-0.11.4/arm-zephyr-eabi/bin/arm-zephyr-eabi-gdb: error while loading shared libraries: libpython3.8.so.1.0: cannot open shared object file: No such file or directory
FATAL ERROR: command exited with status 127: /fullpath/zephyr-sdk-0.11.4/arm-zephyr-eabi/bin/arm-zephyr-eabi-gdb -ex 'target remote :3333' /fullpath/zephyrproject/zephyr/build/zephyr/zephyr.elf
  • 如上面错误,是因为这里是使用pyenv安装的python-3.8.2,不在系统内的搜索路径里,而且默认还是静态(static)编译的,所以会出显上面的错误.下面来重装它,并且使用LD_LIBRARY_PATH指定路径.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
~$ CONFIGURE_OPTS=--enable-shared pyenv install 3.8.2
pyenv: /home/michael/.pyenv/versions/3.8.2 already exists
continue with installation? (y/N) y
Installing Python-3.8.2...
Installed Python-3.8.2 to /home/michael/.pyenv/versions/3.8.2

~$ tree -L 1 /home/michael/.pyenv/versions/3.8.2/lib
/home/michael/.pyenv/versions/3.8.2/lib
├── libpython3.8.a
├── libpython3.8.so -> libpython3.8.so.1.0
├── libpython3.8.so.1.0
├── libpython3.so
├── pkgconfig
└── python3.8

2 directories, 4 files

  • 再次运行调试.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
~$ LD_LIBRARY_PATH=/home/michael/.pyenv/versions/3.8.2/lib west debug
-- west debug: rebuilding
[....]
This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=arm-zephyr-eabi".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
[...]
Reading symbols from /fullpath/zephyrproject/zephyr/build/zephyr/zephyr.elf...
Info : stm32f7x.cpu: hardware has 0 breakpoints, 10 watchpoints
Info : Listening on port 3333 for gdb connections
TargetName Type Endian TapName State
-- ------------------ ---------- ------ ------------------ ------------
0* stm32f7x.cpu hla_target little stm32f7x.cpu halted

Info : Listening on port 6333 for tcl connections
Info : Listening on port 4444 for telnet connections
Remote debugging using :3333
Info : accepting 'gdb' connection on tcp/3333
Debugger attaching: halting execution
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
Info : Unable to match requested speed 2000 kHz, using 1800 kHz
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08001004 msp: 0x20020810
force hard breakpoints
Info : device id = 0x10006451
Info : flash size = 2048 kbytes
Info : Single Bank 2048 kiB STM32F76x/77x found
Info : flash size = 1024 bytes
0x08001004 in z_vprintk (out=0x0, ctx=0x0, fmt=0x0, ap=...) at /fullpath/zephyrproject/zephyr/lib/os/printk.c:292
292 while (*s) {
(gdb)

测试非标准板子(STM32F030 DEMO BOARD)

  • STM32F030 DEMO BOARD
  • 我手里的这块stm32f030_demo是没有STLINK-V2调试器的,但是它有引出GND,VCC,DIO,CLK这样一组接口,刚才好手上有一个JLink-OB也是这样的接口,下面就用它来烧写与调试.
1
~$ west build -b stm32f030_demo samples/basic/blinky
  • 配置openocd连接参数.

    1
    2
    3
    4
    5
    ~$ cat > jlink-ob-stm32f0.cfg<<EOF
    source [find interface/jlink.cfg]
    transport select swd
    source [find target/stm32f0x.cfg]
    EOF
  • 使用openocd烧写.

    1
    2
    ~$ cd build/zephyr
    ~$ openocd -f ~/jlink-ob-stm32f0.cfg -c init -c "reset halt" -c "stm32f0x mass_erase 0" -c "flash write_bank 0 zephyr.bin 0" -c "reset run"

Nuttx

系统简介

  • NuttX是一个专注于标准合规和小内存占用的实时操作系统(RTOS).它可以在8位到32位的微控制器上部署.NuttX在编写时主要参照了POSIXANSI标准.对于那些标准中没有的部分,如fork()等,则参考了VxWorks或其他RTOS.NuttX基本上完全是由C语言实现的,并且通过Kconfig生成GNU makefile.NuttX的发行版包括了NuttX内核本身和相当一部分的中间件和板级支持包.NuttX的内核和绝大多数代码完全是由Gregory Nutt完成的,并由他专门维护.所有的社区贡献都必须经过他批准.NuttX最早是在2007年由Gregory Nutt于BSD协议下释出的.

使用BuildRoot构建工具链(非必要)

  • 如果要使用BuildRoot定制编译的工具链就是如下配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    ~$ git clone https://bitbucket.org/nuttx/buildroot.git buildroot
    ~$ cp configs/cortexm7f-eabi-defconfig-7.4.0 .config
    ~$ make menuconfig
    # 终配置如下
    ~$ grep -v '^$\|^#' .config
    BR2_HAVE_DOT_CONFIG=y
    BR2_arm=y
    BR2_cortex_m7f=y
    BR2_GCC_CORTEX=y
    BR2_GCC_CORTEX_M7F=y
    BR2_ARM_EABI=y
    BR2_ARCH="arm"
    BR2_GCC_TARGET_TUNE="cortex-m7"
    BR2_GCC_TARGET_ARCH="armv7-m"
    BR2_GCC_TARGET_ABI="aapcs-linux"
    BR2_WGET="wget --passive-ftp"
    BR2_SVN="svn co"
    BR2_ZCAT="zcat"
    BR2_BZCAT="bzcat"
    BR2_TAR_OPTIONS=""
    BR2_DL_DIR="$(BASE_DIR)/../archives"
    BR2_STAGING_DIR="$(BUILD_DIR)/staging_dir"
    BR2_NUTTX_DIR="$(TOPDIR)/../nuttx"
    BR2_TOPDIR_PREFIX=""
    BR2_TOPDIR_SUFFIX=""
    BR2_GNU_BUILD_SUFFIX="pc-elf"
    BR2_GNU_TARGET_SUFFIX="nuttx-eabi"
    BR2_PACKAGE_BINUTILS=y
    BR2_BINUTILS_VERSION_2_28_1=y
    BR2_BINUTILS_SUPPORTS_NUTTX_OS=y
    BR2_BINUTILS_VERSION="2.28.1"
    BR2_EXTRA_BINUTILS_CONFIG_OPTIONS=""
    BR2_PACKAGE_GCC=y
    BR2_GCC_VERSION_7_4_0=y
    BR2_GCC_SUPPORTS_SYSROOT=y
    BR2_GCC_SUPPORTS_NUTTX_OS=y
    BR2_GCC_SUPPORTS_DOWN_PREREQ=y
    BR2_GCC_DOWNLOAD_PREREQUISITES=y
    BR2_GCC_VERSION="7.4.0"
    BR2_EXTRA_GCC_CONFIG_OPTIONS=""
    BR2_INSTALL_LIBSTDCPP=y
    BR2_PACKAGE_GDB_HOST=y
    BR2_GDB_VERSION_8_0_1=y
    BR2_PACKAGE_GDB_TUI=y
    BR2_GDB_VERSION="8.0.1"
    BR2_PACKAGE_NXFLAT=y
    BR2_PACKAGE_GENROMFS=y
    BR2_PACKAGE_KCONFIG_FRONTENDS=y
    BR2_KCONFIG_VERSION_4_11_0_1=y
    BR2_KCONFIG_FRONTENDS_VERSION="4.11.0.1"
    BR2_LARGEFILE=y
    BR2_SOFT_FLOAT=y
    BR2_TARGET_OPTIMIZATION="-Os -pipe"

  • 编译成功后,会在buildroot生成一个目录,结构如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ~$ tree -L 2 build_arm_hf/
    build_arm_hf/
    ├── root
    └── staging_dir
    ├── arm-elf -> arm-nuttx-eabi
    ├── arm-nuttx-eabi
    ├── bin
    ├── include
    ├── lib
    ├── libexec
    ├── share
    └── usr

    10 directories, 0 files

编译

  • nuttx Wiki
  • 把上面工具链的绝对路径加入Shell环境变量中使用,也可以使用第三方的工具链,如:Zephyrarm-zephyr-eabi,也可以使用如:gcc-arm-none-eabi-6-2017-q2-update的工具链,在Debian下可以安装系统自带的gcc-arm-none-eabi包.在make menuconfig时,选择CONFIG_ARMV7M_TOOLCHAIN_GNU_EABIL=y.
1
2
3
4
~$ tools/configure.sh -L | grep "f767"
nucleo-144:f767-netnsh
nucleo-144:f767-nsh
nucleo-144:f767-evalos
  • 因为NULEO-F767ZI是有一个以太网接口,这里选择使用nucleo-144:f767-netnsh配置文件.

    1
    2
    3
    4
    ~$ tools/configure.sh  nucleo-144:f767-netnsh
    ~$ make oldconfig
    ~$ make menuconfig
    ~$ make # 如果是使用第三方工具链,就如这样: make CROSSDEV=arm-none-eabi-
  • 这里最终测试的系统配置如下:

ESP8266通信

  • 这里是使用板上的USART6通信,而USART3默认是做为系统的CONSOLE的接口,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    CONFIG_STM32F7_USART6=y
    CONFIG_USART6_SERIALDRIVER=y
    CONFIG_DEV_CONSOLE=y
    CONFIG_NSH_CONSOLE=y
    CONFIG_SERIAL_CONSOLE=y
    CONFIG_USART3_SERIAL_CONSOLE=y
    CONFIG_NUCLEO_CONSOLE_VIRTUAL=y
    CONFIG_NETUTILS_ESP8266_DEV_PATH="/dev/ttyS1"

    # 安装CU命令,就是类似于putty,minicom这样的串口通信工具.
    CONFIG_SYSTEM_CUTERM=y
    CONFIG_SYSTEM_CUTERM_DEFAULT_DEVICE="/dev/ttyS0"
    CONFIG_SYSTEM_CUTERM_DEFAULT_BAUD=115200
    CONFIG_SYSTEM_CUTERM_STACKSIZE=2048
    CONFIG_SYSTEM_CUTERM_PRIORITY=100

  • 同时需要在boards/arm/stm32f7/nucleo-144/include/board.h添加USART6的接口定义.

1
2
3
4
[...]
# define GPIO_USART6_RX GPIO_USART6_RX_2
# define GPIO_USART6_TX GPIO_USART6_TX_2
[...]
  • 连接ESP8266

    1
    2
    3
    4
    5
    6
    7
    STM32F767ZI-NUCLEO          ESP01

    D0 RX ---> TX
    D1 TX ---> RX
    GND ---> GND
    3V3 ---> 3V3
    3V3 ---> CH_PD # 拉高进入正常模式
  • 连接测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    nsh> cu -s 115200 -l /dev/ttyS1
    AT

    OK
    AT+GMR
    AT version:1.7.4.0(May 11 2020 19:13:04)
    SDK version:3.0.4(9532ceb)
    compile time:May 27 2020 10:12:17
    Bin version(Wroom 02):1.7.4
    OK

    AT+SYSRAM?
    +SYSRAM:51952

    OK

外接SPI-SD读卡器

  • 这里使用SPI3:(PB3:CLK),(PB4:MISO),(PB5:MOSI)来外接SD读卡器,根据数据手册stm32f767zi.pdf,NSS(CS)片选可以是软件定义也可以使它硬件(PA4:GPIO_SPI3_NSS_2)定义的,因为这里的使用场景非常简单,就是用PA4来做从机的CS片选.
  • nuttx的系统内boards/arm/stm32f7/nucleo-144/src没有mmcsd相关的文件,这里可以有从其它板子的
    stm32_mmcsd.c文件复制修改一下就可以使用.
  • boards/arm/stm32f7/nucleo-144/src/nucle-144.h定义CS.
1
2
3
4
5
6
7
[...]
#define GPIO_SPI_CS (GPIO_OUTPUT | GPIO_PUSHPULL | GPIO_SPEED_50MHz | \
GPIO_OUTPUT_SET)
#if defined(CONFIG_MMCSD_SPI)
#define GPIO_SPI3_CARD_CS (GPIO_SPI_CS | GPIO_PORTA | GPIO_PIN4)
#endif
[...]
  • boards/arm/stm32f7/nucleo-144/src/stm32_mmcsd.c内定义函数的实现.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
[....]
#ifdef CONFIG_STM32F7_SPI3
int stm32_spi3register(struct spi_dev_s *dev, spi_mediachange_t callback,
void *arg)
{
/* TODO: media change callback */
return OK;
}
#endif

/*****************************************************************************
* Name: stm32_mmcsd_initialize
*
* Description:
* Initialize SPI-based SD card and card detect thread.
****************************************************************************/

int stm32_mmcsd_initialize(int port, int minor)
{
struct spi_dev_s *spi;
int rv;

stm32_configgpio(GPIO_SPI3_CARD_CS); /* Assign CS */
stm32_gpiowrite(GPIO_SPI3_CARD_CS, 1); /* Ensure the CS is inactive */

mcinfo("INFO: Initializing mmcsd port %d minor %d \n",
port, minor);

spi = stm32_spibus_initialize(port);
if (spi == NULL)
{
mcerr("ERROR: Failed to initialize SPI port %d\n", port);
return -ENODEV;
}

rv = mmcsd_spislotinitialize(minor, minor, spi);
if (rv < 0)
{
mcerr("ERROR: Failed to bind SPI port %d to SD slot %d\n",
port, minor);
return rv;
}

spiinfo("INFO: mmcsd card has been initialized successfully\n");
return OK;
}
  • 修改文件boards/arm/stm32f7/nucleo-144/src/stm32_spi.c内的相关函数内容.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    [...]
    #ifdef CONFIG_STM32F7_SPI3
    void stm32_spi3select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected)
    {
    spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert");
    #if defined(CONFIG_MMCSD_SPI)
    stm32_gpiowrite(GPIO_SPI3_CARD_CS, !selected);
    #endif
    }

    uint8_t stm32_spi3status(FAR struct spi_dev_s *dev, uint32_t devid)
    {
    uint8_t ret = 0;
    #if defined(CONFIG_MMCSD_SPI)
    if (devid == SPIDEV_MMCSD(0))
    {
    /* Note: SD_DET is pulled high when there\'s no SD card present. */
    /* 因为读卡没CD脚(插卡检测),或者不用该功能,就必须返回卡已经插入的条件.
    * 凭此条件去进行下一步,读卡写卡操作,很重要. */

    ret |= SPI_STATUS_PRESENT;
    }
    #endif
    return ret;
    }
  • 在系统初始化的流程内加入MMCSD_SPI的初始流程.修改文件boards/arm/stm32f7/nucleo-144/src/stm32_appinitialize.c.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [...]
    #ifdef CONFIG_MMCSD_SPI
    /* Initialize the MMC/SD SPI driver (SPI2 is used) */

    ret = stm32_mmcsd_initialize(3, CONFIG_NSH_MMCSDMINOR);
    if (ret < 0)
    {
    syslog(LOG_ERR, "Failed to initialize SD slot %d: %d\n",
    CONFIG_NSH_MMCSDMINOR, ret);
    }
    #endif
    [....]
  • 最后是修改boards/arm/stm32f7/nucleo-144/src/Makefile文件,加入如下内容.

    1
    2
    3
    4
    5
    [...]
    ifeq ($(CONFIG_MMCSD_SPI),y)
    CSRCS += stm32_mmcsd.c
    endif
    [...]

QSPI驱动(未测试成功)

  • 不知为何,工程文件内没有定义QSPI的管脚.这里只是通过编译,还未成功读写它.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    ~$ grep "/* QSPI"  boards/arm/stm32f7/nucleo-144/include/board.h -A 20
    /* QSPI
    *
    * reference from UM1974 chapter 6.14
    * stm32f7/hardware/stm32f76xx77xx_pinmap.h
    *
    * PB6 GPIO_QSPI_CS CN10-13
    * PB2 GPIO_QSPI_SCK CN10-15
    * PD11 GPIO_QSPI_IO0 CN10-23
    * PD12 GPIO_QSPI_IO1 CN10-21
    * PE2 GPIO_QSPI_IO2 CN10-25
    * PD13 GPIO_QSPI_IO3 CN10-19
    *
    * */
    #define GPIO_QSPI_CS GPIO_QUADSPI_BK1_NCS_1
    #define GPIO_QSPI_SCK GPIO_QUADSPI_CLK_1
    #define GPIO_QSPI_IO0 GPIO_QUADSPI_BK1_IO0_3
    #define GPIO_QSPI_IO1 GPIO_QUADSPI_BK1_IO1_3
    #define GPIO_QSPI_IO2 GPIO_QUADSPI_BK1_IO2_1
    #define GPIO_QSPI_IO3 GPIO_QUADSPI_BK1_IO3_2


烧写与测试

  • 编译成功后nuttx内会有nuttx,nuttx.bin,nuttx.hex三个文件,通过openocd烧写与调试目标板子.

    1
    ~$ sudo openocd -f board/stm32f7discovery.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000"
  • 连接网卡与USB接口,使用minicom连接串口,进入系统.有时引同会长时间无法初始化,尝试按一下板子上的B1 USER按键.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ~$ minicom -o -b 115200 -D /dev/ttyACM0

    nsh> help
    help usage: help [-v] [<cmd>]

    . cat df hexdump mkdir mw set umount
    [ cd echo ifconfig mkfatfs nslookup sleep unset
    ? cp exec ifdown mkfifo ps source usleep
    addroute cmp exitifup mkrd pwd test wget
    arp dirname false kill mh rm time xd
    basename dd free ls mount rmdir true
    break delroute help mb mv route uname

    Builtin Apps:
    ping6 renew ntpcstop sh
    ntpcstart ping mm nsh

Iotjs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
~$ git clone https://github.com/Samsung/iotjs.git
~$ ls
apps buildroot iotjs nuttx
# 须要先构建它.
~$ cd iotjs && tools/build.py --target-arch=arm --target-os=nuttx --nuttx-home=/fullpath/nuttx --target-board=stm32f7nucleo --jerry-heaplimit=78
==> Initialize submodule

git submodule init

Submodule 'deps/http-parser' (https://github.com/Samsung/http-parser.git) registered for path 'deps/http-parser'
Submodule 'deps/jerry' (https://github.com/jerryscript-project/jerryscript.git) registered for path 'deps/jerry'
Submodule 'deps/libtuv' (https://github.com/Samsung/libtuv.git) registered for path 'deps/libtuv'
Submodule 'deps/mbedtls' (https://github.com/ARMmbed/mbedtls.git) registered for path 'deps/mbedtls'
git submodule update
  • 编译中出现下面的错误,是因为头文件里的一些条件宏定义的结果,也就是说在nuttx系统内没有选择CONFIG_SERIAL_TERMIOS=y,所以才会导至error: field 'orig_termios' has incomplete type.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    In file included from /fullpath/iotjs/deps/libtuv/include/uv.h:77:0,
    from /fullpath/iotjs/deps/libtuv/src/fs-poll.c:22:
    /fullpath/iotjs/deps/libtuv/include/uv-unix.h:428:18: error: field 'orig_termios' has incomplete type
    struct termios orig_termios; \
    ^
    /fullpath/iotjs/deps/libtuv/include/uv.h:680:3: note: in expansion of macro 'UV_TTY_PRIVATE_FIELDS'
    UV_TTY_PRIVATE_FIELDS
    ^
    make[5]: *** [CMakeFiles/tuv.dir/build.make:63: CMakeFiles/tuv.dir/src/fs-poll.c.obj] Error 1
    make[4]: *** [CMakeFiles/Makefile2:73: CMakeFiles/tuv.dir/all] Error 2
    make[3]: *** [Makefile:130: all] Error 2
    make[2]: *** [CMakeFiles/libtuv.dir/build.make:111: deps/libtuv/src/libtuv-stamp/libtuv-build] Error 2
    make[1]: *** [CMakeFiles/Makefile2:184: CMakeFiles/libtuv.dir/all] Error 2
    make: *** [Makefile:130: all] Error 2
  • apps/system内,创建一个iotjs的目录,具的app内容是来自于STM32F4下面的.

    1
    2
    ~$ mkdir apps/system/iotjs
    ~$ cp iotjs/config/nuttx/stm32f4dis/app/* apps/system/iotjs
  • 必须要在app/system/Kconfig加上一条source "/<fullpath>/apps/system/iotjs/Kconfig"记录.

使用串口与ESP8266通信

  • 在使用ESP8266时,要注意配置几个必须项,这里使用板上的UART4来通信.
    1
    2
    3
    -> System Type -> STM32 Peripheral Support -> [*] UART4
    -> Application Configuration -> Network Utilities -> [*] ESP8266
    -> Application Configuration -> System Libraries and NSH Add-Ons -> [*] CU minimal serial terminal
  • UART4定义缺失的错误
    1
    2
    3
    4
    5
    6
    7
    8
    9
    CC:  chip/stm32_serial.c
    chip/stm32_serial.c:1037:20: error: 'GPIO_UART4_TX' undeclared here (not in a function)
    .tx_gpio = GPIO_UART4_TX,
    ^
    chip/stm32_serial.c:1038:20: error: 'GPIO_UART4_RX' undeclared here (not in a function)
    .rx_gpio = GPIO_UART4_RX,
    ^
    make[1]: *** [Makefile:154: stm32_serial.o] Error 1

STM32F103最小系统

  • 这里使用的最小板系统,标准JTAG与大部分管脚能引出来,清晰明了,这里重点参照nuttx板子内的README.md.但是这里在使用USB开启CDC/ACM串口时没成功.
1
~$ tools/configure.sh  stm32f103-minimum:usbnsh
  • 看了这个系统内的文档说明,STM32F103C8T6的内部flash128KB而不是它数据文档所说的64KB,所下这里修改ld文件如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ~$ cat boards/arm/stm32/stm32f103-minimum/scripts/ld.script
    [....]
    /* The STM32F103C8T6 has 64Kb of FLASH beginning at address 0x0800:0000 and
    * 20Kb of SRAM beginning at address 0x2000:0000. When booting from FLASH,
    * FLASH memory is aliased to address 0x0000:0000 where the code expects to
    * begin execution by jumping to the entry point in the 0x0800:0000 address
    * range.
    *
    * NOTE: While the STM32F103C8T6 states that the part has 64Kb of FLASH,
    * all parts that I have seen do, in fact, have 128Kb of FLASH. That
    * additional 64Kb of FLASH can be utilized by simply change the LENGTH
    * of the flash region from 64K to 128K.
    */

    MEMORY
    {
    flash (rx) : ORIGIN = 0x08000000, LENGTH = 128K
    sram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
    }
    [...]
  • 配置openocd通过Jlink-OB来烧写调试.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    ~$ cat ~/jlink-ob-stm32f1-swd.cfg
    source [find interface/jlink.cfg]
    transport select swd
    source [find target/stm32f1x.cfg]

    # 烧写
    ~$ openocd -f ~/jlink-ob-stm32f1-swd.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000" -c "reset run"
    Open On-Chip Debugger 0.10.0+dev-01423-g3ffa14b04-dirty (2020-10-14-08:59)
    Licensed under GNU GPL v2
    For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
    Info : J-Link ARM-OB STM32 compiled Aug 22 2012 19:52:04
    Info : Hardware version: 7.00
    Info : VTarget = 3.300 V
    Info : clock speed 1000 kHz
    Info : SWD DPIDR 0x1ba01477
    Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
    Info : starting gdb server for stm32f1x.cpu on 3333
    Info : Listening on port 3333 for gdb connections
    target halted due to debug-request, current mode: Thread
    xPSR: 0x01000000 pc: 0x08000130 msp: 0x20000f54
    Info : device id = 0x20036410
    Info : flash size = 128kbytes
    auto erase enabled
    wrote 78848 bytes from file nuttx.bin in 7.988087s (9.639 KiB/s)

  • 配置openocd通过其它带有ST-Link调试板子来烧写调试,一般的官方评估板都会带有调试器如,NUCLEO的系列,这里是使用NUCLEO-L152RE板上的ST-LINK来烧写调试.首先,把NUCLEO-L152RE板上CN2跳线取掉,根据官方文档(SWD)CN4的端线序是1:VDD,2:SWCLK,3:GND,4:SWDIO,5:NRST,6:SWO,这里只需要三根连接既可,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
      SWD         STM32F103C8T6
PIN2 SWCLK ----> P14 SWCLK
PIN3 GND ----> GND
PIN4 SWDIO ----> P13 SWDIO

~$ openocd -f interface/stlink.cfg -f target/stm32f1x.cfg -c init -c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000" -c "reset run"
Open On-Chip Debugger 0.10.0+dev-01423-g3ffa14b04-dirty (2020-10-14-08:59)
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
Info : clock speed 1000 kHz
Info : STLINK V2J22M5 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.262028
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f1x.cpu on 3333
Info : Listening on port 3333 for gdb connections
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x08000130 msp: 0x20000d40
Info : device id = 0x20036410
Info : flash size = 128kbytes
auto erase enabled
wrote 109568 bytes from file nuttx.bin in 5.901268s (18.132 KiB/s)
  • 因为STM32F103C8T6的内存只有20K,所以很容易就爆了,最经典的错误就是无法运行内置app,如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
NuttShell (NSH) NuttX-9.1.0
nsh> ?
help usage: help [-v] [<cmd>]

. cmp exit kill mount rmdir true
[ dirname export ls mv rmmod uname
? date false lsmod mw set umount
basename dd free mb printf sleep unset
cat df help mkdir ps source usleep
cd echo hexdump mksmartfs pwd test xd
cp exec insmod mh rm time

Builtin Apps:
chat sh hello spi nsh cu
nsh> free
total used free largest
Umem: 17072 15272 1800 1736

nsh> spi
nsh: spi: command not found
  • 原来是因为,内存不够,无法把程序从FLASH复制到内存中运行,所以会出现上面错误,如果打开编译调试错误出,会从nsh shell得到更进一步的错误信息详情,参考.
  • 我这里处理的方法就是把各种线程栈(STACKSIZE)的体积缩小到最大只能是1024,如上所示,内存只有1800,但是编译时设置的spi toolSTACKSIZE2048.

连接ESP8266

  • 这里是使用USART3,并且是设置:
    1
    -> System Type -> U[S]ART Configuration -> Serial Driver Configuration -> [*] Disable reordering of ttySx devices.
    ESP8266的串口路径是/dev/ttyS1. 连接图如下.
1
2
3
4
5
6
7
  STM32            ESP8266
PB10 TX3 ------> RX
PB11 RX3 ------> TX
3V3 ------> CH_PD # 这里应该使用一个GPIO来驱动它.
3V3 ------> 3V3
GND ------> GND

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
nsh> ?
help usage: help [-v] [<cmd>]

. cmp exit kill mount rmdir true
[ dirname export ls mv rmmod uname
? date false lsmod mw set umount
basename dd free mb printf sleep unset
cat df help mkdir ps source usleep
cd echo hexdump mksmartfs pwd test xd
cp exec insmod mh rm time

Builtin Apps:
chat sh spi nsh cu
nsh> cu -s 115200 -l /dev/ttyS1
AT

OK
AT+GMR
AT version:1.7.4.0(May 11 2020 19:13:04)
SDK version:3.0.4(9532ceb)
compile time:May 27 2020 10:12:17
Bin version(Wroom 02):1.7.4
OK

读写SD卡(over SPI)

  • 这里只能使用SPI1做为SD接口,因为在boards/arm/stm32/stm32f103-minimum/src/stm32_mmcsd.c内在已经硬编码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /*****************************************************************************
    * Pre-processor Definitions
    ****************************************************************************/

    #ifndef CONFIG_STM32_SPI1
    # error "SD driver requires CONFIG_STM32_SPI1 to be enabled"
    #endif

    #ifdef CONFIG_DISABLE_MOUNTPOINT
    # error "SD driver requires CONFIG_DISABLE_MOUNTPOINT to be disabled"
    #endif

    /*****************************************************************************
    * Private Definitions
    ****************************************************************************/

    static const int SD_SPI_PORT = 1; /* SD is connected to SPI1 port */
    static const int SD_SLOT_NO = 0; /* There is only one SD slot */

  • 基本的必须配置项如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    CONFIG_STM32_SPI=y
    CONFIG_STM32_SPI1=y
    CONFIG_SPI=y
    CONFIG_SPI_EXCHANGE=y
    CONFIG_SPI_DRIVER=y
    CONFIG_MMCSD_SPI=y
    CONFIG_MMCSD_SPICLOCK=20000000
    CONFIG_MMCSD_SPIMODE=0

    CONFIG_MMCSD=y
    CONFIG_MMCSD_NSLOTS=1
    CONFIG_MMCSD_SPI=y
    CONFIG_MMCSD_SPICLOCK=20000000
    CONFIG_MMCSD_SPIMODE=0
    CONFIG_MMCSD_IDMODE_CLOCK=400000
    CONFIG_NSH_MMCSDMINOR=0
    CONFIG_NSH_MMCSDSLOTNO=0
    CONFIG_NSH_MMCSDSPIPORTNO=1

    CONFIG_FS_FAT=y
    CONFIG_FAT_LCNAMES=y
    CONFIG_FAT_LFN=y
    CONFIG_FAT_MAXFNAME=32
    CONFIG_FAT_LFN_ALIAS_TRAILCHARS=0
    CONFIG_FSUTILS_MKFATFS=y

读写W25Q32FV

  • 通过查看代码发现,W25Q32FV也是使用SPI1默认也是硬编码写,这里是默认使用SPI1是的常规必须选项.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    CONFIG_STM32_SPI1=y
    CONFIG_STM32_SPI=y

    CONFIG_MTD_W25=y
    CONFIG_W25_SPIMODE=0
    CONFIG_W25_SPIFREQUENCY=20000000

    CONFIG_MTD=y
    CONFIG_MTD_PARTITION=y
    CONFIG_MTD_BYTE_WRITE=y
    CONFIG_MTD_SMART=y
    CONFIG_MTD_SMART_SECTOR_SIZE=1024
    CONFIG_MTD_SMART_WEAR_LEVEL=y
    CONFIG_MTD_W25=y
    CONFIG_FSUTILS_MKSMARTFS=y
  • 按照上面的配置,连接W25QF32V的线路如下:

    1
    2
    3
    4
    5
    6
    7
    8
    W25QF32V       STM32F103

    CS ----> PA4/NSS
    DO ----> PA6/MISO
    DI ----> PA7/MOSI
    CLK ----> PA5/SCK
    GND ----> GND
    VCC ----> 3V3
  • 格化格,挂载,读写测试.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    nsh> mkdir /tmp
    nsh> ls /
    /:
    dev/
    mnt/
    proc/
    nsh> mksmartfs /dev/smart0p1
    nsh> mount -t smartfs /dev/smart0p1 /tmp
    nsh> echo "11223456" > /tmp/file1.txt
    nsh> cat /tmp/file1.txt
    11223456
  • STM32F103C8T6上大部分的接口都描述了Pin的功能,少部分如:PB12,PB13...,这些需要查询stm32f103c8.pdf内的,Chapter 3, Table 5内容.

扩展使用SPI2

  • STM32F103C8T6最小板,引出了两个SPI:

    • SPI1: PA4(NSS), PA5(SCK), PA6(MISO), PA7(MOSI)
    • SPI2: PB12(NSS), PB13(SCK), PB14(MISO), PB15(MOSI)
  • 但是在Nuttx的里只开启了SPI1,同时只能接一个外设.所以,我要参照文件来修改它,目标是把SPI1连接到SD over SPI,SPI2连接到W25QF32V.

  • 根据FLASH_SPI1_CS添加FLASH_SPI2_CS宏定义,指定PB12,最终文件如下:

    1
    2
    3
    4
    5
    6
    7
    ~$ cat boards/arm/stm32/stm32f103-minimum/src/stm32f103_minimum.h
    [...]
    /* SPI chip selects */

    #define FLASH_SPI2_CS (GPIO_OUTPUT|GPIO_CNF_OUTPP|GPIO_MODE_50MHz|\
    GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN12)
    [...]
  • 修改stm32_spi.c,这个文件修改比较多,做成patch文件如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    ~$ git diff  boards/arm/stm32/stm32f103-minimum/src/stm32_spi.c  > spi2.patch
    diff --git a/boards/arm/stm32/stm32f103-minimum/src/stm32_spi.c b/boards/arm/stm32/stm32f103-minimum/src/stm32_spi.c
    index 6f3a585902..01b5b861e8 100644
    --- a/boards/arm/stm32/stm32f103-minimum/src/stm32_spi.c
    +++ b/boards/arm/stm32/stm32f103-minimum/src/stm32_spi.c
    @@ -75,7 +75,7 @@ void stm32_spidev_initialize(void)
    */

    #ifdef CONFIG_MTD_W25
    - stm32_configgpio(FLASH_SPI1_CS); /* FLASH chip select */
    + stm32_configgpio(FLASH_SPI2_CS); /* FLASH chip select */
    #endif

    #ifdef CONFIG_CAN_MCP2515
    @@ -197,7 +197,7 @@ void stm32_spi1select(FAR struct spi_dev_s *dev, uint32_t devid,
    #endif

    #ifdef CONFIG_MTD_W25
    - stm32_gpiowrite(FLASH_SPI1_CS, !selected);
    + //stm32_gpiowrite(FLASH_SPI1_CS, !selected);
    #endif
    }

    @@ -227,6 +227,9 @@ uint8_t stm32_spi1status(FAR struct spi_dev_s *dev, uint32_t devid)
    void stm32_spi2select(FAR struct spi_dev_s *dev, uint32_t devid,
    bool selected)
    {
    +#ifdef CONFIG_MTD_W25
    + stm32_gpiowrite(FLASH_SPI2_CS, !selected);
    +#endif
    }

    uint8_t stm32_spi2status(FAR struct spi_dev_s *dev, uint32_t devid)
    @@ -294,6 +297,16 @@ int stm32_spi1cmddata(FAR struct spi_dev_s *dev, uint32_t devid,
    return -ENODEV;
    }
    #endif
    +
    +#ifdef CONFIG_STM32_SPI2
    +int stm32_spi2cmddata(FAR struct spi_dev_s *dev, uint32_t devid,
    + bool cmd)
    +{
    + return -ENODEV;
    +}
    +#endif
    +
    +
    #endif

    #endif /* CONFIG_STM32_SPI1 || CONFIG_STM32_SPI2 */

  • 修改stm32_w25.c如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    git diff  boards/arm/stm32/stm32f103-minimum/src/stm32_w25.c
    diff --git a/boards/arm/stm32/stm32f103-minimum/src/stm32_w25.c b/boards/arm/stm32/stm32f103-minimum/src/stm32_w25.c
    index 6e9d12718d..63ba5153ce 100644
    --- a/boards/arm/stm32/stm32f103-minimum/src/stm32_w25.c
    +++ b/boards/arm/stm32/stm32f103-minimum/src/stm32_w25.c
    @@ -47,7 +47,7 @@
    #include <errno.h>
    #include <debug.h>

    -#ifdef CONFIG_STM32_SPI1
    +#ifdef CONFIG_STM32_SPI2
    # include <nuttx/spi/spi.h>
    # include <nuttx/mtd/mtd.h>
    # include <nuttx/fs/smart.h>
    @@ -67,13 +67,13 @@
    * timer
    */

    -#define W25_SPI_PORT 1
    +#define W25_SPI_PORT 2

    /* Configuration ************************************************************/
    /* Can't support the W25 device if it SPI1 or W25 support is not enabled */

    #define HAVE_W25 1
    -#if !defined(CONFIG_STM32_SPI1) || !defined(CONFIG_MTD_W25)
    +#if !defined(CONFIG_STM32_SPI2) || !defined(CONFIG_MTD_W25)
    # undef HAVE_W25
    #endif

  • 修改stm32_bringup.c如下.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ~$ git diff boards/arm/stm32/stm32f103-minimum/src/stm32_bringup.c
    diff --git a/boards/arm/stm32/stm32f103-minimum/src/stm32_bringup.c b/boards/arm/stm32/stm32f103-minimum/src/stm32_bringup.c
    index efa651034e..b4b0379bde 100644
    --- a/boards/arm/stm32/stm32f103-minimum/src/stm32_bringup.c
    +++ b/boards/arm/stm32/stm32f103-minimum/src/stm32_bringup.c
    @@ -143,7 +143,7 @@

    /* Can't support the W25 device if it SPI1 or W25 support is not enabled */

    -#if !defined(CONFIG_STM32_SPI1) || !defined(CONFIG_MTD_W25)
    +#if !defined(CONFIG_STM32_SPI2) || !defined(CONFIG_MTD_W25)
    # undef HAVE_W25
    #endif

开启串口调试

  • 如果没有在配置系统里打开相应的DEBUG选项,系统只出错时,只会给出一个简单错误号.下面是打开针对SPI,FS,MMC/SD的出错提示.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    CONFIG_DEBUG_ALERT=y
    CONFIG_DEBUG_FEATURES=y
    CONFIG_DEBUG_ERROR=y
    CONFIG_DEBUG_FS=y
    CONFIG_DEBUG_FS_ERROR=y
    CONFIG_DEBUG_IRQ=y
    CONFIG_DEBUG_IRQ_ERROR=y
    CONFIG_DEBUG_MEMCARD=y
    CONFIG_DEBUG_MEMCARD_ERROR=y
    CONFIG_DEBUG_SPI=y
    CONFIG_DEBUG_SPI_ERROR=y
    CONFIG_DEBUG_FULLOPT=y
    CONFIG_ARCH_HAVE_HARDFAULT_DEBUG=y
    CONFIG_ARCH_HAVE_MEMFAULT_DEBUG=y
    CONFIG_STM32_DISABLE_IDLE_SLEEP_DURING_DEBUG=y
1
2
nsh> mount -t vfat /dev/mmcsd1 /mnt/sd1
nsh: mount: mount failed: 19
  • 如果碰到类似的错误号,可以打开nuttx/include/errno.h,会看到如下所示:

    1
    2
    #define ENODEV              19
    #define ENODEV_STR "No such device"
  • 最终同时开启SPI1,SPI2的接口,包含了SPI,FS,MMC/SD,MTD一些必须选项,配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44

    CONFIG_STM32_SPI1=y
    CONFIG_STM32_SPI2=y
    CONFIG_STM32_SPI=y

    CONFIG_ARCH_HAVE_SPI_BITORDER=y
    CONFIG_SPI=y
    CONFIG_SPI_EXCHANGE=y
    CONFIG_SPI_CMDDATA=y
    CONFIG_SPI_DRIVER=y
    CONFIG_MMCSD=y
    CONFIG_MMCSD_NSLOTS=1
    CONFIG_MMCSD_SPI=y
    CONFIG_MMCSD_SPICLOCK=20000000
    CONFIG_MMCSD_SPIMODE=0
    CONFIG_MMCSD_IDMODE_CLOCK=400000

    CONFIG_MTD=y
    CONFIG_MTD_PARTITION=y
    CONFIG_MTD_BYTE_WRITE=y
    CONFIG_MTD_SMART=y
    CONFIG_MTD_SMART_SECTOR_SIZE=1024
    CONFIG_MTD_SMART_WEAR_LEVEL=y
    CONFIG_MTD_W25=y
    CONFIG_W25_SPIMODE=0
    CONFIG_W25_SPIFREQUENCY=20000000

    CONFIG_FS_NEPOLL_DESCRIPTORS=8
    CONFIG_FS_MQUEUE_MPATH="/var/mqueue"
    CONFIG_FS_FAT=y
    CONFIG_FS_SMARTFS=y
    CONFIG_SMARTFS_ERASEDSTATE=0xff
    CONFIG_SMARTFS_MAXNAMLEN=16
    CONFIG_FS_PROCFS=y
    CONFIG_FS_PROCFS_REGISTER=y
    CONFIG_FS_PROCFS_EXCLUDE_ENVIRON=y

    CONFIG_FSUTILS_MKFATFS=y
    CONFIG_FSUTILS_MKSMARTFS=y
    CONFIG_NSH_MMCSDMINOR=0
    CONFIG_NSH_MMCSDSLOTNO=0
    CONFIG_NSH_MMCSDSPIPORTNO=1
    CONFIG_NSH_CODECS_BUFSIZE=128

  • 测试系统如下.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    NuttShell (NSH) NuttX-9.1.0
    nsh> ls /dev
    /dev:
    console
    mmcsd0
    null
    smart0p0
    smart0p1
    smart0p2
    smart0p3
    ttyS0
    nsh> free
    total used free largest
    Umem: 17536 12872 4664 4664
    nsh> mkdir /mnt /p0
    nsh: mkdir: too many arguments
    nsh> mkdir /mnt
    nsh> mkdir /p0
    nsh> mount -t vfat /dev/mmcsd0 /mnt
    nsh> mount -t smartfs /dev/smart0p0 /p0
    nsh> df
    Block Number
    Size Blocks Used Available Mounted on
    16384 15611 3 15608 /mnt
    1024 64 11 53 /p0
    0 0 0 0 /proc
    nsh> free
    total used free largest
    Umem: 17536 14888 2648 2584
    nsh> ls /p0
    /p0:
    file.txt
    nsh> cat /p0/file.txt
    test
    nsh> free
    total used free largest
    Umem: 17536 14888 2648 2584
    nsh> ls /mnt
    /mnt:
    file1.txt
    nsh> cat /mnt/file1.txt
    1112222ssss

NUCLEO-L152RE (MB1136 c-03)

提交代码给NuttX

  • Github中文文档
  • Making Changes Using Git
  • NuttX代码是在Github上,所以要为它提交代码,需要先有Github帐号.
  • 在自己的GithubforkNuttX.再在本地克隆刚才forkNuttX.
  • 并且把原https://github.com/apache/incubator-nuttx.git设置成上游(upstream).
1
2
~$ git clone <your forked incubator-nuttx project clone url>
~$ git remote add upstream https://github.com/apache/incubator-nuttx.git
  • 创建一个本地的开发分支,并且把它pull自己fork项目中去.
    1
    2
    3
    4
    5
    6
    7
    8
    ~$ git checkout -b dev/stm32l152re-ili93418b-driver
    Switched to a new branch 'dev/stm32l152re-ili93418b-driver'

    ~$ git push
    fatal: The current branch dev/stm32l152re-ili93418b-driver has no upstream branch.
    To push the current branch and set the remote as upstream, use

    git push --set-upstream origin dev/stm32l152re-ili93418b-driver
  • 按照提示,需要关联到远程分支,把本地分支dev/stm32l152re-ili93418b-driver推送到origin远程分支上.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ~$ git push --set-upstream origin dev/stm32l152re-ili93418b-driver
    Username for 'https://github.com': xxxxxx
    Password for 'https://xxxxxxx@github.com':
    Total 0 (delta 0), reused 0 (delta 0)
    remote:
    remote: Create a pull request for 'dev/stm32l152re-ili93418b-driver' on GitHub by visiting:
    remote: https://github.com/xxxxxx/incubator-nuttx/pull/new/dev/stm32l152re-ili93418b-driver
    remote:
    To https://github.com/xxxxx/incubator-nuttx
    * [new branch] dev/stm32l152re-ili93418b-driver -> dev/stm32l152re-ili93418b-driver
    Branch 'dev/stm32l152re-ili93418b-driver' set up to track remote branch 'dev/stm32l152re-ili93418b-driver' from 'origin'.
  • 关联到远程分支后,以后就可以直接push,查看.git/config如下
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    ~$ cat .git/config
    [core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
    [remote "origin"]
    url = https://github.com/xxxxx/incubator-nuttx
    fetch = +refs/heads/*:refs/remotes/origin/*
    [branch "master"]
    remote = origin
    merge = refs/heads/master
    [remote "upstream"]
    url = https://github.com/apache/incubator-nuttx.git
    fetch = +refs/heads/*:refs/remotes/upstream/*
    [branch "dev/stm32l152re-ili93418b-driver"]
    remote = origin
    merge = refs/heads/dev/stm32l152re-ili93418b-driver
  • 读取上游的更新并且合并到本地的master分支.再push到自己的origin的创库.
    1
    2
    3
    4
    ~$ git checkout master  # 本地切换到master分支
    ~$ git fetch upstream # 读取上游更改,同步.
    ~$ git merge upstream/master # 合并上游到本地
    ~$ git push # push同步,把本的master同步远端的origin/master
  • 创建新的更改或文件并且push到远程分支
    1
    2
    3
    ~$ git add new-file.c
    ~$ git commit new-file.c
    ~$ git push
  • 此时github的分支上面,会有一个提示,Create Pull Request,把当前的分支推送到upstream上去,提交合并请求.
  • 如果运行rebase upstream/master后,发现代码有问题,可以使用git reset --hard HEAD~1回退到指定的节点,~[num]回退第几个结点.这里可以使用gitg图形工具可以直观的显示.假如这里是回退到创建分支时第一次commit之前, 在些可以重新修改或添加文件,再重新commit, 并且要使用git push --force才行.之后再可以git fetch upstream; git rebase upstream/master.

合并多个commit为一个完整commit

  • 为了保持提交记录的更简洁明了,需要把多个commit合并到一个完整的commit,然后再push到上游库中.命令的方式是:git rebase -i [startpoint] [endpoint].如果不指定endpoint,则该区间的终点默认是当前分支HEAD所指向的commit.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    ~$ git rebase -i HEAD~3
    pick a68185edc0f2cbd38c8fdbcffaf516278f4f Fix merge conflicts
    pick efe10a20278f53af9e6fff5754de39b8c8c4 net/icmp: add sanity check to avoid wild data length
    pick fb7480c67637bfa2164f4f76ceff6f509d24 net/neighbor/neighbor_ethernet_out.c: fix build error without ICMPv6
    pick 0a262336bd9964b693b57fe93d992482d5d3 arch/arm/src/stm32/stm32_otghsdev.c: Fix syslog formats
    [....]
    # Rebase dd4b5e0c68..18d489a8dd onto dd4b5e0c68 (32 commands)
    #
    # Commands:
    # p, pick <commit> = use commit /* 保留该commit */
    # r, reword <commit> = use commit, but edit the commit message /* 保留该commit,但我需要修改该commit的注释 */
    # e, edit <commit> = use commit, but stop for amending /* 保留该commit, 但我要停下来修改该提交(不仅仅修改注释) */
    # s, squash <commit> = use commit, but meld into previous commit /* 将该commit和前一个commit合并 */
    # f, fixup <commit> = like "squash", but discard this commit's log message /* 如sqaush,但是不保留该提交的注释信息 */
    # x, exec <command> = run command (the rest of the line) using shell /* 执行shell命令 */
    # b, break = stop here (continue rebase later with 'git rebase --continue')
    # d, drop <commit> = remove commit /* 丢弃该commit */
    # l, label <label> = label current HEAD with a name
    # t, reset <label> = reset HEAD to a label
    # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
    # . create a merge commit using the original merge commit's
    # . message (or the oneline, if no original merge commit was
    # . specified). Use -c <commit> to reword the commit message.
    #
    # These lines can be re-ordered; they are executed from top to bottom.
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    #
    # However, if you remove everything, the rebase will be aborted.
    #
    # Note that empty commits are commented out
  • 如上面的说明一样,支持多种编辑,现在假如改成如下所示.修改完成后保存,就会转到注释的修改界面,再保存.它就执行了rebase,再用git push -f把相应的修改强制提交上去.
    1
    2
    3
    4
    pick c029a68185edc0f2cbd38c8fdbcffaf516278f4f Fix merge conflicts
    s efe10a20278f53af9e6fff5754de39b8c8c4 net/icmp: add sanity check to avoid wild data length
    s fb7480c67637bfa2164f4f76ceff6f509d24 net/neighbor/neighbor_ethernet_out.c: fix build error without ICMPv6
    f 0a262336bd9964b693b57fe93d992482d5d3 arch/arm/src/stm32/stm32_otghsdev.c: Fix syslog formats
  • 它其实是在.git下面的文件.
    1
    2
    3
    4
    5
    6
    ~$ head  .git/rebase-merge/git-rebase-todo.backup
    pick a68185edc0f2cbd38c8fdbcffaf516278f4f Fix merge conflicts
    pick efe10a20278f53af9e6fff5754de39b8c8c4 net/icmp: add sanity check to avoid wild data length
    pick fb7480c67637bfa2164f4f76ceff6f509d24 net/neighbor/neighbor_ethernet_out.c: fix build error without ICMPv6
    pick 0a262336bd9964b693b57fe93d992482d5d3 arch/arm/src/stm32/stm32_otghsdev.c: Fix syslog formats
    [....]
  • 分支合并到主线时,可以删除该分支.
    1
    2
    ~$ git branch -d <本地分支>
    ~$ git push origin --delete <远端分支>
  • 如果因为rebase时所产生的CONFLICT (content): Merge conflict in src/xxxx.cpp,并且确定冲突可以以一方为标准处理,可以使用下面命令自动处理.--theirs就是使用pull上游仓库版本,--ours是使用本地版本,再把它commit就算是合并成功了.
    1
    2
    ~$ git checkout --theirs src/xxxx.cpp
    ~$ git commit

Git其它应用

1
~$ git format-patch -1 HEAD
  • 在自动处理合并分支的冲突时,如果只有一边是修改的情况下,参考这里可以使用如下:
1
~$ git merge --strategy-option theirs

git提交时自动修改(自增)版本号的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
~$ cat .git/hooks/pre-commit
#!/bin/bash

export VER_FILE=src/utils/utils.pri

if [ ! -e ${VER_FILE} ]; then
exit 1;
fi

echo "start to update the version in $VER_FILE"
# 211.8.73
export VERSION=$(grep "^VERSION =" ${VER_FILE} | awk '{print $3}' | tr -d '\r')
# VARR(211 8 73)
IFS='.' read -r -a VARR <<< "$VERSION"
# VARR(211 8 74)
VARR[2]=$((VARR[2]+1))
# 211. 8 .74
VERSION=$(echo ${VARR[@]} | fold -w3 | paste -sd.)
# replace 211.8.73 with 211.8.74
sed -i "/^VERSION/s/=.*/= ${VERSION// /}/" ${VER_FILE}

git使用图形工具(meld)对比代码

  • .git/config添加下面内容

    1
    2
    3
    4
    5
    6
    7
    # Add the following to your .gitconfig file.
    [diff]
    tool = meld
    [difftool]
    prompt = false
    [difftool "meld"]
    cmd = meld "$LOCAL" "$REMOTE"
  • 对比不同分支上的同一个文件

    1
    ~$ git difftool mybranch master -- target.file
  • 对比当前分支与other-branchsrc目录下的文件,--后的参数可以省掉,也可以具体指某一个文件或者目录名.

    1
    ~$ git difftool other-branch -- src
  • 当前分支的文件与其它的commit对比.

    1
    ~$ git difftool HEAD~2 -- src/file.txt
  • 合并other-branch到当前分支,并使用other-branch来解决冲突(theirs).

    1
    ~$ git merge -X theirs other-branch
  • 回退一个合并

    1
    git reset --merge HEAD~1
  • 强制fetch远程仓库,覆盖本地仓库,替代pull时冲突提示(慎用)

    1
    2
    3
    4
    # fetch from the default remote, origin
    ~$ git fetch
    # reset your current branch (master) to origin's master
    ~$ git reset --hard origin/master

STM32F4-Discovery(MB997C)

Audio(CS43L22)支持

SPI SD卡支持

USB-OTG

BLE Sniffer

Ethernet 8720A

Arm Mbed-OS

配置开发环境

  • 这里使用的是当前最新的v6.3版本.Mbed支持三种不同类型的开发环境(桌面IDE,在线IDE,命令行),且支持多系统平台(Win,Mac,Linux),这是使用Keil,IAR所不能比拟的.这里会根据官方文档说明,实践一下桌面与命令行的开发.而且它使用的是C++语言开发,这样有别于传统的Keil,IAR的C语开发,它的代码风格与Arduino一样.并且它内置的实时操作系统就是FreeRTOS.

Mbed Studio

  • 使用Mbed Studio需要注册一个帐号,安装完成第一次打开IDE,会需要先登录.它与Web Stduio还有同一个优点,可以从线上导入官方的模版工程.

    1
    2
    3
    4
    5
    6
    ~$ wget -c https://studio.mbed.com/installers/latest/linux/MbedStudio.sh
    ~$ ./MbedStudio.sh
    ~$ du -sh ~/.local/bin/mbed-studio
    ~$ ls ~/.config/Mbed Studio
    api-targets.json Cache Cookies GPUCache library-pipeline mbed-studio.log 'Network Persistent State'
    blob_storage config.json Cookies-journal library-cache 'Local Storage' mbed-studio-tools recentworkspace.json
  • Mbed Studio原本是使用Arm Compiler 6,这里可以也可以切换到Arm Embedded GCC Compiler

1
2
3
4
5
6
7
8
~$ cat > ~/.config/Mbed Studio/external-tools.json <<EOF
> {
> "bundled": {
> "gcc": "/fullpath/gcc-arm-none-eabi-9-2020-q2-update/bin"
> },
> "defaultToolchain": "GCC_ARM"
> }
> EOF
  • 如上面所示,Mbed Studio也是如同VScode这样的IDE,也是使用json格式配置文件,
    打开界面菜单:File -> Settings -> Open Perferences.

测试FRDM-KL25Z

更新OpenSDA的固件

  • Mbed Studio需要最新的固件来支持调试FRDM-KL25Z,至少需要mbed_if_v2.0_frdm_kl25z.s19才能支持CMSIS-DAP,所以需按照上述链接下载到固件(Pemicro_OpenSDA_Debug_MSD_Update_Apps_2020_05_12.zip).解压后,文件夹有*.SDA后缀的固件文件,还有一些Notes与指导手册等.电脑连到KL25ZSDA接口时,会在系统内看到一个FRDM-KL25Z的盘符.
  • 这里还有一个问题,升级固件时,必须让板子进入Bootloder模式,此时它会挂载盘符叫BOOTLODER.发现只能Windows的系统下进行升级,按住板子上的RST键,接入SDA上电,因为板子内的固件是v1.01,在Linux下无法挂载出一个USB盘符, 而只能在windows XP,Win 7下是可以挂载的且可以升级成功.这里原因没有深究它了.
  • 解压固件后的目录内还有一个OpenSDA_Bootloader_Update_App_v111_2013_12_11.zip,再解压出就是BOOTUPDATEAPP_Pemicro_v111.SDA要升级的固件文件,这里把MSD-DEBUG-FRDM-KL25Z_Pemicro_v118.SDA,BOOTUPDATEAPP_Pemicro_v111.SDA,20140530_k20dx128_kl25z_if_opensda.s19三个文件直接复制进BOOTLOADER盘符内,就可以升级了.升级完成后,接入SDA后在Linux下会自动挂载一个MBED盘.
  • 再次按住板子上的RST键,接入SDA上电,进入BOOTLOADER模式,打开BOOTLOADER盘内的SDA_INFO.HTM跳转到网页,查看网页的信息是否与升级的固件版本对应上.并且固件在v1.11进,也就可以自动在Linux下挂载BOOTLOADER盘了,可以方便的进行后续版本的升级了.
  • 新建工程,导入官方示例mbed-os-example-blinky,界面如下:
    mbed-studio-blinky-project.png
  • 更新后,可以使用openocd连接调试.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    ~$ openocd -c "adapter driver cmsis-dap" -f board/frdm-kl25z.cfg
    Open On-Chip Debugger 0.10.0+dev-01423-g3ffa14b04-dirty (2020-10-14-08:59)
    Licensed under GNU GPL v2
    For bug reports, read
    http://openocd.org/doc/doxygen/bugs.html
    Warn : Interface already configured, ignoring
    Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
    Info : add flash_bank kinetis kl25.pflash
    Info : Listening on port 6666 for tcl connections
    Info : Listening on port 4444 for telnet connections
    Info : CMSIS-DAP: SWD Supported
    Info : CMSIS-DAP: FW Version = 1.0
    Info : CMSIS-DAP: Interface Initialised (SWD)
    Info : SWCLK/TCK = 0 SWDIO/TMS = 1 TDI = 0 TDO = 0 nTRST = 0 nRESET = 1
    Info : CMSIS-DAP: Interface ready
    Info : clock speed 1000 kHz
    Info : SWD DPIDR 0x0bc11477
    Info : SWD DPIDR 0x0bc11477
    Error: Failed to write memory at 0xe000edf0
    Info : kl25.cpu: external reset detected
    Warn : **** Your Kinetis MCU is probably locked-up in RESET/WDOG loop. ****
    Warn : **** Common reason is a blank flash (at least a reset vector). ****
    Warn : **** Issue 'kinetis mdm halt' command or if SRST is connected ****
    Warn : **** and configured, use 'reset halt' ****
    Warn : **** If MCU cannot be halted, it is likely secured and running ****
    Warn : **** in RESET/WDOG loop. Issue 'kinetis mdm mass_erase' ****
    Info : starting gdb server for kl25.cpu on 3333
    Info : Listening on port 3333 for gdb connections

Mbed CLI

  • 这里是在Linux下面的安装需求,需要系统先安装了Git,Python3.7.x,Mercurial等环境.
    1
    2
    ~$ sudo apt-get install python3 python3-pip git mercurial -y
    ~$ pip install mbed-cli

安装配置交叉工具链

1
2
3
4
5
6
7
8
9
~$ mbed config -G ARM_GCC_PATH /fullpath/gcc-arm-none-eabi-9-2020-q2-update/bin
[mbed] fullpath/gcc-arm-none-eabi-9-2020-q2-update/bin now set as global ARM_GCC
~$ mbed config --list
[mbed] Global config:
GCC_ARM_PATH=/fullpath/gcc-arm-none-eabi-9-2020-q2-update/bin
ARMC6_PATH=/fullpath/ARMCompiler6.15/bin

[mbed] Local config (/home/michael):
Couldn't find valid mbed program in /home/michael

新建工程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
~$ mbed new mbed-example-program
[mbed] Working path "/fullpath/Mbed Programs" (directory)
[mbed] Creating new program "mbed-example-program" (git)
[mbed] Adding library "mbed-os" from "https://github.com/ARMmbed/mbed-os" at branch/tag "latest"
[mbed] Updating reference "mbed-os" -> "https://github.com/ARMmbed/mbed-os/#0db72d0cf26539016efbe38f80d6f2cb7a3d4414"
[mbed] Auto-installing missing Python modules (mbed_cloud_sdk, mbed_ls, mbed_host_tests, mbed_greentea, manifest_tool, icetea, pycryptodome, cryptography)...
~$ tree -L 1 mbed-example-program/
mbed-example-program/
├── mbed_app.json
├── mbed-os
├── mbed-os.lib
└── mbed_settings.py

1 directory, 3 files
~$ mbed ls -a
[mbed] Working path "/fullpath/Mbed Programs/mbed-example-program" (program)
mbed-example-program (mbed-example-program)
`- mbed-os (https://github.com/ARMmbed/mbed-os#0db72d0cf265)

  • 上面新建的工程,默认添加了mbed-os的支持,也可以使用--create-only选项创建不含系统的工程.
    1
    2
    3
    4
    5
    6
    ~$ mbed new project2 --create-only
    [mbed] Working path "/fullpath/Mbed Programs" (directory)
    [mbed] Creating new program "project2" (git)
    ~$ tree -L 1 project2/
    project2/
    └── mbed_settings.py

导入工程

1
2
3
4
~$ mbed import https://github.com/ARMmbed/mbed-os-example-blinky#mbed-os-5.15.0  my-blink
[mbed] Working path "/fullpath/github/ArmMbed" (directory)
[mbed] Importing program "my-blink" from "https://github.com/ARMmbed/mbed-os-example-blinky" at branch/tag "mbed-os-5.15.0"
[mbed] Adding library "mbed-os" from "https://github.com/ARMmbed/mbed-os" at rev #64853b354fa1

为工程添加库

1
2
3
4
5
6
~$ cd my-blink
~$ mbed add https://github.com/ARMmbed/mbed-cloud-client
[mbed] Working path "/fullpath/Mbed Programs/my-blink" (program)
[mbed] Adding library "mbed-cloud-client" from "https://github.com/ARMmbed/mbed-cloud-client" at latest revision in the current branch
[mbed] Updating reference "mbed-cloud-client" -> "https://github.com/ARMmbed/mbed-cloud-client/#f72a23e0dc21de4c82ee53fe947153341419a5b9"

  • 如果要删除库就直接:mbed remove mbed-cloud-client

编译工程

  • 查看可以支持的板子.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ~$ mbed compile --supported  # mbed compile -S
    [mbed] Working path "/fullpath/ArmMbed/mbed-os-example-blinky" (program)
    | Target | mbed OS 2 | mbed OS 5 | ARM | uARM | GCC_ARM | IAR |
    | ------------- | --------- | --------- | --------- | ---- | --------- | --------- |
    | ADV_WISE_1510 | - | Supported | Supported | - | Supported | Supported |
    | ADV_WISE_1570 | - | Supported | Supported | - | Supported | Supported |
    | ARCH_MAX | - | Supported | Supported | - | Supported | Supported |
    | ARCH_PRO | - | Supported | Supported | - | Supported | Supported |
    [......]

    ~$
  • 编译

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    ~$ mbed compile -m KL25Z -t GCC_ARM
    [mbed] Working path "/fullpath/ArmMbed/my-blink" (program)
    Building project my-blink (KL25Z, GCC_ARM)
    Scan: my-blink
    Compile [ 0.4%]: at24mac.cpp
    [...]
    Link: my-blink
    Elf2Bin: my-blink
    | Module | .text | .data | .bss |
    | ---------------- | ------------- | ----------- | ----------- |
    | [fill] | 48(+48) | 0(+0) | 28(+28) |
    | [lib]/c.a | 4828(+4828) | 2108(+2108) | 89(+89) |
    | [lib]/gcc.a | 1004(+1004) | 0(+0) | 0(+0) |
    | [lib]/misc | 200(+200) | 4(+4) | 28(+28) |
    | main.o | 84(+84) | 0(+0) | 0(+0) |
    | mbed-os/drivers | 92(+92) | 0(+0) | 0(+0) |
    | mbed-os/hal | 1440(+1440) | 4(+4) | 67(+67) |
    | mbed-os/platform | 4204(+4204) | 264(+264) | 220(+220) |
    | mbed-os/rtos | 6468(+6468) | 168(+168) | 5973(+5973) |
    | mbed-os/targets | 2424(+2424) | 4(+4) | 19(+19) |
    | Subtotals | 20792(+20792) | 2552(+2552) | 6424(+6424) |
    Total Static RAM memory (data + bss): 8976(+8976) bytes
    Total Flash memory (text + data): 23344(+23344) bytes

    Image: ./BUILD/KL25Z/GCC_ARM/my-blink.bin
  • 设置默认的target与交叉工具链

    1
    2
    3
    4
    5
    6
    7
    ~$ mbed target KL25Z
    [mbed] Working path "/fullpath/Mbed Programs/my-blink" (program)
    [mbed] KL25Z now set as default target in program "my-blink"
    ~$ mbed toolchain GCC_ARM
    [mbed] Working path "/fullpath/Mbed Programs/my-blink" (program)
    [mbed] GCC_ARM now set as default toolchain in program "my-blink"

测试与调试

  • 运行代码测试

    1
    2
    ~$ mbed test -m KL25Z -t GCC_ARM
    [...]
  • 查看测试列表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    ~$ mbed test --compile-list  | head
    Test Case:
    Name: mbed-os-features-device_key-tests-device_key-functionality
    Path: ./mbed-os/features/device_key/TESTS/device_key/functionality
    Test Case:
    Name: mbed-os-features-frameworks-utest-tests-unit_tests-basic_test
    Path: ./mbed-os/features/frameworks/utest/TESTS/unit_tests/basic_test
    Test Case:
    [....]
  • 连接板子运行测试

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    ~$ mbed test -m KL25Z -t GCC_ARM --run
    [mbed] Working path "/home/michael/3TB-DISK/Mbed Programs/my-blink" (program)
    mbedgt: greentea test automation tool ver. 1.7.4
    mbedgt: test specification file './BUILD/tests/KL25Z/GCC_ARM/test_spec.json' (specified with --test-spec option)
    mbedgt: using './BUILD/tests/KL25Z/GCC_ARM/test_spec.json' from current directory!
    mbedgt: detecting connected mbed-enabled devices...
    mbedgt: detected 1 device
    mbedgt: processing target 'KL25Z' toolchain 'GCC_ARM' compatible platforms... (note: switch set to --parallel 1)
    mbedgt: running 4 tests for platform 'KL25Z' and toolchain 'GCC_ARM'
    mbedgt: mbed-host-test-runner: started
    mbedgt: retry mbedhtrun 1/1
    mbedgt: ['mbedhtrun', '-m', 'KL25Z', '-p', '/dev/ttyACM0:9600', '-f', '"BUILD/tests/KL25Z/GCC_ARM/mbed-os/TESTS/psa/spm_smoke/spm_smoke.bin"', '-e', '"mbed-os/TESTS/host_tests"', '-d', '/media/michael/MBED', '-c', 'default', '-t', '02000201242BD1925E8A1EE0', '-r', 'default', '-C', '4', '--sync', '5', '-P', '60'] failed after 1 count
    [...]

Ardunio

  • Links:
    • stm32duino
    • wiki
    • Nucleo-F767ZINucleo-L152RE都是兼容Arduino管脚的,这里是使用Nucleo-L152RE为目标对像.

添加STM32 Cores

烧写方式

  • 下载stm32-programmers,解压后,直接运行Linux下的安装程序,根据向导提示,安装在当前用户的目录下.安装完后,目录如下:

    1
    2
    3
    4
    ~/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin$ ls
    ExternalLoader HSM libssl.so libstp11_SAM.so.conf STM32CubeProgrammer STM32MP_KeyGen_CLI STM32_Programmer_CLI
    FlashLoader libcrypto.so libstp11_SAM.so RSSe STM32CubeProgrammerLauncher STM32MP_SigningTool_CLI STM32_Programmer.sh

  • 这里是使用Nucleo-L152RE为目标板,选择Tools -> Boards: <any> -> STM32 Boards (select from submenu -> Nucleo-64.

  • Upload方法,选择Tools -> Upload method -> STM32CubeProgrammer (SWD)

更新ST-Link的固件

  • JTAG and SWD Guide

  • 烧写时提示如下的错误.

    1
    2
    3
    4
    5
    6
    7
    8
     STM32CubeProgrammer v2.4.0
    -------------------------------------------------------------------

    Error: Old ST-LINK firmware version. Upgrade ST-LINK firmware
    Error: Old ST-LINK firmware version. Upgrade ST-LINK firmware
    Error: Old ST-LINK firmware!Please upgrade it.
    Error: Old ST-LINK firmware!Please upgrade it.

  • 下载stsw-link007,后解压它.

  • 解压目录如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ~$ tree -L 2  stsw-link007
    stsw-link007
    ├── AllPlatforms
    │   ├── native
    │   ├── StlinkRulesFilesForLinux
    │   └── STLinkUpgrade.jar
    ├── readme.txt
    └── Windows
    ├── ST-LinkUpgrade.exe
    └── STLinkUSBDriver.dll
  • 根据它的readme.txt提示,安装完成 StlinkRulesFilesForLinux后下面,就可以运行更新GUI程序更新固件了.

    1
    ~$ java -jar STLinkUpgrade.jar
  • 更新完最新的固件后可以,用ST官方STM32CubeProgrammer读写,但是想用它的ST-link外接给STM32F103最小系统板做SWD烧写调试时出错了.

1
2
3
4
5
6
7
8
9
~$ st-info --probe
Found 1 stlink programmers
serial: 30363641464634383535353037353531383731xxxxxx
hla-serial: "\x30\x36\x36\x41\x46\x46\x34\x38\x35\x35\x35\x30\x37\x35\x35\x31\x38\x37\x31\x38\x32\x37\x34\x37"
flash: 2097152 (pagesize: 2048)
sram: 524288
chipid: 0x0451
descr: F76xxx

  • stlink-gui
1
~$ apt-get install stlink-gui
  • 连接成功后读取内存如下。

SPI SD示例

  • 这里选择标准库内的File -> Examples -> Examples for any board -> SD -> listfiles的示例,程序如下所示,管脚定义兼容Nucleo-L152RE,只是CS这里与原程序定义不符.Nucleo-L152RE里是pin 10 (CS),所以只需要在程序内改成!SD.begin(10).
1
2
3
4
5
6
7
8
9
10
11
12
13
The circuit:
SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

[...]
if (!SD.begin(10)) {
Serial.println("initialization failed!");
while (1);
}
[...]
  • 一键upload,如果编译烧写成功后,使用串口查看它的输出.

树莓派相关

FreeRTOS

协议分析工具

FTDI232H

PyFTDI

I2C

  • i2c通信, SCL(AD0),SDA(AD1,AD2). I2C的地址是一个7-bit的数值,加上第8-bit方向位(0:写,1:读),构成一个8-bit数值.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    from pyftdi.i2c import I2cController
    # Instantiate an I2C controller
    i2c = I2cController()

    # Configure the first interface (IF/1) of the FTDI device as an I2C master
    i2c.configure('ftdi://ftdi:2232h/1')

    # Get a port to an I2C slave device
    slave = i2c.get_port(0x21)

    # Send one byte, then receive one byte
    slave.exchange([0x04], 1)

    # Write a register to the I2C slave
    slave.write_to(0x06, b'\x00')

    # Read a register from the I2C slave
    slave.read_from(0x00, 1)

SPI

  • 下面是通过使用UM232H来读取一颗裸SPI NOR Flash W25Qxx的厂商编号(jedec_id).接线如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    UM232H           W25Q64FV
    AD0 <-----> CLK pin6
    AD1 <-----> DI pin5
    AD2 <-----> DO pin2
    AD3 <-----> CS pin1
    GND <-----> GND pin4
    VCC <-----> VCC pin8
    VCC <-----> /HOLD pin7
    VCC <-----> /WP pin3
  • 简单测试读取jedec_id

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import usb
import usb.util
from pyftdi.spi import SpiController
dev = usb.core.find(idVendor=0x0403, idProduct=0x6014)

spi = SpiController()
spi.configure(dev)

# Get a port to a SPI slave w/ /CS on A*BUS3 and SPI mode 0 @ 12MHz
slave = spi.get_port(cs=0,freq=12E6,mode=0)

jedec_id = slave.exchange([0x9f],3)

print(hex(jedec_id[1]<< 8 | jedec_id[2]))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pyspiflash/spiflash/tests$ ./serialflash.py
Using FTDI device ftdi://ftdi:232h:1:67/1
Flash device: Winbond W25Q64 8 MiB @ SPI freq 12.0 MHz
.Read 8192 KiB in 7 seconds @ 1152 KiB/s
..Erase 1024 KiB from flash @ 0x700000 (may take a while...)
Erased 1024 KiB in 17 seconds @ 59 KiB/s
Build test sequence
Writing 1024 KiB to flash (may take a while...)
Wrote 1024 KiB in 14 seconds @ 70 KiB/s
Reading 1024 KiB from flash
Read 1024 KiB in 915 ms @ 1118 KiB/s
Verify flash
Reference: 4942ea371ad576065759f232f429a8abf10c755a
Retrieved: 4942ea371ad576065759f232f429a8abf10c755a
...
----------------------------------------------------------------------
Ran 6 tests in 42.775s

OK

FlashROM读取

  • FT2232SPI_Programmer

  • Unpacking the binary firmware /w Binwalk

  • Zyxel firmware extraction and password analysis

  • flashrom

  • 探测flash的类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ~$ flashrom -L

    ~$ flashrom -p ft2232_spi:type=2232H,port=A
    flashrom v1.2 on Linux 5.16.13-20220310 (x86_64)
    flashrom is free software, get the source code at https://flashrom.org

    Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
    Found Macronix flash chip "MX25L6405" (8192 kB, SPI) on ft2232_spi.
    Found Macronix flash chip "MX25L6405D" (8192 kB, SPI) on ft2232_spi.
    Found Macronix flash chip "MX25L6406E/MX25L6408E" (8192 kB, SPI) on ft2232_spi.
    Found Macronix flash chip "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E/MX25L6473F" (8192 kB, SPI) on ft2232_spi.
    Multiple flash chip definitions match the detected chip(s): "MX25L6405", "MX25L6405D", "MX25L6406E/MX25L6408E", "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E/MX25L6473F"
    Please specify which chip definition to use with the -c <chipname> option.

  • 读取flash内容。

1
2
3
4
5
6
7
8
~$ flashrom -p ft2232_spi:type=2232H,port=A -r test-mx25l6445e.rom -c "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E/MX25L6473F"
flashrom v1.2 on Linux 5.16.13-20220310 (x86_64)
flashrom is free software, get the source code at https://flashrom.org

Using clock_gettime for delay loops (clk_id: 1, resolution: 1ns).
Found Macronix flash chip "MX25L6436E/MX25L6445E/MX25L6465E/MX25L6473E/MX25L6473F" (8192 kB, SPI) on ft2232_spi.
Reading flash... done.

屏幕驱动

OpenOCD

  • OpenOCD支持FTDIMPSSE功能,--enable-ftdi Enable building support for the MPSSE mode of FTDI
1
2
~$ cd openocd
~$ ./configure --enable-sysfsgpio --enable-buspirate --enable-ftdi
  • 除了需要开启openocd的支持,还有就是接线,这里试用了interface/ftdi/ft232h-module-swd.cfg,interface/ftdi/minimodule-swd.cfg两个配置文件都可以连接成功.配置文件内有接线注释,参考上面的一些链接好像是说要在ADBUS1,ADBUS2中间接一个470 ohm的电阻, 但是这里没有接.只是要确认配置文件内的vid_pid与所连接的硬件匹配.
  • 使用Jlink-ob或者其它板上的STLink只需要三根线,但是这里必需要接nTRST,如:stm32f103zet6就是PB4.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # FT232HQ minimodule channel 0 (Channel A)
    # Connector FTDI Target
    # Pin Name
    # --------- ------ ------
    # CN2-10 GND GND
    # CN2-13 ADBUS0 (TCK) SWCLK
    # CN2-14 ADBUS2 (TDI/TDO) SWDIO
    # CN2-15 ADBUS1 (TDO/TDI) SWDIO
    # CN2-17 ADBUS4 (GPIOL0) nTRST

1
2
~$ openocd -f interface/ftdi/ft232h-module-swd.cfg -f target/stm32f1x.cfg -c init \
-c "reset halt" -c "flash write_image erase nuttx.bin 0x08000000"

树莓派(RassberyPi)

Saleae 逻辑分析仪

Saleae AnalzerSDK

SDIO协议插件

  • SaleaeSDIOAnalyzer
  • AnalyzerSDKSaleaeSDIOAnalyzer两个目录必需要在同一级目录内,再进入到SaleaeSDIOAnalyzer内,直接cmake . && make.如果无错,就会生成libSDIOAnalyzer.so.
  • Configure Logic to look for the Analyzer Plugin
    Launch Logic manually
    Options -> Preferences
    Under [For Developers], “Search this path for Analyzer Plugins”
    Browse for the ../sdmmc-analyzer/xcode4/build/Debug directory
    Click “Save” and close Logic

SDMMC协议

  • SD/MMC Analyzer for Logic
  • 这个源码是用python脚本去编译的,这里在它的目录建一个CMake脚本来处理编译.成功后会看到一个libSDMMCAnalyzer.so.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
sdmmc-analyzer$ cat CMakeLists.txt
project("Saleae SDMMC Analyzer")
cmake_minimum_required(VERSION 3.0)

message(WARNING "CMake support is still experimental!")

# Find Analyzer include dir
find_path(
ANALYZER_SDK_INCLUDE_DIR
NAMES
Analyzer.h
AnalyzerChannelData.h
AnalyzerHelpers.h
AnalyzerResults.h
AnalyzerSettings.h
AnalyzerTypes.h
SimulationChannelDescriptor.h
PATHS
../include/
../AnalyzerSDK/include
DOC
"Include directory of the analyzer SDK."
)

if(NOT ANALYZER_SDK_INCLUDE_DIR)
message(SEND_ERROR "Analyzer SDK include directory not found")
else()
message(STATUS
"Analyzer SDK include directory found at ${ANALYZER_SDK_INCLUDE_DIR}")
endif()

# needed to differ between 32 and 64 bit library
set(ANALYZER_BITNESS)
set(ANALYZER_LIB_NAME "")

if(CMAKE_SIZEOF_VOID_P EQUAL 4)
message(STATUS "32 Bit detected")
set(ANALYZER_BITNESS 32)
set(ANALYZER_LIB_NAME "Analyzer")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
message(STATUS "64 Bit detected")
set(ANALYZER_BITNESS 64)
set(ANALYZER_LIB_NAME "Analyzer64")
else()
message(FATAL_ERROR "Environment not supported")
endif()

if(NOT (WIN32 OR UNIX))
# I have no idea what to do under MacOS
message(WARNING "Environment may not be supported")
endif()

# find library
find_library(
ANALYZER_SDK_LIBRARY
NAMES
${ANALYZER_LIB_NAME}
PATHS
../lib/
../AnalyzerSDK/lib/
DOC
"Analyzer SDK library. \
If you set it yourself, choose the correct architecture"
)

if(NOT ANALYZER_SDK_LIBRARY)
message(SEND_ERROR "Analyzer SDK library not found")
else()
message(STATUS "Analyzer SDK library found at ${ANALYZER_SDK_LIBRARY}")
endif()


add_library(SDMMCAnalyzer SHARED
src/SDMMCAnalyzer.cpp
src/SDMMCAnalyzer.h
src/SDMMCAnalyzerResults.cpp
src/SDMMCAnalyzerResults.h
src/SDMMCAnalyzerSettings.cpp
src/SDMMCAnalyzerSettings.h
src/SDMMCHelpers.cpp
src/SDMMCHelpers.h
src/SDMMCSimulationDataGenerator.cpp
src/SDMMCSimulationDataGenerator.h
)

target_include_directories(SDMMCAnalyzer PUBLIC
source
${ANALYZER_SDK_INCLUDE_DIR}
)

target_link_libraries(SDMMCAnalyzer
PUBLIC
${ANALYZER_SDK_LIBRARY}
)

target_compile_features(SDMMCAnalyzer
PRIVATE
cxx_nullptr
)

QSPI协议插件

STM8S103

SDCC示例编译

Arduino支持

编程工具

  • stm8flash
  • stm8flash开源工具,是针对stlink硬件烧写的,我这里还是使用openocd+ft2232这样的方式对它进行编程烧写。

其它资源

谢谢支持

  • 微信二维码: