nRF52840 ADC校准

ADC具有温度相关偏移量,如果ADC要运行在较大的温度范围内,则开启校准会校准结果更加准确

校准方法:定期运行CALIBRATEOFFSET,硬件会自动进行校准

1 nordic提供的底层函数:

ret_code_t nrf_drv_saadc_calibrate_offset()
{
    ASSERT(m_cb.state != NRF_DRV_STATE_UNINITIALIZED);

    ret_code_t err_code;

    if (m_cb.adc_state != NRF_SAADC_STATE_IDLE)
    {
        err_code = NRF_ERROR_BUSY;
        NRF_LOG_WARNING("Function: %s, error code: %s.", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }
    //将ADC的状态设置为校准
    m_cb.adc_state = NRF_SAADC_STATE_CALIBRATION;

    nrf_saadc_event_clear(NRF_SAADC_EVENT_CALIBRATEDONE);//清除CALIBRATEDONE事件(寄存器写入0)

    nrf_saadc_int_enable(NRF_SAADC_INT_CALIBRATEDONE); //使能CALIBRATEDONE 事件中断(寄存器写入1)
    nrf_saadc_task_trigger(NRF_SAADC_TASK_CALIBRATEOFFSET);//触发校准task(寄存器写入1)
    err_code = NRF_SUCCESS;
    NRF_LOG_INFO("Function: %s, error code: %s.", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}m_cb.adc_state = NRF_SAADC_STATE_CALIBRATION;

    nrf_saadc_event_clear(NRF_SAADC_EVENT_CALIBRATEDONE);//清除CALIBRATEDONE事件(寄存器写入0)

    nrf_saadc_int_enable(NRF_SAADC_INT_CALIBRATEDONE); //使能CALIBRATEDONE 事件中断(寄存器写入1)
    nrf_saadc_task_trigger(NRF_SAADC_TASK_CALIBRATEOFFSET);//触发校准task(寄存器写入1)
    err_code = NRF_SUCCESS;
    NRF_LOG_INFO("Function: %s, error code: %s.", (uint32_t)__func__, (uint32_t)NRF_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}

其中:ADC 状态有以下三种

typedef enum
{
    NRF_SAADC_STATE_IDLE        = 0,(空闲)
    NRF_SAADC_STATE_BUSY        = 1,(在进行ADC采集)
    NRF_SAADC_STATE_CALIBRATION = 2 (ADC校准)
} nrf_saadc_state_t;
/**
 * @brief Function for triggering a specific SAADC task.
 *
 * @param[in] saadc_task SAADC task.
 */
__STATIC_INLINE void nrf_saadc_task_trigger(nrf_saadc_task_t saadc_task)
{
    *((volatile uint32_t *)((uint8_t *)NRF_SAADC + (uint32_t)saadc_task)) = 0x1UL;
}0x1UL;
}
#define NRF_SAADC                       ((NRF_SAADC_Type          *) NRF_SAADC_BASE)
#define NRF_SAADC_BASE                  0x40007000UL

 

2 上层调用:周期性调用nrf_drv_saadc_calibrate_offset()来启动ADC校准

 

1)温度采集线程中每2s进行一次校准,其他时间则是进行ADC数据采集及转换

void camera_temp_common_thread_main(const void *arg)
{
    uint32_t calibration_counter = 0;
    while (true) { //每2s校准一次
        if ((calibration_counter++ % CALIBRATION_INTERVAL) == 0) {
            camera_temp_calibrate();
        }
       //获取camera温度
        for (int i = 0; i < CAMERA_NUM_SENSORS; ++i) {
            const int32_t temp = camera_temp_read(i);
            __atomic_store_n(&m_cached_temps[i], temp, __ATOMIC_RELAXED);
        }
        osDelay(TEMP_UPDATE_INTERVAL_MS);
    }
}

其中:

#define TEMP_UPDATE_INTERVAL_MS         100

#define CALIBRATION_INTERVAL            20

2)校准函数调用实现

先调用底层函数nrf_drv_saadc_calibrate_offset()启动校准,然后等待校准完成,

通过判断ADC状态是否为IDLE来确定校准是否完成

void camera_temp_calibrate(void)
{
    adc_calibrate();
}
void adc_calibrate(void)
{
    UHAL_ASSERT(m_periph_init, "ADC not initialized");
    UHAL_ASSERT(nrf_drv_saadc_calibrate_offset() == NRF_SUCCESS, "Failed to start calibration");
    while (nrf_drv_saadc_is_busy());   //等待校准完成
}
;   //等待校准完成
}
bool nrf_drv_saadc_is_busy(void)
{
    return (m_cb.adc_state != NRF_SAADC_STATE_IDLE);
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值