0%

日志信息分类

以下内容系摘抄整理。

日志的等级由低到高应该是:Debug < Info < Warn < Error < Fatal

DEBUG INFO WARN ERROR FATAL
严重程度 最低 一般 较高 极高
严重性说明 调试时使用,便于开发者快速地详细地了解系统运行状况。正式发布时会禁用。 输出信息以反馈系统运行状态给用户。 可修复的潜在错误或不规范的代码、编译条件等。 可修复错误。软件无法正常运行。 相当严重的错误,可能无法修复。继续运行难以保证。
使用情况 用于打印程序应该出现的正常状态信息, 便于追踪定位。 表明系统出现轻微的不合理但不影响运行和使用。 表明出现了系统错误和异常,无法正常完成目标操作。

错误日志格式整理

错误日志格式大致可以有以下类型。

1
2
3
log.error(“[接口名或操作名] [Some Error Msg] happens. [params] [Probably Because]. [Probably need to do].”);

log.error(String.format(“[接口名或操作名] [Some Error Msg] happens. [%s]. [Probably Because]. [Probably need to do].”, params));

1
2
3
4
5
log.error(“[Some Error Msg] happens to 错误参数或内容 when [in some condition]. [Probably Because]. [Probably need to do].”);

log.error(String.format(“[Some Error Msg] happens to %s when [in some condition]. [Probably Because]. [Probably need to do].”, parameters));

[Probably Reason]. [Probably need to do]. 在某些情况下可以省略; 在一些重要接口和场景下最好能说明一下。

每一条错误日志都是独立的,尽可能完整、具体、直接说明何种场景下发生了什么错误,由什么原因导致,要采用什么措施或步骤。

错误日志的意义

错误日志是排查问题的重要手段之一。 当我们编程实现一项功能时, 通常会考虑可能发生的各种错误及相应原因:

要排查出相应的原因, 就需要一些关键描述来定位原因。这就会形成三元组:错误现象 -> 错误关键描述 -> 最终的错误原因

需要针对每一种错误尽可能提供相应的错误关键描述,从而定位到相应的错误原因。也就是说,编程的时候,要仔细思考, 哪些描述是非常有利于定位错误原因的, 尽可能将这些描述添加到错误日志中。

REFERENCE

  1. 日志级别的选择:Debug、Info、Warn、Error还是Fatal

smb 服务可以让多种设备跨平台、跨设备传输、共享文件内容,包括 linux 、mac 、windows、android等。一般开启服务的叫 server,使用服务的叫 client。

注意事项:

  1. 设置前需要确认自己的路由器是否 OK,有些便宜的路由器确实不能支持稳定的 smb 服务,甚至不能稳定ping通同一局域网内的设备,建议购买支持 wifi6 的路由器。

下面介绍三个主流PC的smb服务开启流程(仅供参考)。

Linux

在debian系linux的配置流程如下:

  1. 安装 samba 服务:sudo apt install samba
  2. 为需要分享的文件/文件夹配置权限:chomd 755 /home/isletspace/share
  3. 配置 smb.conf 文件:sudo vim /etc/samba/smb.conf
1
2
3
4
5
6
7
8
9
[share]
comment = share
path = /home/isletspace/share
browseable = no
available = yes
writable = yes
read only = no
create mask = 0755
valid users = user01

上面的配置信息解释如下:

[share]smb://xxxx.xxx/share 访问时的第二级域名

comment:smb 访问路径说明

browseable:是否可在局域网中可见

writable:是否可写入

read only:是否只可读

create mask:操作权限,普通人访问的就设置 0755 ,如果只有自己用,可以设置 0777

valid users:可用用户 user01

  1. 创建 samba 用户:sudo useradd user01
  2. 设置 samba 密码:sudo smbpasswd -a user01
  3. 重启 samba 服务:sudo service smbd restart
  4. 在其他设备上测试网络情况:
1
2
3
4
# 测试是否可以ping通
ping xxx.xxx.xxx.xxx
# 在文件浏览器中访问以下路径
smb://xxx.xxx.xxx.xxx

其他命令:

1
2
3
4
5
6
7
8
9
10
11
# 查看samba服务器中已拥有哪些用户:
sudo pdbedit -L

# 删除samba服务中的某个用户
sudo smbpasswd -x 用户名

# 删除linux某个用户
sudo userdel 用户名

# 删除linux中某个用户所有信息
sudo userdel -r 用户名

Mac

Mac开启服务大致如文章《Mac 开启局域网smb文件共享》所述。

Windows

windows 的流程太复杂,但基本上靠这篇文章《Windows 10/ 11 下安全并正确地使用 SMB 共享》可以搞定

参考

  1. Ubuntu 20 开启samba文件共享

首先要说明的一点,linux 上的 v2ray 分为两部分:

  • 使用QT 制作的 qv2ray GUI界面

  • v2ray 的运行核心

这两部分需要分别安装和下载。

Github 上的项目路径:https://github.com/v2fly/

qv2ray 安装

GUI 界面的安装可以参考:新手起步

安装、配置完毕之后的使用界面如下。

image-20220703213806263

如果使用 ubuntu 或者 kali 等系统的稳定版本,则可以参考以下命令:

1
2
3
4
5
6
7
8
9
10
# 安装必要工具
sudo apt install -y gnupg ca-certificates curl
# 添加软件源公钥
curl https://qv2ray.net/debian/pubkey.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/qv2ray-stable-archive.gpg
# 添加软件源
echo "deb [arch=amd64] https://qv2ray.net/debian/ stable main" | sudo tee /etc/apt/sources.list.d/qv2ray.list
# 更新软件源
sudo apt update
# 安装 qv2ray GUI界面
sudo apt install -y qv2ray

v2ray 核心安装

注意:这个一定要和 qv2ray 安装统一个时期的版本,github上有个 pre-release 的 v5.0.7 版本,里面缺少了组件(v2ctl),是不能跟 qv2ray 一起使用的。

image-20220703214344707

可以参考 neworld.space 的教程《Linux Qv2ray 使用教程》 进行安装。

image-20220703212715215

如果安装版本不正确,会报 v2ray core faied with an exit code: 2 的错误。

浏览器代理

设置完之后,还不能马上使用,需要在浏览器中进行代理设置。

例如,火狐浏览器的设置中,找到 “网络代理” 。

image-20220703212900206

可以选择 “使用系统代理设置” 和 “手动配置代理”两种。

image-20220703212931436

其中手动配置代理就需要对照着 qv2ray 的设置信息来配置即可。

image-20220703213204330

命令行代理

命令行如果需要代理,则需要安装 proxychains

1
sudo apt install -y proxychians

安装完之后用 sudo 权限去配置 /etc/proxychains.conf 文件,将文件最后面的 sock4 127.0.0.1 9095 改成 和 qv2ray 图形配置中的 sock5 一样的配置信息,如 sock5 127.0.0.1 1089 即可。

如果是在mac系统下,则配置文件的路径为 /usr/local/etc

如下所示,则是OK的。

image-20220706185814369

使用的时候,直接在命令前面加 proxychains 或者 proxychains4 即可,如:

1
proxychains ping google.com

搞定 v2ray 和 proxychains ,下次拉代码再也不痛苦了。

项目文件初始化

C项目初始化

1
curl -s https://storage.islet.space/08_Script/project/c_init.sh | bash -s --
  1. 生成文件夹:build / src / inc / lib / doc
  2. 生成空文档:README.mdsrc/main.cCMakeLists.txt
  3. 下载代码格式化模板:.clang-format
  4. 下载git忽略文件模板:.gitignore
image-20220627212514361

环境初始化

嵌入式工程师开发环境初始化

1
curl -s https://storage.islet.space/08_Script/debian/init.sh | bash -s --
  1. 安装 zshohmyzsh ,并设置 zsh 为默认shell
  2. 安装常用工具:vim / nodejs
  3. 安装编译软件: gcc / lcov / valgrind / cmake / make / git / repo
  4. 安装交叉编译器: android-ndk-r20b / gcc-arm-none-eabi-5.4 / gcc-arm-none-eabi-10.3

python 开发环境初始化

1
curl -s https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh | bash -s --

FTDI 硬件是由 FTDI chip 公司开发的用于高性能 USB 转各种底层通信协议 的芯片。所支持的协议包括 UART / SPI / I2C / JTAG etc. ,还有特殊的 bit-bang 协议。

FT4232 基本上是 FT2232 的升级版,从 2个8bit 独立通道,升级成 4个8bit 独立通道,每个通道都具有独立互不干扰的时钟。

FT4232HL 芯片可以实现 USB 2.0 转换成 四个虚拟通道VCP,即 Virtual COM Port) 的功能,该四个虚拟通道可以模拟 UART / JTAG / SPI / I2C 功能,IO口电压为 3.3V

