使用与B-U585I-IOT02A探索板连接的摄像头模块

介绍

STMicroelectronics最新推出的物联网探索板B-U585I-IOT02A,搭载了STM32U585AII6Q微控制器。STM32U5系列属于STM32微控制器的超低功耗类别,相比同类产品具有增强的性能和安全性。利用这些功能,该探索板包含了丰富的组件,可用于开发多种多功能、安全且高效的物联网应用。这些组件包括WiFi和BLE通信模块、外部存储器以及各种环境传感器。

B-U585I-IOT02A还包括一个摄像头模块扩展连接器,允许连接外部摄像头模块。特别是,B-CAMS-OMV套件中包含的MB1379摄像头模块与探索板完全兼容,并基于流行的OV5640 500万像素CMOS图像传感器。接下来的教程演示了如何从一个空项目开始与该模块进行接口。


但请注意,该连接器的丝印(图1)错误地指示应使用MB1183摄像头模块。这是不正确的,原因如下:

  1. MB1183模块无法单独购买。只能通过购买包含该模块的ST评估板来获取(参见AN5020中的表4)。由于评估板比探索板或NUCLEO板昂贵得多,获取该模块可能成本过高。

  2. MB1183模块要求摄像头模块连接器的引脚1和2提供1.8V电压,但这些引脚在B-U585I-IOT02A上连接到测试点(即它们处于悬空状态)。因此,虽然可以使用MB1183模块与该探索板,但必须先添加一个1.8V稳压器以提供正确的电压。图2展示了如何使用小型SOT-23-3器件(显示的是AP2138N-1.8TRG1DICT-ND稳压器)来实现这一点。

  3. MB1183模块基于S5K5CAGA CMOS图像传感器,ST对其支持较差。驱动程序从STM32U5微控制器包和GitHub上获取,类似于OV5640传感器的驱动程序。然而,S5K5CAGA驱动程序已过时,并且缺乏OV5640驱动程序提供的许多功能。

您可能还会看到对MB1066摄像头模块的引用(例如在AN5020中)。该模块的引脚排列与B-U585I-IOT02A上的摄像头模块连接器兼容。


1 摄像头模块连接器的错误丝印标记


2 焊接在B-U585I-IOT02A上的小型稳压器(SOT-23-3封装),用于为CN7的引脚1提供1.8V电压(使用MB1183摄像头模块时需要)


要求

