一. 测试平台
环境:win10,64位,MDK集成开发环境.
SDK:nRF5_SDK_15.2
协议栈:s132_nrf52_6.1_softdevice.hex.
硬件平台:pca10040开发板
参考例程:nRF5_SDK_15.2.0_9412b96\examples\peripheral\saadc
ADC的最快采样时间为5us采样一个点,如果为两通道扫描采样的话,最快为10us采样一次
二. Application移植
1. 添加相关头文件
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
2. SAADC的工作模式
(1). 单次采样模式
SAADC初始化
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
//
}
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_AIN1);
err_code = nrf_drv_saadc_init(NULL, saadc_callback);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(0, &channel_config);
APP_ERROR_CHECK(err_code);
}
启动一次ADC采样,获取ADC值
nrf_drv_saadc_sample_convert(0,&saadc_val);
(2).单缓冲中断模式
SAADC初始化,相关中断函数
#define SAMPLES_IN_BUFFER 6
static nrf_saadc_value_t m_buffer_pool[SAMPLES_IN_BUFFER];
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{ float val;
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
ret_code_t err_code;
//设置好缓存,为下次转换预备缓冲
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
int i;
for (i = 0; i < p_event->data.done.size; i++)
{
val = p_event->data.done.p_buffer[i] * 3.6 /1024;
printf("Voltage = %.3fV\r\n", val);
}
}
}
void saadc_init(void)
{
ret_code_t err_code;
nrf_saadc_channel_config_t channel_0_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);
err_code = nrf_drv_saadc_init(NULL, saadc_callback);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool,SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
}
启动一次ADC采样,要采样次数等于SAMPLES_IN_BUFFER时,才会进入中断
nrf_drv_saadc_sample();
(3).双缓冲PPI采样
用PPI的方式去触发SAADC,工作方式如下所示:
所以相对之前的初始化会复杂一点,需要初始化定时器,设置采样时间(这个采样时间是采样一个点的时间,如果采样时间设置为400ms,采集5个点,则全部的采样时间为400*5=2s。如果为两个通道,则400ms取两个点,取五次),设置PPI通道,初始化SAADC
#define SAMPLES_IN_BUFFER 5
static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
static nrf_saadc_value_t m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t m_ppi_channel;
void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
}
void saadc_sampling_event_init(void)
{
ret_code_t err_code;
err_code = nrf_drv_ppi_init();
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);
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();
/* setup ppi channel so that timer compare event is triggering sample task in SAADC */
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
timer_compare_event_addr,
saadc_sample_task_addr);
APP_ERROR_CHECK(err_code);
}
void saadc_sampling_event_enable(void)
{
ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
APP_ERROR_CHECK(err_code);
}
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
ret_code_t err_code;
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
int i;
for (i = 0; i < SAMPLES_IN_BUFFER; i++)
{
NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
}
}
}
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);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(0, &channel_config);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
}
启动ADC,值需要初始化ADC即可,数据会不停的缓冲在easydma中,每次数据需要及时读取,不然会被覆盖掉。
saadc_init();
saadc_sampling_event_init();
saadc_sampling_event_enable();
防止数据覆盖的方式:
①采样完之后,在ADC中断函数中关掉定时器,等数据处理完再开启定时器,可以用下面两条语句
nrf_drv_timer_disable(&m_timer);
nrf_drv_timer_enable(&m_timer);
② 同时将ADC,PPI,TIMER都关掉,可以有效降低功耗
启动ADC
void ADC_PWM_START(void)
{
nrf_saadc_enable();
nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
nrf_drv_timer_enable(&m_timer);
}
关闭ADC,需要将相关标志位清楚,不然会导致错误
void ADC_PWM_STOP(void)
{
nrf_drv_timer_disable(&m_timer);
nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
nrf_saadc_disable();
}
(4)采样数据的存放方式
在模式2和3中,如果是多通道的话,数据将会交替存放,如下所示:
假设采集数据为3,通道为2