Миландр

Ключевым подразделением нашей компании является Центр Проектирования интегральных микросхем
Текущее время: 2017-окт-18 08:24

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 25 ]  На страницу 1, 2  След.
Автор Сообщение
 Заголовок сообщения: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-23 16:49 
Не в сети

Зарегистрирован: 2015-окт-19 22:02
Сообщения: 7
Здравствуйте уважаемые специалисты!
Есть такая проблема:
У меня в проекте есть UART с включенным FIFO
Код:
  RST_CLK_PCLKcmd(RST_CLK_PCLK_UART2, ENABLE);
   /* Установка коэффициента деления*/
  UART_BRGInit(MDR_UART2, UART_HCLKdiv1);
   /* Инициализация структуры */
  /* выбор скорости передачи/приема данных*/
  UART_InitStructure.UART_BaudRate                = 1500000;
 
  UART_InitStructure.UART_WordLength              = UART_WordLength8b;
  UART_InitStructure.UART_StopBits                = UART_StopBits1;
  UART_InitStructure.UART_Parity                  = UART_Parity_Even; // UART_Parity_No;   
  UART_InitStructure.UART_FIFOMode                = UART_FIFO_ON;
  UART_InitStructure.UART_HardwareFlowControl     = UART_HardwareFlowControl_RXE | UART_HardwareFlowControl_TXE;

  UART_DMAConfig(MDR_UART2,UART_IT_FIFO_LVL_2words,UART_IT_FIFO_LVL_2words);      //FIFO
  UART_DMACmd(MDR_UART2, UART_DMA_TXE | UART_DMA_RXE | UART_DMA_ONERR, ENABLE);   //FIFO

  /* Конфигурация UART2 */
  UART_Init (MDR_UART2,&UART_InitStructure);

/* Включение UART2 */
  UART_Cmd(MDR_UART2,ENABLE);
Цитата:
UART_InitStructure.UART_BaudRate= 1500000;
ДА, именно такая скорость, все работает через хитрую схему ( с этим проблем НЕТ).
Так же в проекте есть АЦП записывающее снимаемые значения в DMA:
Код:
/* DMA Конфигурация */
  /* сброс настроек DMA*/
  DMA_DeInit();
  DMA_StructInit(&DMA_InitStr);

  DMA_PriCtrlStr.DMA_SourceBaseAddr = (uint32_t)(&(MDR_ADC->ADC1_RESULT));
  DMA_PriCtrlStr.DMA_DestBaseAddr = (uint32_t)ADCConvertedValue;
  DMA_PriCtrlStr.DMA_SourceIncSize = DMA_SourceIncNo;
  DMA_PriCtrlStr.DMA_DestIncSize = DMA_DestIncHalfword;
  DMA_PriCtrlStr.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  DMA_PriCtrlStr.DMA_Mode = DMA_Mode_Basic;
  DMA_PriCtrlStr.DMA_CycleSize = 10;
  DMA_PriCtrlStr.DMA_NumContinuous = DMA_Transfers_1;
  DMA_PriCtrlStr.DMA_SourceProtCtrl = DMA_SourcePrivileged;
  DMA_PriCtrlStr.DMA_DestProtCtrl = DMA_DestPrivileged;
 
  DMA_InitStr.DMA_PriCtrlData = &DMA_PriCtrlStr;
  DMA_InitStr.DMA_Priority = DMA_Priority_High;
  DMA_InitStr.DMA_UseBurst = DMA_BurstClear;
  DMA_InitStr.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;
  /* Выбор канала */
  DMA_Init(DMA_Channel_ADC1, &DMA_InitStr);
  DMA_Cmd(DMA_Channel_ADC1, ENABLE);