本文基于 FT423H 的迷你模块进行开发,该芯片的官方说明如 《FT4232HL》 。

ENVIRONMENT

libusb 1.0 - Library for talking to USB devices from user-space. Needed by libftdi. libconfuse - Library for parsing configuration files. Needed by ftdi_eeprom.

ELECTRICAL SPECIFICATION

image-20220623145709022

FT4232HL开发板 正面 视图引脚分布:

img

FT4232HL开发板 反面 视图引脚分布:

SPI PINOUT

如果使用 libMPSSE 进行 SPI 通信开发,则默认使用下方的通信接口。

image-20220707162556201

FT4232HL PIN DESCRIPTION

image-20220707162928727

Bit-Bang 模式下的 FT4232H 的引脚

FT4232H的通道 A、B、C 或通道 D 可以被配置为 bit-bang 接口。有两种类型的 bit-bang 模式:同步和异步。

当配置为任何 bit-bang 模式(同步或异步)时,使用的引脚和信号的描述见表3.6

image-20220707163519992
image-20220707163532847

DRIVER INSTALL

FT4232H 的驱动分为 VCP / D2XXX 和 D3XXX 三个。其中,D3XXX 是适用于 USB 3.0 的,这里不需要安装。

window 版本的驱动安装器就包含了 VCP 和 D2XXX。

驱动安装页面:Virtual COM Port Drivers

官方驱动安装教程:Windows 10/11 Installation Guide

装了CDM驱动的Windows平台
linux平台的usb列表

注意:驱动安装完毕之后,PC 不会立即识别 该设备。需要使用 跳线帽,将 CN3 的 13 口进行短接。让设备供上5V的电。

image-20220623145344049

D2XXX 编程指南

D2XXX 是针对 FTDI 的专用接口(Proprietary Interface )。

FTDI provides two alternative software interfaces for its range of USB-UART and USB-FIFO ICs. One interface provides a Virtual COM Port (VCP) which appears to the system as a legacy COM port. The second interface, D2XX, is provided via a proprietary DLL (FTD2XX.DLL). The D2XX interface provides special functions that are not available in standard operating system COM port APIs, such as setting the device into a different mode or writing data into the device EEPROM.

FTDI 为USB-UART 和 USB-FIFO IC 提供两种可供选择的软件接口:虚拟串口VCP,Virtual COM Port) 和 D2XXX

在 Windows 上,D2XXX 和 VCP 驱动 则在同一个驱动包中进行分发,称为 综合驱动模块(CDM, Combined Driver Model)。下图解释了 Windows 端的 CDM 模块架构。

image-20220627122210831

而在 类Unix平台 和 Windows CE 上,VCP 和 D2XXX 是相互排斥的选项,因为在一个特定的时间内,一个特定的设备ID只能安装一种驱动类型。

Windows 上虽然可以装 VCP 和 D2XXX 两种驱动,但是任意时间也只有一种驱动能用。

VCP 是专用于 虚拟串口 的驱动,因此FTDI 官方并不提供 应用级 示例代码。而 D2XXX 是 FTDI 的专用接口,官方提供了 FTD2XXX 库的应用程序以供开发。

image-20220627140842391

其中,libMPSSE 是 SPI/I2C/JTAG 的通信的库文件,依赖于底层的 libftd2xx

FT_SetBitMode()

image-20220707154811965

ucMarsk 设置说明

位模式的必要值。这设置了哪些位是输入和输出。位值为0时,将相应的引脚设为输入,位值为1时,将相应的引脚设为输出。

在CBUS Bit Bang的情况下,这个值的上位数控制哪些引脚是输入和输出,而下位数控制哪些输出是高电平和低电平。

注意: 它与 FT_SetBitMode() 不是互相的关系

根据 SPI PINOUT 的图标说明,应该将以下引脚的掩码设置为如下:

主控引脚 所接从设备引脚 输入输出状态 掩码
A0 SCLK output 1
A1 MOSI output 1
A2 MISO input 0
A3 SNCS output 1
A4 x
A5 x
A6 x
A7 x

此时,掩码必须设置为 0xFB0x0B

ucMode 设置说明

0x0 = Reset 0x1 = Asynchronous Bit Bang 0x2 = MPSSE (FT2232, FT2232H, FT4232H and FT232H devices only) 0x4 = Synchronous Bit Bang (FT232R, FT245R, FT2232, FT2232H, FT4232H and FT232H devices only) 0x8 = MCU Host Bus Emulation Mode (FT2232, FT2232H, FT4232H and FT232H devices only) 0x10 = Fast Opto-Isolated Serial Mode (FT2232, FT2232H, FT4232H and FT232H devices only) 0x20 = CBUS Bit Bang Mode (FT232R and FT232H devices only) 0x40 = Single Channel Synchronous 245 FIFO Mode (FT2232H and FT232H devices only)

FT_GetBitMode()

FT_GetBitMode 返回各引脚的瞬时值。将返回一个单字节,其中包含各引脚的当前值,包括那些输入和输出的引脚。

或对FT232R的可用位模式的描述,请参见应用说明 "FT232R和FT245R的bit-bang模式"。 关于FT2232的可用位模式的描述,请参见应用说明 "FT2232的位模式功能"。 关于FT232B和FT245B的比特爆炸模式的描述,见应用说明 "FT232B/FT245B比特爆炸模式"。 关于T4232H和FT2232H器件支持的位模式的描述,请参见IC数据表。 这些应用说明可从FTDI网站下载。

FT_SetBaudRate()

数据传输的速率可以通过使用 FT_SetBaudRate() 命令来控制。异步模式的时钟实际上是所设波特率的16倍。一个9600波特的值将以每秒(9600x16)=153600 byte的速度传输数据,或每6.5μS一个 byte。

FTDI 器件最大可设置的波特率是 3M baud,但为了让数据有时间在 WR# 选通周围设置和保持,数据的波特率最大应该是 1M baud(62500x16)。最小的数据波特率是 4.8kbaud(300 x 16)。

FT_Read()

image-20220707151059741

FT_Read always returns the number of bytes read in lpdwBytesReturned. This function does not return until dwBytesToRead bytes have been read into the buffer. The number of bytes in the receive queue can be determined by calling FT_GetStatus or FT_GetQueueStatus, and passed to FT_Read as dwBytesToRead so that the function reads the device and returns immediately.

When a read timeout value has been specified in a previous call to FT_SetTimeouts, FT_Read returns when the timer expires or dwBytesToRead have been read, whichever occurs first. If the timeout occurred, FT_Read reads available data into the buffer and returns FT_OK. An application should use the function return value and lpdwBytesReturned when processing the buffer. If the return value is FT_OK, and lpdwBytesReturned is equal to dwBytesToRead then FT_Read has completed normally. If the return value is FT_OK, and lpdwBytesReturned is less then dwBytesToRead then a timeout has occurred and the read has been partially completed. Note that if a timeout occurred and no data was read, the return value is still FT_OK.

FT_Read() 总是返回在 lpdwBytesReturned 中读取的字节数。 在 dwBytesToRead 字节被读入缓冲区之前,该函数不会返回。接收队列中的字节数可以通过调用FT_GetStatus()FT_GetQueueStatus() 来确定,并作为 dwBytesToRead 传给 FT_Read(),以便该函数读取设备并立即返回。

当在先前对 FT_SetTimeouts() 的调用中指定了一个读取超时值时,FT_Read() 在定时器过期或 dwBytesToRead 已被读取时返回,以先发生者为准。如果超时发生,FT_Read() 将可用数据读入缓冲区并返回 FT_OK

在处理缓冲区时,应用程序应使用该函数的返回值和 lpdwBytesReturned 。如果返回值为 FT_OK,并且 lpdwBytesReturned 等于 dwBytesToRead ,那么 FT_Read() 已经正常完成。如果返回值是 FT_OK,并且 lpdwBytesReturned 小于 dwBytesToRead,那么就发生了一个超时,读取已经部分完成。

请注意,如果发生了超时并且没有读取任何数据,返回值仍然是 FT_OKFT_IO_ERROR 的返回值表明函数的参数有错误,或者发生了致命的错误,如USB断开连接。

BIT BANG MODE

异步Bit-Bang模式

异步 Bit-Bang 模式与 BM-style Bit-Bang 模式相同。在任何配置为异步模式的通道上,以正常方式写入设备的数据将被自锁到并行I/O数据引脚(那些被配置为输出的引脚)。每个I/O引脚都可以独立设置为输入或输出。数据的时钟输出速率由波特率发生器控制。

