|
STM32F4 использование DMA при работе с АЦП, DMA повреждает данные |
|
|
|
May 16 2013, 06:56
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Здравствуйте уважаемые форумчане. В STM32F415 использую 11 каналов ADC1 для измерения напряжения. С помощью DMA2 передаю значения из АЦП в массив и в прерывании от таймера с частотой 5 кГц считываю данные из массива. На все 11 входов подано синусоидальное напряжение, но почему-то во всех каналах получаю такую картину:
Т.е. примерно через два периода получаю неверное значение напряжение. Ниже привожу инициализацию АЦП и DMA: CODE RCC->APB2ENR|=RCC_APB2ENR_ADC1EN; //Тактирование АЦП1 ADC1->CR2|=ADC_CR2_CONT; //Режим преобразования - непрерывный
ADC1->CR1|=ADC_CR1_SCAN; //Режим сканирования последовательности каналов
ADC1->CR2|=ADC_CR2_DMA; //Включаем DMA ADC1->CR2|=ADC_CR2_DDS;
ADC1->SQR1|=ADC_SQR1_L_3 |ADC_SQR1_L_1; //Сканируемая пос-ть каналов 0,1-10
ADC1->SQR3|=ADC_SQR3_SQ1_2 |ADC_SQR3_SQ1_1 /*Измеряем 1,5 В PA6 IN6*/
|ADC_SQR3_SQ2_3 |ADC_SQR3_SQ2_2 |ADC_SQR3_SQ2_0 /*Измеряем U_IN_VIPR_B PC3 IN13*/
|ADC_SQR3_SQ3_3 |ADC_SQR3_SQ3_1 |ADC_SQR3_SQ3_0 /*Измеряем U_IN_BPA PC1 IN11*/
|ADC_SQR3_SQ4_3 |ADC_SQR3_SQ4_2 /*Измеряем U_IN_VIPR_C PC2 IN12*/
|ADC_SQR3_SQ5_3 |ADC_SQR3_SQ5_1 /*Измеряем U_IN_BP_B PC0 IN10*/
|ADC_SQR3_SQ6_1; /*Измеряем I_OUT_INV_A PA2 IN2*/
ADC1->SQR2|=ADC_SQR2_SQ7_1 |ADC_SQR2_SQ7_0 /*Измеряем I_OUT_INV_B PA3 IN3*/
|ADC_SQR2_SQ8_0 /*Измеряем I_OUT_INV_C PA1 IN1*/
|ADC_SQR2_SQ9_2 /*Измеряем U_BAT PA4 IN4*/
|ADC_SQR2_SQ10_2 |ADC_SQR2_SQ10_0; /*Измеряем I_BAT PA5 IN5*/
/*Измеряем U_IN_VIPR_A PA0 IN0*/ ADC1->SMPR2|=ADC_SMPR2_SMP6 |ADC_SMPR2_SMP2 |ADC_SMPR2_SMP3 |ADC_SMPR2_SMP1 |ADC_SMPR2_SMP4 |ADC_SMPR2_SMP5 |ADC_SMPR2_SMP0; //Время конверсии 480 тактов ADC1->SMPR1|=ADC_SMPR1_SMP13 |ADC_SMPR1_SMP11 |ADC_SMPR1_SMP12 |ADC_SMPR1_SMP10; //Время конверсии 480 тактов ADC1->CR2|=ADC_CR2_ADON; //Включаем АЦП ADC1->CR2|=ADC_CR2_SWSTART; //Старт преобразования
ДМА: CODE DMA_InitTypeDef DMA_InitStructure;
RCC->AHB1ENR|=RCC_AHB1ENR_DMA2EN;
DMA_InitStructure.DMA_Channel = DMA_Channel_0; DMA_InitStructure.DMA_PeripheralBaseAddr = (unsigned int)&ADC1->DR; DMA_InitStructure.DMA_Memory0BaseAddr = (unsigned int)&ADC1Massiv; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_InitStructure.DMA_BufferSize = 11; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream4, &DMA_InitStructure); DMA_Cmd(DMA2_Stream4, ENABLE);
Массив куда передаю: Код signed int ADC1Massiv[11]; Подскажите, что я делаю не так. Сейчас упростил по максимуму - оставил один канал АЦП IN0, вот инициализация: Код RCC->APB2ENR|=RCC_APB2ENR_ADC1EN; //Тактирование АЦП1 ADC1->CR2|=ADC_CR2_CONT; //Режим преобразования - непрерывный
ADC1->CR1|=ADC_CR1_SCAN; //Режим сканирования последовательности каналов
ADC1->CR2|=ADC_CR2_DMA; //Включаем DMA ADC1->CR2|=ADC_CR2_DDS;
/*ADC1->SQR1|=ADC_SQR1_L_3 |ADC_SQR1_L_1;*/ //Сканируемая пос-ть каналов 0,1-10 /*Измеряем U_IN_VIPR_A PA0 IN0*/ ADC1->SMPR2|=ADC_SMPR2_SMP0; //Время конверсии 480 тактов
ADC1->CR2|=ADC_CR2_ADON; //Включаем АЦП ADC1->CR2|=ADC_CR2_SWSTART; //Старт преобразования В инициализации DMA все также как и выше, за исключением, что теперь: DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disnable; Но всеравно принимаю неправильные значения:
Сообщение отредактировал sidy - May 16 2013, 07:00
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 21)
|
May 16 2013, 09:21
|
Участник