Код:
/* Сброс настроек ADC */
  ADC_DeInit();
   
  ADC_StructInit(&sADC);
  ADC_Init (&sADC);

 
  ADCx_StructInit (&sADCx);

  sADCx.ADC_ClockSource      = ADC_CLOCK_SOURCE_ADC;                           //Источник тактирования внешний clock
  sADCx.ADC_SamplingMode     = ADC_SAMPLING_MODE_CICLIC_CONV;
  sADCx.ADC_ChannelSwitching = ADC_CH_SWITCHING_Disable;
  sADCx.ADC_ChannelNumber    = ADC_CH_ADC2;   

  sADCx.ADC_Channels         = 0;
  sADCx.ADC_LevelControl     = ADC_LEVEL_CONTROL_Disable;
  sADCx.ADC_LowLevel         = 0;
  sADCx.ADC_HighLevel        = 0;
  sADCx.ADC_VRefSource       = ADC_VREF_SOURCE_INTERNAL;
  sADCx.ADC_IntVRefSource    = ADC_INT_VREF_SOURCE_INEXACT;

   sADCx.ADC_Prescaler        = ADC_CLK_div_None;

  sADCx.ADC_DelayGo          = 7;
  ADC1_Init (&sADCx);
  ADC1_ITConfig((ADCx_IT_END_OF_CONVERSION  | ADCx_IT_OUT_OF_RANGE), DISABLE);

Так же в проекте предполагается прерывание по заполнению значениями снятых с АЦП в DMA, но
Код:
NVIC_EnableIRQ(DMA_IRQn);
делает общее прерывание по DMA, соответственно при посылки/приеме через UART, я тоже попадаю в прерывание, чего бы не хотелось!

Вопросы: как сделать прерывание исключительно по заполнению снятых с АЦП данных в DMA? Как разделить область памяти отводимой под работу с FIFO и область памяти отведенной под работу с АЦП?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-23 17:33 
Не в сети

Зарегистрирован: 2014-июн-25 09:29
Сообщения: 46
Цитата:
как сделать прерывание исключительно по заполнению снятых с АЦП данных в DMA?

Никак. Это - узкое место МК семейства 1986ВЕ9х. Прерывания по любому каналу DMA приходится обрабатывать в одном и том же обработчике.

Цитата:
Как разделить область памяти отводимой под работу с FIFO и область памяти отведенной под работу с АЦП?

Поясните, пожалуйста, что вы имеете в виду. Разделить, значит совместно использовать?
Если требуется отсылать результаты АЦП по UART, то тогда можно, например, использовать режим пинг-понг в работе с DMA. Складываем результаты АЦП в буфер 1, а в это время отправляем по UART результаты из буфера 2. Затем, наоборот, складываем результаты АЦП в буфер 2, а в это время отправляем по UART результаты из буфера 1.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-24 14:53 
Не в сети

Зарегистрирован: 2015-окт-19 22:02
Сообщения: 7
Тут я имею в веду (с)Документация на семейство 1986ВЕ9Х
Цитата:
Если необходимо оставлять адрес неизменным при чтении или записи
данных, для примера, при работе с FIFO, можно соответствующим образом настроить
контроллер на работу с фиксированным адресом

В итоге хотелось бы получить фиксированный адрес для FIFO и фиксированный адрес для значений АЦП, что бы они не перекликались в работе, т.к. по UART могут идти разные "отладочные" и "рабочие" данные не связанные с измерениями АЦП. :?: :roll:


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-24 16:44 
Не в сети

Зарегистрирован: 2011-сен-05 12:12
Сообщения: 168
Откуда: Саратов
Rudthaky писал(а):
Тут я имею в веду (с)Документация на семейство 1986ВЕ9Х
Цитата:
Если необходимо оставлять адрес неизменным при чтении или записи
данных, для примера, при работе с FIFO, можно соответствующим образом настроить
контроллер на работу с фиксированным адресом

В итоге хотелось бы получить фиксированный адрес для FIFO и фиксированный адрес для значений АЦП, что бы они не перекликались в работе, т.к. по UART могут идти разные "отладочные" и "рабочие" данные не связанные с измерениями АЦП. :?: :roll:

имеется в виду адрес, например, источника данных: DMA может брать их из памяти (тогда нужен автоинкремент) или из регистра внешнего устройства (например, FIFO, хотя никто не запрещает по DMA читать регистр состояния).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-28 10:47 
Не в сети

Зарегистрирован: 2014-июн-25 09:29
Сообщения: 46
Rudthaky писал(а):
В итоге хотелось бы получить фиксированный адрес для FIFO и фиксированный адрес для значений АЦП, что бы они не перекликались в работе, т.к. по UART могут идти разные "отладочные" и "рабочие" данные не связанные с измерениями АЦП.