为了使数据发生变化,必须有新的数据写入,而且 波特率时钟 必须跳动。如果没有新的数据被写入通道,引脚将保持最后写入的值。

  1. 那这个波特率时钟 怎么控制?能否指定任一引脚进行输出?

同步Bit-Bang模式

The synchronous Bit-Bang mode will only update the output parallel I/O port pins whenever data is sent from the USB interface to the parallel interface. When this is done, data is read from the USB Rx FIFO buffer and written out on the pins. Data can only be received from the parallel pins (to the USB Tx FIFO interface) when the parallel interface has been written to.

With Synchronous Bit-Bang mode, data will only be sent out by the FT4232H if there is space in the FT4232H USB TXFIFO for data to be read from the parallel interface pins. This Synchronous Bit-Bang mode will read the data bus parallel I/O pins first, before it transmits data from the USB RxFIFO. It is therefore 1 byte behind the output, and so to read the inputs for the byte that you have just sent, another byte must be sent.

同步模式只有在数据从USB接口发送到并行接口时才会更新输出的 并行I/O端口 引脚。当这样做的时候,数据从USB Rx FIFO缓冲器中读出,并在引脚上写出。只有当并行接口被写入时,才能从并行引脚接收数据(到USB Tx FIFO接口)。

同步Bit-Bang模式与异步Bit-Bang模式的不同之处在于,只有当USB接口写入并行输出时,设备的并行输出才被读取。这使得控制程序更容易测量对USB输出刺激的反应,因为返回到USB接口的数据与输出数据是同步的。

在同步模式下,读和写操作会被同步进行。此时,数据总线引脚会在写入数据前先读取数据(针对每个byte)。因此,该数据引脚读取到的数值总是比写出去的数值要慢一个byte。

与异步模式不同,数据引脚只会在写入数据前立即进行读取操作。因此,为了读取 “写入一个byte的响应结果” ,必须要发送另一个byte。 另外,只有当设备中有空间可以从引脚读取数据时,数据才会被写入引脚。

每个引脚都可以独立设置为输入或输出。数据的时钟输出率由波特率发生器控制。要改变引脚的状态,必须写入新的数据,并且波特率时钟必须跳动(the baud rate clock hask to tick)。如果没有新的数据被写入设备,输出引脚将保持最后写入的数值。

当同步模式被启用时,I/O信号线的配置如表3.1所示。请注意,在首次进入同步模式后,任何引脚的默认配置,如果设置为输出,则默认被设置为 输出低电平(0V)。(随后向任何引脚写一个 1 将把该引脚设置为VCCIO) 当进入同步模式后,如果希望在任何输出上驱动一个高值,那么有必要首先用 FT_SetBitMode() 方法把这些引脚设置为输入,用 FT_Write() 把它们写一个 1 ,然后用 FT_SetBitMode() 把它们设置为输出。请注意,当设备处于同步位串模式时,EEPROM UART信号反转选项(signal inversion option)对这些引脚没有影响。

image-20220707152918917

FT200XD 和 FT201X提供两条信号线;FT220X、FT230X 和 FT234XD提供四条信号线;而 FT221X、FT231X 和 FT240X上总共有八条信号线。

任何一个FT-X系列器件的CBUS引脚都可以被配置为在器件处于同步位串模式时发出 内部读取 RD#内部写入 WR# 频段(strobes)(注意,FT200XD、FT220X、FT221X和FT234XD只有一个CBUS 引脚,因此只能选择 RD#WR# )。通过在内部EEPROM中设置适当的值,CBUS 引脚也可用于提供时钟信号。

所有的bit-bang模式都需要使用D2XX驱动,不可能通过VCP驱动使用这些功能,也不可能同时使用 CBUS bit-bangVCP。表3.2列出了用于同步 bit-bang 模式的基本命令。这些功能的完整描述可在《D2XX程序员指南》中找到。

image-20220707152805911

FTDI BIT-BANG

FT432 如果需要配置成 Bit-Bang模式,需要:

  1. 使用 FT_Open() 打开对应通道
  2. 使用 FT_SetBitMode() 为8个pin配置输入或输出,FTDI 称之为掩码(mask),0则代表输入,1则代表输出,例如 0x0F 则代表 0~3 pin 设置为输出,4~7 pin设置为输入。
  3. 同时,在 FT_SetBitMode() 第三个参数 ucEnable 传递参数即可打开对应模式,如:
    1. FT_BITMODE_SYNC_BITBANG 即 同步 Bit-Bang 模式
    2. FT_BITMODE_SYNC_BITBANG 即 异步 Bit-Bang 模式
    3. FT_BITMODE_RESET 即 默认的 UART 模式。
  4. FT4232 的每个通道都是具有独立时钟的,为 FT_SetBaudRate() 传递参数即可设置SPI通信频率。实际上此处设置的并不是 SPI外设的工作频率,而是该 channel 通过 FT_Write() 接口改变引脚高低电平的频率。
    1. 同步 Bit-Bang 模式下,每 100000 波特率约为 250KHz 时钟,如果使其工作在 1MHz 频率下,则需要设置波特率为 400000
    2. 异步 Bit-Bang 模式下的时钟为波特率的 16
  5. 使用读取和写入的接口 FT_Write()FT_Read() 会按照该通道设定的时钟频率去改变/读取引脚数据。

操作一次 FT_Write() ,如下,即可在 一个频率的半个周期内 改变 8个pin 的高低电平。

1
2
3
4
5
6
bytes_written_number = 0;
ftStatus = FT_Write(ft_handle,
&(byte_write_to_slave->all),
bits_to_send,
&bytes_written_number);
CHECK_STATUS(ftStatus);
  • ft_handle 是通道的句柄(注意:一个通道一个句柄,不是一个句柄适用所有通道)

  • byte_write_to_slave.all 是一个 8bit 的 UCHAR 类型数据。

  • bits_to_send 为 待发送数据量

  • bytes_written_number 是 已写入数据量

例1

如果将 掩码 配置为 0xFF ,即8个通道均为输出。且输出每个通道单次输出的数值,均为 0xFF,输出 16次,即调用 FT_Write() 16次,那么得到的图像应该如下:

index

例2

如果将 掩码 配置为 0xFF 。交替输出 0xFF0x00,输出 16 次,那么得到的图像应该如下:

Q: 为什么上面只有8个时钟,即1个byte大小,为什么是输出16次?

A: 因为FTDI的 FT_Write() 接口写入一次数据,只能控制半个周期内的8个pin脚数据,如果需要发送一个周期的数据,则需要写两次,如果需要发送8个bit,则需要输出16次。

2

例3

如果将 掩码 配置为 0x0B,即 0000 1011 ,(按照 MPSSE-SPI Example 设置的相同配置),pin0SCKpin1MOSIpin2MISOpin3CS

默认情况下,输入引脚的电平会被拉低。如果设置为输入引脚,FT_Write() 无法改变其电平。

FT_Write() 一共需要写入 32次数据:

1
2
3
4
5
UCHAR byte_write_to_slave[32] = {
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x03, 0x02,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00,
0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00};

3

可以看到在 byte_write_to_slave[14]byte_write_to_slave[15] 时需要主动拉高 pin1 的电平,并维持 2个 falf period(即 one period)。

再用 FT_Read() 读取 32 次数据,将数据存储到 UCHAR byte_read_from_slave[32] 中,并从 byte_read_from_slave[16] ~ byte_read_from_slave[31] 的 16 个数据中,每间隔1个数据,将对应 pin2 的数据左移存储到 data_read 中。

代码可以是这样的:

1
2
3
4
5
UCHAR data_read = 0;
for (int i = 0; i < 8; i++)
{
data_read |= ( byte_read_from_slave[ 16 + i * 2 ] & 0x03) << ( 7 - i );
}

Q: 为什么 FT_Read() 需要读取32次数据?

A: 因为这是 同步 Bit-Bang 模式的特性,根据手册说明,每次读取一定数据量之前,都要写入一定的数据量。异步 Big-Bang 模式是不用这样的。

SPI + BIT-BANG

如果按照例3 的方法去发送数据,可能会发现收到的数据一直是异常的。

因为 输出引脚 会保持其最后的输出电平,如 byte_read_from_slave[31] 数据为 0x00,这就让 pin0 ,即 SCK 发送完数据之后保持了低电平,与 CPOL=1 的要求相违背。

因此不能只发送和接收32个数据,而应该在对应的发送数据的前后加上一个周期,即声明一个长度为36的数组 UCHAR byte_read_from_slave[36] 。

byte_read_from_slave[0] / byte_read_from_slave[1] / byte_read_from_slave[34] / byte_read_from_slave[35] 均应设置为 0x09 ,如下波形所示。

image-20220714173158679

FTDI HAL

