You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于nRF52840-DK通过SPIM读取Arducam测试寄存器值异常排查

问题描述

我采用裸机编程方式,将Arducam Mini 2MP Plus通过SPIM接口连接至nRF52840-DK开发板。根据Arducam datasheet,其SPI从机接口固定为SPI模式0(POL=0、PHA=1),SCLK最高速率8MHz,读写周期内需保持CSn有效,命令字节最高位为读写位(0读1写),低7位为寄存器地址。写入时为命令+数据字节,读取时为命令+哑字节,从MISO获取寄存器值。测试寄存器地址为0x00,我编写代码向其写入0x55后尝试读回,但得到的是0x52、0x1c等错误值而非0x55。已用逻辑分析仪验证nRF52840-DK的SPIM接口功能正常,请问我遗漏了什么或操作有误?

代码实现
#include<stdint.h>
#include "nrf52840.h"
#include "nrf52840_bitfields.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"


int spi_init(unsigned int pin_cs, unsigned int pin_mosi, unsigned int pin_miso,unsigned int pin_clk)
{
    NRF_SPIM3->PSEL.CSN = pin_cs;
    NRF_SPIM3->PSEL.SCK = pin_clk;
    NRF_SPIM3->PSEL.MOSI = pin_mosi;
    NRF_SPIM3->PSEL.MISO = pin_miso;

    /* Change the SPI mode here */
    NRF_SPIM3->CONFIG = (SPIM_CONFIG_CPHA_Leading << SPIM_CONFIG_CPHA_Pos) |
    (SPIM_CONFIG_CPOL_ActiveHigh << SPIM_CONFIG_CPOL_Pos) |
    (SPIM_CONFIG_ORDER_MsbFirst << SPIM_CONFIG_ORDER_Pos);

    /* Change the frequency here */
    NRF_SPIM3->FREQUENCY = SPIM_FREQUENCY_FREQUENCY_M4;

    NRF_SPIM3->ENABLE = (SPIM_ENABLE_ENABLE_Enabled << SPIM_ENABLE_ENABLE_Pos);

    return 0;
}

int spi_read(uint8_t address)
{
    uint8_t tx_buf[2];
    tx_buf[0] = address;
    tx_buf[1] = 0; // dummy byte

    uint8_t rx_buf[2] ;
    rx_buf[0] = 0;
    rx_buf[1] = 0; // dummy byte

    /* The SPI transaction will last for max(n_tx, n_rx) bytes */
    NRF_SPIM3->TXD.MAXCNT = 2;
    NRF_SPIM3->RXD.MAXCNT = 2;

    NRF_SPIM3->TXD.PTR = (uint32_t)tx_buf;
    NRF_SPIM3->RXD.PTR = (uint32_t)rx_buf;
    NRF_SPIM3->EVENTS_END = 0;
    
    /* Start the transaction */
    NRF_SPIM3->TASKS_START = 1;
    /* Busy wait until it has finished */
    while (NRF_SPIM3->EVENTS_END == 0) {
    };

    NRF_SPIM3->EVENTS_END = 0;
    return rx_buf[1];
}

int spi_write(uint8_t address, uint8_t value)
{
    
    static uint8_t tx_buf[2];
    tx_buf[0] = address;
    tx_buf[1] = value;

    /* The SPI transaction will last for max(n_tx, n_rx) bytes */
    NRF_SPIM3->TXD.MAXCNT = 2;
    NRF_SPIM3->RXD.MAXCNT = 0;

    NRF_SPIM3->TXD.PTR = (uint32_t)tx_buf;
    NRF_SPIM3->RXD.PTR = (uint32_t)0;
    NRF_SPIM3->EVENTS_END = 0;

    
    /* Start the transaction */
    NRF_SPIM3->TASKS_START = 1;
    /* Busy wait until it has finished */
    while (NRF_SPIM3->EVENTS_END == 0) {
    };

    NRF_SPIM3->EVENTS_END = 0;
    return 0;
}

int main(void)
{
    spi_init(31, 30, 29, 28);
    int data = 0xff;
    while(1){
        // spi_testing 
        spi_write(0x00 | 0x80,0x55);
        data = spi_read(0x00 & 0x7F);
        if(data == 0x55){
            // SPIM is working 
        }
        nrf_delay_ms(1000);
    }
}
排查与解决建议
  • SPI模式配置错误:Arducam要求的是SPI模式0(POL=0、PHA=1),对应nRF52840 SPIM的配置应该是SPIM_CONFIG_CPHA_Trailing(PHA=1,时钟后沿采样),但当前代码中用的是SPIM_CONFIG_CPHA_Leading(PHA=0,前沿采样),这会导致数据采样时序不匹配,是核心问题。修改CONFIG行:

    NRF_SPIM3->CONFIG = (SPIM_CONFIG_CPHA_Trailing << SPIM_CONFIG_CPHA_Pos) |
    (SPIM_CONFIG_CPOL_ActiveHigh << SPIM_CONFIG_CPOL_Pos) |
    (SPIM_CONFIG_ORDER_MsbFirst << SPIM_CONFIG_ORDER_Pos);
    
  • CSn时序问题:当前使用SPIM自动控制CSn,部分设备对CSn的拉低/拉高时序有严格要求。可以尝试改为手动控制CSn:在spi_init中配置CSn为输出引脚并初始拉高,在spi_write和spi_read函数开头拉低CSn,事务结束后拉高,确保读写操作间的CSn状态符合设备要求。

  • 设备初始化延迟:Arducam上电后需要一定时间稳定,在spi_init后添加nrf_delay_ms(100);等延迟,再执行读写操作。

  • SPI速率确认:当前配置的是4MHz(SPIM_FREQUENCY_FREQUENCY_M4),虽然低于设备最高8MHz,但可以尝试降低速率(比如1MHz)测试是否是速率兼容性问题。

  • RX配置优化:在spi_write函数中,将RXD.MAXCNT设为2并读取返回值,部分设备会在写入时返回状态字节,可用于排查写入是否成功。

内容的提问来源于stack exchange,提问作者shakingwindow

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 22:01:01