1.一般是启动某个通道实现一定数目的ADC数据提取。
方法1:设置ADC为软件触发,为连续采样。设置DMA为normal模式。等DMA传输完成 开启DMA完成中断 ,在中断中关闭ADC。
这样实际内部运行过程ADC在连续采样,但是DMA 计数器递减为0停止运行,这样就实现了定量ADC数目。
方法2:设置ADC为软件触发,单次采样,设置DMA为normal模式,DMA 第一个位置开启链式传输,这样第一个ADC转换完成,自动启动下一个DMA 自动开启ADC,这样就实现了 定量ADC数目,这种做法优点不需要开启DMA中断,但是链式传输不如方法一连续.
#define ADC_OPERMODE_SELECT /* ADC Operation mode: select mode */
#define ADC_TRIGGER_SOFTWARE /* ADC Trigger: software trigger */
#define ADC_CONVMODE_ONESHOT /* ADC Conversion mode: one-shot */
#define ADC_VREF_VDD_VSS /* ADC reference voltage: VDD/VSS */
// ADC DMA
// 开启ADC时钟
CGC->PER0 |= CGC_PER0_ADCEN_Msk; /* enables input clock supply */
ADC->ADM0 = 0x00U; /* disable AD conversion and clear ADM0 register */
// P62
PORT->PMC6 |= (1 << 2);
// 48M/8 = 6M
/* AD operation mode: select or scan mode */
ADC->ADM0 = _28_AD_CONVERSION_CLOCK_1 | _00_AD_COMPARATOR_DISABLE;
/* AD conversion mode setting */
ADC->ADM1 = _00_AD_HISPEED;
#ifdef ADC_OPERMODE_SELECT
ADC->ADM1 |= _00_AD_OPERMODE_SELECT;
#endif
#ifdef ADC_OPERMODE_SCAN
ADC->ADM1 |= _80_AD_OPERMODE_SCAN;
#endif
#ifdef ADC_CONVMODE_SEQUENTIAL
ADC->ADM1 |= _00_AD_CONVMODE_SEQUENTIAL;
#endif
#ifdef ADC_CONVMODE_ONESHOT
ADC->ADM1 |= _08_AD_CONVMODE_ONESHOT;
#endif
/* AD reference voltage setting */
#ifdef ADC_VREF_VDD_VSS
ADC->ADM2 = _00_AD_POSITIVE_VDD | _00_AD_NEGATIVE_VSS | _00_AD_AREA_MODE_1 ;
#endif
#ifdef ADC_VREF_AVREFP_AVREFM
ADC->ADM2 = _40_AD_POSITIVE_AVREFP | _20_AD_NEGATIVE_AVREFM | _00_AD_AREA_MODE_1 ;
#endif
/* AD trigger selection */
#ifdef ADC_TRIGGER_SOFTWARE
ADC->ADTRG = _00_AD_TRIGGER_SOFTWARE;
#endif
#ifdef ADC_TRIGGER_HARDWARE_NOWAIT
ADC->ADTRG = _80_AD_TRIGGER_HARDWARE_NOWAIT;
#endif
#ifdef ADC_TRIGGER_HARDWARE_WAIT
ADC->ADTRG = _C0_AD_TRIGGER_HARDWARE_WAIT;
#endif
/* AD comversion result comprision upper limit setting */
ADC->ADUL = _FF_AD_ADUL_VALUE;
/* AD comversion result comprision lower limit setting */
ADC->ADLL = _00_AD_ADLL_VALUE;
/* adhard power up */
ADC->ADM0 |= ADCE;
{
uint8_t ctrl_data_num = 0;
// DMA_VECTOR_ADC DMA中断向量位置
DMAVEC->VEC[DMA_VECTOR_ADC] = ctrl_data_num;
// CTRL_DMACR_SZ_Pos 数据长度(1表示16位 应为ADC结果大于8位,所以选16位)
// CTRL_DMACR_RPTINT_Pos DMA 中断
// CTRL_DMACR_CHNE_Pos 不使用链式触发(所谓的链传输设置过后执行完会自动提取紧挨的DMA信息块)
// CTRL_DMACR_DAMOD_Pos 目标地址是否增加 1表示增加
// CTRL_DMACR_SAMOD_Pos 源地址是否增加 0表示不增加
// CTRL_DMACR_RPTSEL_Pos DMA传输的方向 0表示为 从源地址提取到目标地址
// CTRL_DMACR_MODE_Pos 1 表示否则一直执行 循环模式还是单次模式
DMAVEC->CTRL[ctrl_data_num].DMACR = (1 << CTRL_DMACR_SZ_Pos) | (0 << CTRL_DMACR_RPTINT_Pos)|(1<<CTRL_DMACR_CHNE_Pos)|
(1 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
(0 << CTRL_DMACR_RPTSEL_Pos)| (0 << CTRL_DMACR_MODE_Pos);
// 块大小
DMAVEC->CTRL[ctrl_data_num].DMBLS = 1;
// 每个DMA循环传输次数
DMAVEC->CTRL[ctrl_data_num].DMACT = 10;
// DMA 传输重载值
DMAVEC->CTRL[ctrl_data_num].DMRLD = 10;
// DMA传输源地址
DMAVEC->CTRL[ctrl_data_num].DMSAR = (uint32_t)&ADC->ADCR;
// DMA传输目标地址
DMAVEC->CTRL[ctrl_data_num].DMDAR = (uint32_t)&adc_dma_buf[0];
ctrl_data_num = ctrl_data_num+1;
// 8位传输
DMAVEC->CTRL[ctrl_data_num].DMACR = (0 << CTRL_DMACR_SZ_Pos) | (0 << CTRL_DMACR_RPTINT_Pos)|
(0 << CTRL_DMACR_DAMOD_Pos) | (0 << CTRL_DMACR_SAMOD_Pos) |
(0 << CTRL_DMACR_RPTSEL_Pos)| (0 << CTRL_DMACR_MODE_Pos);
// 块大小
DMAVEC->CTRL[ctrl_data_num].DMBLS = 1;
// 每个DMA循环传输次数
DMAVEC->CTRL[ctrl_data_num].DMACT = 1;
// DMA 传输重载值
DMAVEC->CTRL[ctrl_data_num].DMRLD = 1;
static uint8_t temp;
temp = (1<<7)|(1<<0)|(ADC->ADM0);
// DMA传输源地址
DMAVEC->CTRL[ctrl_data_num].DMSAR = (uint32_t)&temp;
// DMA传输目标地址
DMAVEC->CTRL[ctrl_data_num].DMDAR = (uint32_t)&ADC->ADM0;
/* init DMA registers */
// 开启 DMA时钟
CGC->PER1 |= CGC_PER1_DMAEN_Msk;
// 指定信息块内置地址
DMA->DMABAR = DMAVEC_BASE;
// 开启对应的 DMA
DMA->DMAEN0 |= 1 << 5;
}
ADC->ADM0 |= ADCS;