ManjaroKDE 编译OpenMV

环境

manjaro: 18.1.2
kernel:5.3.7-2
gcc: 9.2.0
openmv: d8782275e3db852ecc041288fc45932526b4dec6

获取源代码

  1. (非必要,可提高国内克隆速度)使用gitee导入openmv及micropython
  2. 克隆库
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 
      |                ^~~~~~~~~~
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'结束,解决办法有两个:

  1. 将strncpy修改为memcpy
  2. 执行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_bufopenmv/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));

相关问题可见此处,另micropython相关问题记录。

你可能感兴趣的:(ManjaroKDE 编译OpenMV)