LM3S9D90 DMA方式ADC高速转换疑点

2019-03-24 09:19发布

小生最近在用LM3S9D90,ADC用高速转换(500K的转换速度算快吗?),因此使用DMA进行数据搬移。有两点我是一直搞不懂的:
1、  DMA仲裁机制是干嘛用的?
2、  ADC的缓冲是否一定要32位的?

以下是节选ADC和DMA初始化程序:

#define SEQUENCER    0                          //采样序列数
#define ADCNumber    500                        //采样的数量
extern unsigned long ADC_CheckNum;
extern unsigned long ADC_Datas[2000];
extern unsigned char ADC_interrupt_Ture;   //ADC结束标志位
extern unsigned char ADC_start;            //ADC转换使能位
extern unsigned char Timer0_number;

unsigned char uDatacontrolTab[1024];    //uDMA控制表
////////////////////////////////ADC的DMA配置////////////////////////////////////
#if       SEQUENCER == 0
#define   INT_ADC_ADDRESS       INT_ADC0                        //ADC中断序列必须要和SEQUENCER采样序列数相同
#define   UDMA_CHANNEL_ADC      UDMA_CHANNEL_ADC0               //设定ADC DMA通道
#define   UDMA_NUMBER_ADDRESS   (ADC0_BASE | ADC_O_SSFIFO0)     //设定DMA数据传输地址
#elif     SEQUENCER == 1
#define   INT_ADC_ADDRESS       INT_ADC1                        //ADC中断序列必须要和SEQUENCER采样序列数相同
#define   UDMA_CHANNEL_ADC      UDMA_CHANNEL_ADC1               //设定ADC DMA通道
#define   UDMA_NUMBER_ADDRESS   (ADC0_BASE | ADC_O_SSFIFO1)     //设定DMA数据传输地址
#elif     SEQUENCER == 2
#define   INT_ADC_ADDRESS       INT_ADC2                        //ADC中断序列必须要和SEQUENCER采样序列数相同
#define   UDMA_CHANNEL_ADC      UDMA_CHANNEL_ADC2               //设定ADC DMA通道
#define   UDMA_NUMBER_ADDRESS   (ADC0_BASE | ADC_O_SSFIFO2)     //设定DMA数据传输地址
#elif     SEQUENCER == 3
#define   INT_ADC_ADDRESS       INT_ADC3                        //ADC中断序列必须要和SEQUENCER采样序列数相同
#define   UDMA_CHANNEL_ADC      UDMA_CHANNEL_ADC3               //设定ADC DMA通道
#define   UDMA_NUMBER_ADDRESS   (ADC0_BASE | ADC_O_SSFIFO3)     //设定DMA数据传输地址
#endif
////////////////////////////////////////////////////////////////////////////////
#define   CPUClock              (SysCtlClockGet()/1000000)
#define   ADCTime_us            100

//ADC定时器1触发初始化
void ADC_Timer1_Init(void)
{
  ADCSequenceConfigure(ADC0_BASE,SEQUENCER,ADC_TRIGGER_TIMER,SEQUENCER);   //配置为定时器1触发
  SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);           //使能定时器1
  TimerConfigure(TIMER1_BASE,TIMER_CFG_A_PERIODIC);       //定时器1使用定时器A的16位周期模式
  TimerLoadSet(TIMER1_BASE, TIMER_A,ADCTime_us*CPUClock); //10US
  TimerControlTrigger(TIMER1_BASE, TIMER_A, 1);           //使能定时器1作为触发源
  TimerEnable(TIMER1_BASE, TIMER_A);                      //启动定时器A
  //TimerDisable(TIMER1_BASE, TIMER_A);                     //禁止定时器A
}

void ADC0_init(void)
{
  SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);   //使能ADC0
  SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);     //设置ADC采样率
  SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);  //使能ADC管脚E
  //GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_2 | GPIO_PIN_3); //配置管脚为ADC端口
  GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_3);  //配置管脚为ADC端口
  ADCReferenceSet(ADC0_BASE,ADC_REF_INT);       //配置ADC0参考电压为3V
  ADCResolutionSet(ADC0_BASE,ADC_RES_12BIT);    //转换结果12位
  ADCSequenceDisable(ADC0_BASE, SEQUENCER);     //禁止所有采样序列
  IntEnable(INT_ADC_ADDRESS);  //使能ADC0 序列中断
  ADCIntEnable(ADC0_BASE, SEQUENCER);           //使能ADC0 序列中断模块

  ADC_Timer1_Init();
  //ADCSequenceConfigure(ADC0_BASE, SEQUENCER, ADC_TRIGGER_ALWAYS, 0);  //配置为ADC0,采样序列0,连续触发
  ADCSequenceStepConfigure(ADC0_BASE, SEQUENCER, 0, ADC_CTL_CH8 | ADC_CTL_IE
                          |ADC_CTL_END);        // 开中断,序列转换接收中断,序列接收
  //ADCHardwareOversampleConfigure(ADC0_BASE,32);  //配置过采样因数
  ADCIntClear(ADC0_BASE,SEQUENCER);  //清除中断
  //ADCSequenceEnable(ADC0_BASE, SEQUENCER);
  //ADCProcessorTrigger(ADC0_BASE, SEQUENCER);  //处理器触发采样
}

