玩转TM4C1294XL(7)——ADC+uDMA+Timer触发配置(uDMA ping-pong模式)

1.简介 简单介绍芯片内部的ADC和uDMA模块,分享ADC+uDMA+Timer触发配置。本人是边学习边记录,内容仅作参考,有错误的地方请见谅。 2.ADC介绍 本部分内容参考自TI官方手册。 芯片内部的ADC模块具有两路ADC,分别为ADC0和ADC1,共享20个输入通道,

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
};

//dma控制块需要1024字节对齐
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];


//ADC队列0中断函数
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); //清中断

    //判断哪个buffer满了,进行切换
    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);
        //启动DMA通道
        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);
    
    //GPIO配置
    GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);
    
    uDMAEnable();
    uDMAControlBaseSet(ControlTable); //设置控制块
    
    //清除通道属性
    uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC0,
                                UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY |
                                UDMA_ATTR_REQMASK);
                                
    //配置主控制块参数,16位数据宽度、源地址不自增、目标地址16bit自增、每次都触发。
    uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT, UDMA_SIZE_16 |
                          UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
                          
    //配置副控制块参数,16位数据宽度、源地址不自增、目标地址16bit自增、每次都触发。
    uDMAChannelControlSet(UDMA_CHANNEL_ADC0 | UDMA_ALT_SELECT, UDMA_SIZE_16 |
                          UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
                          
    //主控制块发送设置,ping-pong模式、源地址(void *)(ADC0_BASE + ADC_O_SSFIFO0)、
    //目标地址ADCBuffer1、传输大小ADC_SAMPLE_BUF_SIZE
    uDMAChannelTransferSet(UDMA_CHANNEL_ADC0 | UDMA_PRI_SELECT,
                           UDMA_MODE_PINGPONG,
                           (void *)(ADC0_BASE + ADC_O_SSFIFO0),
                           ADCBuffer1, ADC_SAMPLE_BUF_SIZE);

    //副控制块发送设置,ping-pong模式、源地址(void *)(ADC0_BASE + ADC_O_SSFIFO0)、
    //目标地址ADCBuffer2、传输大小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);
    //开启DMA通道
    uDMAChannelEnable(UDMA_CHANNEL_ADC0);

    //  ADC0时钟配置 全速1M  PIOSC为16M时钟
    ADCClockConfigSet(ADC0_BASE, ADC_CLOCK_SRC_PIOSC | ADC_CLOCK_RATE_FULL, 1);
    //等待时钟配置
    SysCtlDelay(10);
                           
    //关闭队列0中断
    IntDisable(INT_ADC0SS0);
    ADCIntDisable(ADC0_BASE, 0);

    //关闭队列0
    ADCSequenceDisable(ADC0_BASE, 0);

    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_TIMER, 0);  //定时器触发
//    ADCSequenceConfigure(ADC0_BASE, 0, ADC_TRIGGER_ALWAYS, 0); //连续不断采样 全速

    //队列0,编号0,通道ch0|最后一个采样通道
    ADCSequenceStepConfigure(ADC0_BASE, 0, 0, ADC_CTL_CH0 | ADC_CTL_END);
    //使能队列0
    ADCSequenceEnable(ADC0_BASE, 0);

    //使能队列0的dma
    ADCSequenceDMAEnable(ADC0_BASE, 0);

    //开启队列0的dma传输完成中断
    ADCIntEnableEx(ADC0_BASE, ADC_INT_DMA_SS0);
    
    //开启队列0中断控制器
    IntEnable(INT_ADC0SS0);
    
    //使能处理器中断控制器
    IntMasterEnable();
    
    //定时器配置
    TimerConfigure(TIMER0_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC);
    //16k频率
    TimerLoadSet(TIMER0_BASE, TIMER_A, (SystemCoreClock/16000) - 1);
    //使能定时器A触发
    TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
    //使能定时器
    TimerEnable(TIMER0_BASE, TIMER_A);
}

       ADC0队列0转换完成后dma自动将数据放入缓存中,ping-pong模式使用了双缓冲,dma传输完成后会进入ADC0SS0_Handler中断函数,函数中切换缓存然后重新启动传输。

keil工程下载

知秋君
上一篇 2024-07-05 09:12
下一篇 2024-07-05 08:48

相关推荐