小生最近在用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 编辑 ]
此帖出自
小平头技术问答
一周热门 更多>