1.简介 ???????简单介绍芯片内部的ADC和uDMA模块,分享ADC+uDMA+Timer触发配置。本人是边学习边记录,内容仅作参考,有错误的地方请见谅。
2.ADC介绍 ???????本部分内容参考自TI官方手册。 ???????芯片内部的ADC模块具有两路ADC,分别为ADC0和ADC1,共享20个输入通道,最大采样速度2M(两个ADC交替采样最大可以达到4M),可以配置成4个采样队列,支持软件触发、定时器触发、pwm触发、比较器触发、io口触发,支持硬件平均(最多64次采样),8个数字比较器,参考电压可选择。
图1 ADC模块功能框图
??????? ???????需要注意的是4个队列的长度不一样,队列0最多支持8个通道,队列1和2支持4个通道,队列3只支持1个通道。
图2 ADC的队列长度表
??????? 3.uDMA介绍 ???????本部分内容参考自TI官方手册。 ???????芯片内部的uDMA模块具有32个独立通道,支持内存到内存、内存到外设、外设到内存三个传输方向,支持多种传输模式,支持8位、16位、32位数据宽度,一次可传输的数据长度最大1024,源地址和目标地址自增可控。uDMA的通道配置参数存储在用户提供的RAM中,需要在程序中定义一个长度为1024字节的数组用于存放通道配置参数,这个数组需要以1024字节进行地址对齐。
图3 uDMA控制参数结构表
4.配置代码 ???????本部分代码实现timer触发ADC转换使用uDMA搬运,uDMA工作在ping-pong模式下。
enum BUFFER_STATUS
{
EMPTY,
FILLING,
FULL
};
static uint8_t ControlTable[1024] __attribute__ ((aligned(1024)));
uint16_t ADCBuffer1[ADC_SAMPLE_BUF_SIZE];
uint16_t ADCBuffer2[ADC_SAMPLE_BUF_SIZE];
static enum BUFFER_STATUS BufferStatus[2];
uint32_t adc_int_count = 0;
void ADC0SS0_Handler(void)
{
adc_int_count++;
HWREG(ADC0_BASE + ADC_O_ISC) = HWREG(ADC0_BASE + ADC_O_RIS) & (1 << 8);
if ((uDMAChannelModeGet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT) ==
UDMA_MODE_STOP) && (BufferStatus[0] == FILLING)) {
BufferStatus[0] = FULL;
BufferStatus[1] = FILLING;
} else if ((uDMAChannelModeGet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT) ==
UDMA_MODE_STOP) && (BufferStatus[1] == FILLING)) {
BufferStatus[0] = FILLING;
BufferStatus[1] = FULL;
}
if(BufferStatus[0] == FULL) {
BufferStatus[0] = EMPTY;
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG,
(void *)(ADC0_BASE + ADC_O_SSFIFO0),
ADCBuffer1, ADC_SAMPLE_BUF_SIZE);
uDMAChannelEnable(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT);
} else if(BufferStatus[1] == FULL) {
BufferStatus[1] = EMPTY;
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,
(void *)(ADC0_BASE + ADC_O_SSFIFO0),
ADCBuffer2, ADC_SAMPLE_BUF_SIZE);
uDMAChannelEnable(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT);
}
}
void bsp_InitAdc0(void)
{
BufferStatus[0] = FILLING;
BufferStatus[1] = EMPTY;
SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
uDMAEnable();
uDMAControlBaseSet(ControlTable);
uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0,
UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY |
UDMA_ATTR_REQMASK);
uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 |
UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_SIZE_16 |
UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
UDMA_MODE_PINGPONG,
(void *)(ADC0_BASE + ADC_O_SSFIFO0),
ADCBuffer1, ADC_SAMPLE_BUF_SIZE);
uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT,
UDMA_MODE_PINGPONG,
(void *)(ADC0_BASE + ADC_O_SSFIFO0),
ADCBuffer2, ADC_SAMPLE_BUF_SIZE);
uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0, UDMA_ATTR_USEBURST);
uDMAChannelEnable(UDMA_CHANNEL_ADC0);
ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
SysCtlDelay(10);
IntDisable(INT_ADC0SS0);
ADCIntDisable(ADC0_BASE, 0);
ADCSequenceDisable(ADC0_BASE, 0);
ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);
ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 | ADC_CTL_END);
ADCSequenceEnable(ADC0_BASE, 0);
ADCSequenceDMAEnable(ADC0_BASE, 0);
ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0);
IntEnable(INT_ADC0SS0);
IntMasterEnable();
TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC);
TimerLoadSet(TIMER0_BASE, TIMER_A, (SystemCoreClock/16000) - 1);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
TimerEnable(TIMER0_BASE, TIMER_A);
}
???????ADC0队列0转换完成后dma自动将数据放入缓存中,ping-pong模式使用了双缓冲,dma传输完成后会进入ADC0SS0_Handler中断函数,函数中切换缓存然后重新启动传输。
keil工程下载
|