FTDI HAL 是基于 D2XX 库、由个人编写的、可替换libMPSSE的SPI库,目前仅有SPI相关的代码。

2022年7月11日 16:10

各通道的可以配置不同的handle和config 参数去打开和关闭。也可以读GPIO,没问题了。

image-20220711161012120

ftd2xx_hal_read_pin_level

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
/**
* @brief GPIO 电平读取接口
* @param {FT_HANDLE*} ft_handle:待读取通道句柄
* @param {UCHAR} pin_to_read:待读取引脚
* @param {UCHAR*} pin_level:电平值
* @return FT_OK if successful, otherwise the return value is an FT error code.
*/
FT_STATUS ftd2xx_hal_read_pin_level(FT_HANDLE* ft_handle,
UCHAR pin_to_read,
UCHAR* pin_level)
{
FT_STATUS ftStatus = FT_OK;
FTD2XX_HAL_DATA byte_read_from_slave;
FTD2XX_HAL_DATA byte_write_to_slave;
DWORD byte_read_number = 0;
byte_write_to_slave.all = 0;

if (pin_to_read > 7 || pin_level == NULL)
{
return FT_INVALID_ARGS;
}

ftStatus =
FT_Write(*ft_handle, &(byte_write_to_slave.all), 1, &byte_read_number);
CHECK_STATUS(ftStatus);

// 从同道中读取8个pin的电平
byte_read_number = 0;
ftStatus =
FT_Read(*ft_handle, &(byte_read_from_slave.all), 1, &byte_read_number);
CHECK_STATUS(ftStatus);

*pin_level = (byte_read_from_slave.all >> pin_to_read) & 0x01;

return ftStatus;
}

电平读取能力分析

  • 利用esp32 的 GPIO 发送pwm波(宽度为 350ns ,周期约为 750ns ),发送 10000次后停止,该接口能够读取到 76~80 次。

image-20220712121857849
  • 拉长 pwm波周期至 33us,同样发送 10000次后停止,该接口能够读取到 6660 次左右。

image-20220712122514462

GPIO电平读取频率大致在 5KHz ~ 50KHz 之间,即接口两次调用的时间间隔在 20us ~ 200us 之间。

DEBUG RECORD

NULL expression encountered

image-20220711123340879

这是因为运行需要 sudo 权限,即 sudo ./tmp/galileo_sdk/application/sample_app_raw_data_irq 。如果还是不行,应该是没有卸载 ftdi_siousbserial ,即 sudo rmmod ftdi_sio usbserial

注意:卸载 usbserial 后,如果这时候linux系统内有其他设备对 libusb-1.0-0-dev 有依赖,那它会无法正常工作。

REFERENCE

  1. FTDI GPIO example
  2. aehparta/ftdi-bitbang
  3. FTDI Knowledgebase
  4. swharden/AVR-projects
  5. Bit-Bang FTDI USB-to-Serial Converters to Drive SPI Devices
  6. libFTDI - FTDI USB driver with bitbang mode
  7. Documents/Application Notes

环境部署

  1. 直接使用绝对路径,如 "D:\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin\STM32_Programmer_CLI.exe",这种方法可以在 PowerShell 或 cmd 直接使用。
  2. "D:\STMicroelectronics\STM32Cube\STM32CubeProgrammer\bin 添加到 系统环境变量 中,这种方法只有 PowerShell 可以使用,cmd 还是不可以。
image-20220615134109619

使用说明

STM32_Programmer_CLI 的指令参数有多种分类,包括适用于 STM32 MCUSTM32 MPUMCU安全烧录STM32WBxx 三个部分。

下面是这个软件的官方说明:

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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
      -------------------------------------------------------------------
STM32CubeProgrammer v2.9.0
-------------------------------------------------------------------


Usage :
STM32_Programmer_CLI.exe [command_1] [Arguments_1][[command_2] [Arguments_2]...]

Generic commands:

