реклама на сайте
подробности

 
 
> STM32F4 использование DMA при работе с АЦП, DMA повреждает данные
sidy
сообщение May 16 2013, 06:56
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
2 страниц V   1 2 >  
Start new topic
Ответов (1 - 21)
nx6310
сообщение May 16 2013, 09:21
Сообщение #2


Участник
*

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



Может вам стоит считывать массив по прерываниям dma после заполнения массива
Go to the top of the page
 
+Quote Post
sidy
сообщение May 16 2013, 10:06
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 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

}
Go to the top of the page
 
+Quote Post
DASM
сообщение May 16 2013, 10:11
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Это не неверные значения, вы просто тереяте где-то кусок времени. При этом Вы не привели ни описание массива куда считываются,ни прочей сопутсвующей информации (как-то запущенные в фоне другие задачи). Процессор с MMU ?
Go to the top of the page
 
+Quote Post
sidy
сообщение May 16 2013, 10:43
Сообщение #5


Местный
***

Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333



Цитата(DASM @ May 16 2013, 14:11) *
Это не неверные значения, вы просто тереяте где-то кусок времени. При этом Вы не привели ни описание массива куда считываются,ни прочей сопутсвующей информации (как-то запущенные в фоне другие задачи). Процессор с MMU ?

Сейчас считываю просто в переменную unsigned int. Я уже отключил весь фон и расчеты. Посмотрел programming manual на CortexM4 про MMU там ничего нет.
Go to the top of the page
 
+Quote Post
DASM
сообщение May 16 2013, 10:45
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



В какую еще переменную ? График то откуда ?
Go to the top of the page
 
+Quote Post
sidy
сообщение May 16 2013, 10:52
Сообщение #7


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
DASM
сообщение May 16 2013, 11:33
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Вот думаю и стоит копать в сторону всяких магических "if(i>=400)
i=0", а также volatile переменных. Но никак не в сторону DMA engine
Go to the top of the page
 
+Quote Post
Ruslan1
сообщение May 16 2013, 13:27
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 360
Регистрация: 6-03-06
Из: Кишинев
Пользователь №: 15 025



Цитата(DASM @ May 16 2013, 14:33) *
Вот думаю и стоит копать в сторону всяких магических "if(i>=400)
i=0", а также volatile переменных. Но никак не в сторону DMA engine

Поддерживаю. Если первую синусоиду еще можно объяснить (потеря данных) то на второй картинке данные явно продублированы а не потеряны, чего быть не может. То есть просто отсутствует (или сбивается) синхронизация чтения из собранного буфера.

Ну или это просто кольцо такое на "примерно два периода" и место сшивки- это самый новый и самый старый отчеты.
Go to the top of the page
 
+Quote Post
Flexz
сообщение May 16 2013, 14:17
Сообщение #10


Местный
***

Группа: Свой
Сообщений: 252
Регистрация: 9-10-08
Из: Московская обл.
Пользователь №: 40 797



Настройте для начала один канал АЦП с записью в массив с помощью DMA, безо всяких таймеров. И смотрите данные по прерыванию TC.
Go to the top of the page
 
+Quote Post
sidy
сообщение May 16 2013, 14:56
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
DASM
сообщение May 16 2013, 17:06
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Сделайте Mass[i] = i ; i ++ и покажите график.Мне по прежнему кажется что Ацп тут не причем.

и вообще пишите такие вещи более явно.
const int dSz = 400;
unsigned iD =0;
signed short dataArr[dSz];
dataArr [iD % dSz] = readAdc(); dSz ++;
Go to the top of the page
 
+Quote Post
aoreh
сообщение May 16 2013, 18:29
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 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 ++;
Go to the top of the page
 
+Quote Post
DASM
сообщение May 16 2013, 20:06
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



rolleyes.gif С телефона писал =) Хорошее правило const писать - это бы не скомпилировалось =)
Go to the top of the page
 
+Quote Post
haker_fox
сообщение May 17 2013, 03:12
Сообщение #15


Познающий...
******

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



А постоянку не подавали на вход? Тогда будь это потеря данных, или дубляж, должна быть одна прямая...


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
aoreh
сообщение May 17 2013, 06:47
Сообщение #16


Участник
*

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



Цитата(DASM @ May 16 2013, 23:06) *
Хорошее правило const писать

100500%!
Go to the top of the page
 
+Quote Post
haker_fox
сообщение May 17 2013, 13:45
Сообщение #17


Познающий...
******

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



QUOTE (aoreh @ May 17 2013, 15:47) *
100500%!

И в отдельный файлик config.hpp вынести вместо дефайнов. Иногда такие вещи имеет смысл настраивать от проекта к проекту, и здорово, когда они в одном месте...


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
DASM
сообщение May 17 2013, 14:51
Сообщение #18


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Уходим в офф, но насчет дефайнов крайне важно знать меру. Копался тут с сурцами STM - в шоке - куча огромная дефайнов, все вызывают друг друга (подставляются),но, главное - НАХРЕНА чтобы записать один переферийный регистр, причем один раз при включении питания, городить всю эту ахинею, в которой честно скажу, за полчаса не разобрался. Нагло написал AFMAP = 1 << 0 | 1 << 7; // my comments
и забил на весь этот стмовский бред. Совесть не мучает ни разу.
Go to the top of the page
 
+Quote Post
sidy
сообщение May 17 2013, 17:21
Сообщение #19


Местный
***

Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333



Разобрался в чем было дело. Когда я ставил точку останова во время работы, отладчик на какоето время (всегда произвольное) останавливал выполнение программы, потом продолжал и только после выполнение программы останавливалось окончательно. Разобрался с этим выводя данные с АЦП тут же в ЦАП.

Задам еще один вопрос в данной теме. Мне с приходом определенного уровня сигнала с АЦП необходимо вывести 5 импульсов. Как это лучше сделать используя таймер и регистры захвата сравнения

Сообщение отредактировал sidy - May 17 2013, 17:28
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение May 17 2013, 18:16
Сообщение #20


Гуру
******

Группа: Модераторы
Сообщений: 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)
Go to the top of the page
 
+Quote Post
haker_fox
сообщение May 18 2013, 05:04
Сообщение #21


Познающий...
******

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



QUOTE (sidy @ May 18 2013, 02:21) *
Разобрался с этим выводя данные с АЦП тут же в ЦАП.

Сорри за банальный совет, но почему бы не отлаживаться в консоли?
QUOTE (sidy @ May 18 2013, 02:21) *
Задам еще один вопрос в данной теме. Мне с приходом определенного уровня сигнала с АЦП необходимо вывести 5 импульсов. Как это лучше сделать используя таймер и регистры захвата сравнения

Записать в регистр сравнения число 5, настроить прерывание по сравнению, в котором выключать таймер. В основной программе (или в задаче ОС, если используете) мониторить определенный уровень. Как только уровень пришёл, запускаете таймер.


--------------------
Выбор.
Go to the top of the page
 
+Quote Post
sidy
сообщение May 18 2013, 13:35
Сообщение #22


Местный
***

Группа: Участник
Сообщений: 280
Регистрация: 2-11-08
Пользователь №: 41 333



Цитата(haker_fox @ May 18 2013, 09:04) *
Записать в регистр сравнения число 5

Это в регистр TIMx->CCR1? Но этот регистр, как я понимаю сформирует скважность, но не число импульсов?
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 15:10
Рейтинг@Mail.ru


Страница сгенерированна за 0.01589 секунд с 7
ELECTRONIX ©2004-2016