From 4e2b75003732d2fbf1d24395240c92523f1c15bc Mon Sep 17 00:00:00 2001 From: NeoZng Date: Thu, 9 Feb 2023 00:09:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E6=95=99=E7=A8=8B?= =?UTF-8?q?=E5=92=8C=E6=B3=A8=E9=87=8A=E4=BB=A5=E5=8F=8A=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HAL_N_Middlewares/Src/freertos.c | 3 ++ README.md | 4 +-- TODO.md | 14 ++++----- VSCode+Ozone使用方法.md | 51 +++++++++++++++++++++++++++++--- bsp/usb/bsp_usb.c | 2 +- 修改HAL配置时文件目录的更改.md | 10 ++++--- 6 files changed, 66 insertions(+), 18 deletions(-) diff --git a/HAL_N_Middlewares/Src/freertos.c b/HAL_N_Middlewares/Src/freertos.c index 76c1b60..e0a893a 100644 --- a/HAL_N_Middlewares/Src/freertos.c +++ b/HAL_N_Middlewares/Src/freertos.c @@ -31,6 +31,7 @@ #include "daemon.h" #include "robot.h" + /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -145,6 +146,8 @@ void MX_FREERTOS_Init(void) { void StartDefaultTask(void const * argument) { /* init code for USB_DEVICE */ + USB_ResetPort(USB_OTG_FS); + USBD_FS_SPEED MX_USB_DEVICE_Init(); /* USER CODE BEGIN StartDefaultTask */ /* Infinite loop */ diff --git a/README.md b/README.md index 94493dc..af19f8a 100644 --- a/README.md +++ b/README.md @@ -10,9 +10,9 @@ - **开发方式**: - 本框架使用stm32cubemx生成,基于makefile,使用arm gnu工具链开发,利用arm-none-eabi-gcc编译(make命令,命令行为mingw32-make)。 + 本框架使用stm32cubemx生成,基于makefile编译系统(后期拟修改为cmake+nijna+makefile以提高编译速度,对于目前的版本您可以考虑自行安装ccache以提高编译速度),使用arm gnu工具链开发,利用arm-none-eabi-gcc编译(make命令,命令行为mingw32-make)。 - > !deprecated:若需使用keil5开发,请在stm32cubemx的`project manager`标签页下将工具链改为MDK,然后在keil中自行添加所需包含的.c文件和头文件。关于如何在keil下添加dsplib,请参考文档。在vscode中也有**KEIL assistant**和**Embedded IDE**插件可供使用。 + > ***==!deprecated==***:若需使用keil5开发,请在stm32cubemx的`project manager`标签页下将工具链改为MDK,然后在keil中自行添加所需包含的.c文件和头文件。关于如何在keil下添加dsplib,请参考文档。在vscode中也有**KEIL assistant**和**Embedded IDE**插件可供使用。 > > ***强烈推荐使用VSCode进行开发,Ozone进行调试。*** diff --git a/TODO.md b/TODO.md index 53a7609..131efdd 100644 --- a/TODO.md +++ b/TODO.md @@ -30,7 +30,7 @@ #### bsp_gpio -- [ ] 增加GPIO引脚的控制(有待商榷是否需要单独添加,HAL实际上已经提供较好的封装) +- [x] 增加GPIO引脚的控制(有待商榷是否需要单独添加,HAL实际上已经提供较好的封装) #### bsp_usb @@ -76,8 +76,8 @@ #### refereeUI -- [ ] 提供UI绘制封装 -- [ ] 绘制电容剩余容量/当前底盘状态/当前云台状态/底盘位置/射表 +- [x] 提供UI绘制封装 +- [x] 绘制电容剩余容量/当前底盘状态/当前云台状态/底盘位置/射表 - [ ] 绘制视觉识别UI/识别状态/击打状态 #### ==master_machine== @@ -113,7 +113,7 @@ 需要重写部分数据结构,并在bsp_spi完成之后移植到新的bsp上。(等待bsp_spi的测试) -- [ ] 重构imu模块 +- [x] 重构imu模块 #### remote_control @@ -133,7 +133,7 @@ #### controller -- [ ] 增加前馈数据 +- [x] 增加前馈数据 #### user_lib @@ -154,7 +154,7 @@ #### referee_communication -- [ ] 增加裁判系统多机通信功能 +- [x] 增加裁判系统多机通信功能 #### controller @@ -204,7 +204,7 @@ #### robot_cmd -- [ ] 解耦各个应用的运行模式 +- [x] 解耦各个应用的运行模式 - [ ] 优化消息发布和接收性能 #### gimbal diff --git a/VSCode+Ozone使用方法.md b/VSCode+Ozone使用方法.md index 98f1c13..adfd154 100644 --- a/VSCode+Ozone使用方法.md +++ b/VSCode+Ozone使用方法.md @@ -6,7 +6,7 @@ > TODO: > -> 1. 添加一键编译+启用ozone调试d 脚本,使得整个进一步流程自动化 +> 1. 添加一键编译+启用ozone调试脚本,使得整个进一步流程自动化 > 2. 增加更多的背景知识介绍 > 3. 增加VSCode下RTT viewer的支持 @@ -149,6 +149,32 @@ ITM是instrument trace macrocell指令追踪宏单元的缩写,它用于提供 > 而对于直接运行在电脑上的程序(.exe),就不需要GDBserver和物理调试器,GDB程序可以直接访问电脑上运行的程序和CPU的寄存器等。 + + +### 字节对齐 + +这是内存硬件设计和汇编语言设计的结果。在使用结构体的时候,如果你不做任何事情,编译器会自动帮助你完成字节对齐以提高内存访问的效率。stm32是4字节地址和数据总线的设计,单词可以传输32位数据,因此,访问4字节数据(也就是stm32的“字”,“字长”)效率最高。然而,历史的缘由导致i一个内存地址只存储8位的数据,如果你要访问float数据,则一次需要读取4个地址。当这四个地址是连续的时候,你只需要一次就可以将数据读出。然而,如果一个float数据被存放在0x03-0x07这四个地址,cpu首先要读出0x00-0x03这四个连续的地址,然后再取出最后一个字节;随后读取0x04-0x07这四个连续的字节,再取出前三个字节;最后将最后一个字节和前三个字节拼接在一起,形成我们需要的float数据。 + +`#pragma`可能是最复杂的预编译指令,不同的编译器支持不同的`#pragma`指令,如常用的`#pragma once`可以替代header guard。arm gnu gcc编译器支持通过`#pragma pack()`来设置字节对齐,支持的对齐参数包括空/1/2/4/8,会启动对应长度的对齐方式。用于通信的结构体(串口/CAN/spi等外设接收数据的时候都是连续的,不会像结构体一样被编译器对齐)在声明时,采用如下的方式: + +```c +#pragma pack(1) // 从这句话开始,使用字节对齐(1),即紧凑,关闭对齐 + +typedef struct +{ + uint8_t id; + // ... + +} CANInstance; + +#pragma pack() // 从这里开始,恢复默认配置,一般来说默认配置是 pack(4),如果遇到double/longlong等也会变为8字节对齐 +// 使用两个#pragma包裹你的结构体声明 +``` + +如果您有兴趣,可以了解一下内存硬件的组织和连接方式,包括奇偶地址/片选/行列扩展等,可以帮助你更好地理解字节对齐。 + + + ## 环境配置 > ***所有需要编辑的配置文件都已经在basic_framework的仓库中提供,如果不会写,照猫画虎。*** @@ -172,7 +198,7 @@ ITM是instrument trace macrocell指令追踪宏单元的缩写,它用于提供 - **C/C++**:提供C/C++的调试和代码高亮支持 - **Better C++ Syntax**:提供更丰富的代码高亮和智能提示 - **C/C++ Snippets**:提供代码块(关键字)补全 - - **Cortex-Debug**,**Cortex-Debug: Device Support Pack - STM32F4**:提供调试支持 + - **Cortex-Debug**,**Cortex-Debug: Device Support Pack - STM32F4**:提供调试支持。cortex debug还会自动帮助你安装一些调试相关的插件。 - **IntelliCode**,**Makfile Tools**:提供代码高亮支持 ![image-20221112172157533](assets\image-20221112172157533.png) @@ -425,7 +451,9 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 4. 片上外设。这里可以查看外设的**控制寄存器**和**状态寄存器**的值,如果通过断点无法定位bug,则需要查找数据手册和Cortex M4指南的相关内容,根据寄存器值来判断程序当前的情况。 -5. 断点。所有添加的断点都会显示于此,注意,不像我们自己的电脑,单片机的DBG外设对断点的数量有限制(资源所限),超过5个断点会导致debug失败,此时将断点减少即可。 +5. 断点。所有添加的断点都会显示于此,注意,不像我们自己的电脑,单片机的DBG外设对断点的数量有限制(资源所限),超过5个断点会导致debug失败,此时将断点减少即可。由于单行代码编译之后可能会对应多条汇编指令,或一条表达式由多个表达式构成,你还可以插入**行内断点**以逐个执行表达式或汇编语句,你还可以在汇编窗口插入断点调试汇编代码,帮助你发现错误。 + + 对于不方便判断何时需要停止代码执行进行观察和测试的情况,你可以右键行号左侧的断点栏插入条件断点,输入表达式,当表达式满足时才会进入断点。 6. 调试控制台。调试器输出的信息会显示在这里,要**查看**和**追踪**的变量的信息也会显示在这里。如果调试出现问题,报错信息同样也会在这里显示。要是出现异常,可以复制这里的信息在搜索引擎里查找答案,不过最好的方法是查询gdb和openocd的官方文档。 @@ -452,9 +480,23 @@ VSCode `ctrl+,`进入设置,通过`搜索`找到cortex-debug插件的设置。 建议安装以下插件: 1. Hex Hover Converter,鼠标悬停在数值上的时候会自动显示其对应的16、2、10进制值和编码 + 2. Hex Editor,在查看汇编代码和机器代码的时候,提供2、10、16进制转换,并且可以以16进制或2进制的格式编辑文件。 + 3. GitLens,提供强大的可视化Git支持 +4. Blockman - Highlight Nested Code Blocks 此插件会高亮嵌套的代码块(即花括号包围的部分或for/while/ifelse代码块) + +5. bookmark提供代码中插入书签的功能,从而快速在页面间跳转。 + +6. Code Issue Manager,为团队提供issues和todo管理,方便协同开发 + +7. github copilot:超强,超快,需要一些小钱 + +8. `ctrl+k ctrl+s`配置属于你的快捷键,提高效率! + + + --- @@ -885,7 +927,7 @@ download_jlink: 首先设定了flash烧录区的起始地址,下面两个构建目标分别用于daplink和jlink的下载。我们统一使用openocd进行烧录。命令中,`-c`表明的是启动openocd之后要执行的命令,openocd作为一个gdbserver是用作调试的,因此这里我们在`flash write_image`之后直接`reset`让单片机复位开始运行程序,然后立刻退出调试,从而达到下载程序运行但不调试的目的。 -接下来我们希望能够直接下载,不要在命令行里面输入`make download_dap`这么复杂的指令,因此在tasks.json中添加如下两个任务: +接下来我们希望能够直接下载,不要在命令行里面输入`make download_dap`这么复杂的指令,我们可以利用make构建伪造目标来实现命令行命令执行,因此在tasks.json中添加如下两个任务: ```json { @@ -906,6 +948,7 @@ download_jlink: "isDefault": false, } }, +// 实际上也可以直接编写命令行指令,他们是等效的 ``` 这样,在工具栏的Terminal页面,就可以选择对应的任务直接下载执行了。你也可以通过快捷键`ctrl+shift+B`唤起任务执行页面进行选择。如果你希望立刻检验你代码修改的效果,在下载之前进行编译,那么在`command`信息下新增加一个`mingw32-make -j24`即可,或者添加一个`preLaunchTask`。对于调试,如果不想点两下想在修改代码之后直接调试,也可以在launch.json中增加`preLaunchTask`(文件中已经添加,需要的话取消注释即可)。 diff --git a/bsp/usb/bsp_usb.c b/bsp/usb/bsp_usb.c index 331f148..279a89c 100644 --- a/bsp/usb/bsp_usb.c +++ b/bsp/usb/bsp_usb.c @@ -12,7 +12,7 @@ __weak void USBTransmitCpltCallback(uint32_t len) uint8_t *USBInit() { - USB_ResetPort(USB_OTG_FS); // 上电后重新枚举usb设备 + // 上电后重新枚举usb设备 USBTransmit((uint8_t *)"USB DEVICE READY", sizeof("USB DEVICE READY")); // 发送初始化完成信息 bsp_usb_rx_buffer = CDCInitRxbufferNcallback(USBTransmitCpltCallback); // 获取接收数据指针 diff --git a/修改HAL配置时文件目录的更改.md b/修改HAL配置时文件目录的更改.md index 56edb61..6c1a83a 100644 --- a/修改HAL配置时文件目录的更改.md +++ b/修改HAL配置时文件目录的更改.md @@ -3,10 +3,12 @@ > 仅修改引脚位置和外设配置时 1. 在generate code之前,保存Makefile的副本 (因为修改了makefile的内容,添加了注释和伪构建目标,HAL无法正确识别格式导致直接其将整个文件清空) -2. 生成之后,将原makefile的内容替换到新的makefile中 -3. 将原main.c和freertos.c以及stm32f4xx_it.c替换到新的Src文件夹下 (Src的内容不用修改,**除非你新增了功能,那么需要将新增的初始化头文件`xxx.h`包含到main函数中,然后调用其对应的`MX_xxx_Init()`函数对硬件进行初始化**) -4. 将新生成的Src,Inc,Driver/STM32F4xx_HAL_Driver放入HAL_N_Middlewares下的对应位置(第三个目录只有新增了功能的时候才需要添加) +2. 生成之后,将原makefile的内容替换到新的makefile中,注意保留新添加的src code和include path. +3. 将原main.c和freertos.c以及stm32f4xx_it.c替换到新的Src文件夹下 (Src的内容不用修改,**除非你新增了功能,那么需要将新增的初始化头文件`xxx.h`包含到main函数中,然后调用其对应的`MX_xxx_Init()`函数对硬件进行初始化**)如果在cubemx中配置了新的硬件,则main.c将会包含新的头文件并添加MX_xxx_Init()以供外设初始化.freertos中会新增任务的声明和定义. 对于这两个文件将之前的内容覆写到新的文件中即可(注意不要把新生成的东西覆盖). +4. 将新生成的Src,Inc,Driver/STM32F4xx_HAL_Driver放入HAL_N_Middlewares下的对应位置(第三个目录只有新增了功能的时候才需要添加).Middlewares在大部分时候不需要更新,直接删除根目录下的Middlewares文件夹.(内部包含ST的usb库和segger的rtt viewer支持,如果新增了usb功能则需要将st的部分复制到HAL_N_Middlewares/Middletowns/ST下) +5. 删除根目录下的Drivers & Src & Inc & Middlewares文件夹. +6. 一切搞定之后,重新编译你的代码 > Q:为什么这么做? -> A:CubeMX生成的依赖库和文件有很大的冗余,占用空间较多.为了方便pull&push已经将Driver和Middlewares中不需要的文件全部删除. 修改HAL的配置(在没有新增其他库和依赖的情况下,大部分我们的更改都属于这种情况)大多是对初始化配置,即放在Inc和Src下的文件进行修改;若新增了功能,可能还会新增Driver/STM32F4xx_HAL_Driver的内容(比如新添加了flash或iic,原来没有这两个功能). \ No newline at end of file +> A:CubeMX生成的依赖库和文件有很大的冗余,占用空间较多.为了方便pull&push并精简仓库,已经将Driver和Middlewares中不需要的文件全部删除. 修改HAL的配置(在没有新增其他库和依赖的情况下,大部分我们的更改都属于这种情况)大多是对初始化配置,即放在Inc和Src下的文件进行修改;若新增了功能,可能还会新增Driver/STM32F4xx_HAL_Driver的内容(比如新添加了flash或iic,原来没有这两个功能). 实际上最节省空间的方式是生成软链接(快捷方式),将你需要的依赖文件在必要的时候链接到你的可执行文件中(你在cubemx内部已经下载了f4开发包,应该放在"用户名/STM32Cubemx/"下) \ No newline at end of file