本帖最后由 MariaBrook 于 2013-1-22 18:09 编辑
欧耶!终于碰上了传说中的“STM32F10x DMA+ADC 传输错位”问题。我使用DMA1_Channel1传输ADC1的11个通道数据,使用DMA2_Channel5传输ADC3的5个通道数据。ADC1和ADC3都由串口指令启动,启动后收集一组数据,发送给串口。
关键的代码只有两个函数。时钟及其他功能已在主函数中实现。
#define ADC_AM1 11 // 用作ADC1
#define ADC_AM3 5 // 用作ADC3
#define ADC_AM ADC_AM1 + ADC_AM3
volatile uint16_t adcResult_1[ADC_AM1]; // 存放ADC1的数据,DMA1_Channel1的目标
volatile uint16_t adcResult_3[ADC_AM3]; // 存放ADC3的数据,DMA2_Channel5的目标
volatile uint16_t adcResult[ADC_AM]; // 存放上面两个数组的数据
// **** 首先是初始化函数。这个函数里面的东东,大家应该比较熟悉了。基本功能就是初始化ADC1、ADC3、DMA1、DMA2 ********************
// ***************************************************************************************************************************
void ADC_initMyScan(void){
uint8_t i;
// **** 初始化IO口 ****
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//**** 初始化ADC1 ****
ADC_DeInit(ADC1);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 不使用双ADC
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 扫描模式打开
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 不使用连续转换模式,而是把控制权交给串口
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 关闭外部触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = ADC_AM1; // 规则通道11个
ADC_Init(ADC1, &ADC_InitStructure); // 构建ADC1
for(i = 0; i < ADC_AM1; i++){
ADC_RegularChannelConfig(adcUserADC_1, adcUserChannal_1, (i + 1), ADC_SampleTime_55Cycles5);
}
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1) == SET);
// **** 初始化ADC3 ****
ADC_DeInit(ADC3);
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 不使用双ADC
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 扫描模式打开
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 不使用连续转换模式,而是把控制权交给串口
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 关闭外部触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = ADC_AM3; // 规则通道11个
ADC_Init(ADC3, &ADC_InitStructure); // 构建ADC1
for(i = 0; i < ADC_AM3; i++){
ADC_RegularChannelConfig(adcUserADC_3, adcUserChannal_3, (i + 1), ADC_SampleTime_55Cycles5);
}
ADC_Cmd(ADC3, ENABLE);
ADC_ResetCalibration(ADC3);
while(ADC_GetResetCalibrationStatus(ADC3) == SET);
ADC_StartCalibration(ADC3);
while(ADC_GetCalibrationStatus(ADC3) == SET);
// **** 配置DMA ****
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = DMA1_C1_IRQ_LEVEL_PRE;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = DMA1_C1_IRQ_LEVEL_SUB;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Channel4_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = DMA2_C5_IRQ_LEVEL_PRE;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = DMA2_C5_IRQ_LEVEL_SUB;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(ADC1->DR); //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&adcResult_1; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //从外设读取数据 DMA_DIR_PeripheralDST是从存储器读
DMA_InitStructure.DMA_BufferSize = ADC_AM1; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道x拥有高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA1_Channel1, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道
DMA_Cmd(DMA1_Channel1, ENABLE); //启动DMA通道
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //构建DMA中断
DMA_ITConfig(DMA1_Channel1, DMA_IT_TE, ENABLE); //构建DMA中断
DMA_DeInit(DMA2_Channel5); // 为ADC3
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(ADC3->DR); //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&adcResult_3; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //从外设读取数据 DMA_DIR_PeripheralDST是从存储器读
DMA_InitStructure.DMA_BufferSize = ADC_AM3; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道x拥有高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA2_Channel5, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道
DMA_Cmd(DMA2_Channel5, ENABLE); //启动DMA通道
DMA_ITConfig(DMA2_Channel5, DMA_IT_TC, ENABLE); //构建DMA中断
DMA_ITConfig(DMA2_Channel5, DMA_IT_TE, ENABLE); //构建DMA中断
ADC_DMACmd(ADC1, ENABLE);
ADC_DMACmd(ADC3, ENABLE);
}
// **** 这个函数用来输出采样数据值 ********************************************************************
// **** adcDmaFinFlag_1和adcDmaFinFlag_3在DMA的传输完成中断中被置位 ************************************************
// ***********************************************************************************************************
uint8_t adc_debug(void){
uint8_t i, flag;
my_printf_SendString("\r\nEnter the ADC debug program!");
my_printf_SendString("\r\nPlease enter s to start!");
my_printf_SendString("\r\nPlease enter q to jump out!");
while(1){
flag = get_one_byte(&uart1DataTemp);
switch (flag){
case 's':
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_SoftwareStartConvCmd(ADC3, ENABLE);
while(adcDmaFinFlag_1 == FALSE);
adcDmaFinFlag_1 = FALSE;
while(adcDmaFinFlag_3 == FALSE);
adcDmaFinFlag_3 = FALSE;
ADC_resultToFinal(); // **** 将数据赋给一个与外部借口对应的数组 *********************
my_printf_SendString("\r\nRound: ");
for(i = 0; i < ADC_AM; i++){
my_printf_SendASCII_num16Hex(adcResult);
my_printf_SendString(" ");
}
break;
case 'q':
my_printf_SendString("\r\nEnd circle!");
return TRUE;
default:
my_printf_SendString("\r\nCom is not valid! ");
break;
}
}
return TRUE;
}
// **** 将数据赋给一个与外部借口对应的数组 *********************
// ******************************************************************
void ADC_resultToFinal(void){
adcResult[0] = adcResult_3[0];
adcResult[1] = adcResult_3[1];
adcResult[2] = adcResult_3[2];
adcResult[3] = adcResult_3[3];
adcResult[4] = adcResult_3[4];
adcResult[5] = adcResult_1[0];
adcResult[6] = adcResult_1[1];
adcResult[7] = adcResult_1[2];
adcResult[8] = adcResult_1[3];
adcResult[9] = adcResult_1[4];
adcResult[10] = adcResult_1[5];
adcResult[11] = adcResult_1[6];
adcResult[12] = adcResult_1[7];
adcResult[13] = adcResult_1[8];
adcResult[14] = adcResult_1[9];
adcResult[15] = adcResult_1[10];
}
DMA1_Channel1会将ADC1的11个数据存放在adcResult_1中
DMA2_Channel5会将ADC3的5个数据存放在adcResult_3中
串口会先显示adcResult_3的5个数,再显示adcResult_1的11个数,以“Round:”开始。
// **** 下面就是运行结果了 ***************************************************************************
// ******* 没有信号输入时 ****************
Round: 07E9 000D 0007 0008 0008 000C 0009 0008 0007 0007 0007 0008 0008 0007 0008 0008
// **** 通道有信号时 ADC3的5个通道分别加上信号*******************
Round: 07EE 01FF 0006 0004 0004 000D 0007 0008 0007 0008 0007 0007 0008 0007 0007 0007
Round: 07E9 000D 0216 0009 0007 000D 0007 0008 0007 0007 0008 0007 0007 0007 0007 0007
Round: 07E1 0009 0005 01FF 0005 000D 0007 0008 0007 0008 0008 0007 0008 0007 0007 0007
Round: 085E 0008 0004 0004 0212 000E 0007 0007 0007 0007 0007 0008 0008 0007 0008 0007
Round: 07E9 000D 0007 0008 0008 000C 0009 0008 0007 0007 0007 0008 0008 0007 0008 0008
每个round里面的第一个数据,不知道是从哪里冒出来的。在使用示波器测量所有引脚为0V的情况下,这个数据依然存在。
ADC3本来应该在0、1、2、3的数据,到了1、2、3、4处,第五个通道上的数据被丢掉了。
// **** 通道有信号时 ADC1的11个通道分别加上信号*******************
Round: 07E1 000A 0005 0004 0005 000E 01FF 000A 0007 0007 0007 0007 0007 0007 0007 0007
Round: 07E2 0009 0005 0004 0004 021D 0009 0007 0007 0008 0007 0008 0007 0007 0007 0007
Round: 07E0 0009 0005 0004 0004 000D 0007 0007 0007 0007 0007 0212 0009 0007 0007 0007
Round: 07E0 0009 0005 0004 0004 000E 0007 0216 0009 0007 0007 0008 0008 0008 0008 0007
Round: 07DE 0009 0003 0006 0005 000E 0007 0007 09F1 000E 0007 0007 0007 0007 0008 0007
Round: 07E6 000D 0007 0007 0007 000E 0007 0009 0007 09EA 000E 0008 0007 0008 0007 0007
Round: 07E4 0009 0004 0004 0004 000D 0007 0007 0007 0008 0007 0008 0008 09E8 000E 0007
Round: 07E2 0009 0004 0005 0004 0011 0007 0008 0007 0008 0007 0008 0009 0008 0007 09EB
Round: 07E2 0009 0005 0005 0004 000D 0007 0007 0007 0008 0008 0008 0008 0007 09E8 000E
Round: 07E3 0009 0004 0004 0004 000D 0007 0007 0007 0008 09E8 000E 0008 0007 0007 0007
Round: 07DF 0009 0005 0004 0004 000E 0007 0008 0007 0008 0008 0007 09DD 000E 0007 0007
这些信号转换成电压值,都和输入信号一一对应。
那为什么ADC3的DMA传输出了错位的问题,而ADC1的DMA传输没有出问题呢?
|