要跟随本教程,需要以下软件和硬件。

  • STM32CubeIDE(版本1.11.0)

    • 如果您更喜欢使用不同的IDE,您也可以选择使用独立的STM32CubeMX工具,并在项目设置中选择不同的工具链/IDE。生成的代码可以导入到您所需的开发环境中。如果您选择这种方式,下面的步骤仍然可以作为指导。
  • B-U585I-IOT02A探索板

  • B-CAMS-OMV套件

    • 包括MB1379摄像头模块和适配板
  • Micro-B USB线缆(例如,993-1294-ND

步骤

本步骤演示如何配置和初始化STM32U5,使其能够控制摄像头模块并从中读取图像。它还展示了如何添加摄像头本身的驱动程序(OV5640),并提供了一个额外的抽象层以进一步简化编码。如果您不关心CubeMX配置,而是想直接开始使用一个工作示例,STM32CubeU5 MCU包中的BSP示例就是您所需要的。

步骤 1 。创建 STM32CubeIDE 项目

当然,如果您是从现有的STM32U5项目开始,可以跳过此步骤。

  1. 通过选择文件( File > 新建( New > STM32 项目( STM32 Project 来启动 STM32 项目向导。

  2. STM32 项目目标选择( STM32 Project Target Selection )工具中,选择板卡选择器( Board Selector )选项卡,并选择B-U585I-IOT02A板卡(使用左侧的板卡过滤器缩小搜索范围),如图3所示。点击下一步 >。


    3 选择B-U585I-IOT02A探索板作为项目的目标板卡。

  3. 提供项目名称(例如,“b-u585i-iot02a_camera”),然后点击完成。在项目创建过程中,您应该会看到几个提示。按以下方式回答:

    • 当提示 使用默认模式初始化所有外设?( Initialize all peripherals with their default Mode? )” 时,点击否( No

    • 如果 提示 “设备配置工具编辑器与设备配置工具透视图关联。您是否要立即打开此透视图? Device Configuration Tool editor is associated with Device Configuration Tool perspective.Do you want to open this perspective now?” ,点击

    • 当提示 必须启用指令缓存( ICACHE )以达到最大性能。可以从 ICACHE 下的 Pinout 选项卡启用 ICACHE 。您是否仍要生成代码?( The instruction cache (ICACHE) must be enabled to reach the maximum performance.The ICACHE can be enabled from the Pinout tab under ICACHE.Do you still want to generate code? ”,点击

步骤 2 STM32CubeMX 配置

  1. Pinout & Configuration 选项卡下,从透视图左侧的组件列表中选择ICACHE 组件,并将模式(Mode) 更改为“1-way (direct mapped cache)”(图4)。


    4 启用指令缓存(ICACHE)。

  2. 从组件列表中选择I2C1 外设。在Mode 面板中,将I2C 选项更改为“I2C”,并验证此操作是否导致Pinout视图中的PB8和PB9引脚变为绿色(它们应该已经带有用户标签)。可选地,在**Configuration 面板的 Parameter Settings 选项卡下,将 I2C 速度模式( I2C Speed Mode )更改为 快速模式( Fast Mode 这些步骤如图5所示。


    5 启用并配置PB8和PB9引脚上的I2C总线。

  3. 从组件列表中选择DCMI 外设。

    1. 在Mode面板中,将DCMI 选项更改为“Slave 8 bits External Synchro”。

    2. 在Configuration面板中,选择 Parameter Settings 选项卡。将 Pixel clock polarity 更改为“Active on Rising Edge”,将Vertical synchronization polarity 更改为“Active High”,并将Horizontal synchronization polarity更改为“Active High”(图6)。


      6 启用并配置数字相机接口(Digital Camera Interface,DCMI)外设以与OV5640图像传感器接口。

    3. 在Configuration面板中,选择NVIC Settings 选项卡并勾选以启用“DCMI/PSSI全局中断(DCMI/PSSI global interrupt)”(图7)。


      7 启用“DCMI/PSSI全局中断(DCMI/PSSI global interrupt)”。

    4. 在Configuration面板中选择GPIO Settings 项卡,并将引脚映射更改为与信号表匹配,如图8所示。最简单的方法在STM32CubeMX用户手册(UM1718)的第4.4.5节中讨论:

      要手动将功能重新映射到另一个引脚,请按照以下步骤操作:

      1. 在Pinout视图中,按住CTRL键,然后左键单击并按住引脚:如果有任何引脚可以重新定位,它们将以蓝色高亮显示并闪烁。

      2. 将功能拖动到目标引脚。


      8 配置DCMI GPIO 设置( GPIO Settings 以匹配相机模块连接器引脚排列(参见UM2839中的表27),

  4. 使用引脚排列视图 (Pinout view) 将引脚PI1设置为GPIO_Input,并将引脚PI2和PI3设置为GPIO_Output,如图9所示。


    9 启用剩余的相机控制信号:PLUG、RSTI和XSDN(参见UM2839中的表27)。

  5. 从组件列表中选择GPIO 外设,并配置PI1、PI2和PI3引脚以匹配图10中所示的信号表。


    10 配置剩余的相机控制信号:PLUG、RSTI和XSDN。

  6. 从组件列表中选择GPDMA1

    1. 模式 (Mode) 面板中,将通道12 - 8 字内部 FIFO / 2D 寻址 (Channel 12 - 8 Words Internal FIFO / 2D addressing) 选项更改为 链表模式 (Linked-List Mode)”

    2. 在配置(Configuration)面板中,选择CH12 选项卡,并将链表选项的执行模式(循环 / 线性) Execution Mode (circular/linear) of the Linked List 设置为“循环(Circular)”(图11)。


      11 :启用 并配置通用DMA 1(GPDMA1)外设的通道12。

    3. 配置 (Configuration) 面板中,选择NVIC 设置 (NVIC Settings) 选项卡 ,并勾选复选框以启用“GPDMA1 通道 12 全局中断 (GPDMA1 Channel 12 global interrupt) ”(图12)。


      12 启用“GPDMA1 通道 12 全局中断 (GPDMA1 Channel 12 global interrupt) ”。

  7. 从组件列表中选择LINKEDLIST

    1. 点击添加列表按钮 (Add List) ,然后选择“YourQueueName”列表。按照图13中的高亮部分配置列表。


      13 :配置 GPDMA链表队列。

    2. 选择“YourNodeName”节点,并按照图14中的高亮部分配置节点。


      14 配置GPDMA链表的第一个节点。

    3. 点击添加节点按钮,并选择“YourNodeName”节点。按照与DCMINode1相同的方式配置节点,但使用“DCMINode2”作为节点名称(图15)。


      15 添加并配置GPDMA链表的第二个节点。

  8. 选择项目管理器(Project Manager) 选项卡,并切换到代码生成器( Code Generator ) 选项。勾选“为每个外设生成一对 ‘.c/.h’ 文件 (Generate peripheral initialization as a pair of ‘.c/.h’ files per peripheral) ”旁边的复选框。如图16所示。


    16 更改代码生成设置,为每个外设生成一对‘.c/.h’文件。

  9. 保存 *.ioc 文件(文件 (File ) > 保存 (Save) )。当提示“您要生成代码吗? (Do you want to generate Code?) ”,点击

步骤 3 :初始化链表

尽管我们在步骤 2(g) 中配置了链表,但并非所有初始化代码都会在保存 .ioc 文件时自动生成。链表队列仍然需要通过将以下代码片段添加到 main.c 文件来与 GPDMA 的通道 12 关联。

  1. 在e main.c 文件中,将指令 #include "linked_list.h" 添加到 USER CODE Includes 部分。

  2. USER CODE PV 部分,添加以下代码行:

    extern DMA_QListTypeDef DCMIQueue;
    
  3. USER CODE 2 部分,添加以下代码行:

    MX_DCMIQueue_Config();
    HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel12, &DCMIQueue);
    __HAL_LINKDMA(&hdcmi, DMA_Handle, handle_GPDMA1_Channel12);
    

    这些子步骤总结在图 17 中。此时,项目应该可以成功构建。


    17 main.c 文件所做的更改,以将先前配置的“DCMIQueue”与 GPDMA1 的通道 12 关联。

步骤 4 :添加摄像头驱动程序

  1. 首先,必须获取/定位 OV5640 驱动程序。它包含在 STM32CubeU5 MCU 包中,也可以从 stm32-ov5640 GitHub 库获取。然而,因为我们使用 STM32CubeIDE 创建了项目,STM32CubeU5 MCU 包已自动下载并保存到本地 STM32Cube 库。如果不确定本地库在机器上的位置,只需选择窗口 > 首选项( Window > Preferences ,然后从STM32Cube 类别中选择固件更新程序(Firmware Updater)。固件安装库路径将如图 18 所示列出。我们将在下面的步骤 4(d) 中使用此位置。


    18 :确定本地 STM32Cube 库的位置。

  2. 项目资源管理器( Project Explorer 中,右键单击 Drivers 目录并选择导入( Import )… (图 19)。


    19 将资源导入 Drivers 目录。

  3. 从常规类别中,选择文件系统( File System )(图 20)。点击 下一步 >


    20 选择文件系统( File System 作为要导入的资源。

  4. 导航到 STM32CubeU5 MCU 包的 Drivers 目录(位于上面的步骤 4(a) 中)。通过勾选旁边的复选框选择ov5640驱动程序(参见图21)。点击完成


    21 从STM32CubeU5 MCU包组件驱动程序中选择ov5640驱动程序目录。

  5. 当新头文件添加到项目中时,包含它们的文件夹路径必须在包含路径列表中,以确保编译器能够找到它们。在项目资源管理器中,右键单击刚刚添加的ov5640目录,并选择添加 / 删除包含路径 (图22)。当出现 选择要修改的配置( Select configurations to modify 对话框时,确保“Debug”和“Release”选项旁边的复选框都被勾选,然后点击确定


    22 将新导入的包含ov5640驱动程序文件的目录添加到包含路径列表中。

步骤 5 :添加 BSP 驱动程序

  1. 下载精简的B-U585I-IOT02A BSP文件库的内容,并将B-U585I-IOT02A目录复制到 <project_name>/Drivers/BSP 目录中。

  2. 类似于步骤4(e),将此新目录添加到包含路径列表中。即,在项目资源管理器( Project Explorer 中右键单击B-U585I-IOT02A目录,并选择添加 / 删除包含路径( Add/remove include paths )…。然后点击确定。此时,项目应包含图23中显示的驱动程序文件。


    23 按照步骤4和5添加驱动程序文件后,项目子结构的结果。

  3. 最后在 main.c 文件中,将指令 #include "b_u585i_iot02a_camera.h" 添加到 USER CODE Includes 部分。

    示例用法

    按照上述步骤配置/初始化STM32U5、添加图像传感器驱动程序并包含BSP抽象层后,可以轻松从连接的摄像头模块子板捕获图像。作为一个示例,以下代码初始化摄像头,捕获640x480大小的图像,并将其保存到位于SRAM中的数据缓冲区中。由于B-U585I-IOT02A不包含显示器,下一节提供了从SRAM读取图像并在PC上查看的几种可能方法之一。

    1. 在STM32CubeIDE中打开 main.c 文件。在 USER CODE PV 部分,添加以下代码行:

      uint32_t CameraBuf[640*480/2];
      volatile uint8_t frameFlag;
      
    2. USER CODE 0 部分,添加以下代码行:

      void BSP_CAMERA_FrameEventCallback(uint32_t Instance)
      {
        frameFlag = 1;
      }
      
    3. USER CODE 2 部分,添加以下代码行:

      // Start w/ LEDs off
      HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_SET);
      HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_SET);
      
      // Initialize camera
      if (BSP_CAMERA_Init(0, CAMERA_R640x480, CAMERA_PF_RGB565) != BSP_ERROR_NONE)
      {
        HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, GPIO_PIN_RESET);
      }
      else
      {
        HAL_Delay(1000); // give the camera time to return good images
      
        // Take snapshot
        frameFlag = 0;
        BSP_CAMERA_Start(0, (uint8_t *)CameraBuf, CAMERA_MODE_SNAPSHOT);
        while (frameFlag == 0);
        HAL_GPIO_WritePin(LED_GREEN_GPIO_Port, LED_GREEN_Pin, GPIO_PIN_RESET);
      }
      

    项目应成功构建(项目 > 构建项目( Project > Build Project )。请注意,RAM使用率相当高,因为我们存储的是原始RGB565图像,每个像素需要2字节的存储空间。因此,640x480像素需要600 KiB的内存(在768 KiB的可用SRAM中)。

    查看捕获的图像

    在不安装额外软件和/或编写额外代码的情况下,从设备内存中读取数据的最直接方法是使用STM32CubeIDE调试工具。

    1. 将MB1379摄像头模块插入B-U585I-IOT02A探索板的CN7摄像头连接器。将USB线缆连接在PC和探索板的CN8 ST-LINK USB连接器之间。

    2. 调试STM32CubeIDE项目(即,运行 > 调试( Run > Debug )。如果这是首次启动应用程序,应会出现 编辑启动配置属性( Edit launch configuration properties 对话框。如果出现,只需点击 “确定”

    3. 一旦应用程序加载完毕且调试会话开始,程序应在 main() 函数的开头暂停。通过选择运行 > 恢复继续( Run > Resume 执行程序。

    4. 当B-U585I-IOT02A上的绿色用户LED(LD7)亮起时,图像捕获完成。通过选择运行 > 暂停( Run > Suspend 来暂停调试会话。

    5. 如图24所示,打开内存(Memory)视图 (窗口>显示视图>内存((Window > Show View > Memory) ),并点击绿色加号以添加要监视的新地址。在出现的对话框中,在文本字段中输入“CameraBuf”并点击“ 确定 ”。


      24 在正在进行的调试会话中,在内存视图中创建内存监视器。

    6. 点击内存视图中的导出图标。在出现的“ 导出内存( Export Memory ”对话框中,将格式选项更改为“RAW 二进制( RAW Binary ”。对于长度选项,输入CameraBuf数组的长度。回想一下,我们将CameraBuf定义为 uint32_t CameraBuf[640*480/2];。因此,

      \textrm{Length} = \frac{640 \cdot 480}{2} \cdot 4

      文件名( File name 段中填写输出文件的路径。点击 确定 ”(图25)。


      25 将包含捕获图像的SRAM部分导出到本地文件。

    7. 要将原始的RGB565图像转换为可用格式,可以使用流行的ffmpeg工具。下面还提供了使用GIMP的替代解决方案。假设它已安装在您的系统上,打开您首选的终端应用程序,并使用以下命令使用ffmpeg将RGB565图像转换为PNG图像。输出应如图26所示。

      ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb565 -s 640x480 -i <input_file> -f image2 -vcodec png <output_file>
      


      26 使用ffmpeg将原始RGB565图像转换为PNG格式。

      OV5640捕获的转换图像如下所示,如图27所示。


      27 使用B-U585I-IOT02A发现板上的MB1379摄像头模块捕获的示例图像。

    8. 作为ffmpeg方法的替代方案,可以使用GNU图像处理程序(GIMP)来查看和操作导出的原始RGB565图像。只需将图像保存为.data扩展名(参见上面的图25)并使用GIMP打开它。应该会出现一个如图28所示的对话框。修改图像设置,如图所示,然后单击 打开


      28 使用GIMP打开原始RGB565图像进行查看/操作。