环境
manjaro: 18.1.2
kernel:5.3.7-2
gcc: 9.2.0
openmv: d8782275e3db852ecc041288fc45932526b4dec6
获取源代码
- (非必要,可提高国内克隆速度)使用gitee导入openmv及micropython
- 克隆库
git clone https://gitee.com/fefr/openmv.git
cd openmv
vim .gitmodules
将.gitmodules
中的url替换成https://gitee.com/fefr/openmv.git,如下
[submodule "src/micropython"]
path = src/micropython
url = https://gitee.com/fefr/micropython.git
branch = openmv
然后同步子模块
git submodule init
git submodule update --recursive
micropython
库中又引入了其他子模块,故需要加入--recursive
,其子模块默认是拉取github上的资源,若速度慢时可参照上边的方法将micropython
的子模块地址修改为gitee。
以上步骤可直接使用命令git clone https://github.com/openmv/openmv --recurse-submodules
获取,但国内速度可能非常慢。
安装工具
pacman -S arm-none-eabi-gcc amr-none-eabi-binutils arm-none-eabi-newlib
若漏掉arm-none-eabi-newlib
则会在make
的时候报错:
/usr/lib/gcc/arm-none-eabi/9.2.0/include/stdint.h:9:16: fatal error: stdint.h: No such file or directory
9 | # include_next <stdint.h>
| ^~~~~~~~~~
compilation terminated.
编译
切换到openmv/src
目录下执行make
会报错:
src/winc.c: In function 'wifi_callback_sta':
src/winc.c:380:13: error: 'strncpy' output may be truncated copying 32 bytes from a string of length 32 [-Werror=stringop-truncation]
380 | strncpy((char*) wscan_result.ssid, (const char *) scan_result->au8SSID, WINC_MAX_SSID_LEN-1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/winc.c:344:13: error: 'strncpy' output may be truncated copying 32 bytes from a string of length 32 [-Werror=stringop-truncation]
344 | strncpy(netinfo->ssid, con_info->acSSID, WINC_MAX_SSID_LEN-1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
具体原因可参考这里,大概原因就是scan_result->au8SSID
大小与wscan_result.ssid
一样且strncpy
第三个参数是WINC_MAX_SSID_LEN-1
(即wscan_result.ssid
大小),编译器认为wscan_result.ssid[WINC_MAX_SSID_LEN-1]
可能不为'\0'
而报错,因为使用strncpy
表明使用者原意wscan_result.ssid
是一个字符串,而字符串必定以'\0'
结束,解决办法有两个:
- 将strncpy修改为memcpy
- 执行strncpy后添加一行代码
wscan_result.ssid[WINC_MAX_SSID_LEN-1] = '\0';
继续执行make
后报错:
main.c: In function '__fatal_error':
main.c:210:9: error: array subscript 0 is outside array bounds of 'char[1]' [-Werror=array-bounds]
210 | if (f_open(&vfs_fat->fatfs, &fp, "ERROR.LOG",
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
211 | FA_WRITE|FA_CREATE_ALWAYS) == FR_OK) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
main.c:80:13: note: while referencing '_vfs_buf'
80 | extern char _vfs_buf;
| ^~~~~~~~
原因是在openmv/src/omv/main.c
中有定义如下:
extern char _vfs_buf;
static fs_user_mount_t *vfs_fat = (fs_user_mount_t *) &_vfs_buf;
_vfs_buf
是char型而fs_user_mount_t
是一个结构体,-Werror=array-bounds
可能对某些情况下的强制转换前后数组大小有特殊检查,实验如下:
extern char _vfs_buf[1];
static fs_user_mount_t *vfs_fat = (fs_user_mount_t *) _vfs_buf;
以上代码依然报错,但改成如下时则没有报错:
extern char _vfs_buf[1];
static fs_user_mount_t *vfs_fat = (fs_user_mount_t *) &_vfs_buf[0];
以上不是解决办法,因为_vfs_buf
在openmv/src/omv/stm32fxx.ld.S
中定义,是连接脚本中的一个符合(参考文档),解决办法如下:
extern char _vfs_buf[];
static fs_user_mount_t *vfs_fat = (fs_user_mount_t *) _vfs_buf;
同样需要修改的地方还有openmv/src/omv/lepton.c
中的_line_buf
及_vospi_buf
:
extern uint8_t _line_buf[];
extern uint8_t _vospi_buf[];
...
static uint8_t *vospi_packet = _line_buf;
static uint8_t *vospi_buffer = _vospi_buf;
备注:
Nordic的代码使用ld连接脚本的符号时在C文件中声明为指针:
extern char *_vfs_buf;
这种用法虽然在参考文档中没有提及但更好理解,因为ld文件中的符号并没有实际分配空间,和goto使用的符号很像。
如果使用以上方法时紧接着下面的
static fs_user_mount_t *vfs_fat = (fs_user_mount_t *) _vfs_buf;
会报错initializer element is not constant,此时需要将vfs_fat的赋值移到函数里才能编译通过,因为此时_vfs_buf是一个变量不能在全局作为初始化值,而声明为_vfs_buf[]时_vsf_buf只是一个符号在实际内存中不占用空间故能作为初始化值。
之后能顺利编译完成。
编译OPENMV3固件
以上是执行make
默认编译的是OPENMV4
,使用命令make TARGET=OPENMV3
编译时会报错:
src/stm32f7xx_ll_usb.c: In function 'USB_WritePacket':
src/stm32f7xx_ll_usb.c:820:7: error: 'packed' attribute ignored for type 'uint32_t *' {aka 'long unsigned int *'} [-Werror=attributes]
820 | USBx_DFIFO(ch_ep_num) = *((__packed uint32_t *)src);
| ^~~~~~~~~~
src/stm32f7xx_ll_usb.c: In function 'USB_ReadPacket':
src/stm32f7xx_ll_usb.c:846:5: error: 'packed' attribute ignored for type 'uint32_t *' {aka 'long unsigned int *'} [-Werror=attributes]
846 | *(__packed uint32_t *)dest = USBx_DFIFO(0);
| ^
cc1: all warnings being treated as errors
此问题是packed
属性只支持结构体共同体等复合类型而不支持整形等的基本数据类型,为什么编译OPENMV4
的时候没有问题呢?因为OPENMV3
的代码没有修复这个bug。
将openmv/src/sthal/f7/src/stm32f7xx_ll_usb.c
相应代码修改成以下内容即可:
USBx_DFIFO(ch_ep_num) = __UNALIGNED_UINT32_READ(src);
...
__UNALIGNED_UINT32_WRITE(dest, USBx_DFIFO(0));