Для каждого канала DMA индивидуально настраиваются адрес источника и приемника, а также все остальные параметры. Поэтому вы можете спокойно настроить канал DMA для работы с АЦП, указав в качестве источника регистр результата АЦП, а в качестве приемника - буфер, в который будете складывать результаты. Для источника надо будет запретить автоувеличение адреса, а для приемника - разрешить.
Для канала DMA по передаче данных по UART надо будет в качестве источника указать буфер с исходными данными, а качестве приемника - регистр данных UART. Для источника надо будет разрешить автоувеличение адреса, а для приемника - запретить.
Сложнее с приемом данных по UART посредством DMA. Проблема в том, что мы должны заранее знать, сколько символов нужно принять, чтобы настроить параметр DMA_CycleSize. Если протокол обмена по UART предполагает обмен пакетами с фиксированным количеством символов, то использование DMA возможно, в противном случае - очень проблематично. Если всё же найдете возможным применение DMA в этом контексте, то в качестве источника надо будет указать регистр данных UART, а качестве приемника - буфер для приема данных. Для источника надо будет запретить автоувеличение адреса, а для приемника - разрешить.
Для каждого канала DMA нужно будет отдельно создать по две структуры параметров: DMA_CtrlDataInitTypeDef и
DMA_ChannelInitTypeDef.
В обработчике прерываний от DMA нужно будет анализировать, от какого канала возникло прерывание.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-28 11:55 
Не в сети

Зарегистрирован: 2011-сен-05 12:12
Сообщения: 168
Откуда: Саратов
andelie писал(а):
В обработчике прерываний от DMA нужно будет анализировать, от какого канала возникло прерывание.

как? Ничего умнее чем у каждого канала смотреть код режима канала (0 - обработка завершена) не придумал.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-28 12:13 
Не в сети

Зарегистрирован: 2014-июн-25 09:29
Сообщения: 46
Вот обработчик прерываний от DMA из одного моего старого проекта. Здесь используется сразу три канала DMA.
Код:
// Обработчик для прерывания от DMA
void DMA_IRQHandler (void)
{
   // Это прерывание по завершению передачи по каналу SW4
   if (!(U_Generator_DMA_Ctrl_Base_Ptr->DMA_Control & 0x3FF0))
   // Биты  4..13 в слове DMA_Control управляющей структуры данных канала показывают количество оставшихся передач. Если это количество равно 0, то передача закончена.    
   // См. с.447 описания камня 1986ВЕ9х.
   // Можно использовать DMA_GetCurrTransferCounter (DMA_Channel_SW4, DMA_CTRL_DATA_PRIMARY);
   {
      // Подготовить к работе новый цикл цифро-аналоговых преобразований
      U_Generator_DMA_InitStructure.DMA_CycleSize = U_GENERATOR_BUFFER_SIZE;
      DMA_Init (DMA_Channel_SW4, &U_Generator_DMA_Channel_InitStructure);
   }

   // Это прерывание по завершению передачи по каналу ADC1
   if (!(U_ADC_DMA_ADC1_Ctrl_Base_Ptr->DMA_Control & 0x3FF0))
   {
      DMA_Cmd (DMA_Channel_ADC1, DISABLE);

      ADC1_Cmd (DISABLE);

      isr_evt_set (EVENT_ADC1_EOC, U_ADC_Task_ID);      
   }

   // Это прерывание по завершению передачи по каналу ADC2
   if (!(U_ADC_DMA_ADC2_Ctrl_Base_Ptr->DMA_Control & 0x3FF0))
   {
      DMA_Cmd (DMA_Channel_ADC2, DISABLE);

      ADC2_Cmd (DISABLE);
      
      isr_evt_set (EVENT_ADC2_EOC, U_ADC_Task_ID);      
   }
   
}


Ничего лучшего придумать не смог. Ну нет в этом камне отдельных прерываний для каждого канала DMA.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-28 12:34 
Не в сети

Зарегистрирован: 2011-сен-05 12:12
Сообщения: 168
Откуда: Саратов
andelie писал(а):
Вот обработчик прерываний от DMA из одного моего старого проекта. Здесь используется сразу три канала DMA.

интересно поведение такого обработчика, если при входе в обработчик обслуживание генератора еще не завершилось, а завершится при обработке второго АЦП.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июн-28 13:45 
Не в сети

Зарегистрирован: 2014-июн-25 09:29
Сообщения: 46
novikovfb писал(а):
если при входе в обработчик обслуживание генератора еще не завершилось, а завершится при обработке второго АЦП.

