如何使用ADC 能找到一些例程。但是ADC是怎么控制采样速度的。
有两种AD的采样模式:阻塞(blocking mode)和非阻塞(no-blocking mode)
阻塞模式:
调用函数:nrf_drv_saadc_sample_convert完成采样。采样完成后return采样值。
非阻塞模式:
此模式触发方式有两种CPU显式触发或使用PPI。
1.CPU显式调用函数nrf_drv_saadc_sample实现触发。触发后会调用ADC初始化时写入的回调函数。
2.使用PPI,调用函数nrf_drv_saadc_sample_task_get();实现触发。触发后会调用ADC的初始化时写入的回调函数。
非阻塞模式在触发前都需要调用函数nrf_drv_saadc_buffer_convert(buffer, 1);。这个函数是告诉AD库,采样到的数据保存在buffer变量。采样的次数为1.(次数可以设置多次)
官方此处对两种模式做了介绍,可以查看下
官方AD模式–阻塞与非阻塞介绍
===================================== 分割线 ====================================
如下我对使用PPI模式下的代码做详细解析:
PPI是NORDIC的一个外设。有点像DMA。其会自动将外设数据在没有CPU参与的情况下。将数据存入内存的指定地址。
代码参考是的SDK 外设的SAADC的例程。
nRF5_SDK_15.2.0_9412b96\examples\peripheral\saadc
例程将AD的初始化放到如下三个自定义函数里面
1.通道和缓冲区初始化
//AD初始化
void saadc_init(void)
{
ret_code_t err_code;
nrf_saadc_channel_config_t channel_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0); //定义引脚通道初始化参数结构体。
err_code = nrf_drv_saadc_init(NULL, saadc_callback); //初始化ad的回调函数,完成采样周期后,调用saadc_callback
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(0, &channel_config);//AD引脚通道的初始化。使用默认参数初始化AIN0。
APP_ERROR_CHECK(err_code);
//设置AD的缓冲区。调用两次nrf_drv_saadc_buffer_convert是为了实现双缓冲。其传入的内存首地址是不一样的。
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code); //m_buffer_pool是一个二维数组
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
}
2.采样事件的设置
//采样事件的设置
void saadc_sampling_event_init(void)
{
ret_code_t err_code;
err_code = nrf_drv_ppi_init(); //初始化PPI
APP_ERROR_CHECK(err_code);
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler); //初始化一个定时器
APP_ERROR_CHECK(err_code);
/* setup m_timer for compare event every 400ms */
uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);
nrf_drv_timer_extended_compare(&m_timer,
NRF_TIMER_CC_CHANNEL0,
ticks,
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
false);
nrf_drv_timer_enable(&m_timer); //定时器启动。定时器周期为400MS
uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
NRF_TIMER_CC_CHANNEL0);
uint32_t saadc_sample_task_addr = nrf_drv_saadc_sample_task_get(); //开始启动sample
/* setup ppi channel so that timer compare event is triggering sample task in SAADC */
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);//设置PPI
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
timer_compare_event_addr,
saadc_sample_task_addr); //ppi通道将AD的事件和定时器事件联合
APP_ERROR_CHECK(err_code);
}
3.使能PPI
涉及到采样速度的地方
1.ADC初始化的时候,需要设置模数转换采集时间。就是芯片引脚到外设产生采集需要10us的时间。
2.触发时间。如上例中400ms产生一次触发。那么根据上例的配置。缓冲区是5.那么完整的采集周期就是5*400ms=2000ms=2s。那么每2s就会调用一次saadc_callback函数。
3.AD的最大的速度。受制硬件的AD转换速率。