//DMA初始化
void UDMA_Init(void)
{
  SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); //使能DMA时钟
  uDMAEnable();   //使能DMA控制
  uDMAControlBaseSet(uDatacontrolTab);        //DMAA控制表设置

  uDMAChannelAttributeDisable(UDMA_CHANNEL_ADC,
                                  UDMA_ATTR_USEBURST |
                                  UDMA_ATTR_ALTSELECT |
                                  UDMA_ATTR_HIGH_PRIORITY |
                                  UDMA_ATTR_REQMASK); //属性设置
  /*ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_ADC0,
                                 UDMA_ATTR_USEBURST );*/

  uDMAChannelControlSet(UDMA_CHANNEL_ADC |
                            UDMA_PRI_SELECT,
                            UDMA_SIZE_32 |
                            UDMA_DST_INC_32 |
                            UDMA_SRC_INC_NONE |
                            UDMA_ARB_1);    //通道控制设置
  uDMAChannelControlSet(UDMA_CHANNEL_ADC |
                            UDMA_ALT_SELECT,
                            UDMA_SIZE_32 |
                            UDMA_DST_INC_32 |
                            UDMA_SRC_INC_NONE |
                            UDMA_ARB_1);    //通道控制设置

  uDMAChannelTransferSet(UDMA_CHANNEL_ADC |
                             UDMA_PRI_SELECT,
                             UDMA_MODE_PINGPONG,
                             (void*)UDMA_NUMBER_ADDRESS,
                             ADC_Datas,
                             ADCNumber);    //通道传输参数
  uDMAChannelTransferSet(UDMA_CHANNEL_ADC |
                             UDMA_ALT_SELECT,
                             UDMA_MODE_PINGPONG,
                             (void*)UDMA_NUMBER_ADDRESS,
                             ADC_Datas+500,
                             ADCNumber);    //通道传输参数
  uDMAChannelEnable(UDMA_CHANNEL_ADC);  //通道使能
  //uDMAChannelRequest(UDMA_CHANNEL_ADC0);
}


void ADC0_Temperature(void)            //ADC转换中断程序
{
  unsigned long ulMode;
  ADCIntClear(ADC0_BASE,SEQUENCER);
      ulMode = uDMAChannelModeGet(UDMA_CHANNEL_ADC | UDMA_PRI_SELECT);
  asm ("nop");
  if(ulMode == UDMA_MODE_STOP)
  {
    uDMAChannelTransferSet(UDMA_CHANNEL_ADC |
                              UDMA_PRI_SELECT,
                              UDMA_MODE_PINGPONG,
                              (void*)UDMA_NUMBER_ADDRESS,
                              ADC_Datas,
                              ADCNumber);
  }
  ulMode = uDMAChannelModeGet(UDMA_CHANNEL_ADC | UDMA_ALT_SELECT);
  asm ("nop");
  if(ulMode == UDMA_MODE_STOP)                                       
  {
    uDMAChannelTransferSet(UDMA_CHANNEL_ADC |
                              UDMA_ALT_SELECT,
                              UDMA_MODE_PINGPONG,
                              (void*)UDMA_NUMBER_ADDRESS,
                              ADC_Datas+500,
                              ADCNumber);    //通道传输参数
  }
  asm ("nop");
  if(!uDMAChannelIsEnabled(UDMA_CHANNEL_ADC))
  {
    uDMAChannelTransferSet(UDMA_CHANNEL_ADC |
                              UDMA_PRI_SELECT,
                              UDMA_MODE_PINGPONG,
                              (void*)UDMA_NUMBER_ADDRESS,
                              ADC_Datas,
                              ADCNumber);
    uDMAChannelEnable(UDMA_CHANNEL_ADC);  //重新使能通道
  }
  ADC_interrupt_Ture++;
}

       ADC转换的分辨率是12位数据,因此缓冲应该用16位就够用了。但是如果用16位的话,DMA搬移过去的值并不是实际上我要的值。

向各位大大求助

[ 本帖最后由 onion100 于 2012-9-6 10:25 编辑 ] 此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
2条回答
ddllxxrr
2019-03-24 21:14
 精彩回答 2  元偷偷看……0人看过

一周热门 更多>

相关问题

    相关文章