Группа: Участник
Сообщений: 72
Регистрация: 28-06-10
Пользователь №: 58 174

|
Может вам стоит считывать массив по прерываниям dma после заполнения массива
|
|
|
|
|
May 16 2013, 10:06
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Попробовал по прерыванию все также - откуда-то берутся неправильные значения Код void DMA2_Stream4_IRQHandler ( void ) { // Test on DMA Stream Transfer Complete interrupt if ( DMA_GetITStatus(DMA2_Stream4, DMA_IT_TCIF4) ) { // Clear Stream0 HalfTransfer DMA_ClearITPendingBit ( DMA2_Stream4, DMA_IT_TCIF4 ); NewSample=ADC1Massiv;
} // if // Test on DMA Stream HalfTransfer Complete interrupt // Test on DMA Stream Transfer Complete interrupt
}
|
|
|
|
|
May 16 2013, 10:43
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Цитата(DASM @ May 16 2013, 14:11)  Это не неверные значения, вы просто тереяте где-то кусок времени. При этом Вы не привели ни описание массива куда считываются,ни прочей сопутсвующей информации (как-то запущенные в фоне другие задачи). Процессор с MMU ? Сейчас считываю просто в переменную unsigned int. Я уже отключил весь фон и расчеты. Посмотрел programming manual на CortexM4 про MMU там ничего нет.
|
|
|
|
|
May 16 2013, 10:52
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Цитата(DASM @ May 16 2013, 14:45)  В какую еще переменную ? График то откуда ? DMA настроил чтобы данные записывались в переменную, затем в прерывании от таймера с частотой 5 кГц: Код Mass[i++]=ADC1; if(i>=400) i=0; на i=0 ставлю точку останова в процессе работы и смотрю график.
Сообщение отредактировал sidy - May 16 2013, 10:55
|
|
|
|
|
May 16 2013, 14:56
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Цитата(Flexz @ May 16 2013, 18:17)  Настройте для начала один канал АЦП с записью в массив с помощью DMA, безо всяких таймеров. И смотрите данные по прерыванию TC. Сейчас я настроил один канал АЦП вообще без использования DMA. Т.е. Запускаю преобразование АЦП по таймеру, а считываю измеренное значение по прерыванию end of conversion от АЦП. И всеравно получаю подобные картины. Возможно АЦП неправильно настроен? Цитата Поддерживаю. Если первую синусоиду еще можно объяснить (потеря данных) то на второй картинке данные явно продублированы а не потеряны, чего быть не может. То есть просто отсутствует (или сбивается) синхронизация чтения из собранного буфера. Ну или это просто кольцо такое на "примерно два периода" и место сшивки- это самый новый и самый старый отчеты. Я думаю дублирования или старых данных тут нет, потому что я заполняю массив: Код Mass[i++]=ADC1; if(i>=400) i=0; и делаю останов во время работы на строке i=0;
Сообщение отредактировал sidy - May 16 2013, 15:19
|
|
|
|
|
May 16 2013, 18:29
|
Участник

Группа: Участник
Сообщений: 37
Регистрация: 16-06-11
Пользователь №: 65 731

|
Цитата(DASM @ May 16 2013, 20:06)  Сделайте Mass[i] = i ; i ++ и покажите график.Мне по прежнему кажется что Ацп тут не причем.
и вообще пишите такие вещи более явно. const int dSz = 400; unsigned iD =0; signed short dataArr[dSz]; dataArr [iD % dSz] = readAdc(); dSz ++; dataArr [iD % dSz] = readAdc(); iD ++;
|
|
|
|
|
May 17 2013, 06:47
|
Участник

Группа: Участник
Сообщений: 37
Регистрация: 16-06-11
Пользователь №: 65 731

|
Цитата(DASM @ May 16 2013, 23:06)  Хорошее правило const писать 100500%!
|
|
|
|
|
May 17 2013, 18:16
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (sidy @ May 17 2013, 20:21)  необходимо вывести 5 импульсов. Как это лучше сделать используя таймер и регистры захвата сравнения Вот посмотрите, как я планировал решать подобную задачу. К сожалению, код для того проекта писал впоследствии не я и другой программист пошел другим путем, поэтому проверить идею не довелось.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 18 2013, 05:04
|

Познающий...
     
Группа: Свой
Сообщений: 2 963
Регистрация: 1-09-05
Из: г. Иркутск
Пользователь №: 8 125

|
QUOTE (sidy @ May 18 2013, 02:21)  Разобрался с этим выводя данные с АЦП тут же в ЦАП. Сорри за банальный совет, но почему бы не отлаживаться в консоли? QUOTE (sidy @ May 18 2013, 02:21)  Задам еще один вопрос в данной теме. Мне с приходом определенного уровня сигнала с АЦП необходимо вывести 5 импульсов. Как это лучше сделать используя таймер и регистры захвата сравнения Записать в регистр сравнения число 5, настроить прерывание по сравнению, в котором выключать таймер. В основной программе (или в задаче ОС, если используете) мониторить определенный уровень. Как только уровень пришёл, запускаете таймер.
--------------------
Выбор.
|
|
|
|
|
May 18 2013, 13:35
|
Местный
  
Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333

|
Цитата(haker_fox @ May 18 2013, 09:04)  Записать в регистр сравнения число 5 Это в регистр TIMx->CCR1? Но этот регистр, как я понимаю сформирует скважность, но не число импульсов?
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|