Files
CHJ/user/MCU/lhl_adc.c
2026-03-20 21:19:04 +08:00

557 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "../main/SystemInclude.h"
/*初始化内部基准源 */
static void ADC_REF_Init(u8 vref,u8 vdrive)
{
REF_InitTypeDef REF_InitStructure;
REF_InitStructure.VREF = vref; // 内部基准电压
REF_InitStructure.VDRIVE = vdrive;//VDrive输出电压
REF_InitStructure.VREF_Boost = DISABLE;
LHL_REF_Init(&REF_InitStructure);
}
static void ADC_Init(ADC_ID_t ADCx ,u8 SPS ,u8 Gain, u8 PChan, u8 NChan )
{
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.AINP = PChan; // ADC0输入通道
ADC_InitStructure.AINM = NChan;
ADC_InitStructure.PGA = Gain; // 内部PGA增益x1
ADC_InitStructure.FS = SPS; // ADC输出速率
ADC_InitStructure.Code = ADC_CODE_BIPOLAR; // 双极性数据
ADC_InitStructure.Mode = ADC_MODE_CONTINUOUS_CONVERSION; // 连续转换模式
ADC_InitStructure.Trigger = ADC_TRIGGER_SOFTWARE; // 软件触发
ADC_InitStructure.ReferenceSelect = ADC_REF_REFP_to_REFN; // 内部基准
ADC_InitStructure.REF_BUFP = ENABLE; // 使能基准缓冲
ADC_InitStructure.REF_BUFM = ENABLE;
ADC_InitStructure.REF_Precharge= DISABLE;
ADC_InitStructure.Reference = 2500.0f;
LHL_ADC_Init(ADCx, &ADC_InitStructure);
}
static void ADC_SyncInit(u8 SPS ,u8 Gain0, u8 PChan0, u8 NChan0 ,u8 Gain1, u8 PChan1, u8 NChan1 )
{
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.AINP = PChan0; // ADC0输入通道
ADC_InitStructure.AINM = NChan0;
ADC_InitStructure.PGA = Gain0; // 内部PGA增益x1
ADC_InitStructure.FS = SPS; // ADC输出速率
ADC_InitStructure.Code = ADC_CODE_BIPOLAR; // 双极性数据
ADC_InitStructure.Mode = ADC_MODE_CONTINUOUS_CONVERSION; // 连续转换模式
ADC_InitStructure.Trigger = ADC_TRIGGER_SOFTWARE; // 软件触发
ADC_InitStructure.ReferenceSelect = ADC_REF_REFP_to_REFN; // 内部基准
ADC_InitStructure.REF_BUFP = ENABLE; // 使能基准缓冲
ADC_InitStructure.REF_BUFM = ENABLE;
ADC_InitStructure.REF_Precharge= DISABLE;
ADC_InitStructure.Reference = 2500.0f;
LHL_ADC_Init(ADC_0, &ADC_InitStructure);
ADC_InitStructure.AINP = PChan1; // ADC1输入通道
ADC_InitStructure.AINM = NChan1;
ADC_InitStructure.PGA = Gain1; // 内部PGA增益x1
LHL_ADC_Init(ADC_1, &ADC_InitStructure); // 同步模式下ADC1与ADC0配置相同
}
/*********************************************************************************************************************************************/
/*中断方式*/
/*********************************************************************************************************************************************/
//ADC0采样初始化----------------------------------------------------------
void ADC0_Conversion_Init(ADC_Config_TypeDef adc_config)
{
ADC_REF_Init(REF_INTERNAL_2P5V,REF_INTERNAL_2P5V);/* 1. 初始化内部基准源 */
ADC_Init(ADC_0, adc_config.SPS, adc_config.Gain0, adc_config.PChan0, adc_config.NChan0); /* 2. 初始化ADC0 */
}
//ADC1采样初始化----------------------------------------------------------
void ADC1_Conversion_Init(ADC_Config_TypeDef adc_config)
{
ADC_REF_Init(REF_INTERNAL_2P5V,REF_INTERNAL_2P5V);/* 1. 初始化内部基准源 */
ADC_Init(ADC_1, adc_config.SPS, adc_config.Gain1, adc_config.PChan1, adc_config.NChan1); /* 2. 初始化ADC1 */
}
//ADC同步采样初始化----------------------------------------------------------
void ADC0_1_SyncConversion_Init(ADC_Config_TypeDef adc_config)
{
ADC_REF_Init(REF_INTERNAL_2P5V,REF_INTERNAL_2P5V); /* 1. 初始化内部基准源 */
ADC_SyncInit(adc_config.SPS,adc_config.Gain0,adc_config.PChan0,adc_config.NChan0,
adc_config.Gain1,adc_config.PChan1,adc_config.NChan1); /* 2. 初始化ADC0和ADC1 */
/* 3. 使能ADC的同步转换功能
* 进行同步转换需要保证ADC0和ADC1的配置包括输出速率转换模式触发源完全相同。
* ADC_0的启动源软件寄存器或者硬件trigger自动被应用到ADC_1此时两个ADC的启动同时受ADC_0的启动源控制。
*/
LHL_ADC_SetSync(ENABLE);
/* 4. 同步转换仅需开启ADC0的数据Ready中断 */
LHL_ADC_ITConfig(ADC_0, ADC_IT_RDY, ENABLE);
NVIC_EnableIRQ(ADC0_IRQn);
NVIC_SetPriority(ADC0_IRQn, 0);
/* 5. 启动转换仅需开启ADC0 */
LHL_ADC_Start(ADC_0);
}
//ADC 读单次数据24位ADC数据转换成16位并偏移32768
u32 ADC_ReadSampleData(ADC_ID_t ADCx)
{
volatile u32 reg_data = 0;
reg_data = (ADCx == ADC_0) ? LHL_ADC_GetData(ADC_0) : LHL_ADC_GetData(ADC_1);
reg_data = ((((reg_data & 0xFFFFFF) | ((reg_data & 0x800000) ? 0xFF000000 : 0)) >> 8) + 32768) & 0xFFFF;
return reg_data ;
}
////开始转换控制---------------------------------------------------------------
//void StartADCConversion(ADC_ID_t ADCx)
//{
// (ADCx == ADC_0) ? LHL_ADC_Start(ADC_0): LHL_ADC_Start(ADC_1);
//}
//停止转换控制---------------------------------------------------------------
void StopADCConversion(ADC_ID_t ADCx)
{
(ADCx == ADC_0) ? LHL_ADC_Stop(ADC_0): LHL_ADC_Stop(ADC_1);
}
/*********************************************************************************************************************************************/
/*DMA 方式 一种用法是设置ADC后*/
/*********************************************************************************************************************************************/
#define MAX_ADC_COUNT 10
typedef struct {
uint32_t BufferA[MAX_ADC_COUNT];//MAX_ADC_COUNT 每次搬运ADC数量 ADC_SPS_977大概1ms一个总计10ms
uint32_t BufferB[MAX_ADC_COUNT];
} ADC_DATA_t; /* 双缓冲要求ADC缓存为转换次数的2倍 */
ADC_DATA_t adcData0 , adcData1;//
__RW uint8_t adcFlag0 , adcFlag1;//DMA搬运完成标志
//设置准备与开始转换---------------------------------------------------------------
void DMA_ADC0_Conversion_Init(uint8_t Gain0, uint8_t PChan0, uint8_t NChan0)
{
DMA_HandleTypeDef DMA_Handle_ADC0;
/* 1.1 初始化内部基准 */
ADC_REF_Init(REF_INTERNAL_2P5V,REF_INTERNAL_2P5V);
/* 1.2 初始化ADC */
ADC_Init(ADC_0, SPS_977, Gain0, PChan0, NChan0);
/* 1.3 使能ADC0的DMA功能 */
LHL_ADC_DMACmd(ADC_0, ENABLE);
DMA_DMAMUX_CFG(DMA_CHANNEL_2 ,REQUEST_SOURCE_ADC0);
/* 2.2 配置DMA通道0 */
DMA_Handle_ADC0.Channel = DMA_CHANNEL_2;
DMA_Handle_ADC0.Mode = DMA_DIRECT_MODE; // Direct Mode
DMA_Handle_ADC0.Request = DMA_HARDWARE_REQUEST;
DMA_Handle_ADC0.Init.Direction = DMA_PERIPH_TO_MEMORY; // 外设->内存
DMA_Handle_ADC0.Init.Src_Address = (uint32_t)(&ADC->ADC_DATA_0);
DMA_Handle_ADC0.Init.Dest_Address = (uint32_t)&adcData0;
DMA_Handle_ADC0.Init.Data_Width = DMA_DATA_WIDTH_4B;
DMA_Handle_ADC0.Init.Data_Size = 1;
DMA_Handle_ADC0.Init.Repetition = MAX_ADC_COUNT*2; // 双缓冲的大循环采样双倍数据
DMA_Handle_ADC0.Init.Trans_Mode = DMA_CYCLIC_TRANSMISSION; // 循环模式
if (LHL_DMA_Init(&DMA_Handle_ADC0) != LHL_OK)
{
while(1); // DMA Init Error
}
/* 2.3 使能DMA中断并启动*/
LHL_DMA_ITConfig(&DMA_Handle_ADC0, DMA_IT_MAJOR | DMA_IT_HALF, ENABLE); // 双缓冲必须开启半中断和主中断
NVIC_EnableIRQ(DMA1_CH2_CH3_IRQn);
LHL_DMA_Start(&DMA_Handle_ADC0);
memset(&adcData0, 0, sizeof(adcData0));
adcFlag0 = 0;
LHL_ADC_Start(ADC_0); // 启动ADC0转换完成后自动触发DMA搬运数据
}
void DMA_ADC0_1_SyncConversion_Init(uint8_t Gain0, uint8_t PChan0, uint8_t NChan0 ,uint8_t Gain1, uint8_t PChan1, uint8_t NChan1 )
{
DMA_HandleTypeDef DMA_Handle_ADC0 , DMA_Handle_ADC1;
ADC_REF_Init(REF_INTERNAL_2P5V,REF_INTERNAL_2P5V); /* 1. 初始化内部基准源 */
ADC_SyncInit(SPS_977,Gain0,PChan0,NChan0,Gain1,PChan1,NChan1); /* 2. 初始化ADC0和ADC1 */
LHL_ADC_SetSync(ENABLE); // 同步模式
LHL_ADC_DMACmd(ADC_0, ENABLE);// 使能ADC0和ADC1的DMA功能
LHL_ADC_DMACmd(ADC_1, ENABLE);
/* 3.1 配置DMAUXDMA通道0的请求源来自ADC0 */
DMA_DMAMUX_CFG(DMA_CHANNEL_2,REQUEST_SOURCE_ADC0);//将DMAMUX链接到DMA通道
/* 3.2 配置DMA通道0 */
DMA_Handle_ADC0.Channel = DMA_CHANNEL_2;
DMA_Handle_ADC0.Request = DMA_HARDWARE_REQUEST;
DMA_Handle_ADC0.Mode = DMA_DIRECT_MODE;
DMA_Handle_ADC0.Init.Direction = DMA_PERIPH_TO_MEMORY; // 外设->内存
DMA_Handle_ADC0.Init.Src_Address = (uint32_t)(&pADC->ADC_DATA_0);
DMA_Handle_ADC0.Init.Dest_Address = (uint32_t)&adcData0;
DMA_Handle_ADC0.Init.Data_Width = DMA_DATA_WIDTH_4B;
DMA_Handle_ADC0.Init.Data_Size = 1; // 每次DMA触发传输1个数据
DMA_Handle_ADC0.Init.Repetition = MAX_ADC_COUNT*2; // 大循环10次
DMA_Handle_ADC0.Init.Trans_Mode = DMA_CYCLIC_TRANSMISSION; // 循环模式
if (LHL_DMA_Init(&DMA_Handle_ADC0) != LHL_OK)
{
while(1); // DMA Init Error
}
LHL_DMA_ITConfig(&DMA_Handle_ADC0, DMA_IT_MAJOR | DMA_IT_HALF, ENABLE); // 开启DMA0主中断
NVIC_EnableIRQ(DMA1_CH2_CH3_IRQn);
/* 4.1 配置DMAUXDMA通道1的请求源来自ADC1 */
DMA_DMAMUX_CFG(DMA_CHANNEL_3,REQUEST_SOURCE_ADC1);//将DMAMUX链接到DMA通道
/* 4.2 配置DMA通道1 */
DMA_Handle_ADC1.Channel = DMA_CHANNEL_3;
DMA_Handle_ADC1.Request = DMA_HARDWARE_REQUEST;
DMA_Handle_ADC1.Mode = DMA_DIRECT_MODE;
DMA_Handle_ADC1.Init.Direction = DMA_PERIPH_TO_MEMORY;
DMA_Handle_ADC1.Init.Src_Address = (uint32_t)(&pADC->ADC_DATA_1); // 改为ADC DATA 1
DMA_Handle_ADC1.Init.Dest_Address = (uint32_t)&adcData1;
DMA_Handle_ADC1.Init.Data_Width = DMA_DATA_WIDTH_4B;
DMA_Handle_ADC1.Init.Data_Size = 1;
DMA_Handle_ADC1.Init.Repetition = MAX_ADC_COUNT*2;
DMA_Handle_ADC1.Init.Trans_Mode = DMA_CYCLIC_TRANSMISSION;
if (LHL_DMA_Init(&DMA_Handle_ADC1) != LHL_OK)
{
while(1); // DMA Init Error
}
LHL_DMA_ITConfig(&DMA_Handle_ADC1, DMA_IT_MAJOR | DMA_IT_HALF, ENABLE);
NVIC_EnableIRQ(DMA1_CH2_CH3_IRQn);
/* 5 使能DMA0和DMA1*/
LHL_DMA_Start(&DMA_Handle_ADC0);
LHL_DMA_Start(&DMA_Handle_ADC1);
adcFlag0 = 0;
adcFlag1 = 0;
LHL_ADC_Start(ADC_0); // 启动ADC0转换完成后自动触发DMA搬运数据
}
/* 不开同步ADC0开始自动转换每次ADC0转换完成触发DMA0搬运数据到adcData
* 当DMA0搬运ADC0的数据达到10个则触发半中断数据此时放在A区
* 继续搬运数据达到20个则触发主中断数据此时存放在B区
* 所有数据搬运完成后自动停止,等待再次触发。*/
/* 开同步ADC0和ADC1开始同步转换。
* 当DMACH0搬运ADC0的数据达到10个则触发半中断数据此时放在A区DMACH1同样搬运10个ADC1的数据
* 继续搬运数据达到20个则触发主中断数据此时存放在B区*/
//读ADC数据---------------------------------------------------------------
uint32_t DMA_ADC_ReadData(uint8_t ADCx)
{
volatile uint32_t reg_data = 0;
uint32_t* buffer_ptr = NULL;
ADC_DATA_t* adc_data ;
uint8_t flag = 0;
if(ADCx == ADC_0) { flag = adcFlag0; adcFlag0 = 0;} //清除全局标志
else if(ADCx == ADC_1){ flag = adcFlag1; adcFlag1 = 0;} //清除全局标志
else return 0; // 没有该ADC
if (flag == 0) return 0;// 没有新数据
adc_data = (ADCx == ADC_0) ? &adcData0 : &adcData1;//选择ADC数据源/缓冲区
buffer_ptr = (flag == 1) ? adc_data->BufferA : adc_data->BufferB;//flag=1半中断 flag=2全中断两种
for(uint8_t i = 0; i < MAX_ADC_COUNT; i++)
{
buffer_ptr[i] = ((((buffer_ptr[i] & 0xFFFFFF) | ((buffer_ptr[i] & 0x800000) ? 0xFF000000 : 0)) >> 8) + 32768) & 0xFFFF;//处理成16位数据
reg_data += buffer_ptr[i];//计算连续采样的和
}
reg_data = reg_data / MAX_ADC_COUNT;//求平均
return reg_data ;
}
/*********************************************************************************************************************************************/
/*DMA 序列方式 */
/*********************************************************************************************************************************************/
#if 1 //DMA_ADC序列方式采集与获取
//Channel Sequencer =========================================================================
__RW uint8_t adcFlag;//DMA搬运完成标志
#define SEQUENCER_COUNT 4 //最大ADC_MAX_SEQUENCER_CHANNELS
// ADC0配置表 - 根据实际需求调整
static const SeqChannelConfig ADC0seq_configs[SEQUENCER_COUNT] = {
{ADC0_AINP_AIN0, ADC0_AINM_AVSS}, // Seq0
{ADC0_AINP_AIN1, ADC0_AINM_AIN0}, // Seq1
{ADC0_AINP_AIN2, ADC0_AINM_AIN1}, // Seq2
{ADC0_AINP_AIN3, ADC0_AINM_AIN2}, // Seq3
// {ADC0_AINP_AIN4, ADC0_AINM_AIN3}, // Seq4
// {ADC0_AINP_AIN5, ADC0_AINM_AIN4}, // Seq5
// {ADC0_AINP_AIN6, ADC0_AINM_AIN5}, // Seq6
// {ADC0_AINP_AIN7, ADC0_AINM_AIN6}, // Seq7
};
// ADC1配置表 - 根据实际需求调整
static const SeqChannelConfig ADC1seq_configs[SEQUENCER_COUNT] = {
{ADC1_AINP_AIN0, ADC1_AINM_AVSS}, // Seq0
{ADC1_AINP_AIN1, ADC1_AINM_AIN0}, // Seq1
{ADC1_AINP_AIN2, ADC1_AINM_AIN1}, // Seq2
{ADC1_AINP_AIN3, ADC1_AINM_AIN2}, // Seq3
// {ADC1_AINP_AIN4, ADC1_AINM_AIN3}, // Seq4
// {ADC1_AINP_AIN5, ADC1_AINM_AIN4}, // Seq5
// {ADC1_AINP_AIN6, ADC1_AINM_AIN5}, // Seq6
// {ADC1_AINP_AIN7, ADC1_AINM_AIN6}, // Seq7
};
/* 运行逻辑启动ADC0后
* ==》ADC转换完毕触发DMA0搬运ADC0的数据
* ==》DMA0搬运完毕触发DMA1根据序列器配置ADC0的下一个转换通道
* ==》DMA1配置完毕ADC0下一个通道自动启动转换
* ==》待所有ADC通道转换完毕则停止并触发DMA1主中断 */
ADC_Data_t adcBuffer[SEQUENCER_COUNT]; /* 单ADC序列器缓存区 */
void DMA_ADC0_SingleChannel_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_SingleCSInitTypeDef ADC_CSInitStructure; /* 单ADC序列器初始化结构体 */
ADC_Config_t ADC_Config[SEQUENCER_COUNT] __ALIGN(32); /* 单ADC序列器参数必须32位对齐 */
DMAMUX_InitTypeDef DMAMUX_InitStructure;
DMA_HandleTypeDef DMA_Handle_ADCstatus ,DMA_Handle_ADCcontrol;
/* 1. 初始化内部基准 */
ADC_REF_Init(REF_INTERNAL_2P5V,REF_INTERNAL_2P5V);
/* 2.1 初始化ADC0和ADC1通道序列器首先配置ADC通用参数固定模式单次转换。
* 然后序列器模式专用结构体配置:多个顺序通道,序列器循环模式,序列器触发源 */
ADC_InitStructure.FS = ADC_SPS_12P5; // 输出速率12.5SPS4通道轮询吞吐率近似1SPS
ADC_InitStructure.PGA = ADC_PGA_GAIN_1;
ADC_InitStructure.Code = ADC_CODE_BIPOLAR;
ADC_InitStructure.ReferenceSelect = ADC_REF_REFP_to_REFN;
ADC_InitStructure.REF_BUFP = ENABLE;
ADC_InitStructure.REF_BUFM = ENABLE;
ADC_InitStructure.REF_Precharge = DISABLE;
ADC_InitStructure.Reference = 2500.0f;
ADC_CSInitStructure.ADC_ID = ADC_0; // ADC0
ADC_CSInitStructure.ADC_CFG = ADC_Config; // 序列配置
ADC_CSInitStructure.Active_Channels = SEQUENCER_COUNT; // 序列通道数量
ADC_CSInitStructure.Cycle_Mode = DISABLE; // 循环使能:软件触发一次,无限循环;硬件触发一次,循环序列后等待下次触发。
ADC_CSInitStructure.Sequencer_Trigger = ADC_TRIGGER_SOFTWARE; // 循环禁用:软件触发一次,循环序列后停止;硬件触发一次,依次采集一个通道。
for (int i = 0; i < SEQUENCER_COUNT; i++) { //SEQUENCER_COUNT =4: ADC0的序列转换通道0->1->2->3->0->1->...
ADC_CSInitStructure.AINP_Channel[i] = ADC0seq_configs[i].ainp_channel;
ADC_CSInitStructure.AINM_Channel[i] = ADC0seq_configs[i].ainm_channel;
}
LHL_ADC_SingleChannelSequencerInit(&ADC_InitStructure, &ADC_CSInitStructure);
/* 2.2 通道序列器模式必须使能相应ADC的DMA功能 */
LHL_ADC_DMACmd(ADC_0, ENABLE); // 使能ADC0的DMA功能
/* 3.1 配置DMAUXDMA0的请求源来自ADC0 */
DMA_DMAMUX_CFG(DMA_CHANNEL_0 ,REQUEST_SOURCE_ADC0);
/* 3.2 配置DMA0用于读取ADC0数据和状态 */
DMA_Handle_ADCstatus.Channel = DMA_CHANNEL_0; // 句柄hDMA0
DMA_Handle_ADCstatus.Mode = DMA_CHAINING_MODE;
DMA_Handle_ADCstatus.Request = DMA_HARDWARE_REQUEST;
DMA_Handle_ADCstatus.Init.Direction = DMA_PERIPH_TO_MEMORY;
DMA_Handle_ADCstatus.Init.Src_Address = (uint32_t)(&pADC->ADC_STATUS_0); // 源地址读取ADC0数据
DMA_Handle_ADCstatus.Init.Dest_Address = (uint32_t)adcBuffer;
DMA_Handle_ADCstatus.Init.Data_Width = DMA_DATA_WIDTH_4B;
DMA_Handle_ADCstatus.Init.Data_Size = 2; // 状态和数据共2个寄存器
DMA_Handle_ADCstatus.Init.Repetition = SEQUENCER_COUNT;
DMA_Handle_ADCstatus.Init.Trans_Mode = DMA_CYCLIC_TRANSMISSION;
DMA_Handle_ADCstatus.Init.Chaining = TO_DMA_CHANNEL_1; // 完成后自动触发DMA1
if (LHL_DMA_Init(&DMA_Handle_ADCstatus) != LHL_OK)
{
while(1); // DMA Init Error
}
/* 4.1 配置DMA1用于配置ADC0的通道寄存器 */
DMA_Handle_ADCcontrol.Channel = DMA_CHANNEL_1; // 句柄更改->hDMA1
DMA_Handle_ADCcontrol.Mode = DMA_DIRECT_MODE;
DMA_Handle_ADCcontrol.Request = DMA_HARDWARE_REQUEST;
DMA_Handle_ADCcontrol.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Handle_ADCcontrol.Init.Src_Address = (uint32_t)ADC_Config; // 源地址读取ADC0通道序列器的配置参数
DMA_Handle_ADCcontrol.Init.Dest_Address = (uint32_t)(&pADC->ADC_CONTROL_0); // 目的地址是ADC0寄存器
DMA_Handle_ADCcontrol.Init.Data_Width = DMA_DATA_WIDTH_4B;
DMA_Handle_ADCcontrol.Init.Data_Size = 2;
DMA_Handle_ADCcontrol.Init.Repetition = SEQUENCER_COUNT;
DMA_Handle_ADCcontrol.Init.Trans_Mode = DMA_CYCLIC_TRANSMISSION;
if (LHL_DMA_Init(&DMA_Handle_ADCcontrol) != LHL_OK)
{
while(1); // DMA Init Error
}
/* 4.2 使能DMA中断 */
LHL_DMA_ITConfig(&DMA_Handle_ADCcontrol, DMA_IT_MAJOR, ENABLE);
NVIC_EnableIRQ(DMA1_CH1_IRQn);
/* 5. 显式启动DMA*/
LHL_DMA_Start(&DMA_Handle_ADCstatus);
adcFlag = 0;
memset(&adcBuffer,0,sizeof(adcBuffer));
}
/* 运行逻辑: 启动ADC0在同步模式下ADC1同时启动
* ==》ADC转换完毕触发DMA0搬运ADC0和ADC1的数据。
* ==》DMA0搬运完毕触发DMA1搬运ADC0和ADC1的配置参数启动下一组ADC转换通道直到所有序列通道转换完成 */
typedef struct{ /* 双ADC的双缓存区 */
ADC_DualData_t BufferA[SEQUENCER_COUNT];
ADC_DualData_t BufferB[SEQUENCER_COUNT];
} ADC_DualData_Buffer_t;
ADC_DualData_Buffer_t adcDualBuffer; /* 双ADC的数据缓冲区 */
#define TCD_COUNT 2 /* 双缓冲用到2个描述符 */
void DMA_ADC0_1_DualChannel_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
ADC_DualCSInitTypeDef ADC_DualCSInitStructure; /* 双ADC序列器初始化结构体 */
ADC_DualConfig_t ADC_DualConfig[SEQUENCER_COUNT] __ALIGN(128); /* 双ADC序列器参数必须128位对齐 */
DMAMUX_InitTypeDef DMAMUX_InitStructure;
DMA_HandleTypeDef DMA_Handle_ADCstatus ,DMA_Handle_ADCcontrol;/* 共用到2路DMA */
DMA_InitTypeDef DMA_InitStructure[TCD_COUNT]; /* TCD描述符需要对应数量的DMA参数结构体 */
DMA_DES_N_TypeDef TCD_Quene[TCD_COUNT] __ALIGN(32); /* DMA TCD描述符必须32位对齐*/
/* 1.1 初始化内部基准 */
ADC_REF_Init(REF_INTERNAL_2P5V,REF_INTERNAL_OFF);
/* 1.2 初始化ADC0和ADC1通道序列器首先配置ADC通用参数模式必须为单次转换。
* 然后序列器模式专用结构体配置:多个通道号,序列器循环模式,以及序列器触发源 */
ADC_InitStructure.FS = ADC_SPS_12P5; // 输出速率
ADC_InitStructure.PGA = ADC_PGA_GAIN_1;
ADC_InitStructure.Code = ADC_CODE_BIPOLAR;
ADC_InitStructure.ReferenceSelect = ADC_REF_REFP_to_REFN;
ADC_InitStructure.REF_BUFP = ENABLE;
ADC_InitStructure.REF_BUFM = ENABLE;
ADC_InitStructure.REF_Precharge = DISABLE;
ADC_InitStructure.Reference = 2500.0f;
ADC_DualCSInitStructure.ADC_CFGs = ADC_DualConfig; // 双通道序列器参数表
ADC_DualCSInitStructure.Active_Channels = SEQUENCER_COUNT; // 序列通道共4个
ADC_DualCSInitStructure.Cycle_Mode = DISABLE; // 循环使能:软件触发一次,无限循环;硬件触发一次,循环序列后等待下次触发。
ADC_DualCSInitStructure.Sequencer_Trigger = ADC_TRIGGER_SOFTWARE; // 循环禁用:软件触发一次,循环序列后停止;硬件触发一次,依次采集一个通道。
for (int i = 0; i < SEQUENCER_COUNT; i++) {
ADC_DualCSInitStructure.AINP0_Channel[i] = ADC0seq_configs[i].ainp_channel;
ADC_DualCSInitStructure.AINM0_Channel[i] = ADC0seq_configs[i].ainm_channel;
ADC_DualCSInitStructure.AINP1_Channel[i] = ADC1seq_configs[i].ainp_channel;
ADC_DualCSInitStructure.AINM1_Channel[i] = ADC1seq_configs[i].ainm_channel;
}
LHL_ADC_DualChannelSequencerInit(&ADC_InitStructure, &ADC_DualCSInitStructure); // 初始化ADC双序列器功能
/* 1.3 通道序列器模式必须使能同步模式和相应ADC的DMA功能 */
LHL_ADC_SetSync(ENABLE); // 必须使用同步模式
LHL_ADC_DMACmd(ADC_0, ENABLE); // 必须使能ADC0和ADC1的DMA功能
LHL_ADC_DMACmd(ADC_1, ENABLE);
/* 2. 配置DMAUXDMA0的请求源来自ADC0 */
DMA_DMAMUX_CFG(DMA_CHANNEL_0 ,REQUEST_SOURCE_ADC0);
/* 3. 配置DMA用于读取ADC0和ADC1的数据和状态 */
DMA_Handle_ADCstatus.Channel = DMA_CHANNEL_0; // 句柄hDMA0
DMA_Handle_ADCstatus.Mode = DMA_SCATTER_GATHER_MODE; // 分散聚合模式
DMA_Handle_ADCstatus.Request = DMA_HARDWARE_REQUEST; // 硬件触发
DMA_Handle_ADCstatus.TCD_Count = TCD_COUNT; // 2个TCD用于双缓冲
DMA_Handle_ADCstatus.TCD_List = TCD_Quene; // TCD链表
DMA_Handle_ADCstatus.TCD_Init = DMA_InitStructure; // TCD初始化队列
DMA_InitStructure[0].Direction = DMA_PERIPH_TO_MEMORY; // TCD0用于ADC0和ADC1的数据读取
DMA_InitStructure[0].Src_Address = (uint32_t)(&pADC->IO_CONTROL_IOUT);
DMA_InitStructure[0].Data_Width = DMA_DATA_WIDTH_16B;
DMA_InitStructure[0].Dest_Address = (uint32_t)&adcDualBuffer.BufferA[0];// 指向缓存区A
DMA_InitStructure[0].Data_Size = 2;
DMA_InitStructure[0].Repetition = SEQUENCER_COUNT;
DMA_InitStructure[0].Trans_Mode = DMA_INTERVAL_TRANSMISSION; // 间隔传输用于读写多个不相邻的寄存器
DMA_InitStructure[0].Src_Interval_Factor = 3;
DMA_InitStructure[0].Dest_Interval_Factor = 1;
DMA_InitStructure[0].Chaining = TO_DMA_CHANNEL_1; // 链式触发DMA1用于ADC序列通道切换
DMA_InitStructure[0].TCD_Address = (int32_t)&TCD_Quene[1]; // 完成后加载TCD1用于数据缓冲区切换
DMA_InitStructure[0].Auto_Start = DISABLE;
DMA_InitStructure[0].INT_Major = DISABLE;
DMA_InitStructure[0].INT_Half = DISABLE;
DMA_InitStructure[1].Direction = DMA_PERIPH_TO_MEMORY; // TCD1与TCD0基本一致
DMA_InitStructure[1].Src_Address = (uint32_t)(&pADC->IO_CONTROL_IOUT);
DMA_InitStructure[1].Data_Width = DMA_DATA_WIDTH_16B;
DMA_InitStructure[1].Dest_Address = (uint32_t)&adcDualBuffer.BufferB[0];// 指向缓存区B
DMA_InitStructure[1].Data_Size = 2;
DMA_InitStructure[1].Repetition = 4;
DMA_InitStructure[1].Trans_Mode = DMA_INTERVAL_TRANSMISSION;
DMA_InitStructure[1].Src_Interval_Factor = 3;
DMA_InitStructure[1].Dest_Interval_Factor = 1;
DMA_InitStructure[1].Chaining = TO_DMA_CHANNEL_1;
DMA_InitStructure[1].TCD_Address = (int32_t)&TCD_Quene[0]; // 完成后回到TCD0
DMA_InitStructure[1].Auto_Start = DISABLE;
DMA_InitStructure[1].INT_Major = DISABLE;
DMA_InitStructure[1].INT_Half = DISABLE;
if (LHL_DMA_Init(&DMA_Handle_ADCstatus) != LHL_OK)
{
while(1); // DMA Init Error
}
/* 4. 配置DMA1用于配置ADC0和ADC1的各个设置寄存器 */
DMA_Handle_ADCcontrol.Channel = DMA_CHANNEL_1; // 注意句柄更改->hDMA1
DMA_Handle_ADCcontrol.Mode = DMA_DIRECT_MODE;
DMA_Handle_ADCcontrol.Request = DMA_HARDWARE_REQUEST;
DMA_Handle_ADCcontrol.Init.Direction = DMA_MEMORY_TO_PERIPH;
DMA_Handle_ADCcontrol.Init.Src_Address = (uint32_t)&ADC_DualConfig[0]; // 源地址保存了ADC双通道序列器的配置参数列表
DMA_Handle_ADCcontrol.Init.Data_Width = DMA_DATA_WIDTH_16B;
DMA_Handle_ADCcontrol.Init.Dest_Address = (uint32_t)(&pADC->INTERRUPT_CONTROL_0); // 目的地址是ADC1 CHANNEL_CFG寄存器
DMA_Handle_ADCcontrol.Init.Data_Size = 2;
DMA_Handle_ADCcontrol.Init.Repetition = SEQUENCER_COUNT; // 主循环次数等于序列器通道数
DMA_Handle_ADCcontrol.Init.Trans_Mode = DMA_INTERVAL_TRANSMISSION;
DMA_Handle_ADCcontrol.Init.Src_Interval_Factor = 1;
DMA_Handle_ADCcontrol.Init.Dest_Interval_Factor = 3;
if (LHL_DMA_Init(&DMA_Handle_ADCcontrol) != LHL_OK)
{
while(1); // DMA Init Error
}
/* 5. 配置完毕使能DMA1中断 */
LHL_DMA_ITConfig(&DMA_Handle_ADCcontrol, DMA_IT_MAJOR, ENABLE); // 开启DMA1主中断
NVIC_EnableIRQ(DMA1_CH1_IRQn);
/* 6. 显式启动DMA0 */
LHL_DMA_Start(&DMA_Handle_ADCstatus);
adcFlag = 0;
memset(&adcDualBuffer,0,sizeof(adcDualBuffer));
}
//读ADC数据---------------------------------------------------------------
uint32_t ADC_ReadSingleData(uint8_t SeqChannelNum)//根据序列通道0-8读取
{
volatile uint32_t reg_data;
if (adcFlag > 0)
{
reg_data = adcBuffer[SeqChannelNum].ADC_Data ;//24bit补码形式
reg_data = ((((reg_data & 0xFFFFFF) | ((reg_data & 0x800000) ? 0xFF000000 : 0)) >> 8) + 32768) & 0xFFFF;
adcFlag = 0;
}
return reg_data ;
}
uint32_t ADC_ReadDualData(ADC_ID_t adcx ,uint8_t SeqChannelNum)//根据序列通道0-8读取
{
volatile uint32_t reg_data;
volatile uint32_t uCurrentBuffer = LHL_DMA_GetDestAddress(DMA_CHANNEL_0); // 获取DMA0当前指向的Buffer 状态寄存器参数搬运通道DMA_CHANNEL_0
if (adcFlag > 0)
{
if (uCurrentBuffer < (uint32_t)adcDualBuffer.BufferB) // 通过获取DMA0的目的地址判断数据存放在哪个Buffer
{
//The dual ADC data is stored in BufferB;
if(adcx == ADC_0) reg_data = adcDualBuffer.BufferB[SeqChannelNum].ADC0_Data ;
else reg_data = adcDualBuffer.BufferB[SeqChannelNum].ADC1_Data ;
}
else
{
//The dual ADC data is stored in BufferA
if(adcx == ADC_0) reg_data = adcDualBuffer.BufferA[SeqChannelNum].ADC0_Data ;
else reg_data = adcDualBuffer.BufferA[SeqChannelNum].ADC1_Data ;
}
reg_data = ((((reg_data & 0xFFFFFF) | ((reg_data & 0x800000) ? 0xFF000000 : 0)) >> 8) + 32768) & 0xFFFF;
adcFlag = 0;
}
return reg_data ;
}
#endif