#include <stdbool.h>
#include <stdio.h>
#include <assert.h>
#include "rtdbg.h"
#include "adc_sample.h"
#include "main.h"
/* 设置数据缓存大小,当SAADC采样完此大小数据时产生一次采样完成事件,采样过程中不需要CPU参与(所有通道均采集完成) */
#define SAMPLE_IN_BUFFER (ADC_CHANNEL_NUMS * 1) //数据缓存大小
static int16_t adc_buffer[SAMPLE_IN_BUFFER]; //数据缓存地址
static adc_sample_t adc_sample = {RT_NULL};
static saadc_cplt_cb_t saadc_callback_list[ADC_CHANNEL_NUMS] = {NULL};
static bool m_status = false;
static bool m_int_status = false;
DMA_HandleTypeDef hdma_adc3;
#if 1
TIM_HandleTypeDef htim3;
ADC_HandleTypeDef hadc3;
/****************** weak callback ******************/
void DMA2_Stream0_IRQHandler(void)
{
if(m_int_status == true) return;
HAL_ADC_Stop_DMA(&hadc3);
for(int i = 0; i < ADC_CHANNEL_NUMS; i++)
{
if(saadc_callback_list[i] != NULL)
{
float sample_value = adc_buffer[i] * 3.3 / 4096;
saadc_callback_list[i](sample_value);
//LOG_D("p_buffer[%d] :%f", i, sample_value);
}
}
HAL_DMA_IRQHandler(&hdma_adc3);
HAL_ADC_Start_DMA(&hadc3, (uint32_t*)adc_buffer, sizeof(adc_buffer));
m_int_status = false;
}
void TIM3_IRQHandler(void)
{
HAL_TIM_IRQHandler(&htim3);
}
/* 定时器3初始化 */
static uint8_t MX_TIM3_Init(void)
{
uint8_t err_ret = RT_ERROR;
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim3.Instance = TIM3;
htim3.Init.Prescaler = 8400;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 10 * SAMPLE_TIME_INTERVAL; //设置采样周期
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
do{
if (HAL_TIM_Base_Init(&htim3) != HAL_OK) break;
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK) break;
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) break;
err_ret = RT_EOK;
LOG_D("MX_TIM3_Init success!");
}while(0);
return err_ret;
}
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
LOG_D("MX_DMA_Init success!");
}
static void MX_DMA_DeInit(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_DISABLE();
/* DMA interrupt init */
/* DMA2_Stream0_IRQn interrupt configuration */
HAL_NVIC_DisableIRQ(DMA2_Stream0_IRQn);
LOG_D("MX_DMA_DeInit success!");
}
/**
* @brief ADC3 Initialization Function
* @param None
* @retval None
*/
static uint8_t MX_ADC3_Init(void)
{
uint8_t err_ret = RT_ERROR;
ADC_ChannelConfTypeDef sConfig = {0};
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */
hadc3.Instance = ADC3;
hadc3.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc3.Init.Resolution = ADC_RESOLUTION_12B;
hadc3.Init.ScanConvMode = ENABLE;
hadc3.Init.ContinuousConvMode = DISABLE;
hadc3.Init.DiscontinuousConvMode = DISABLE;
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO;
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc3.Init.NbrOfConversion = ADC_CHANNEL_NUMS;
hadc3.Init.DMAContinuousRequests = ENABLE;
hadc3.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
do
{
if (HAL_ADC_Init(&hadc3) != HAL_OK) break;
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.*/
sConfig.Channel = ADC_CHANNEL_3;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK) break;
/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time. */
sConfig.Channel = ADC_CHANNEL_6;
sConfig.Rank = 2;
if (HAL_ADC_ConfigChannel(&hadc3, &sConfig) != HAL_OK) break;
err_ret = RT_EOK;
LOG_D("MX_ADC3_Init success!");
}while(0);
return err_ret;
}
static void saadc_sample_start(void)
{
do{
if (HAL_ADC_Start_DMA(&hadc3, (uint32_t*)adc_buffer, sizeof(adc_buffer)) != HAL_OK) {
LOG_D("HAL_ADC_Start_DMA error!");
break;
}
if (HAL_TIM_Base_Start_IT(&htim3) != HAL_OK) {
LOG_D("HAL_TIM_Base_Start_IT error!");
break;
}
m_int_status = false;
}while(0);
}
static void saadc_init(void)
{
MX_TIM3_Init();
MX_DMA_Init();
MX_ADC3_Init();
}
static void saadc_unint(void)
{
HAL_TIM_Base_Stop_IT(&htim3); //关闭采集定时器
HAL_ADC_Stop_DMA(&hadc3); //关闭ADC DMA采集
/* 初始化定时器为默认配置 */
HAL_TIM_Base_DeInit(&htim3);
/* 初始化DMA为默认配置 */
MX_DMA_DeInit();
/* 初始化SAADC为默认配置 */
HAL_ADC_DeInit(&hadc3);
}
#endif
static void saadc_sample(uint8_t channel, saadc_cplt_cb_t callback)
{
int i = 1;
i = i;
//assert(channel < ADC_CHANNEL_NUMS);
saadc_callback_list[channel] = callback;
if(m_status == true) return;
saadc_init();
saadc_sample_start();
m_status = true;
LOG_D("saadc_sample is ernter!");
}
static void saadc_sample_cplt(uint8_t channel)
{
assert(channel < ADC_CHANNEL_NUMS);
saadc_callback_list[channel] = NULL;
int idx = 0;
for(; idx < ADC_CHANNEL_NUMS; idx++)
if(saadc_callback_list[idx] != NULL) break;
if(m_status == false || idx < ADC_CHANNEL_NUMS) return;
saadc_unint();
m_status = false;
LOG_D("saadc_sample_cplt is ernter!");
}
static int adc_sample_init(void)
{
assert(ADC_CHANNEL_NUMS < 8);
adc_sample.sample = saadc_sample;
adc_sample.sample_cplt = saadc_sample_cplt;
return 0;
}
INIT_PREV_EXPORT(adc_sample_init);
adc_sample_t* adc_sample_get(void)
{
return &adc_sample;
}
问 在stm32中移植了ADC+DMA+TIM周期采集电池电压,第二次调用会出现IBUSERR的段错误