修改文档文件夹位置,添加部分文档
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 153 KiB |
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 89 KiB |
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 6.5 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 93 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 196 KiB After Width: | Height: | Size: 196 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 224 KiB |
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 274 KiB |
|
@ -64,7 +64,7 @@
|
||||||
#define configTICK_RATE_HZ ((TickType_t)1000)
|
#define configTICK_RATE_HZ ((TickType_t)1000)
|
||||||
#define configMAX_PRIORITIES ( 7 )
|
#define configMAX_PRIORITIES ( 7 )
|
||||||
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
#define configMINIMAL_STACK_SIZE ((uint16_t)128)
|
||||||
#define configTOTAL_HEAP_SIZE ((size_t)30000)
|
#define configTOTAL_HEAP_SIZE ((size_t)20000)
|
||||||
#define configMAX_TASK_NAME_LEN ( 32 )
|
#define configMAX_TASK_NAME_LEN ( 32 )
|
||||||
#define configUSE_16_BIT_TICKS 0
|
#define configUSE_16_BIT_TICKS 0
|
||||||
#define configUSE_MUTEXES 1
|
#define configUSE_MUTEXES 1
|
||||||
|
|
14
README.md
|
@ -211,7 +211,7 @@ ROOT:.
|
||||||
│ settings.json # 工作区配置文件,根据自己的需要配置
|
│ settings.json # 工作区配置文件,根据自己的需要配置
|
||||||
│ tasks.json # 任务配置文件,包括一键编译下载调试等
|
│ tasks.json # 任务配置文件,包括一键编译下载调试等
|
||||||
│
|
│
|
||||||
├─assets # 说明文档的图片
|
├─.assets # 说明文档的图片
|
||||||
├─application # 应用层
|
├─application # 应用层
|
||||||
├─bsp # 板级支持包
|
├─bsp # 板级支持包
|
||||||
├─modules # 模块层
|
├─modules # 模块层
|
||||||
|
@ -230,11 +230,11 @@ ROOT:.
|
||||||
|
|
||||||
### 软件分层
|
### 软件分层
|
||||||
|
|
||||||
![image-20221113211942850](assets/framework.png)
|
![image-20221113211942850](.assets/framework.png)
|
||||||
|
|
||||||
### 运行任务
|
### 运行任务
|
||||||
|
|
||||||
![image-20230413195155471](assets/image-20230413195155471.png)
|
![image-20230413195155471](.assets/image-20230413195155471.png)
|
||||||
|
|
||||||
### 初始化流程
|
### 初始化流程
|
||||||
|
|
||||||
|
@ -249,14 +249,10 @@ APP会调用其所有的模块的初始化函数(注册函数),这是因
|
||||||
|
|
||||||
main函数唯一需要的函数是app层的`robot.c`中的`RobotInit()`函数,它首先会调用BSP初始化,然后进行所有应用的初始化;每个应用会调用对应模块的初始化;一些依赖通信外设的模块会将通信支持相关的bsp进行初始化。初始化结束之后实时系统启动。
|
main函数唯一需要的函数是app层的`robot.c`中的`RobotInit()`函数,它首先会调用BSP初始化,然后进行所有应用的初始化;每个应用会调用对应模块的初始化;一些依赖通信外设的模块会将通信支持相关的bsp进行初始化。初始化结束之后实时系统启动。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 程序运行流程
|
### 程序运行流程
|
||||||
|
|
||||||
![运行](assets/总程序流程.png)
|
![运行](.assets/总程序流程.png)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 程序数据流
|
### 程序数据流
|
||||||
|
|
||||||
![数据流](assets/数据流.png)
|
![数据流](.assets/数据流.png)
|
||||||
|
|
|
@ -55,8 +55,8 @@ ENTRY(Reset_Handler)
|
||||||
/* Highest address of the user mode stack */
|
/* Highest address of the user mode stack */
|
||||||
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
|
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
|
||||||
/* Generate a link error if heap and stack don't fit into RAM */
|
/* Generate a link error if heap and stack don't fit into RAM */
|
||||||
_Min_Heap_Size = 0x6000; /* required amount of heap */
|
_Min_Heap_Size = 0x5000; /* required amount of heap */
|
||||||
_Min_Stack_Size = 0x6000; /* required amount of stack */
|
_Min_Stack_Size = 0x5000; /* required amount of stack */
|
||||||
|
|
||||||
/* Specify the memory areas */
|
/* Specify the memory areas */
|
||||||
MEMORY
|
MEMORY
|
||||||
|
|
|
@ -123,17 +123,17 @@ void MX_FREERTOS_Init(void)
|
||||||
void StartDefaultTask(void const *argument)
|
void StartDefaultTask(void const *argument)
|
||||||
{
|
{
|
||||||
/* init code for USB_DEVICE */
|
/* init code for USB_DEVICE */
|
||||||
MX_USB_DEVICE_Init(); // USB初始化
|
MX_USB_DEVICE_Init(); // USB???
|
||||||
/* USER CODE BEGIN StartDefaultTask */
|
/* USER CODE BEGIN StartDefaultTask */
|
||||||
vTaskDelete(NULL); // 删除默认任务,防止占用CPU
|
vTaskDelete(NULL); // ??????,????CPU
|
||||||
/* USER CODE END StartDefaultTask */
|
/* USER CODE END StartDefaultTask */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Private application code --------------------------------------------------*/
|
/* Private application code --------------------------------------------------*/
|
||||||
/* USER CODE BEGIN Application */
|
/* USER CODE BEGIN Application */
|
||||||
/**
|
/**
|
||||||
* @brief 注意,为方便统一管理,
|
* @brief ??,???????,
|
||||||
* 所有的机器人任务都在applicatoin/robot_task.h中进行
|
* ??????????applicatoin/robot_task.h???
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/* USER CODE END Application */
|
/* USER CODE END Application */
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
> 1. 添加一键编译+启用ozone调试脚本,使得整个进一步流程自动化
|
> 1. 添加一键编译+启用ozone调试脚本,使得整个进一步流程自动化
|
||||||
> 2. 增加更多的背景知识介绍
|
> 2. 增加更多的背景知识介绍
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 前言
|
## 前言
|
||||||
|
|
||||||
了解过嵌入式开发的你一定接触过Keil,这款20世纪风格UI的IDE伴随很多人度过了学习单片机的岁月。然而由于其缺少代码补全、高亮和静态检查的支持,以及为人诟病的一系列逆天的设置、极慢的编译速度(特别是在开发HAL库时),很多开发者开始转向其他IDE。
|
了解过嵌入式开发的你一定接触过Keil,这款20世纪风格UI的IDE伴随很多人度过了学习单片机的岁月。然而由于其缺少代码补全、高亮和静态检查的支持,以及为人诟病的一系列逆天的设置、极慢的编译速度(特别是在开发HAL库时),很多开发者开始转向其他IDE。
|
||||||
|
@ -57,7 +55,7 @@ CubeMX进行初始化 --> VSCode编写代/进行编译/简单调试 --> Ozone变
|
||||||
```shell
|
```shell
|
||||||
# 网盘中的文件:
|
# 网盘中的文件:
|
||||||
basic_framework.zip # 本仓库文件,注意,可能不为最新,建议从仓库clone并定时pull
|
basic_framework.zip # 本仓库文件,注意,可能不为最新,建议从仓库clone并定时pull
|
||||||
daplink_register_license.rar # daplink license注册机
|
daplink_register_license.rar # daplink license注册机
|
||||||
gcc-arm-none-eabi-10.3-2021.10-win32.zip # arm-gnu-toolchain
|
gcc-arm-none-eabi-10.3-2021.10-win32.zip # arm-gnu-toolchain
|
||||||
JLinkARM.dll # 修改过的jlink运行链接库
|
JLinkARM.dll # 修改过的jlink运行链接库
|
||||||
JLink_Windows_V722b.exe # JLink软件包
|
JLink_Windows_V722b.exe # JLink软件包
|
||||||
|
@ -86,7 +84,7 @@ C语言代码由固定的词汇(关键字)按照固定的格式(语法)
|
||||||
|
|
||||||
对于单个.c文件,从C语言开始到单片机可识别的.bin文件,一般要经历以下几步:
|
对于单个.c文件,从C语言开始到单片机可识别的.bin文件,一般要经历以下几步:
|
||||||
|
|
||||||
![img](assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp)
|
![img](.assets/v2-2797ea99d0d38eb9996993bb0ad77ab2_720w.webp)
|
||||||
|
|
||||||
首先是编译**预处理**Preprocessing,这一步会展开宏并删除注释,将多余的空格去除。预处理之后会生成.i文件。
|
首先是编译**预处理**Preprocessing,这一步会展开宏并删除注释,将多余的空格去除。预处理之后会生成.i文件。
|
||||||
|
|
||||||
|
@ -102,7 +100,7 @@ C语言代码由固定的词汇(关键字)按照固定的格式(语法)
|
||||||
|
|
||||||
### C语言内存模型
|
### C语言内存模型
|
||||||
|
|
||||||
<img src="assets/image-20221112160213066.png" alt="image-20221112160213066" style="zoom:80%;" />
|
<img src=".assets/image-20221112160213066.png" alt="image-20221112160213066" style="zoom:80%;" />
|
||||||
|
|
||||||
以上是C语言常见的内存模型,即C语言的代码块以及运行时使用的内存(包括函数、变量等)的组织方式。
|
以上是C语言常见的内存模型,即C语言的代码块以及运行时使用的内存(包括函数、变量等)的组织方式。
|
||||||
|
|
||||||
|
@ -112,7 +110,7 @@ C语言代码由固定的词汇(关键字)按照固定的格式(语法)
|
||||||
|
|
||||||
然后就是最重要的**堆**和**栈**。在一个代码块内定义的变量会被放在栈区,一旦离开作用域(出了它被定义的`{}`的区域),就会立刻被销毁。在调用函数或进入一个用户自定义的`{}`块,都会在栈上开辟一块新的空间,空间的大小和内存分配由操作系统或C库自动管理。**一般来说,直接通过变量访问栈内存,速度最快**(对于单片机)。而堆则是存储程序员自行分配的变量的地方,即使用`malloc(),realloc() ,new`等方法获取的空间,都被分配在这里。
|
然后就是最重要的**堆**和**栈**。在一个代码块内定义的变量会被放在栈区,一旦离开作用域(出了它被定义的`{}`的区域),就会立刻被销毁。在调用函数或进入一个用户自定义的`{}`块,都会在栈上开辟一块新的空间,空间的大小和内存分配由操作系统或C库自动管理。**一般来说,直接通过变量访问栈内存,速度最快**(对于单片机)。而堆则是存储程序员自行分配的变量的地方,即使用`malloc(),realloc() ,new`等方法获取的空间,都被分配在这里。
|
||||||
|
|
||||||
> 在CubeMX初始化的时候,Project mananger标签页下有一个Linker Setting的选项,这里是设置最小堆内存和栈内存的地方。如果你的程序里写了大规模的数组,或使用`malloc()`等分配了大量的空间,可能出现栈溢出或堆挤占栈空间的情况。需要根据MCU的资源大小,设置合适的stack size和heap size。
|
> 在CubeMX初始化的时候,Project mananger标签页下有一个Linker Setting的选项,这里是设置最小堆内存和栈内存的地方。如果你的程序里写了大规模的数组,或使用`malloc()`等分配了大量的空间,可能出现栈溢出或堆挤占栈空间的情况。需要根据MCU的资源大小,设置合适的stack size和heap size。
|
||||||
|
|
||||||
RTOS创建任务的时候也会为每个任务分配一定的栈空间,它会替代MCU的硬件裸机进行内存的分配。可以在CubeMX中设置。如果一个任务里定义了大量的变量,可能导致实时系统运行异常,请增大栈空间。
|
RTOS创建任务的时候也会为每个任务分配一定的栈空间,它会替代MCU的硬件裸机进行内存的分配。可以在CubeMX中设置。如果一个任务里定义了大量的变量,可能导致实时系统运行异常,请增大栈空间。
|
||||||
|
|
||||||
|
@ -132,7 +130,7 @@ RTOS创建任务的时候也会为每个任务分配一定的栈空间,它会
|
||||||
|
|
||||||
### Debug外设工作原理
|
### Debug外设工作原理
|
||||||
|
|
||||||
![image-20221112145717063](assets/image-20221112145717063.png)
|
![image-20221112145717063](.assets/image-20221112145717063.png)
|
||||||
|
|
||||||
DBG支持模块(红框标注部分,也可以看作一个外设)通过一条专用的AHB-AP总线和调试接口相连(Jtag或swd),并且有与**数据**和**外设**总线直接相连的桥接器。它还同时连接了中断嵌套管理器(因此同样可以捕获中断并进行debug)和ITM、DWT、FPB这些调试支持模块。因此DBG可以直接获取内存或片上外设内的数据而不需要占用CPU的资源,并将这些数据通过专用外设总线发送给调试器,进而在上位机中读取。
|
DBG支持模块(红框标注部分,也可以看作一个外设)通过一条专用的AHB-AP总线和调试接口相连(Jtag或swd),并且有与**数据**和**外设**总线直接相连的桥接器。它还同时连接了中断嵌套管理器(因此同样可以捕获中断并进行debug)和ITM、DWT、FPB这些调试支持模块。因此DBG可以直接获取内存或片上外设内的数据而不需要占用CPU的资源,并将这些数据通过专用外设总线发送给调试器,进而在上位机中读取。
|
||||||
|
|
||||||
|
@ -146,7 +144,7 @@ ITM是instrument trace macrocell指令追踪宏单元的缩写,它用于提供
|
||||||
|
|
||||||
### GDB调试MCU原理
|
### GDB调试MCU原理
|
||||||
|
|
||||||
![image-20221117121323757](assets/image-20221117121323757.png)
|
![image-20221117121323757](.assets/image-20221117121323757.png)
|
||||||
|
|
||||||
不论使用MDK(KEIL)还是VSCode还是Ozone,实际上背后的流程相同。首先GDB会建立TCP/IP端口并提供接口,调试服务器(Server)作为硬件调试器和GDB软件的桥梁,将硬件调试器的相关功能(也就是DBG外设支持的那些功能)映射到GDB的接口上(通过连接到GDB建立的端口)。之后启动调试,将可执行文件下载到目标MCU上,然后从main开始执行
|
不论使用MDK(KEIL)还是VSCode还是Ozone,实际上背后的流程相同。首先GDB会建立TCP/IP端口并提供接口,调试服务器(Server)作为硬件调试器和GDB软件的桥梁,将硬件调试器的相关功能(也就是DBG外设支持的那些功能)映射到GDB的接口上(通过连接到GDB建立的端口)。之后启动调试,将可执行文件下载到目标MCU上,然后从main开始执行
|
||||||
|
|
||||||
|
@ -154,8 +152,6 @@ ITM是instrument trace macrocell指令追踪宏单元的缩写,它用于提供
|
||||||
|
|
||||||
> 而对于直接运行在电脑上的程序(.exe),就不需要GDBserver和物理调试器,GDB程序可以直接访问电脑上运行的程序和CPU的寄存器等。
|
> 而对于直接运行在电脑上的程序(.exe),就不需要GDBserver和物理调试器,GDB程序可以直接访问电脑上运行的程序和CPU的寄存器等。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 字节对齐
|
### 字节对齐
|
||||||
|
|
||||||
这是内存硬件设计和汇编语言设计的结果。在使用结构体的时候,如果你不做任何事情,编译器会自动帮助你完成字节对齐以提高内存访问的效率。stm32是4字节地址和数据总线的设计,单词可以传输32位数据,因此,访问4字节数据(也就是stm32的“字”,“字长”)效率最高。然而,历史的缘由导致一个内存地址只存储8位的数据,如果你要访问float数据,则一次需要读取4个地址。当这四个地址是连续的时候,你只需要一次就可以将数据读出。然而,如果一个float数据被存放在0x03-0x07这四个地址,cpu首先要读出0x00-0x03这四个连续的地址,然后再取出最后一个字节;随后读取0x04-0x07这四个连续的字节,再取出前三个字节;最后将最后一个字节和前三个字节拼接在一起,形成我们需要的float数据。
|
这是内存硬件设计和汇编语言设计的结果。在使用结构体的时候,如果你不做任何事情,编译器会自动帮助你完成字节对齐以提高内存访问的效率。stm32是4字节地址和数据总线的设计,单词可以传输32位数据,因此,访问4字节数据(也就是stm32的“字”,“字长”)效率最高。然而,历史的缘由导致一个内存地址只存储8位的数据,如果你要访问float数据,则一次需要读取4个地址。当这四个地址是连续的时候,你只需要一次就可以将数据读出。然而,如果一个float数据被存放在0x03-0x07这四个地址,cpu首先要读出0x00-0x03这四个连续的地址,然后再取出最后一个字节;随后读取0x04-0x07这四个连续的字节,再取出前三个字节;最后将最后一个字节和前三个字节拼接在一起,形成我们需要的float数据。
|
||||||
|
@ -178,17 +174,15 @@ typedef struct
|
||||||
|
|
||||||
如果您有兴趣,可以了解一下内存硬件的组织和连接方式,包括奇偶地址/片选/行列扩展等,可以帮助你更好地理解字节对齐。
|
如果您有兴趣,可以了解一下内存硬件的组织和连接方式,包括奇偶地址/片选/行列扩展等,可以帮助你更好地理解字节对齐。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 环境配置
|
## 环境配置
|
||||||
|
|
||||||
> ***所有需要编辑的配置文件都已经在basic_framework的仓库中提供,如果不会写,照猫画虎。***
|
> ***所有需要编辑的配置文件都已经在basic_framework的仓库中提供,如果不会写,照猫画虎。***
|
||||||
|
|
||||||
> 2022-12-01更新:
|
> 2022-12-01更新:
|
||||||
>
|
>
|
||||||
> **VSCode上线了一款新的插件:**
|
> **VSCode上线了一款新的插件:**
|
||||||
>
|
>
|
||||||
> ![image-20221201134906999](assets/image-20221201134906999.png)
|
> ![image-20221201134906999](.assets/image-20221201134906999.png)
|
||||||
>
|
>
|
||||||
> 支持一键配置Arm GNU工具链、MinGW64(make工具)和OpenOCD!可以尝试使用这个插件替代下面的配置流程。并且,此插件还提供了一键下载、一键调试的支持,只需要选择合适的下载器配置即可,全部都是图形化界面的操作!
|
> 支持一键配置Arm GNU工具链、MinGW64(make工具)和OpenOCD!可以尝试使用这个插件替代下面的配置流程。并且,此插件还提供了一键下载、一键调试的支持,只需要选择合适的下载器配置即可,全部都是图形化界面的操作!
|
||||||
>
|
>
|
||||||
|
@ -206,17 +200,15 @@ typedef struct
|
||||||
- **Cortex-Debug**,**Cortex-Debug: Device Support Pack - STM32F4**:提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件。
|
- **Cortex-Debug**,**Cortex-Debug: Device Support Pack - STM32F4**:提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件。
|
||||||
- **IntelliCode**,**Makfile Tools**:提供代码高亮支持
|
- **IntelliCode**,**Makfile Tools**:提供代码高亮支持
|
||||||
|
|
||||||
![image-20221112172157533](assets/image-20221112172157533.png)
|
![image-20221112172157533](.assets/image-20221112172157533.png)
|
||||||
|
|
||||||
![image-20221112172208749](assets/image-20221112172208749.png)
|
![image-20221112172208749](.assets/image-20221112172208749.png)
|
||||||
|
|
||||||
![image-20221112172221756](assets/image-20221112172221756.png)
|
![image-20221112172221756](.assets/image-20221112172221756.png)
|
||||||
|
|
||||||
![image-20221112172239386](assets/image-20221112172239386.png)
|
![image-20221112172239386](.assets/image-20221112172239386.png)
|
||||||
|
|
||||||
![image-20221112172254809](assets/image-20221112172254809.png)
|
![image-20221112172254809](.assets/image-20221112172254809.png)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
> MinGW、Arm GNU toolchain和OpenOCD也可以通过**MSYS2**使用pacman包管理器(和apt/yum类似)直接安装,这种方法一步到位,**==这是更推荐使用的方式==**,请参看[附录5](##附录5:利用MSYS2安装依赖环境)。
|
> MinGW、Arm GNU toolchain和OpenOCD也可以通过**MSYS2**使用pacman包管理器(和apt/yum类似)直接安装,这种方法一步到位,**==这是更推荐使用的方式==**,请参看[附录5](##附录5:利用MSYS2安装依赖环境)。
|
||||||
>
|
>
|
||||||
|
@ -224,17 +216,17 @@ typedef struct
|
||||||
|
|
||||||
- 安装MinGW,等待界面如下:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
- 安装MinGW,等待界面如下:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
||||||
|
|
||||||
![image-20221112172051589](assets/image-20221112172051589.png)
|
![image-20221112172051589](.assets/image-20221112172051589.png)
|
||||||
|
|
||||||
安装好后,打开MinGW后将所有的支持包勾选,然后安装:
|
安装好后,打开MinGW后将所有的支持包勾选,然后安装:
|
||||||
|
|
||||||
![image-20221112172348408](assets/image-20221112172348408.png)
|
![image-20221112172348408](.assets/image-20221112172348408.png)
|
||||||
|
|
||||||
![image-20221112172420037](assets/image-20221112172420037.png)
|
![image-20221112172420037](.assets/image-20221112172420037.png)
|
||||||
|
|
||||||
安装完以后,将MinGW的bin文件夹添加到环境变量中的path下,按下菜单键搜索**编辑系统环境变量**打开之后:
|
安装完以后,将MinGW的bin文件夹添加到环境变量中的path下,按下菜单键搜索**编辑系统环境变量**打开之后:
|
||||||
|
|
||||||
![image-20221112172716320](assets/image-20221112172716320.png)
|
![image-20221112172716320](.assets/image-20221112172716320.png)
|
||||||
|
|
||||||
图片看不清请打开原图。验证安装:
|
图片看不清请打开原图。验证安装:
|
||||||
|
|
||||||
|
@ -244,7 +236,7 @@ typedef struct
|
||||||
|
|
||||||
- 配置gcc-arm-none-eabi环境变量,**把压缩包解压以后放在某个地方**,然后同上,将工具链的bin添加到PATH:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
- 配置gcc-arm-none-eabi环境变量,**把压缩包解压以后放在某个地方**,然后同上,将工具链的bin添加到PATH:(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
||||||
|
|
||||||
![image-20221112172858593](assets/image-20221112172858593.png)
|
![image-20221112172858593](.assets/image-20221112172858593.png)
|
||||||
|
|
||||||
<center>安装路径可能不一样,这里要使用你自己的路径而不是直接抄</center>
|
<center>安装路径可能不一样,这里要使用你自己的路径而不是直接抄</center>
|
||||||
|
|
||||||
|
@ -256,17 +248,15 @@ typedef struct
|
||||||
|
|
||||||
- **将OpenOCD解压到一个文件夹里**,稍后需要在VSCode的插件中设置这个路径。(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
- **将OpenOCD解压到一个文件夹里**,稍后需要在VSCode的插件中设置这个路径。(will be deprecated soon,请注意这种方法将会在主分支发布正式版的时候删除)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- **CubeMX生成代码**:
|
- **CubeMX生成代码**:
|
||||||
|
|
||||||
在project manager标签页工具链选择makefile
|
在project manager标签页工具链选择makefile
|
||||||
|
|
||||||
![image-20221112173534670](assets/image-20221112173534670.png)
|
![image-20221112173534670](.assets/image-20221112173534670.png)
|
||||||
|
|
||||||
生成的目录结构如下:
|
生成的目录结构如下:
|
||||||
|
|
||||||
![image-20221112174211802](assets/image-20221112174211802.png)
|
![image-20221112174211802](.assets/image-20221112174211802.png)
|
||||||
|
|
||||||
Makefile就是我们要使用的构建规则文件。
|
Makefile就是我们要使用的构建规则文件。
|
||||||
|
|
||||||
|
@ -296,7 +286,7 @@ VSCode常用快捷键包括:
|
||||||
|
|
||||||
为了提供完整的代码高亮支持,需要配置Makefile tools插件的make程序路径,`ctrl+,`打开设置,搜索make path找到设置并填写:
|
为了提供完整的代码高亮支持,需要配置Makefile tools插件的make程序路径,`ctrl+,`打开设置,搜索make path找到设置并填写:
|
||||||
|
|
||||||
![image-20221113152513343](assets/image-20221113152513343.png)
|
![image-20221113152513343](.assets/image-20221113152513343.png)
|
||||||
|
|
||||||
> mingw32-make就是下面介绍的make工具(配合makefile替代手动调用gcc)。这里之所以只要输入mingw32-make而不用完整路径,是因为我们将mingw的bin文件夹加入环境变量了,因此系统会在PATH下自动寻找对应项
|
> mingw32-make就是下面介绍的make工具(配合makefile替代手动调用gcc)。这里之所以只要输入mingw32-make而不用完整路径,是因为我们将mingw的bin文件夹加入环境变量了,因此系统会在PATH下自动寻找对应项
|
||||||
|
|
||||||
|
@ -322,7 +312,7 @@ mingw32-make -j24 # -j参数表示参与编译的线程数,一般使用-j12
|
||||||
>
|
>
|
||||||
> 我对make的编译命令进行了静默处理,只输出error和warning以及最后的生成文件信息。如果想要解除静默(就是下面所说的“你可以看到大致如下的输出”),需要修改Makefile。**本仓库下的makefile中已经用注释标明。**
|
> 我对make的编译命令进行了静默处理,只输出error和warning以及最后的生成文件信息。如果想要解除静默(就是下面所说的“你可以看到大致如下的输出”),需要修改Makefile。**本仓库下的makefile中已经用注释标明。**
|
||||||
|
|
||||||
![image-20221112191712534](assets/image-20221112191712534.png)
|
![image-20221112191712534](.assets/image-20221112191712534.png)
|
||||||
|
|
||||||
就会开始编译了。你可以看到大致如下的输出:
|
就会开始编译了。你可以看到大致如下的输出:
|
||||||
|
|
||||||
|
@ -342,6 +332,7 @@ arm-none-eabi-objcopy -O binary -S build/basic_framework.elf build/basic_framewo
|
||||||
```
|
```
|
||||||
|
|
||||||
由于使用了多线程编译,比KEIL的蜗牛单线程要快了不少。以上内容代表了生成的可执行文件的大小以及格式和内容。.elf文件就是我们需要传递给调试器的东西,在[使用VSCode调试](###简单调试)部分会介绍。典型的编译时间大致如下:
|
由于使用了多线程编译,比KEIL的蜗牛单线程要快了不少。以上内容代表了生成的可执行文件的大小以及格式和内容。.elf文件就是我们需要传递给调试器的东西,在[使用VSCode调试](###简单调试)部分会介绍。典型的编译时间大致如下:
|
||||||
|
|
||||||
1. 从零开始重新编译:~10s
|
1. 从零开始重新编译:~10s
|
||||||
2. 修改文件后编译:~3s
|
2. 修改文件后编译:~3s
|
||||||
|
|
||||||
|
@ -368,23 +359,23 @@ arm-none-eabi-objcopy -O binary -S build/basic_framework.elf build/basic_framewo
|
||||||
|
|
||||||
这样,你就可以点击VSCode工具栏上方的Terminal->Run task选择你刚刚配置的任务开始编译了。**更方便的方法是使用快捷键:`ctrl+shift+B`。** 之后要配置下载任务和调试任务等,也可以利用这种方法,新建一个xxx_task,实现一键下载、一键调试等。
|
这样,你就可以点击VSCode工具栏上方的Terminal->Run task选择你刚刚配置的任务开始编译了。**更方便的方法是使用快捷键:`ctrl+shift+B`。** 之后要配置下载任务和调试任务等,也可以利用这种方法,新建一个xxx_task,实现一键下载、一键调试等。
|
||||||
|
|
||||||
![image-20221112192133103](assets/image-20221112192133103.png)
|
![image-20221112192133103](.assets/image-20221112192133103.png)
|
||||||
|
|
||||||
> 还没配置任务的时候,需要在Terminal标签页中选择Configure Tasks... 创建一个新的.json文件。
|
> 还没配置任务的时候,需要在Terminal标签页中选择Configure Tasks... 创建一个新的.json文件。
|
||||||
>
|
>
|
||||||
> P.S. VSCode中的大部分配置都是通过json文件保存的。当前工作区的配置在项目文件夹中的.vscode下,全局配置在设置中修改。全局配置在当前工作区没有配置的时候会生效,反之被前者覆盖。
|
> P.S. VSCode中的大部分配置都是通过json文件保存的。当前工作区的配置在项目文件夹中的.vscode下,全局配置在设置中修改。全局配置在当前工作区没有配置的时候会生效,反之被前者覆盖。
|
||||||
|
|
||||||
### 如果你编写了新的代码文件...
|
### 如果你编写了新的代码文件
|
||||||
|
|
||||||
Makefile的大部分内容在CubeMX初始化的时候就会帮你生成。如果新增了.c的源文件,你需要在`C_SOURCES`中新增:
|
Makefile的大部分内容在CubeMX初始化的时候就会帮你生成。如果新增了.c的源文件,你需要在`C_SOURCES`中新增:
|
||||||
|
|
||||||
![image-20221112192509718](assets/image-20221112192509718.png)
|
![image-20221112192509718](.assets/image-20221112192509718.png)
|
||||||
|
|
||||||
换行需要在行尾加反斜杠\\
|
换行需要在行尾加反斜杠\\
|
||||||
|
|
||||||
如果新增了头文件,在`C_INCLUDES`中新增头文件所在的文件夹:
|
如果新增了头文件,在`C_INCLUDES`中新增头文件所在的文件夹:
|
||||||
|
|
||||||
![image-20221112192610543](assets/image-20221112192610543.png)
|
![image-20221112192610543](.assets/image-20221112192610543.png)
|
||||||
|
|
||||||
换行需要在行尾加反斜杠\\
|
换行需要在行尾加反斜杠\\
|
||||||
|
|
||||||
|
@ -392,13 +383,11 @@ Makefile的大部分内容在CubeMX初始化的时候就会帮你生成。如果
|
||||||
|
|
||||||
> 和KEIL新增文件的方式很相似,但是更方便。
|
> 和KEIL新增文件的方式很相似,但是更方便。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 简单的调试配置
|
### 简单的调试配置
|
||||||
|
|
||||||
> 在VSCode中调试不能像Keil一样查看变量动态变化,但是支持以外的所有操作,如查看外设和反汇编代码,设置断点触发方式等。
|
> 在VSCode中调试不能像Keil一样查看变量动态变化,但是支持以外的所有操作,如查看外设和反汇编代码,设置断点触发方式等。
|
||||||
>
|
>
|
||||||
> **用于调试的配置参考这篇博客**:[Cortex-debug 调试器使用介绍](https://blog.csdn.net/qq_40833810/article/details/106713462),这里包含了一些背景知识的介绍。你也可以直接查看下面的教程。
|
> **用于调试的配置参考这篇博客**:[Cortex-debug 调试器使用介绍](https://blog.csdn.net/qq_40833810/article/details/106713462),这里包含了一些背景知识的介绍。你也可以直接查看下面的教程。
|
||||||
|
|
||||||
> ❗❗❗***==注意==***❗❗❗
|
> ❗❗❗***==注意==***❗❗❗
|
||||||
>
|
>
|
||||||
|
@ -418,7 +407,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
***其他配置需要的文件已经全部在basic_framework中提供***,包括`openocd.cfg STM32F407.svd .vscode/launch.json`。
|
***其他配置需要的文件已经全部在basic_framework中提供***,包括`openocd.cfg STM32F407.svd .vscode/launch.json`。
|
||||||
|
|
||||||
![image-20221115215531879](assets/image-20221115215531879.png)
|
![image-20221115215531879](.assets/image-20221115215531879.png)
|
||||||
|
|
||||||
<center>主要需要配置这三个路径,第四个gdbPath可以选配</center>
|
<center>主要需要配置这三个路径,第四个gdbPath可以选配</center>
|
||||||
|
|
||||||
|
@ -428,7 +417,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
然后选择run and debug标签页,在选项中选择你配置好的选项,开始调试。**或者使用快捷键:`F5`。**
|
然后选择run and debug标签页,在选项中选择你配置好的选项,开始调试。**或者使用快捷键:`F5`。**
|
||||||
|
|
||||||
![image-20221112180103750](assets/image-20221112180103750.png)
|
![image-20221112180103750](.assets/image-20221112180103750.png)
|
||||||
|
|
||||||
我们的仓库中默认提供了两种下载器的支持,dap-link(无线调试器属于这一种)和j-link(包括小的j-link OB和黑色大盒子jlink)。
|
我们的仓库中默认提供了两种下载器的支持,dap-link(无线调试器属于这一种)和j-link(包括小的j-link OB和黑色大盒子jlink)。
|
||||||
|
|
||||||
|
@ -436,13 +425,13 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
开始调试后,显示的界面如下:
|
开始调试后,显示的界面如下:
|
||||||
|
|
||||||
![](assets/vscodedebug.png)
|
![](.assets/vscodedebug.png)
|
||||||
|
|
||||||
1. 变量查看窗口,包括当前调用栈(当前作用域或代码块)内的局部变量、当前文件的静态变量和全局变量。register选项卡可以查看cpu内核的寄存器数值。
|
1. 变量查看窗口,包括当前调用栈(当前作用域或代码块)内的局部变量、当前文件的静态变量和全局变量。register选项卡可以查看cpu内核的寄存器数值。
|
||||||
|
|
||||||
2. 变量watch窗口。右键单击要查看的变量,选择watch加入查看。
|
2. 变量watch窗口。右键单击要查看的变量,选择watch加入查看。
|
||||||
|
|
||||||
![image-20221113131044191](assets/image-20221113131044191.png)
|
![image-20221113131044191](.assets/image-20221113131044191.png)
|
||||||
|
|
||||||
还支持直接运行到指针所选处(Run to Cursor)以及直接跳转到指针处执行(Jump to Cursor)。添加行内断点(若一个表达式由多个表达式组成)也是很方便的功能,可以帮助进一步定位bug。
|
还支持直接运行到指针所选处(Run to Cursor)以及直接跳转到指针处执行(Jump to Cursor)。添加行内断点(若一个表达式由多个表达式组成)也是很方便的功能,可以帮助进一步定位bug。
|
||||||
|
|
||||||
|
@ -450,7 +439,7 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
VSCode提供的一个最大的便利就是,你可以将鼠标悬停在需要查看的变量上,**不需要添加到watch就能观察变量值。**如果是指针还可以自动解析,获取解引用后的值。结构体也支持直接展开。
|
VSCode提供的一个最大的便利就是,你可以将鼠标悬停在需要查看的变量上,**不需要添加到watch就能观察变量值。**如果是指针还可以自动解析,获取解引用后的值。结构体也支持直接展开。
|
||||||
|
|
||||||
![image-20221113133624273](assets/image-20221113133624273.png)
|
![image-20221113133624273](.assets/image-20221113133624273.png)
|
||||||
|
|
||||||
3. 调用栈。表明在进入当前代码块之前调用了哪些函数,称之为栈也是因为调用的顺序从下至上。当前函数结束之后栈指针会减小,控制权会返还给上一级的调用者。通过调用栈可以确认程序是**如何**(按怎样的顺序)运行到当前位置的。
|
3. 调用栈。表明在进入当前代码块之前调用了哪些函数,称之为栈也是因为调用的顺序从下至上。当前函数结束之后栈指针会减小,控制权会返还给上一级的调用者。通过调用栈可以确认程序是**如何**(按怎样的顺序)运行到当前位置的。
|
||||||
|
|
||||||
|
@ -478,14 +467,10 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
>
|
>
|
||||||
> 如果想直接下载代码不想调试,参阅[附录4](##附录4:VSCode直接烧录代码)。
|
> 如果想直接下载代码不想调试,参阅[附录4](##附录4:VSCode直接烧录代码)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### RTT Viewer日志功能
|
### RTT Viewer日志功能
|
||||||
|
|
||||||
本框架添加了vscode下Segger RTT client的支持。在`.vscode/task.json`中已经添加了启动rtt viewer client的任务。你也可以将此任务作为附加启动任务和调试一起启动,方便查看日志。要使用日志,请包含`bsp_log.h`。注意,需要将jlink的安装目录添加到环境变量中。
|
本框架添加了vscode下Segger RTT client的支持。在`.vscode/task.json`中已经添加了启动rtt viewer client的任务。你也可以将此任务作为附加启动任务和调试一起启动,方便查看日志。要使用日志,请包含`bsp_log.h`。注意,需要将jlink的安装目录添加到环境变量中。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 更好的编辑体验
|
### 更好的编辑体验
|
||||||
|
|
||||||
建议安装以下插件:
|
建议安装以下插件:
|
||||||
|
@ -508,16 +493,10 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
9. live share,和你的小伙伴一起结对编程
|
9. live share,和你的小伙伴一起结对编程
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Ozone可视化调试和LOG功能
|
## Ozone可视化调试和LOG功能
|
||||||
|
|
||||||
> ~~Ozone暂时只支持jlink。~~
|
> ~~Ozone暂时只支持jlink。~~
|
||||||
|
@ -530,19 +509,19 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
**注意,如果希望支持daplink(包括正点原子无线调试器),请务必安装网盘对应的版本(Ozone3.24 32-bit和J-Link7.22b)。**
|
**注意,如果希望支持daplink(包括正点原子无线调试器),请务必安装网盘对应的版本(Ozone3.24 32-bit和J-Link7.22b)。**
|
||||||
|
|
||||||
> 经过测试发现只有32位的ozone3.24支持daplink。
|
> 经过测试发现只有32位的ozone3.24支持daplink。
|
||||||
|
|
||||||
应该先安装Ozone,再安装jlink。以下为步骤:
|
应该先安装Ozone,再安装jlink。以下为步骤:
|
||||||
|
|
||||||
1. 安装Ozone
|
1. 安装Ozone
|
||||||
|
|
||||||
![image-20221116150122397](assets/image-20221116150122397.png)
|
![image-20221116150122397](.assets/image-20221116150122397.png)
|
||||||
|
|
||||||
这一步注意选择install a new instance(安装一个新的实例)。后续一路确认即可。
|
这一步注意选择install a new instance(安装一个新的实例)。后续一路确认即可。
|
||||||
|
|
||||||
2. 安装jlink
|
2. 安装jlink
|
||||||
|
|
||||||
![image-20221116193340770](assets/image-20221116193340770.png)
|
![image-20221116193340770](.assets/image-20221116193340770.png)
|
||||||
|
|
||||||
这一步注意不要勾选update dll in other application,否则jlink会把ozone里面老的驱动和启动项替代掉。choose destination和ozone一样,选择install a new instance。如果安装了老的相同版本的jlink,请先卸载(版本相同不用管,直接新装一个)。
|
这一步注意不要勾选update dll in other application,否则jlink会把ozone里面老的驱动和启动项替代掉。choose destination和ozone一样,选择install a new instance。如果安装了老的相同版本的jlink,请先卸载(版本相同不用管,直接新装一个)。
|
||||||
|
|
||||||
|
@ -556,19 +535,19 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。
|
||||||
|
|
||||||
安装好两个软件之后,打开ozone后会显示一个new project wizard,如果没有打开,在工具栏的File-> New -> New project wizard。
|
安装好两个软件之后,打开ozone后会显示一个new project wizard,如果没有打开,在工具栏的File-> New -> New project wizard。
|
||||||
|
|
||||||
![image-20221113133904084](assets/image-20221113133904084.png)
|
![image-20221113133904084](.assets/image-20221113133904084.png)
|
||||||
|
|
||||||
选择M4内核,为了能够查看外设寄存器的值还需要svd文件。所有mcu的svd都在图中的文件夹里提供,当然你也可以使用我们仓库根目录下的文件。
|
选择M4内核,为了能够查看外设寄存器的值还需要svd文件。所有mcu的svd都在图中的文件夹里提供,当然你也可以使用我们仓库根目录下的文件。
|
||||||
|
|
||||||
![image-20221116150901418](assets/image-20221116150901418.png)
|
![image-20221116150901418](.assets/image-20221116150901418.png)
|
||||||
|
|
||||||
接口选择swd,接口速度不需要太高,如果调试的时候需要观察大量的变量并且使用日志功能,可以调高这个值。如果连接了jlikn,上面的窗口中会显示。如果链接了dap-link,比如无线调试器,会出现Unknown CMSIS-dap。选择你要使用的调试器,然后继续。
|
接口选择swd,接口速度不需要太高,如果调试的时候需要观察大量的变量并且使用日志功能,可以调高这个值。如果连接了jlikn,上面的窗口中会显示。如果链接了dap-link,比如无线调试器,会出现Unknown CMSIS-dap。选择你要使用的调试器,然后继续。
|
||||||
|
|
||||||
![image-20221113134252407](assets/image-20221113134252407.png)
|
![image-20221113134252407](.assets/image-20221113134252407.png)
|
||||||
|
|
||||||
选择构建之后生成的.elf文件(在项目文件夹下的build中)。这是调试器专用的文件格式,对其内容感兴趣可以自行搜索细节。此外ozone还支持.bin .hex .axf(最后一个是amr-cc,也就是keil的工具链会生成的)等格式。
|
选择构建之后生成的.elf文件(在项目文件夹下的build中)。这是调试器专用的文件格式,对其内容感兴趣可以自行搜索细节。此外ozone还支持.bin .hex .axf(最后一个是amr-cc,也就是keil的工具链会生成的)等格式。
|
||||||
|
|
||||||
![image-20221113134605331](assets/image-20221113134605331.png)
|
![image-20221113134605331](.assets/image-20221113134605331.png)
|
||||||
|
|
||||||
这页不要动。如果希望保存jlink的调试日志,最后一个选项选择一个文件或者新建一个日志文件。
|
这页不要动。如果希望保存jlink的调试日志,最后一个选项选择一个文件或者新建一个日志文件。
|
||||||
|
|
||||||
|
@ -586,7 +565,7 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
支持的插件在Ozone的安装目录下的`Plugins/OS`目录:
|
支持的插件在Ozone的安装目录下的`Plugins/OS`目录:
|
||||||
|
|
||||||
![image-20221119174445067](assets/image-20221119174445067.png)
|
![image-20221119174445067](.assets/image-20221119174445067.png)
|
||||||
|
|
||||||
我们的项目是F4的板子,内核时Cortex-M4(CM4),因此选用`FreeRTOSPlugin_CM4.js`(输入的时候js后缀不用输)。 ozone默认输入的命令似乎有误,需要手动修改(这好像和ozone的版本有关,请留意)
|
我们的项目是F4的板子,内核时Cortex-M4(CM4),因此选用`FreeRTOSPlugin_CM4.js`(输入的时候js后缀不用输)。 ozone默认输入的命令似乎有误,需要手动修改(这好像和ozone的版本有关,请留意)
|
||||||
|
|
||||||
|
@ -594,7 +573,7 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
下图的配置是笔者常用的layout。每个窗口是否显示、放在什么位置等都是可以自己定义的。通过工具栏的view选项卡可以自行选择需要展示的窗口。
|
下图的配置是笔者常用的layout。每个窗口是否显示、放在什么位置等都是可以自己定义的。通过工具栏的view选项卡可以自行选择需要展示的窗口。
|
||||||
|
|
||||||
![](assets/ozone.png)
|
![](.assets/ozone.png)
|
||||||
|
|
||||||
1. 调试控制:和vscode类似
|
1. 调试控制:和vscode类似
|
||||||
|
|
||||||
|
@ -602,11 +581,11 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
如果不需要可视化查看变量变化的趋势,但是想不暂停查看变量的值,请右键点击变量,选择一个合适的refresh rate:
|
如果不需要可视化查看变量变化的趋势,但是想不暂停查看变量的值,请右键点击变量,选择一个合适的refresh rate:
|
||||||
|
|
||||||
![image-20221119173731119](assets/image-20221119173731119.png)
|
![image-20221119173731119](.assets/image-20221119173731119.png)
|
||||||
|
|
||||||
如果是一个结构体,你可以为整个结构体都进行刷新率的配置,不需要手动一个个修改。**或直接右键点击窗口**,将refresh打勾:
|
如果是一个结构体,你可以为整个结构体都进行刷新率的配置,不需要手动一个个修改。**或直接右键点击窗口**,将refresh打勾:
|
||||||
|
|
||||||
![image-20221119173918340](assets/image-20221119173918340.png)
|
![image-20221119173918340](.assets/image-20221119173918340.png)
|
||||||
|
|
||||||
3. 断点和运行追踪管理
|
3. 断点和运行追踪管理
|
||||||
|
|
||||||
|
@ -630,8 +609,6 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
如果在调试过程中发现bug或者需要更改代码,不需要终止调试或者关闭窗口。直接前往vscode修改并重新编译,Ozone会自动检测到.elf文件的变化,询问你是否重新加载项目。选择是后会自动开始下载并进入调试。
|
如果在调试过程中发现bug或者需要更改代码,不需要终止调试或者关闭窗口。直接前往vscode修改并重新编译,Ozone会自动检测到.elf文件的变化,询问你是否重新加载项目。选择是后会自动开始下载并进入调试。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- **变量动态查看(可视化)**
|
- **变量动态查看(可视化)**
|
||||||
|
|
||||||
- **在变量的watch窗口右键点击变量,选择一个refresh rate也可以实时查看变量(和keil一样)。**
|
- **在变量的watch窗口右键点击变量,选择一个refresh rate也可以实时查看变量(和keil一样)。**
|
||||||
|
@ -653,7 +630,7 @@ Project.SetOSPlugin(“plugin_name”)
|
||||||
|
|
||||||
- 如果当前文件没有你要的变量,你想查看项目中的其他文件夹,在view-> source files中可以打开该项目所有的源文件,双击可以打开源文件。
|
- 如果当前文件没有你要的变量,你想查看项目中的其他文件夹,在view-> source files中可以打开该项目所有的源文件,双击可以打开源文件。
|
||||||
|
|
||||||
![image-20221113142448939](assets/image-20221113142448939.png)
|
![image-20221113142448939](.assets/image-20221113142448939.png)
|
||||||
|
|
||||||
- **日志打印**
|
- **日志打印**
|
||||||
|
|
||||||
|
@ -697,22 +674,16 @@ CPU选项卡可以查看CPU的寄存器。
|
||||||
|
|
||||||
退出时可以将调试项目保存在项目的根目录下,方便下次调试使用,不需要重新设置。可以为jlink和daplink分别保存一套调试配置。
|
退出时可以将调试项目保存在项目的根目录下,方便下次调试使用,不需要重新设置。可以为jlink和daplink分别保存一套调试配置。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 附录1:为daplink添加license
|
## 附录1:为daplink添加license
|
||||||
|
|
||||||
在网盘上下载`daplink_register_license.rar`,解压出来之后打开。**请关闭杀毒软件。**
|
在网盘上下载`daplink_register_license.rar`,解压出来之后打开。**请关闭杀毒软件。**
|
||||||
|
|
||||||
![image-20221116152032104](assets/image-20221116152032104.png)
|
![image-20221116152032104](.assets/image-20221116152032104.png)
|
||||||
|
|
||||||
根据Ozone打开时提示的daplink的序列号,将其输入注册机,电机generate,就会生成5个license。
|
根据Ozone打开时提示的daplink的序列号,将其输入注册机,电机generate,就会生成5个license。
|
||||||
|
|
||||||
windows菜单搜索J-link license manager,点击添加license,将注册机生成的五个license依次复制黏贴并添加到的license manager中即可。
|
windows菜单搜索J-link license manager,点击添加license,将注册机生成的五个license依次复制黏贴并添加到的license manager中即可。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 附录2:在VSCode中启用SEGGER RTT日志
|
## 附录2:在VSCode中启用SEGGER RTT日志
|
||||||
|
|
||||||
若使用Jlink进行调试,只需要在开始调试之前把`log`任务启动,便可以在终端中看到jlink rtt viewer的日志输出。
|
若使用Jlink进行调试,只需要在开始调试之前把`log`任务启动,便可以在终端中看到jlink rtt viewer的日志输出。
|
||||||
|
@ -721,8 +692,6 @@ windows菜单搜索J-link license manager,点击添加license,将注册机
|
||||||
|
|
||||||
`bsp_log.h`中提供了不同的日志输出接口,包括封装好的三种层级的日志(info warning error),和用户可以自定义输出格式的`PrintLog()`。还提供了一些简单的将浮点数据转化为字符串的函数方便进行日志输出。
|
`bsp_log.h`中提供了不同的日志输出接口,包括封装好的三种层级的日志(info warning error),和用户可以自定义输出格式的`PrintLog()`。还提供了一些简单的将浮点数据转化为字符串的函数方便进行日志输出。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 附录3:Makefile指令介绍
|
## 附录3:Makefile指令介绍
|
||||||
|
|
||||||
> 如果想要进一步学习Makefile,可以参考这个链接:[Makefile Tutorial By Example](https://makefiletutorial.com/)。你会发现,当项目越来越大的时候,makefile也会变得复杂起来,这就有了后继者**CMake**。cmake可以根据一定的规则,生成makefile,然后再利用make命令调用gcc进行程序的编译。~~也许以后还会有ccccmake~~
|
> 如果想要进一步学习Makefile,可以参考这个链接:[Makefile Tutorial By Example](https://makefiletutorial.com/)。你会发现,当项目越来越大的时候,makefile也会变得复杂起来,这就有了后继者**CMake**。cmake可以根据一定的规则,生成makefile,然后再利用make命令调用gcc进行程序的编译。~~也许以后还会有ccccmake~~
|
||||||
|
@ -881,31 +850,31 @@ vpath %.s $(sort $(dir $(ASM_SOURCES))) # 对.s文件的文件名也进行排序
|
||||||
|
|
||||||
# 意味根据makefile,在BUILD_DIR变量指定的路径下将参与编译的所有.c文件编译成.o文件
|
# 意味根据makefile,在BUILD_DIR变量指定的路径下将参与编译的所有.c文件编译成.o文件
|
||||||
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
|
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
|
||||||
@$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
|
@$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
|
||||||
# 上面这句话翻译一下实际上是gcc -c -many_param build/xxx -o build
|
# 上面这句话翻译一下实际上是gcc -c -many_param build/xxx -o build
|
||||||
# 意思是将所有参与编译的文件都列出来,传递一堆编译参数,让他们生成.o文件,并且放在build文件夹下
|
# 意思是将所有参与编译的文件都列出来,传递一堆编译参数,让他们生成.o文件,并且放在build文件夹下
|
||||||
# 意为根据makefile,将.s文件编译成.o文件,具体和上一条命令差不多
|
# 意为根据makefile,将.s文件编译成.o文件,具体和上一条命令差不多
|
||||||
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
|
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
|
||||||
@$(AS) -c $(CFLAGS) $< -o $@
|
@$(AS) -c $(CFLAGS) $< -o $@
|
||||||
# 根据前两步生成的目标文件(.o,这些文件的名字保存在OBJECTS变量里),进行链接生成最终的.elf
|
# 根据前两步生成的目标文件(.o,这些文件的名字保存在OBJECTS变量里),进行链接生成最终的.elf
|
||||||
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
|
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
|
||||||
@$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
@$(CC) $(OBJECTS) $(LDFLAGS) -o $@
|
||||||
@$(SZ) $@ # 输出生成的.elf文件的大小和格式信息
|
@$(SZ) $@ # 输出生成的.elf文件的大小和格式信息
|
||||||
|
|
||||||
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
|
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
|
||||||
$(HEX) $< $@ # elf转换成hex
|
$(HEX) $< $@ # elf转换成hex
|
||||||
|
|
||||||
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
|
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
|
||||||
$(BIN) $< $@ # 转换成bin
|
$(BIN) $< $@ # 转换成bin
|
||||||
|
|
||||||
$(BUILD_DIR): # 如果makefile所处的文件目录下没有build文件夹,这里会新建一个build文件夹.
|
$(BUILD_DIR): # 如果makefile所处的文件目录下没有build文件夹,这里会新建一个build文件夹.
|
||||||
@mkdir $@
|
@mkdir $@
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# clean up,清除编译信息,可以在命令行中通过rm -r build执行,实际上就是把build文件夹删掉
|
# clean up,清除编译信息,可以在命令行中通过rm -r build执行,实际上就是把build文件夹删掉
|
||||||
#######################################
|
#######################################
|
||||||
clean:
|
clean:
|
||||||
rm -r $(BUILD_DIR)
|
rm -r $(BUILD_DIR)
|
||||||
# 你的makefile可能会使用cmd而不是powershell来调用内核,而cmd不支持rm命令,因此可能要修改为rd (remove directory),cmd传入参数的方式为 /x ,x为要传入的参数
|
# 你的makefile可能会使用cmd而不是powershell来调用内核,而cmd不支持rm命令,因此可能要修改为rd (remove directory),cmd传入参数的方式为 /x ,x为要传入的参数
|
||||||
|
|
||||||
|
|
||||||
|
@ -930,8 +899,6 @@ clean:
|
||||||
| -Os | O2基础上,进一步优化代码尺寸 | 去掉了那些会导致最终可执行程序增大的优化,如果想要更小的可执行程序,可选择这个参数。 |
|
| -Os | O2基础上,进一步优化代码尺寸 | 去掉了那些会导致最终可执行程序增大的优化,如果想要更小的可执行程序,可选择这个参数。 |
|
||||||
| -Ofast | 优化到破坏标准合规性的点(等效于-O3 -ffast-math ) | 是在 -O3 的基础上,添加了一些非常规优化,这些优化是通过打破一些国际标准(比如一些数学函数的实现标准)来实现的,所以一般不推荐使用该参数。 |
|
| -Ofast | 优化到破坏标准合规性的点(等效于-O3 -ffast-math ) | 是在 -O3 的基础上,添加了一些非常规优化,这些优化是通过打破一些国际标准(比如一些数学函数的实现标准)来实现的,所以一般不推荐使用该参数。 |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 附录4:VSCode直接烧录代码
|
## 附录4:VSCode直接烧录代码
|
||||||
|
|
||||||
有时候你对自己的代码特别自信,不想debug想直接下载代码,那么直接通过openocd或J-Flash即可(随jlink一起安装)。要是觉得这样有点麻烦还要再开一个软件,他们两者都支持通过命令行执行。你可以在vscode的tasks.json中编写一个额外的任务来实现。这里,我通过给Makefile添加伪构建目标来利用make命令执行下载操作:
|
有时候你对自己的代码特别自信,不想debug想直接下载代码,那么直接通过openocd或J-Flash即可(随jlink一起安装)。要是觉得这样有点麻烦还要再开一个软件,他们两者都支持通过命令行执行。你可以在vscode的tasks.json中编写一个额外的任务来实现。这里,我通过给Makefile添加伪构建目标来利用make命令执行下载操作:
|
||||||
|
@ -943,10 +910,10 @@ clean:
|
||||||
OPENOCD_FLASH_START = 0x08000000 # 如果切换芯片可能需要修改此值
|
OPENOCD_FLASH_START = 0x08000000 # 如果切换芯片可能需要修改此值
|
||||||
|
|
||||||
download_dap:
|
download_dap:
|
||||||
openocd -f openocd_dap.cfg -c init -c halt -c "flash write_image erase $(BUILD_DIR)/$(TARGET).hex $(OPENOCD_FLASH_START)" -c reset -c shutdown
|
openocd -f openocd_dap.cfg -c init -c halt -c "flash write_image erase $(BUILD_DIR)/$(TARGET).hex $(OPENOCD_FLASH_START)" -c reset -c shutdown
|
||||||
|
|
||||||
download_jlink:
|
download_jlink:
|
||||||
openocd -f openocd_jlink.cfg -c init -c halt -c "flash write_image erase $(BUILD_DIR)/$(TARGET).hex $(OPENOCD_FLASH_START)" -c reset -c shutdown
|
openocd -f openocd_jlink.cfg -c init -c halt -c "flash write_image erase $(BUILD_DIR)/$(TARGET).hex $(OPENOCD_FLASH_START)" -c reset -c shutdown
|
||||||
```
|
```
|
||||||
|
|
||||||
首先设定了flash烧录区的起始地址,下面两个构建目标分别用于daplink和jlink的下载。我们统一使用openocd进行烧录。命令中,`-c`表明的是启动openocd之后要执行的命令,openocd作为一个gdbserver是用作调试的,因此这里我们在`flash write_image`之后直接`reset`让单片机复位开始运行程序,然后立刻退出调试,从而达到下载程序运行但不调试的目的。
|
首先设定了flash烧录区的起始地址,下面两个构建目标分别用于daplink和jlink的下载。我们统一使用openocd进行烧录。命令中,`-c`表明的是启动openocd之后要执行的命令,openocd作为一个gdbserver是用作调试的,因此这里我们在`flash write_image`之后直接`reset`让单片机复位开始运行程序,然后立刻退出调试,从而达到下载程序运行但不调试的目的。
|
||||||
|
@ -959,9 +926,9 @@ download_jlink:
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"command":"make download_dap",
|
"command":"make download_dap",
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": false,
|
"isDefault": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "download jlink",
|
"label": "download jlink",
|
||||||
|
@ -979,15 +946,13 @@ download_jlink:
|
||||||
|
|
||||||
> 实际上换用arm gnu工具链之后,可以指定多线程编译,因此消耗的时间非常短,建议都加上先编译的选项,不会占用额外的时间。可以把默认task设置成编译后下载,把默认debug设置成编译后调试,提升开发效率。
|
> 实际上换用arm gnu工具链之后,可以指定多线程编译,因此消耗的时间非常短,建议都加上先编译的选项,不会占用额外的时间。可以把默认task设置成编译后下载,把默认debug设置成编译后调试,提升开发效率。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 附录5:利用MSYS2安装依赖环境
|
## 附录5:利用MSYS2安装依赖环境
|
||||||
|
|
||||||
之所以要使用Linux进行C++开发,是因为在开发环境中配置依赖包、依赖应用和库非常的方便。Debian系有apt,Fedora和Redhat系有yum,他们都可以方便地帮助我们下载开发软件必须的一些文件和工具。在windows的宇宙最强IDEVisual Studio中配置头文件和动态链接库可以称得上是最折磨的事。好在,现在Windows下也有可以使用的包管理工具了:[MSYS2](https://www.msys2.org/)。
|
之所以要使用Linux进行C++开发,是因为在开发环境中配置依赖包、依赖应用和库非常的方便。Debian系有apt,Fedora和Redhat系有yum,他们都可以方便地帮助我们下载开发软件必须的一些文件和工具。在windows的宇宙最强IDEVisual Studio中配置头文件和动态链接库可以称得上是最折磨的事。好在,现在Windows下也有可以使用的包管理工具了:[MSYS2](https://www.msys2.org/)。
|
||||||
|
|
||||||
安装包已经上传到了网盘的`EC/VSCode+Ozone环境配置/msys2-x86_64-20221028.exe`下。安装之后,打开MSYS2 MSYS软件,他是一个类shell的界面:
|
安装包已经上传到了网盘的`EC/VSCode+Ozone环境配置/msys2-x86_64-20221028.exe`下。安装之后,打开MSYS2 MSYS软件,他是一个类shell的界面:
|
||||||
|
|
||||||
![image-20221119222946103](assets/image-20221119222946103.png)
|
![image-20221119222946103](.assets/image-20221119222946103.png)
|
||||||
|
|
||||||
输入以下命令然后一路回车即可:
|
输入以下命令然后一路回车即可:
|
||||||
|
|
||||||
|
@ -996,7 +961,7 @@ pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-arm-none-eabi-toolchain mi
|
||||||
# 需要注意ctrl+V不是黏贴快捷键,而是Ins+Shift.或者右键点击空白处选择黏贴也可以.
|
# 需要注意ctrl+V不是黏贴快捷键,而是Ins+Shift.或者右键点击空白处选择黏贴也可以.
|
||||||
```
|
```
|
||||||
|
|
||||||
![image-20221119223148604](assets/image-20221119223148604.png)
|
![image-20221119223148604](.assets/image-20221119223148604.png)
|
||||||
|
|
||||||
<center>比如上面这样,会让你选择,直接敲回车即可,等待安装</center>
|
<center>比如上面这样,会让你选择,直接敲回车即可,等待安装</center>
|
||||||
|
|
||||||
|
@ -1008,8 +973,6 @@ pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-arm-none-eabi-toolchain mi
|
||||||
|
|
||||||
通过这种方式安装之后,还可以选用ccache加速编译。ccache会根据之前的编译输出建立缓存,使得之后编译时可以直接读取缓存。要开启这个功能,直接在Makefile中搜索PREFIX,将下面一行的内容替代原有内容(即增加ccache在arm-none-eabi-之前)。
|
通过这种方式安装之后,还可以选用ccache加速编译。ccache会根据之前的编译输出建立缓存,使得之后编译时可以直接读取缓存。要开启这个功能,直接在Makefile中搜索PREFIX,将下面一行的内容替代原有内容(即增加ccache在arm-none-eabi-之前)。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 附录6:Windows修改用户名为英文
|
## 附录6:Windows修改用户名为英文
|
||||||
|
|
||||||
1. 右键【任务栏win徽标】->【计算机管理】->【本地用户和组】->【用户】->右键【中文用户名】->【重命名】
|
1. 右键【任务栏win徽标】->【计算机管理】->【本地用户和组】->【用户】->右键【中文用户名】->【重命名】
|
||||||
|
@ -1045,4 +1008,3 @@ pacman -S mingw-w64-x86_64-toolchain mingw-w64-x86_64-arm-none-eabi-toolchain mi
|
||||||
```
|
```
|
||||||
|
|
||||||
如果杀毒软件提示恶意修改,请放行。这会关闭Administator账户。
|
如果杀毒软件提示恶意修改,请放行。这会关闭Administator账户。
|
||||||
|
|
||||||
|
|
|
@ -174,10 +174,11 @@ Dma.USART6_TX.1.PeriphInc=DMA_PINC_DISABLE
|
||||||
Dma.USART6_TX.1.Priority=DMA_PRIORITY_HIGH
|
Dma.USART6_TX.1.Priority=DMA_PRIORITY_HIGH
|
||||||
Dma.USART6_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,FIFOThreshold,MemBurst,PeriphBurst
|
Dma.USART6_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,FIFOThreshold,MemBurst,PeriphBurst
|
||||||
FREERTOS.INCLUDE_vTaskDelayUntil=1
|
FREERTOS.INCLUDE_vTaskDelayUntil=1
|
||||||
FREERTOS.IPParameters=Tasks01,configENABLE_FPU,configMAX_TASK_NAME_LEN,configUSE_TIMERS,configUSE_POSIX_ERRNO,INCLUDE_vTaskDelayUntil
|
FREERTOS.IPParameters=Tasks01,configENABLE_FPU,configMAX_TASK_NAME_LEN,configUSE_TIMERS,configUSE_POSIX_ERRNO,INCLUDE_vTaskDelayUntil,configTOTAL_HEAP_SIZE
|
||||||
FREERTOS.Tasks01=defaultTask,0,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
|
FREERTOS.Tasks01=defaultTask,0,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
|
||||||
FREERTOS.configENABLE_FPU=1
|
FREERTOS.configENABLE_FPU=1
|
||||||
FREERTOS.configMAX_TASK_NAME_LEN=32
|
FREERTOS.configMAX_TASK_NAME_LEN=32
|
||||||
|
FREERTOS.configTOTAL_HEAP_SIZE=20000
|
||||||
FREERTOS.configUSE_POSIX_ERRNO=0
|
FREERTOS.configUSE_POSIX_ERRNO=0
|
||||||
FREERTOS.configUSE_TIMERS=0
|
FREERTOS.configUSE_TIMERS=0
|
||||||
File.Version=6
|
File.Version=6
|
||||||
|
@ -505,7 +506,7 @@ ProjectManager.DeviceId=STM32F407IGHx
|
||||||
ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.27.1
|
ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.27.1
|
||||||
ProjectManager.FreePins=false
|
ProjectManager.FreePins=false
|
||||||
ProjectManager.HalAssertFull=false
|
ProjectManager.HalAssertFull=false
|
||||||
ProjectManager.HeapSize=0x4000
|
ProjectManager.HeapSize=0x5000
|
||||||
ProjectManager.KeepUserCode=true
|
ProjectManager.KeepUserCode=true
|
||||||
ProjectManager.LastFirmware=true
|
ProjectManager.LastFirmware=true
|
||||||
ProjectManager.LibraryCopy=1
|
ProjectManager.LibraryCopy=1
|
||||||
|
@ -516,7 +517,7 @@ ProjectManager.ProjectBuild=false
|
||||||
ProjectManager.ProjectFileName=basic_framework.ioc
|
ProjectManager.ProjectFileName=basic_framework.ioc
|
||||||
ProjectManager.ProjectName=basic_framework
|
ProjectManager.ProjectName=basic_framework
|
||||||
ProjectManager.RegisterCallBack=
|
ProjectManager.RegisterCallBack=
|
||||||
ProjectManager.StackSize=0x4000
|
ProjectManager.StackSize=0x5000
|
||||||
ProjectManager.TargetToolchain=Makefile
|
ProjectManager.TargetToolchain=Makefile
|
||||||
ProjectManager.ToolChainLocation=
|
ProjectManager.ToolChainLocation=
|
||||||
ProjectManager.UnderRoot=false
|
ProjectManager.UnderRoot=false
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
|
|
||||||
可以作为io接口,也可以处理外部中断.
|
可以作为io接口,也可以处理外部中断.
|
||||||
|
|
||||||
![image-20230202151939109](../../assets/image-20230202151939109.png)
|
![image-20230202151939109](../../.assets/image-20230202151939109.png)
|
||||||
|
|
||||||
![img](../../assets/00937839b59a4c039ee8ecb8a5136e3c.png)
|
|
||||||
|
|
||||||
|
|
||||||
|
![img](../../.assets/00937839b59a4c039ee8ecb8a5136e3c.png)
|
||||||
|
|
||||||
使用示例
|
使用示例
|
||||||
|
|
||||||
|
@ -22,4 +20,4 @@ GPIO_Init_Config_s gpio_init = {
|
||||||
GPIOInstance* test_example = GPIORegister(&gpio_init);
|
GPIOInstance* test_example = GPIORegister(&gpio_init);
|
||||||
GPIOSet(test_example);
|
GPIOSet(test_example);
|
||||||
// GPIOxxx(test_exmaple, ...);
|
// GPIOxxx(test_exmaple, ...);
|
||||||
```
|
```
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
>
|
>
|
||||||
> 1. 对`CANCommGet()`进行修改,使得其可以返回数据是否更新的相关信息。
|
> 1. 对`CANCommGet()`进行修改,使得其可以返回数据是否更新的相关信息。
|
||||||
|
|
||||||
|
|
||||||
## 重要提醒
|
## 重要提醒
|
||||||
|
|
||||||
如果传输过程中出现多次丢包或长度校验不通过,尤其是传输长度较大的时候,请开启CAN的Auto Retransmission,并尝试修改CANComm实例的发送和接受ID(以提高在总线仲裁中的优先级)。
|
如果传输过程中出现多次丢包或长度校验不通过,尤其是传输长度较大的时候,请开启CAN的Auto Retransmission,并尝试修改CANComm实例的发送和接受ID(以提高在总线仲裁中的优先级)。
|
||||||
|
@ -40,12 +39,12 @@ typedef struct
|
||||||
} CANComm_Init_Config_s;
|
} CANComm_Init_Config_s;
|
||||||
|
|
||||||
CANComm_Init_Config_s cconfig = {
|
CANComm_Init_Config_s cconfig = {
|
||||||
.can_config = {
|
.can_config = {
|
||||||
.can_handle=&hcan1,
|
.can_handle=&hcan1,
|
||||||
.tx_id=0x02,
|
.tx_id=0x02,
|
||||||
.rx_id=0x03},
|
.rx_id=0x03},
|
||||||
.send_data_len = sizeof(your_data_structure),
|
.send_data_len = sizeof(your_data_structure),
|
||||||
.recv_data_len = sizeof(recv_data_structure)
|
.recv_data_len = sizeof(recv_data_structure)
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -65,7 +64,7 @@ typedef struct
|
||||||
|
|
||||||
只有这样,这个结构体才不会进行padding扩充字节实现字节对齐。你可以尝试一下,如果不使用pack处理,上面的结构体将会占据18个字节以上的空间;开启pack后,会降低至15。更多关于字节对齐的内容,自行查询。
|
只有这样,这个结构体才不会进行padding扩充字节实现字节对齐。你可以尝试一下,如果不使用pack处理,上面的结构体将会占据18个字节以上的空间;开启pack后,会降低至15。更多关于字节对齐的内容,自行查询。
|
||||||
|
|
||||||
> 后期可能更新字节对齐和内存访问相关的教程。
|
> 后期可能更新字节对齐和内存访问相关的教程。
|
||||||
|
|
||||||
`CANCommGet()`是获取来自CANComm接收到的数据的接口,返回值为一个void类型指针,你需要通过**强制类型转换**将其变为你设定的接收类型指针,然后就可以访问其数据了。
|
`CANCommGet()`是获取来自CANComm接收到的数据的接口,返回值为一个void类型指针,你需要通过**强制类型转换**将其变为你设定的接收类型指针,然后就可以访问其数据了。
|
||||||
|
|
||||||
|
@ -92,10 +91,10 @@ static void CANCommRxCallback(can_instance *_instance);
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
struct test
|
struct test
|
||||||
{
|
{
|
||||||
float aa;
|
float aa;
|
||||||
float bb;
|
float bb;
|
||||||
float cc;
|
float cc;
|
||||||
uint16_t dd;
|
uint16_t dd;
|
||||||
};
|
};
|
||||||
#pragma pack()
|
#pragma pack()
|
||||||
```
|
```
|
||||||
|
@ -104,12 +103,12 @@ struct test
|
||||||
|
|
||||||
```c
|
```c
|
||||||
CANComm_Init_Config_s cconfig = {
|
CANComm_Init_Config_s cconfig = {
|
||||||
.can_config = {
|
.can_config = {
|
||||||
.can_handle=&hcan1,
|
.can_handle=&hcan1,
|
||||||
.tx_id=0x02,
|
.tx_id=0x02,
|
||||||
.rx_id=0x03},
|
.rx_id=0x03},
|
||||||
.send_data_len = sizeof(float),
|
.send_data_len = sizeof(float),
|
||||||
.recv_data_len = sizeof(struct test)
|
.recv_data_len = sizeof(struct test)
|
||||||
};
|
};
|
||||||
CANCommInstance* ins = CANCommInit(&cconfig);
|
CANCommInstance* ins = CANCommInit(&cconfig);
|
||||||
```
|
```
|
||||||
|
@ -138,5 +137,4 @@ CAN comm的通信协议如下:
|
||||||
|
|
||||||
接收的流程见代码注释。
|
接收的流程见代码注释。
|
||||||
|
|
||||||
流程图如下:![未命名文件](../../assets/CANcomm.png)
|
流程图如下:![未命名文件](../../.assets/CANcomm.png)
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,15 @@
|
||||||
|
|
||||||
## 硬触发流程
|
## 硬触发流程
|
||||||
|
|
||||||
![image-20221113212706633](assets\image-20221113212706633.png)
|
![image-20221113212706633](.assets\image-20221113212706633.png)
|
||||||
|
|
||||||
`times%10` 是固定相机的采集频率为100hz,请根据视觉算法实际能达到的最大帧率调整。
|
`times%10` 是固定相机的采集频率为100hz,请根据视觉算法实际能达到的最大帧率调整。
|
||||||
|
|
||||||
## 算法解析
|
## 算法解析
|
||||||
|
|
||||||
介绍EKF四元数姿态解算的教程在:[四元数EKF姿态更新算法](https://zhuanlan.zhihu.com/p/454155643)
|
介绍EKF四元数姿态解算的教程在:[四元数EKF姿态更新算法](https://zhuanlan.zhihu.com/p/454155643)
|
||||||
|
|
||||||
|
|
||||||
## 模块移植
|
## 模块移植
|
||||||
|
|
||||||
由于历史遗留问题,IMU模块耦合程度高.后续实现BSP_SPI,将bmi088 middleware删除.仅保留BMI088读取的协议和寄存器定义等,单独实现IMU模块.
|
由于历史遗留问题,IMU模块耦合程度高.后续实现BSP_SPI,将bmi088 middleware删除.仅保留BMI088读取的协议和寄存器定义等,单独实现IMU模块.
|
||||||
> 移植已经完成,请转而使用module/BMI088的模块. 当前文件夹将在beta1.2停止支持, 1.5之后删除. INS_Task届时会被放到algorithm中,以提供对不同IMU的兼容.
|
> 移植已经完成,请转而使用module/BMI088的模块. 当前文件夹将在beta1.2停止支持, 1.5之后删除. INS_Task届时会被放到algorithm中,以提供对不同IMU的兼容.
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
>
|
>
|
||||||
> 支持自定义队列长度,使得订阅者可以自行确定需要的队列长度,适应不同的需求
|
> 支持自定义队列长度,使得订阅者可以自行确定需要的队列长度,适应不同的需求
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 总览和封装说明
|
## 总览和封装说明
|
||||||
|
|
||||||
**重要定义:**
|
**重要定义:**
|
||||||
|
@ -24,14 +22,10 @@ Message Center不同应用间进行消息传递的中介,它的存在可以在
|
||||||
|
|
||||||
Message Center对外提供了四个接口,所有原本要进行信息交互的应用都应该包含`message_center.h`,并在初始化的时候进行注册。
|
Message Center对外提供了四个接口,所有原本要进行信息交互的应用都应该包含`message_center.h`,并在初始化的时候进行注册。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 代码结构
|
## 代码结构
|
||||||
|
|
||||||
.h 文件中包含了外部接口和类型定义,.c中包含了各个接口的具体实现。
|
.h 文件中包含了外部接口和类型定义,.c中包含了各个接口的具体实现。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 外部接口
|
## 外部接口
|
||||||
|
|
||||||
**在代码实现上,话题名实际上就是通过一个字符串体现的。**
|
**在代码实现上,话题名实际上就是通过一个字符串体现的。**
|
||||||
|
@ -74,8 +68,6 @@ my_sub=SubRegister("event_name",sizeof(float));
|
||||||
|
|
||||||
修改第一个可以扩大话题名长度,第二个确定消息队列的长度,数量越大可以保存的消息越多。
|
修改第一个可以扩大话题名长度,第二个确定消息队列的长度,数量越大可以保存的消息越多。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 私有函数和定义
|
## 私有函数和定义
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
@ -99,13 +91,11 @@ static void CheckName(char* name)
|
||||||
|
|
||||||
> 四个外部接口的实现都有详细的注释,有兴趣的同学可以自行阅读。下方也提供了流程图。
|
> 四个外部接口的实现都有详细的注释,有兴趣的同学可以自行阅读。下方也提供了流程图。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 注册、发布、获取消息流程
|
## 注册、发布、获取消息流程
|
||||||
|
|
||||||
包含一个结构图和四个流程图。
|
包含一个结构图和四个流程图。
|
||||||
|
|
||||||
### Message Center的结构![image-20221201150945052](../../assets/image-20221201150945052.png)
|
### Message Center的结构![image-20221201150945052](../../.assets/image-20221201150945052.png)
|
||||||
|
|
||||||
<center>建议打开原图查看</center>
|
<center>建议打开原图查看</center>
|
||||||
|
|
||||||
|
@ -121,19 +111,19 @@ static void CheckName(char* name)
|
||||||
|
|
||||||
遍历发布者的话题结点,如果发现相同的话题,直接返回指针即可;遍历完成后发现尚未创建则创建新的话题。
|
遍历发布者的话题结点,如果发现相同的话题,直接返回指针即可;遍历完成后发现尚未创建则创建新的话题。
|
||||||
|
|
||||||
<img src="../../assets/image-20221201152530558.png" alt="image-20221201152530558" style="zoom: 80%;" />
|
<img src="../../.assets/image-20221201152530558.png" alt="image-20221201152530558" style="zoom: 80%;" />
|
||||||
|
|
||||||
- **订阅者:**
|
- **订阅者:**
|
||||||
|
|
||||||
需要注意,由于不同应用/模块的初始化顺序不同,可能出现订阅者先于发布者订阅某一消息的情况,所以要进行发布者链表的遍历,判断是否已经存在相同话题名的发布者,不存在则要先创建发布者结点再将新建订阅者结点并挂载到前者上。
|
需要注意,由于不同应用/模块的初始化顺序不同,可能出现订阅者先于发布者订阅某一消息的情况,所以要进行发布者链表的遍历,判断是否已经存在相同话题名的发布者,不存在则要先创建发布者结点再将新建订阅者结点并挂载到前者上。
|
||||||
|
|
||||||
<img src="../../assets/image-20221201152904044.png" alt="image-20221201152904044" style="zoom:80%;" />
|
<img src="../../.assets/image-20221201152904044.png" alt="image-20221201152904044" style="zoom:80%;" />
|
||||||
|
|
||||||
### 推送/获取消息的流程
|
### 推送/获取消息的流程
|
||||||
|
|
||||||
- **数组+头尾索引模拟队列**
|
- **数组+头尾索引模拟队列**
|
||||||
|
|
||||||
<img src="../../assets/image-20221201155228196.png" alt="image-20221201155228196" style="zoom: 71%;" />
|
<img src="../../.assets/image-20221201155228196.png" alt="image-20221201155228196" style="zoom: 71%;" />
|
||||||
|
|
||||||
front指向队列头,即最早入队的数据;back指向队列尾,即最新的数据。队列是first in first out(FIFO,先进先出)的结构。back指向的位置是入队数据被写入的位置,front指向的是读取时会出队的位置。当有数据入队,back++;出队则front++。若碰到数组边界,则返回数组头,可以通过取模实现:
|
front指向队列头,即最早入队的数据;back指向队列尾,即最新的数据。队列是first in first out(FIFO,先进先出)的结构。back指向的位置是入队数据被写入的位置,front指向的是读取时会出队的位置。当有数据入队,back++;出队则front++。若碰到数组边界,则返回数组头,可以通过取模实现:
|
||||||
|
|
||||||
|
@ -150,8 +140,6 @@ queue[front]=new_data;
|
||||||
front=(front+1)%SIZE_OF_ARRAY;
|
front=(front+1)%SIZE_OF_ARRAY;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- **发布者推送消息到指定话题**
|
- **发布者推送消息到指定话题**
|
||||||
|
|
||||||
通过发布者指针,将订阅了该话题的所有订阅者遍历,将新数据入队。
|
通过发布者指针,将订阅了该话题的所有订阅者遍历,将新数据入队。
|
||||||
|
@ -160,8 +148,6 @@ front=(front+1)%SIZE_OF_ARRAY;
|
||||||
|
|
||||||
从订阅者指针访问消息队列,取出最先进入队列的数据。注意判断队列是否为空,如果为空则返回0。
|
从订阅者指针访问消息队列,取出最先进入队列的数据。注意判断队列是否为空,如果为空则返回0。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## 示例代码
|
## 示例代码
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
@ -191,4 +177,4 @@ d=SubGetMessage(s,&g1);
|
||||||
d=SubGetMessage(s,&g1);
|
d=SubGetMessage(s,&g1);
|
||||||
d=SubGetMessage(s,&g1); // 此时d等于0
|
d=SubGetMessage(s,&g1); // 此时d等于0
|
||||||
d=SubGetMessage(ss,&g2);
|
d=SubGetMessage(ss,&g2);
|
||||||
```
|
```
|
||||||
|
|