В моем случае это невозможно, так как запуск ADC1, ADC2 и генератора происходят синхронно, а время аналого-цифрового преобразования гораздо больше, чем время отправки данных в регистр ЦАП. Если интересно, то вот обработчик прерывания от таймера, в котором производится такой запуск:

Код:
// Обработчик для прерывания от Timer1
void Timer1_IRQHandler (void)
{
   register uint32_t a1, a2;
   
   // Запуск ADC1 и ADC2
   if ((MDR_ADC->ADC1_CFG & 0x00000001) && (MDR_ADC->ADC2_CFG & 0x00000001))
   {
      a1 = ADC_CLK_div_2 | (ADC_CH_ADC7 << 4) | ADC2_CFG_REG_GO | ADC1_CFG_REG_ADON;
      a2 = ADC_CLK_div_2 | (ADC_CH_ADC6 << 4) | ADC2_CFG_REG_GO | ADC1_CFG_REG_ADON;
      
      MDR_ADC->ADC2_CFG = a2;
      
      MDR_ADC->ADC1_CFG = a1;
   }
   
   // Запуск DAC
   DMA_Request (DMA_Channel_SW4);
   
  // Сбросить флаг прерывания по сравнению
  TIMER_ClearITPendingBit (MDR_TIMER1, TIMER_STATUS_CNT_ARR);
}


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июл-14 15:43 
Не в сети

Зарегистрирован: 2016-фев-26 09:54
Сообщения: 22
Здравствуйте.

После добавления в программу процедуры обработки прерывания по DMA, программа висит вечно в этом обработчике. DMA у меня используют TIMER2 и UART. Также работает блок АЦП, но с него я данные читаю по прерыванию АЦП, т.е. DMA он не использует. В Errata вычитал, что АЦП непрерывно вызывает запрос DMA, а тот в свою очередь непрерывно вызывает прерывание. Правильно ли я понимаю, что если нужен АЦП, то про прерывания от DMA можно забыть и наоборот?

Камень 1986ВЕ93У...

======================UPD======================
Хмм.. Отключил инициализацию АЦП - не помогло. Тоесть и отдельно друг от друга их не получится использовать? Но как, интересно, тут выше люди пользовались этим прерыванием?


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июл-15 10:17 
Не в сети

Зарегистрирован: 2014-июн-25 09:29
Сообщения: 46
Можно одновременно использовать и несколько каналов DMA, и АЦП. Главное - правильно инициализировать DMA.

Ключевые моменты:
1. Обязательно разрешить тактирование SSP1 и SSP2.
2. Запретить все прерывания, в том числе от SSP1 и SSP2.
3. Настроить DMA.
4. Разрешить требуемые прерывания.

Вот пример инициализации DMA для работы в режиме захвата с TIMER3:

Код:
// Конфигурация DMA
static void DMA_Config(void)
{
  // Разрешить тактирование DMA
  // Для корректной работы DMA необходимо разрешить тактирование SSP1 и SSP2
  // Если этого не сделать, то всё время будет возникать прерывание от DMA.   
  RST_CLK_PCLKcmd (RST_CLK_PCLK_DMA | RST_CLK_PCLK_SSP1 | RST_CLK_PCLK_SSP2, ENABLE); 
   
  // Запретить все прерывания, в том числе от SSP1 и SSP2.
  NVIC->ICPR[0] = 0xFFFFFFFF;
  NVIC->ICER[0] = 0xFFFFFFFF;   
   
  // Сбросить все настройки DMA
  DMA_DeInit();
  DMA_StructInit (&DMA_Channel_InitStructure);   
   
  DMA_InitStructure.DMA_SourceBaseAddr = (uint32_t)(&(FM_TIMER->CCR1));      
  DMA_InitStructure.DMA_DestBaseAddr = (uint32_t) TimerCapture;            
  DMA_InitStructure.DMA_CycleSize = U_FM_BUFFER_SIZE;                 // Размер буфера
  DMA_InitStructure.DMA_SourceIncSize = DMA_SourceIncNo;               
  DMA_InitStructure.DMA_DestIncSize = DMA_DestIncHalfword;               
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;       // Читаем и пишем значения по 16 бит (по полслова)
  DMA_InitStructure.DMA_NumContinuous = DMA_Transfers_1;             
  DMA_InitStructure.DMA_SourceProtCtrl = DMA_SourcePrivileged;           // Режим защиты источника
  DMA_InitStructure.DMA_DestProtCtrl = DMA_DestPrivileged;                   // Режим защиты приемника
  DMA_InitStructure.DMA_Mode = DMA_Mode_Basic;                    // Режим работы DMA - базовый
 
  // Задать структуру канала
  DMA_Channel_InitStructure.DMA_PriCtrlData = &DMA_InitStructure;
  DMA_Channel_InitStructure.DMA_Priority = DMA_Priority_High;
  DMA_Channel_InitStructure.DMA_UseBurst = DMA_BurstClear;
  DMA_Channel_InitStructure.DMA_SelectDataStructure = DMA_CTRL_DATA_PRIMARY;
 
  // Инициализировать канал DMA
  DMA_Init (DMA_Channel_TIM3, &DMA_Channel_InitStructure);                   

  MDR_DMA->CHNL_REQ_MASK_CLR = 1 << DMA_Channel_TIM3;
  MDR_DMA->CHNL_USEBURST_CLR = 1 << DMA_Channel_TIM3;

  // Задать приоритет аппаратного прерывания от DMA
  NVIC_SetPriority (DMA_IRQn, 1);    
   
}