-?, -h, --help : Show this help
-c, --connect : Establish connection to the device
<port=<PortName> : Interface identifier. ex COM1, /dev/ttyS0, usb1,
JTAG, SWD...)
USB port optional parameters:
[sn=<serialNumber>] : Serial number of the usb dfu
[PID=<Product ID>] : Product ID. ex: 0xA38F, etc, default 0xDF11
[VID=<Vendor ID>] : Vendor ID. ex: 0x0389, etc, default x0483
UART port optional parameters:
[br=<baudrate>] : Baudrate. ex: 115200, 9600, etc, default 115200
[P=<parity>] : Parity bit, value in {NONE,ODD,EVEN}, default EVEN
[db=<data_bits>] : Data bit, value in {6, 7, 8} ..., default 8
[sb=<stop_bits>] : Stop bit, value in {1, 1.5, 2} ..., default 1
[fc=<flowControl>] : Flow control
Value in {OFF,Hardware,Software} ..., default OFF
rts=<status> : low or high
dtr=<status> : low or high
Not supported for STM32MP
[noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0
[console] : Enter UART console mode
JTAG/SWD debug port optional parameters:
[freq=<frequency>] : Frequency in KHz. Default frequencies:
4000 SWD 9000 JTAG with STLINKv2
24000 SWD 21333 with STLINKv3
[index=<index>] : Index of the debug probe. default index 0
[sn=<serialNumber>]: Serial Number of the debug probe
[ap=<accessPort>] : Access Port index to connect to. default ap 0
[mode=<mode>] : Connection mode. Value in {UR/HOTPLUG/NORMAL/POWERDOWN}
default mode: NORMAL
[reset=<mode>] : Reset modes: SWrst/HWrst/Crst. Default mode: SWrst
Reset mode with UR connection mode is HWrst
[shared] : Enable shared mode allowing connection of two or more
instances of STM32CubeProgrammer or other debugger
to the same ST-LINK probe.
[tcpport=<Port>] : Port used for running ST-Link Server, default 7184
[LPM] : Enable debug in Low Power mode(default mode)
[dLPM] : Disable debug in Low Power mode
[getAuthID] : Get device identification (Option only for STM32U5 series)
[speed=<Reliable/fast>]: Choose flashing Reliable/fast (Option only for STM32U5 series)
SPI port optional parameters:
[br=<baudrate>] : Baudrate.
[cpha=<cpha_val>] : 1Edge or 2Edge. default 1Edge
[cpol=<cpol_val>] : low or high
[crc=<crc_val>] : enable or disable (0/1).
[crcpol=<crc_pol>] : crc polynom value.
[datasize=<size>] : 8bit/16bit
[direction=<val>] : Direction: 2LFullDuplex/2LRxOnly/1LRx/1LTx
[firstbit=<val>] : First Bit: MSB/LSB
[frameformat=<val>]: Frame Format: Motorola/TI
[mode=<val>] : Mode: master/slave
[nss=<val>] : NSS: soft/hard
[nsspulse=<val>] : NSS pulse: Pulse/NoPulse
[delay=<val>] : Delay: Delay/NoDelay, delay of few microseconds
[noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0
CAN port optional parameters:
[br=<rbaudrate>] : Baudrate : 125, 250, 500, 1000 Kbps, default 125
[mode=<canmode>] : CAN Mode : NORMAL, LOOPBACK..., default NORMAL
[ide=<type>] : CAN Type : STANDARD or EXTENDED, default STANDARD
[rtr=<format>] : Frame Format: DATA or REMOTE, default DATA
[fifo=<afifo>] : Msg Receive : FIFO0 or FIFO1, default FIFO0
[fm=<fmode] : Filter Mode : MASK or LIST, default MASK
[fs=<fscale>] : Filter Scale: 16 or 32, default 32
[fe=<fenable>] : Filter Activation : ENABLE or DISABLE, default ENABLE
[fbn=<fbanknb>] : Filter Bank Number : 0 to 13, default 0
[noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0
I2C port optional parameters:
[add=<ownadd>] : Slave address : address in hex format
[br=<sbaudrate>] : Baudrate : 100 or 400 Kbps, default 400
[sm=<smode>] : Speed Mode : STANDARD or FAST, default FAST
[am=<addmode>] : Address Mode : 7 or 10 bits, default 7
[af=<afilter>] : Analog filter : ENABLE or DISABLE, default ENABLE
[df=<dfilter>] : Digital filter : ENABLE or DISABLE, default DISABLE
[dnf=<dnfilter>] : Digital noise filter : 0 to 15, default 0
[rt=<rtime>] : Rise time : 0-1000(STANDARD), 0-300(FAST), default 0
[ft=<ftime>] : Fall time : 0-300 (STANDARD), 0-300(FAST), default 0
[noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0
-version, --version : Displays the tool's version
-l, --list : List all available communication interfaces
<uart> : UART interface
<usb> : USB interface
<st-link> : st-link interface
-q, --quietMode : Enable quiet mode. No progress bar displayed
-log, --log : Store the detailed output in log file
[<file_Path.log>] : Path of the log file,
default path = $HOME/.STM32Programmer/trace.log
-vb, --verbosity : Specify verbosity level
<Level> : Verbosity level, value in {1, 2, 3}
-y, --yes : Ignore confirmation prompt message

Available commands for STM32 MCU:

--skipErase : Skip sector erase before programming
-sl, --safelib : Add a segment into a firmware file (elf,bin
hex,srec) containing computed CRC values
To use only with the safety lib component
<file_path> : File path to be modified
<start_address> : Flash memory start address
<end_address> : Flash memory end address
<slice_size> : Size of data per CRC value
-ms, --mergesbsfu : Add a binary header and a sbsfu segment to an elf file
<elf_file_path> : File path to be modified
<header_file_path> : Header file path
<sbsfu_file_path> : SBSFU file path
-e, --erase : Erase memory pages/sectors devices:
Not supported for STM32MP
[all] : Erase all sectors
[<sectorsCodes>] : Erase the specified sectors identified by sectors
codes. ex: 0, 1, 2 to erase sectors 0, 1 and 2
for EEPROM : ed1 & ed2
[<[start end]>] : Erase the specified sectors starting from
start code to end code, ex: -e [5 10]
-w, --write
-d, --download : Download the content of a file into device memory
<file_path> : File path name to be downloaded: (bin, hex, srec,
elf, stm32 or tsv file)
[<address>] : Start address of download
-w64 : Write a 64-bits data into device memory
<address> : Start address of download
<64-bit_data> : 64-bit data to be downloaded
values should not be separated by space
-w32 : Write a 32-bits data into device memory
<address> : Start address of download
<32-bit_data> : 32-bit data to be downloaded
values should be separated by space
-w16 : Write a 16-bits data into device memory
<address> : Start address of download
<16-bit_data> : 16-bit data to be downloaded
values should be separated by space
-w8 : Write a 8-bits data into device memory
<address> : Start address of download
<8-bit_data> : 8-bit data to be downloaded
values should be separated by space
-v, --verify : Verify if the programming operation is achieved
successfully
-r32 : Read a 32-bit data from device memory
<address> : Read start address
<size> : Size of data
-r16 : Read a 16-bit data from device memory
<address> : Read start address
<size> : Size of data
-r8 : Read a 8-bit data from device memory
<address> : Read start address
<size> : Size of data
-rst : Reset system
-hardRst : Hardware reset
Available only with JTAG/SWD debug port
-halt : Halt core
-run : Run core
-step : Step core
Available only with JTAG/SWD debug port
-score : Get core status
Available only with JTAG/SWD debug port
-coreReg : Read/Write core registers
[<core_register>] R0/../R15/PC/LR/PSP/MSP/XPSR/APSR/IPSR/EPSR/
PRIMASK/BASEPRI/FAULTMASK/CONTROL
[core_reg=<value>] value in case of write opration
Note: multiple registers can be handled at once
Available only with JTAG/SWD debug port
-bkpt : Set a breakpoint
<address> : Breakpoint address
-clrbkpt : Clear a breakpoint
<address> : Breakpoint address
-r, --read
-u, --upload : Upload the device memory content to a .bin/.hex/.srec file
<address> : Start address of read and upload
<size> : Size of memory content to be read
<file_path> : file path with .bin/.hex/.srec extension

-el, --extload : Select a custom external memory-loader for JTAG/SWD
<file_path> : External memory-loader file path
-elbl, --extloadbl : Select a custom external memory-loader for Bootloader interface (SFIx only)
<file_path> : External memory-loader file path
-s, --start
-g, --go : Run the code at the specified address.
[<address>] : Start address
-rdu, --readunprotect: Remove memory's Read Protection by shifting the RDP
level from level 1 to level 0.

-tzenreg, --tzenregression: Remove TrustZone Protection by disabling the TZEN
from 1 to 0.

-ob, --optionbytes : This command allows the user to manipulate the device
's OptionBytes by displaying or modifying them.
[displ] : This option allows the user to display the whole set
of Option Bytes.
[OptByte=<value>] : This option allows the user to program the given
Option Byte.

-lockRDP1 : Lock RDP level 1
<first_half> : First 32-bit of password
<second_half> : Second 32-bit of password
-unlockRDP1 : Unlock RDP level 1
<first_half> : First 32-bit of password
<second_half> : Second 32-bit of password
-lockRDP2 : Lock RDP level 2
<first_half> : First 32-bit of password
<second_half> : Second 32-bit of password
-unlockRDP2 : Unlock RDP level 2
<first_half> : First 32-bit of password
<second_half> : Second 32-bit of password
-ssigfoxc : Save the chip Certificate,
supported for STM32WL devices
<file_path> : Certificate file path

-wsigfoxc : Write the Sigfox credential,
supported for STM32WL devices
<file_path> : Certificate file path (binary, header)
<address> : start address for write

-fillmemory : Fill memory with the given pattern from the chosen address.
<start_address> : Start address for write. The address 0x08000000 is used by default
[size=<value>] : Size of the data to write
[pattern=<value>] : The pattern value to write.
[dataWidth=8|16|32]: The filling data size:
8 bits is selected by default.
-blankcheck : Verifies that the STM32 Flash memory is blank.
If the Flash memory is not blank, the first address with data is highlighted in a message.
Beta commands:

-regdump : Read and dump Core and MCU registers
<file_path.log> : Log file path
[choice=<number>] : Device number from the list of compatible devices (optional), this list
is displayed if the command is performed without this optional argument
-hf : Hard fault analyzer
Helps to identify system faults that occur when the CPU
is driven into a fault condition by the application code.

Available commands for STM32 MPU:

-c, --connect : Establish connection to the device
<port=<PortName> : Interface identifer. ex COM1, /dev/ttyS0, usb1)
USB port optional parameters:
[sn=<serialNum>] : Serial number of the usb dfu
[serial] : Activate USB serial Gadget for MPU devices
UART port optional parameters:
[br=<baudrate>] : Baudrate. ex: 115200, 9600, etc, default 115200
[P=<parity>] : Parity bit, value in {NONE,ODD,EVEN}, default NONE
[db=<data_bits>] : Data bit, value in {6, 7, 8} ..., default 8
[sb=<stop_bits>] : Stop bit, value in {1, 1.5, 2} ..., default 1
[fc=<flowControl>] : Flow control (Not yet supported for STM32MP)
Value in {OFF,Hardware,Software} ..., default OFF
[noinit=noinit_bit]: Set No Init bits, value in {0,1} ..., default 0
-s, --start
-g, --go : Run the code at the specified partition ID.
[<partitionID>] : Partition ID
If not specified, last loaded partition
will be started

[<startAdress>] : Start address
If not specified, last loaded segment address
[<noack>] : No acknowledgment required
If not specified, acknowledgment will be required

-detach : Send detach command to DFU

-wb : Write blob

<blob_file_path> : Blob file path
-pmic : Program PMIC NVM

<PMIC file_path> : PMIC file_path
-gc, --getcertificate : Get the chip Certificate,
supported for devices with security features
<file_path> : Certificate file path into which the chip
certificate will be uploaded

-p, --phaseID : Display the current partition ID to be loaded

-w, --write
-d, --download : Download the content of a file into device memory
<file_path> : File path name to be downloaded: (bin, stm32 file
<partition_id> : Partition ID to be downloaded
-rp, --readPart : Upload a memory partion ID content to a .bin file
<partionID> : Partion to be read
[<offset address>] : Offset address of read and upload
<size> : Size of partion content to be read
<file_path> : Binary file path

-ssp, --ssp : Program an SSP file
<ssp_file_path> : SSP file path to be programmed, bin or ssp extension
<ssp-fw-path> : SSP signed firmware path
[hsm=0|1] : Set user option for HSM use
value in {0 (do not use HSM), 1 (use HSM)}
Default value : hsm=0
<lic_path|slot=slotID> : Path to the license file (if hsm=0)
or reader slot ID if HSM is used (hsm=1)
-tm : Force timeout
<value> : Number of milliseconds
-rst : Reset USB device

OTP structure v1 commands (for STM32MP15xx):
-otp program : This command allows the user to program SAFMEM
memory by modifying the OTP words
[wordID=<value>] : This field contains the OTP word number
[value=<value>] : Loads value into the chosen OTP word
[sha_rsl=<value>] : Loads value into the corresponding shadow read
sticky lock bit
[sha_wsl=<value>] : Loads value into the corresponding shadow write
sticky lock bit
[sl=<value>] : Loads value into the corresponding programming sticky
lock bit
[pl=<value>] : Loads value into the corresponding programming perma-
nent lock bit

-otp displ : This command allows the user to display all or parts
of the OTP structure
[upper] : Displays the loaded upper OTP shadow registers
values and status
[lower] : Displays the loaded lower OTP shadow registers
values and status
[ctrl] : Displays the loaded BSEC control registers

OTP structure v2 commands (except STM32MP15xx):
-otp displ : This command allows the user to display all or parts
of the OTP structure
[word=<id>] : {Optional} display a specific OTP registers {values and status}
Up to 96 OTP words [0 to 95], id value in hex/dec format

-otp write : This command allows to fuse or update OTP words
Up to 96 OTP words [0 to 95] at the same command line
[lock] : {Optional} indicate the operation type, update or permanent lock
[word=<id>] : This field contains the OTP word number in hex/dec format
[value=<value>] : Value to be written in hex format

-otp lock : This command allows to fuse permanently OTP words
Up to 96 OTP words [0 to 95] at the same command line
[word=<id>] : This field contains the OTP word number in hex/dec format

-otp fwrite : This command allows to program a binary file
[lock] : {Optional} indicate the operation type, update or permanent lock
<bin_path> : Binary file path, 32-bits aligned
[word=<id>] : OTP word number in hex/dec format, start word of program

MCU Secure programming specific commands:

-sfi, --sfi : Program an sfi file
[<protocol=Ptype>] : Protocol type to be used : static/live
Only static protocol is supported so far
Default value static
<file_path> : Path of sfi file to be programmed
[hsm=0|1] : Set user option for HSM use
value in {0 (do not use HSM), 1 (use HSM)}
Default value : hsm=0
<lic_path|slot=slotID> : Path to the SFI license file (if hsm=0)
or reader slot ID if HSM is used (hsm=1)
[<licMod_path>|slot=slotID]: list of the integrated SMI license files paths
if HSM is not used (hsm=0)
Or readers slot IDs list if HSM is used (hsm=1)
Used only in combined case
the list order should correspond to
modules integration order within the SFI file

-smi, --smi : Program an smi file
<protocol=Ptype> : Protocol type to be used : static/live
Only static protocol is supported so far
Default value static
<file_path> : Path of smi file to be programmed
[hsm=0|1] : Set user option for HSM use
value in {0 (do not use HSM), 1 (use HSM)}
Default value : hsm=0
[<address>] : Destination address of the smi module
needed only for relocatable SMI
<lic_path|slot=slotID> : Path to the SMI license file (if hsm=0)
or reader slot ID if HSM is used (hsm=1)

-rsse, --rsse : Set the RSSe file path,
supported for devices with security extension
<file_path> : RSSe file path

-a, --abort : This command allows the user
to clean a not properly finished process.
The currently ongoing operation will stop
and the system will return to idle state

-dsecurity : Disable the security for STM32WL

-setdefaultob : Set default Option Bytes for STM32WL

-rssgetversion, --rssgetversion : get the version of RSS
HSM related commands:
-hsmgetinfo : Read the HSM available information
[slot=<SlotID>] : Slot ID of the Smart Card Reader
Default value: slot=1 (the PC integrated SC reader)
-hsmgetcounter : Read the current value of the license counter
[slot=<SlotID>] : Slot ID of the Smart Card Reader
Default value: slot=1 (the PC integrated SC reader)
-hsmgetfwid : Read the Firmware/Module Identifier
[slot=<SlotID>] : Slot ID of the Smart Card Reader
Default value: slot=1 (the PC integrated SC reader)
-hsmgetstatus : Read the current card life-cycle state
[slot=<SlotID>] : Slot ID of the Smart Card Reader
Default value: slot=1 (the PC integrated SC reader)
-hsmgetlicense : Get a license for the current chip
if counter is not null
<file_path> : File path into which the received license
will be stored
[slot=<SlotID>] : Slot ID of the Smart Card Reader
Default value: slot=1 (the PC integrated SC reader)
[protocol=<Ptype>] : Protocol type to be used : static/live
Only static protocol is supported so far
Default value static

-hsmgetlicensefromcertifbin, -hsmglfcb : Get a license for the input certificate
if counter is not null
<certif_file_path.bin> : Input certificate file path
<license_file_path.bin> : File path into which the received license
will be stored
[slot=<SlotID>] : Slot ID of the Smart Card Reader
Default value: slot=1 (the PC integrated SC reader)
[protocol=<Ptype>] : Protocol type to be used : static/live
Only static protocol is supported so far
Default value static

STM32WBxx specific commands:

-getuid64 : Read the device UID
-fusgetstate : Read the FUS state
-fusopgetversion : Read the FUS Operator version
-antirollback : Perform the antirollback operation (Only on Bootloader interface)
-startfus : Perform the startfus operation
Firmware Upgrade commands:
-fwdelete : Delete the BLE stack firmware
-fwupgrade : Upgrade the BLE stack firmware or the FUS firmware
<file_path> : New firmware image file path
<address> : Start address of download
[firstinstall=0|1] : 1 if it is a first install otherwise 0
optional, Default value: firstinstall=0
[startstack=0|1] : 1 to start the stack after the upgrade otherwise 0
optional, Default value: startstack=1
-autoupgrade : Automatically recognize the stack address and Upgrade the BLE stack firmware
<file_path> : New firmware image file path
-v : Verify if the download operation is achieved
successfully before starting upgrade
-startwirelessstack : Start the wireless stack
Key management commands:
-authkeyupdate : Authentication key update
<file_path> : New authentication key file path.
: This is the public key generated by
: STM32TrustedPackageCreator using -sign command.
-authkeylock : Authentication key lock
: Once locked, it's no longuer possible to change it
: using authkeyupdate command
-wusrkey : Write user key
<file_path> : User key file path
<keytype=1|2|3> : User key type, values : 1, 2 or 3.
: 1 = simple key, 2 = master key, 3 = encrypted key.
Serial Wire Viewer specific commands:

-swv : Printf via SWO
<freq=<frequency>> : System Clock in MHz
<portnumber=0-31|all> : ITM port number, values : 0-31, or all for All ports
[<file_Path.log>] : Path of the SWV log file (optional),
: default path = $USER_HOME/STMicroelectronics/STM32Programmer/SWV_Log/swv.log
-RA : Start the reception of swv automatically
-startswv : Printf via SWO & Start the reception of swv automatically
Script Manager command:

-script : Start the execution of Script File
<file_Path.prg> : Path of the script file (.prg)

查看设备列表

下面语句可以查看所有连接至PC端的设备。

1
STM32_Programmer_CLI -l
设备列表

详见:

1
2
3
4
-l,     --list         : List all available communication interfaces
<uart> : UART interface
<usb> : USB interface
<st-link> : st-link interface

设备连接

可以使用多种连接方式,将ST的从设备与PC上位机进行连接,包括 USB / UART / JTAG / SWD / SPI / CAN / I2C 。

使用指令 STM32_Programmer_CLI -c port=SWD 即可自动连接至设备。

设备自动连接

内容读取

使用指令 STM32_Programmer_CLI -c port=SWD -r32 0x08000000 0x400 可以从 地址 0x08000000 起,以 32bit 格式(-r32 )读取 0x400 byte 数据。

以32bit格式读取数据

-r32 可以更换成 -r16-r8

以16bit格式读取数据
以8bit格式读取数据

内容擦除

大面积擦除(Mass erase)所有内容,一般来说烧录的时候不会去擦除全部内容,这部分应该看情况。

1
STM32_Programmer_CLI -c port=SWD -e all
擦除全部内容

详见:

1
2
3
4
5
6
7
8
-e,     --erase        : Erase memory pages/sectors devices:
Not supported for STM32MP
[all] : Erase all sectors
[<sectorsCodes>] : Erase the specified sectors identified by sectors
codes. ex: 0, 1, 2 to erase sectors 0, 1 and 2
for EEPROM : ed1 & ed2
[<[start end]>] : Erase the specified sectors starting from
start code to end code, ex: -e [5 10]

下面两张图是烧录完某 .bin 文件后,flash内部结束尾部临界处的数据。交替烧录两个大小不易的 .bin 文件,可以观察到结尾处都是正常的,并没有出现异常。

临界处数据
image-20220615130543343

程序烧录

1
STM32_Programmer_CLI -c port=SWD -d "\\wsl.localhost\kali-linux\home\liewzheng\Workspace\stm32\20220511-galileo-manifest\out\mixosense_apps\data_collection_irq\data_collection_irq.bin" 0x00 -v
  • -d 是指 文件下载,后方接 文件路径 以及 起始地址 0x00 。这个起始地址应该是 0x08000000 还是 0x00 我也还没搞清楚。

  • -v 是指 代码验证。

image-20220615123114639

详见:

1
2
3
4
-d,     --download     : Download the content of a file into device memory
<file_path> : File path name to be downloaded: (bin, hex, srec,
elf, stm32 or tsv file)
[<address>] : Start address of download

设备复位和运行

1
2
STM32_Programmer_CLI -c port=SWD -hardRst
STM32_Programmer_CLI -c port=SWD -s
image-20220615124508137

报错

端口占用报错

image-20220615121045036

下面所有的脚本都会类比 Linux Shell Script 进行。

Windows有两个命令行 shell:Command shell 和 PowerShell。 每个 shell 都是一个软件程序,它提供你与操作系统或应用程序之间的直接通信,提供一个环境来自动执行 IT 操作。

Command shell 是内置于 Windows中,用于自动执行常规任务(例如用户帐户管理或夜间备份)和批处理 (.bat) 文件。 使用Windows脚本主机,可以在命令外壳中运行更复杂的脚本。 有关详细信息,请参阅 cscript 或 wscript。 通过使用脚本可以比使用用户界面更有效地执行操作。 脚本接受命令行中提供的所有命令。

PowerShell 旨在扩展 Command shell 的功能,以运行名为 cmdlet 的 PowerShell 命令。 Cmdlet 类似于 Windows命令,但提供了更具可扩展性的脚本语言。 可以在 PowerShell 中Windows命令和 PowerShell cmdlet,但命令外壳只能运行 Windows 命令,不能运行 PowerShell cmdlet。

若要实现最可靠、最新的自动化Windows,建议使用 PowerShell 而不是 Windows 命令或 Windows 脚本主机Windows自动化。

Generic Script

注释

windows bat 批处理和 PowerShell 都可以使用 :: 作为注释头部信息。与 Linux Shell Script 和 Python 的 # 不一致(反人类罪)。

1
:: 注释

DEL& RD

del 删除命令只能删除文件,rd 可以删除文件夹

/Q 是静默删除,不提示文字。/S 除目录本身外,还将删除指定目录下的所有子目录和文件。用于删除目录树。

1
2
3
4
5
6
:: 静默删除所有文件和文件夹
del /Q %BUILD_PATH%\*.o
rd /S /Q %BUILD_PATH%\bin
rd /S /Q %BUILD_PATH%\log
rd /S /Q %BUILD_PATH%\lib
rd /S /Q %BUILD_PATH%\map

常见命令对照表

Windows Bat Windows PowerShell Linux Shell Others
help Get-Help man
cd /D Set-Location cd
cd Get-Location pwd
type Get-Content cat
rd /S
rmdir /S
Remove-Item rm -r
del
erase
Remove-Item rm
dir /b ls
dir Get-ChildItem ll
cls Clear-Host clear
doskey Set-Alias alias
md
mkdir
New-Item mkdir
move Move-Item mv
ren
rename
Rename-Item mv
copy Copy-Item cp
echo Write-Output echo

条件语句

bat 的条件语句教程:《if

PowerShell 的条件语句教程:《about_If

REFERENCE

  1. 什么是 PowerShell?
  2. Microsoft.PowerShell.Management
  3. Windows 命令

因为基本上没什么人直接使用 armcc 作为自动化编译、持续集成和交付的工具,更多是使用 UV4 软件读取 .uvprojx 文件来获取编译信息,进而驱动 armcc 进行编译过程。

通过自行编辑 Makefile 文件,使用 make 和 armcc 工具可以对代码文件进行编译,可以进行静态库的生成,也可以生成可烧录文件,但是就不要想着复杂的 make test 等测试功能了。

DIFF BETWEEN THEM

下方详细描述一下使用 arm-none-eabi-gccmakecmakearmccmake 的不同。

  1. 使用 arm-none-eabi-gccmake 编译的 SDK 过程属于 Unix Makefile 编译过程(详见 CMake 工具及官网对 CMakefiles Generators 说明)。暂时不清楚使用 armcccmake 是如何生成 Makefile 的,因为尚不了解toolchain的绑定过程,导致一致检测到的是 windows平台本地的 mingw 工具。
  2. 启动文件不同。详见 ABOUT STARTUP FILE
  3. 工具链指定方式不同。详见 TOOLCHAIN

KEIL MDK ENV

MDK SOFTPACK

MDK5 Software Packs

TOOLCHAIN DOWNLOADS

首先需要安装版本较新的 Keil MDK-ARM 开发软件。最好是在Windows上安装,方便破解。

可以从 About uVision 中查看版本信息。也可以直接在 PowerShell 中直接调用查看。

MDK 的版本为 v5.22 确实是比较老旧的,建议下载 v5.27 及以上版本。

下载链接:MDKv5.28MDKv5.37keygen

官网下载:ARM Compiler 5 Downloads

image-20220608100300944
image-20220608100748964

TOOLCHAIN

下面的一些参数可以从 ARM Compiler v5.06 for uVision armcc User Guide 获取帮助。

FROMELF

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
Options:
--help display this help screen
--vsn display version information
--output file the output file. (defaults to stdout for -text format)
--nodebug do not put debug areas in the output image
--nolinkview do not put sections in the output image

Binary Output Formats:
--bin Plain Binary
--m32 Motorola 32 bit Hex
--i32 Intel 32 bit Hex
--vhx Byte Oriented Hex format

--base addr Optionally set base address for m32,i32

Output Formats Requiring Debug Information
--fieldoffsets Assembly Language Description of Structures/Classes
--expandarrays Arrays inside and outside structures are expanded

Other Output Formats:
--elf ELF
--text Text Information

Flags for Text Information
-v verbose
-a print data addresses (For images built with debug)
-c disassemble code
-d print contents of data section
-e print exception tables
-g print debug tables
-r print relocation information
-s print symbol table
-t print string table
-y print dynamic segment contents
-z print code and data size information
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
Usage: armlink option-list input-file-list
where
option-list is a list of case-insensitive options.
input-file-list is a list of input object and library files.

General options (abbreviations shown capitalised):
--help Print this summary.
--output file Specify the name of the output file.
--via file Read further arguments from file.

Options for specifying memory map information:
--partial Generate a partially linked object.
--scatter file Create the memory map as described in file.
--ro-base n Set exec addr of region containing RO sections.
--rw-base n Set exec addr of region containing RW/ZI sections.

Options for controlling image contents:
--bestdebug Add debug information giving best debug view to image.
--datacompressor off
Do not compress RW data sections.
--no_debug Do not add debug information to image.
--entry Specify entry sections and entry point.
--libpath Specify path to find system libraries from.
--userlibpath Specify path to find user libraries from.
--no_locals Do not add local symbols to image symbol table.
--no_remove Do not remove unused sections from image.

Options for controlling image related information:
--callgraph Create a static callgraph of functions.
--feedback file Generate feedback that can be used by the compiler in file.
--info topic List misc. information about image.
Available topics: (separate multiple topics with comma)
common List common sections eliminated from the image.
debug List eliminated input debug sections.
sizes List code and data sizes for objects in image.
totals List total sizes of all objects in image.
veneers List veneers that have been generated.
unused List sections eliminated from the image.
--map Display memory map of image.
--symbols List symbols in image.
--xref List all cross-references between input sections.

--summary_stderr

ARMCC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Usage:         armcc [options] file1 file2 ... filen
Main options:

--arm Generate ARM code
--thumb Generate Thumb code
--c90 Switch to C mode (default for .c files)
--cpp Switch to C++ mode (default for .cpp files)
-O0 Minimum optimization
-O1 Restricted optimization for debugging
-O2 High optimization
-O3 Maximum optimization
-Ospace Optimize for codesize
-Otime Optimize for maximum performance
--cpu <cpu> Select CPU to generate code for
--cpu list Output a list of all the selectable CPUs
-o <file> Name the final output file of the compilation
-c Compile only, do not link
--asm Output assembly code as well as object code
-S Output assembly code instead of object code
--interleave Interleave source with disassembly (use with --asm or -S)
-E Preprocess the C source code only
-D<symbol> Define <symbol> on entry to the compiler
-g Generate tables for high-level debugging
-I<directory> Include <directory> on the #include search pat

MAKEFILE

make 可以在任一路径下执行,只需要加入 -C <path> 即可,即告诉make工具在 <path> 路径下执行编译。方便了在 windows 命令行环境下的执行。

编写 Makefile 的时候,某些变量可以通过外部传递,而且方法也很简单,甚至内部甚至不需要声明,只需要在引用处写明变量名称即可。然后外部调用时以 VARIABLE="value" 的形式进行声明即可。如下:

1
make libmxs -C 20220607 MANIFEST_PATH="F:\Workspace\20220511-galileo-manifest" TOOLCHAIN_PATH="D:\Keil_v528\ARM\ARMCC\bin"

COMPILING CONTROL STRINGS

下面这些编译参数是复制自 KEIL IDE 的,对应的平台是 STM32L4R9。

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
--c99
-c
--cpu Cortex-M4.fp
-D__MICROLIB -g -O3 --apcs=interwork --split_sections

-I ../app
-I ../M_BSP
-I ../M_BSP/BMM150
-I ../M_BSP/Sensor_R1
-I ../M_BSP/lps33k
-I ../M_BSP/lcd
-I ../M_BSP/PSRAM
-I ../M_BSP/OSPI_NOR
-I ../Driver
-I ../../../Drivers/CMSIS/Include
-I ../../../Drivers/CMSIS/Device/ST/STM32L4xx/Include
-I ../../../Drivers/STM32L4xx_HAL_Driver/Inc
-I ../../../Drivers/BSP/STM32L4R9I_EVAL
-I ../../../Drivers/BSP/Components/Common

-I./RTE/_Watch_EVAL
-IC:/Users/mixo/AppData/Local/Arm/Packs/ARM/CMSIS/5.5.1/CMSIS/Core/Include
-IDrivers/CMSIS/Device/ST/STM32L4xx/Include
-D__UVISION_VERSION="528" -D_RTE_ -DSTM32L4R9xx -DUSE_HAL_DRIVER -DUSE_GVO_390x390
-o .\Watch\*.o --omf_browse .\Watch\*.crf --depend .\Watch\*.d

TOOLCHAIN

在 Makefile 文件中,往往为了互相兼容,默认编译器的名称就是 gcc ,只是前缀不同而已,而 armcc 编译器在使用时则需清晰指定名称。

下方为 armcc 工具链的指定方式:

1
2
3
4
5
6
# 工具链
CC=$(TOOLCHAIN_PATH)\"armcc.exe"
AS=$(TOOLCHAIN_PATH)\"armasm.exe"
AR=$(TOOLCHAIN_PATH)\"armar.exe"
LINK=$(TOOLCHAIN_PATH)\"armlink.exe"
FROM_ELF=$(TOOLCHAIN_PATH)\"fromelf.exe"

下方为 arm-none-eabi-gcc 工具链的指定(由 stm32 CubeMX 生成)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
else
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S

COMPILING PARAMETERS

总结出常见的编译参数如下:

MACRO DEFINITIONS

宏定义参数:-DUSE_HAL_DRIVER / -DSTM32L4R9xx / -D__MICROLIB

其中,前两个还是要依具体芯片的硬件参数来看的

CPU

CPU 参数:--cpu Cortex-M4.fp / --cpu Cortex-M4 等。

使用armcc --cpu list 命令可以查看所有可接受的芯片,如下:

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
--cpu=4
--cpu=4T
--cpu=5T
--cpu=5TE
--cpu=5TEJ
--cpu=6-M
--cpu=6S-M
--cpu=7-A
--cpu=7-R
--cpu=7-M
--cpu=7E-M
--cpu=7-A.security
--cpu=ARM7EJ-S
--cpu=ARM7TDMI
--cpu=ARM720T
--cpu=ARM7TDMI-S
--cpu=ARM9TDMI
--cpu=ARM920T
--cpu=ARM922T
--cpu=ARM9E-S
--cpu=ARM926EJ-S
--cpu=ARM946E-S
--cpu=ARM966E-S
--cpu=Cortex-M0
--cpu=Cortex-M0plus
--cpu=SC000
--cpu=Cortex-M1
--cpu=Cortex-M1.os_extension
--cpu=Cortex-M1.no_os_extension
--cpu=Cortex-M3
--cpu=Cortex-M3-rev0
--cpu=SC300
--cpu=Cortex-M4
--cpu=Cortex-M4.fp.sp
--cpu=Cortex-M7
--cpu=Cortex-M7.fp.sp
--cpu=Cortex-M7.fp.dp
--cpu=Cortex-R4
--cpu=Cortex-R4F
--cpu=Cortex-A5
--cpu=Cortex-A5.vfp
--cpu=Cortex-A5.neon
--cpu=Cortex-A7
--cpu=Cortex-A7.no_neon
--cpu=Cortex-A7.no_neon.no_vfp
--cpu=Cortex-A8
--cpu=Cortex-A8.no_neon
--cpu=Cortex-A8NoNEON
--cpu=Cortex-A9
--cpu=Cortex-A9.no_neon
--cpu=Cortex-A9.no_neon.no_vfp
--cpu=Cortex-A12
--cpu=Cortex-A12.no_neon.no_vfp
--cpu=Cortex-A15
--cpu=Cortex-A15.no_neon
--cpu=Cortex-A15.no_neon.no_vfp
--cpu=Cortex-A17
--cpu=Cortex-A17.no_neon.no_vfp

ABOUT STARTUP FILE

CubeMX 针对不同的编译方式和平台生成对应的 startup file 。而使用 Unix Makefile 编译的 startup_stm32l476xx.s 和 使用 Keil MDK-ARM 的是不一样的。

startup_stm32xxxxxx.s 是使用汇编语言写好的基本程序,当STM32 芯片上电启动的时候,会执行此处的汇编程序,从而建立 C 语言的运行环境,所以称之为启动文件。

由于编译器不一致,所以 .s 的启动文件也不能互相兼容,需要使用 CubeMX重新生成。

image-20220609110616631

DEBUG

ERROR

ERROR #35: PLEASE SELECT FIRST THE TARGET STM32L4XX DEVICE USED IN YOUR APPLICATION

image-20220608105439447

没有添加宏定义,添加 -DSTM32L476xx-DUSE_HAL_DRIVER 即可。

ERROR L6050U: THE CODE SIZE OF THE IMAGE EXCEEDS THE MAXIMUM

image-20220608110734097

版权问题,当你在使用keil时,出现 error: L6050U: The code size of this image (45178 bytes) exceeds the maximum allowed for this version of the linker. 的时候,那就是 keil 没有被破解,软件本身的字节数有局限性,需要下载个MDK注册机进行破解!

Error: A1854E: Unknown opcode 'BLX', maybe wrong target CPU?

image-20220608151900214

WARNING

Warning: #1295-D: Deprecated declaration two_wired_resync - give arg types

image-20220608135309057

在传递参数为空的函数中,必须写 void ,armcc要求比较严格,arm-none-eabi 的要求比较宽松。

REFERENCE

  1. keil编译链接过程以及ARMCC、ARMASM、FROMELF、ARMLINK、ARMAR的使用
  2. ARM Compiler v5.06 for uVision armcc User Guide
  3. ARM® Compiler v5.06 for μVision®

Common Tools

软件启动:utools / alfred

小插件合集:utools

文件搜索:everything(windows)

MD:Typora(插件Pandoc)

图床:picgo

自由:V2Ray-Core / ClashX

网站视频下载:Downie4

截图:Snipaste

解压:Bandizip

思维导图:Xmind

翻译:deepl /

Engineer

BASH:zsh(Oh-my-zsh)

终端插件:fig

zsh皮肤:powerlevel10k

Python

代码编辑器:Jupyter Lab(比Notebook更好用)

Python环境管理工具:Miniconda

Python常用库:

1
pip install pandas xlrd openpyxl xlsxwriter requests lxml html5lib BeautifulSoup4 matplotlib seaborn plotly bokeh scipy statsmodels python-frontmatter opencv-python

Embedded

VS code 插件

git痕迹查看:GitLens

代码注释:Doxygen

Keil开发代替IDE:EIDE

Compiling

交叉编译:cmake / make

单元测试:valgrind lcov

Jenkins

environment Injector

Publish Over FTP

CMake

xUnit

Linux

  • rsync :同步文件。
  • tree :目录树

奇淫巧技

文本替换

object 类型文本替换

object 目前还没有找到替换方法,可以将 object 类型转换成 string 数据类型,再用 str.replace() 方法进行文本替换。

  1. .astype('string') 方法将 object 类型转换成 string 类型。
  2. 使用 .str.replace(<old-string>,<new-string>) 方法对文本进行替换。并使用 tmp 变量进行保存。
  3. tmp 变量重新赋值给原来的变量。
1
2
3
pdata['timestamp'] = pdata.timestamp.astype('string')  # 将 object 类型转换成 string类型
tmp = pdata['timestamp'].str.replace('BIN3-','')
pdata['timestamp'] = tmp

DEBUG RECORD

nonetype object is not subscriptable

大概意思就是,这个 timestampobject 数据类型,替换了之后这个不能显示了估计。

image-20220522012451872