如何在nRF52840-DK上配置HM01B0图像传感器并读取帧?
HM01B0与nRF52840-DK裸机图像捕获解决方案
核心问题分析
你当前的GPIO轮询方案无法工作,核心原因是36MHz的PCLK频率远超GPIO软件轮询的响应能力,导致无法同步采样到D0引脚的有效数据,所以一直读到0x00。结合你已实现I2C寄存器读写、逻辑分析仪能看到D0数据的前提,需要通过传感器寄存器配置+硬件外设同步采样来解决。
一、先完成HM01B0的1位模式寄存器配置
必须通过I2C写入寄存器,确保传感器工作在1位数据输出模式:
- 找到数据接口配置寄存器(参考HM01B0 datasheet,例如地址
0x0100),写入对应值启用1位输出(禁用D1-D3) - 确认PCLK频率配置为36MHz,帧率30FPS,同时匹配VSYNC/HSYNC的极性(高/低电平有效)
- 示例代码(需根据实际寄存器地址调整):
void hm01b0_set_1bit_mode(void) { // 假设0x24是传感器I2C地址,0x0100是接口配置寄存器 i2c_write_reg(0x24, 0x0100, 0x00); // 配置为1位输出模式 // 配置PCLK为36MHz(寄存器地址和值需查官方手册) i2c_write_reg(0x24, 0x0102, 0x01); }
二、nRF52840硬件采样方案(二选一)
方案1:SPIM从机模式(推荐,适配SPI时序)
将HM01B0作为SPIM主机,nRF52840作为从机,利用硬件同步采样:
- 引脚映射:
- HM01B0 PCLK → nRF52840 SPIM SCK
- HM01B0 D0 → nRF52840 SPIM MOSI
- VSYNC/HSYNC保留为GPIO,用中断标记帧/行起始
- 配置要点:
- SPIM模式设为
NRF_SPIM_MODE_0(上升沿采样,匹配PCLK时序) - 启用DMA传输,直接将数据写入帧缓冲区,避免CPU干预
- 用VSYNC中断触发帧捕获,HSYNC中断切换行缓冲区
- SPIM模式设为
SPIM从机配置代码示例
#define SPIM_INSTANCE 0 static nrf_drv_spim_t m_spim = NRF_DRV_SPIM_INSTANCE(SPIM_INSTANCE); static volatile bool m_rx_ready = false; // SPIM事件回调 void spim_event_handler(nrf_drv_spim_evt_t const* p_event, void* p_context) { if (p_event->type == NRF_DRV_SPIM_EVT_RX_DONE) { m_rx_ready = true; } } // 初始化SPIM从机 void spim_slave_init(void) { nrf_drv_spim_config_t spim_cfg = NRF_DRV_SPIM_DEFAULT_CONFIG; spim_cfg.sck_pin = PIN_PCLK; spim_cfg.mosi_pin = PIN_D0; spim_cfg.mode = NRF_SPIM_MODE_0; spim_cfg.bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST; // 匹配传感器数据位序 spim_cfg.role = NRF_SPIM_ROLE_SLAVE; ret_code_t err = nrf_drv_spim_init(&m_spim, &spim_cfg, spim_event_handler, NULL); APP_ERROR_CHECK(err); nrf_drv_spim_enable(&m_spim); }
方案2:GPIOTE + PPI + DMA(灵活同步采样)
利用nRF52840的硬件联动,无需SPI外设:
- GPIOTE配置PCLK为上升沿触发事件
- PPI将PCLK事件链接到GPIOTE读取D0的任务,同时触发DMA写入缓冲区
- VSYNC/HSYNC中断控制DMA的启动/停止,以及行/帧计数
三、帧捕获逻辑修正(替换GPIO轮询)
改用中断触发+DMA传输,避免CPU轮询:
uint8_t frameBuffer[324][324]; static volatile uint32_t current_row = 0; // VSYNC中断:帧起始 void vsync_irq_handler(void) { nrf_gpio_pin_clear_int(PIN_VSYNC); current_row = 0; // 启动第一行数据接收 m_rx_ready = false; nrf_drv_spim_rx(&m_spim, frameBuffer[current_row], 324); } // HSYNC中断:行切换 void hsync_irq_handler(void) { nrf_gpio_pin_clear_int(PIN_HSYNC); if (current_row >= 323) return; current_row++; m_rx_ready = false; nrf_drv_spim_rx(&m_spim, frameBuffer[current_row], 324); } // 初始化GPIO中断 void gpio_irq_init(void) { // VSYNC上升沿中断 nrf_gpio_cfg_input(PIN_VSYNC, NRF_GPIO_PIN_NOPULL); nrf_gpio_cfg_sense_input(PIN_VSYNC, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH); // HSYNC上升沿中断 nrf_gpio_cfg_input(PIN_HSYNC, NRF_GPIO_PIN_NOPULL); nrf_gpio_cfg_sense_input(PIN_HSYNC, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_SENSE_HIGH); nrf_gpio_pin_clear_int(PIN_VSYNC); nrf_gpio_pin_clear_int(PIN_HSYNC); NVIC_EnableIRQ(GPIOTE_IRQn); }
四、关键排查点
- 寄存器配置验证:用I2C读取配置寄存器,确认传感器确实工作在1位模式
- 时序匹配:确保SPIM的时钟相位/极性和HM01B0的PCLK时序完全一致
- 中断极性:检查VSYNC/HSYNC的有效电平是否与代码配置匹配(比如是高电平还是低电平有效)
- DMA缓冲区:确保帧缓冲区大小足够,且内存对齐符合DMA要求
内容的提问来源于stack exchange,提问作者shakingwindow
相关产品推荐
相关产品推荐