Весь проект можно скачать здесь (lab6_2): https://cloud.mail.ru/public/BV1X/iS1hAif1e
В этом же архиве есть много других примеров, в которых используется DMA.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июл-16 08:48 
Не в сети

Зарегистрирован: 2016-фев-26 09:54
Сообщения: 22
Большое спасибо! :)
Странно что в Errata об этом ничего нет. Вроде свежую качал... =(


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июл-17 15:33 
Не в сети

Зарегистрирован: 2016-июл-17 15:26
Сообщения: 2
MWaso писал(а):
Большое спасибо! :)
Странно что в Errata об этом ничего нет. Вроде свежую качал... =(


MWaso, подскажите вам помог данный рецепт andelie? У себя в проекте я тоже наблюдал постоянный вызов прерывания DMA. Сейчас думаю либо отказываться от DMA, либо пытаться использовать рецепт.


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июл-18 12:54 
Не в сети

Зарегистрирован: 2010-июл-08 08:50
Сообщения: 733
Откуда: АО "ПКК Миландр"
MWaso писал(а):
Большое спасибо! :)
Странно что в Errata об этом ничего нет. Вроде свежую качал... =(
Дело не в Errata, а во внимательном прочтении документации.
В описании DMA есть правила обмена данными. Особенно стоит обратить внимание на Правило 19.
Ключевыми моментами при настройке DMA являются следующие моменты:
1. Заблокировать (замаскировать) обработку от всех каналов DMA (регистр MDR_DMA->CHNL_REQ_MASK_SET = 0xFFFFFFFF; ).
2. Разрешить работу всех каналов DMA (MDR_DMA->CHNL_ENABLE_SET = 0xFFFFFFFF; )
3. Разблокировать обработку от нужных каналов DMA (MDR_DMA->CHNL_REQ_MASK_CLR = (1 << X); //где X - номер канала, который необходимо обрабатывать).


Вернуться к началу
 Профиль  
 
 Заголовок сообщения: Re: Вопрос о прерывании по DMA
СообщениеДобавлено: 2016-июл-21 17:03 
Не в сети

Зарегистрирован: 2016-фев-26 09:54
Сообщения: 22
vitkorob, пока cделал без использования этого прерывания, так что не проверял. Но на будущее себе записал.

Petr, признаюсь, этот раздел с правилами DMA вызывает у меня сонливость и в голове откладывается очень медленно. Я читал несколько раз. Честно. Но когда-нибудь я его усвою. Обещаю.

Тот факт, что спящий контроллер SSP вызывает запрос DMA, это, наверное, все-же ошибка, достойная упоминания в errata, а не так что береженого бог бережет. Я так понял, ваш совет про маскирование всех ненужных каналов тоже помог бы в той ситуации.

Вот еще несколько непонятных моментов, непонятных из документации: dma_req[C] - это, как я понимаю, внутренний (невидимый пользователю) регистр запросов по каналам. Правильно? А dma_sreq[C] чем отличается? И есть ли он вообще в 1986ВЕ9х?

И еще непонятно, что дают режимы доступа, выбираемые битами HPROT. Чем буферизованный отличается от кешированного и что дает привелегированность.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 25 ]  На страницу 1, 2  След.

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: רגוזין רומאן и гости: 3


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB