557 lines
28 KiB
C
557 lines
28 KiB
C
#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 配置DMAUX:DMA通道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 配置DMAUX:DMA通道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.5SPS(4通道轮询吞吐率近似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 配置DMAUX:DMA0的请求源来自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. 配置DMAUX:DMA0的请求源来自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
|