Миландр

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

Часовой пояс: UTC+03:00




Начать новую тему  Ответить на тему  [ 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
Сообщения: 121
Цитата:
как сделать прерывание исключительно по заполнению снятых с АЦП данных в 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
Сообщения: 183
Откуда: Саратов
Rudthaky писал(а):
Тут я имею в веду (с)Документация на семейство 1986ВЕ9Х
Цитата:
Если необходимо оставлять адрес неизменным при чтении или записи
данных, для примера, при работе с FIFO, можно соответствующим образом настроить
контроллер на работу с фиксированным адресом
В итоге хотелось бы получить фиксированный адрес для FIFO и фиксированный адрес для значений АЦП, что бы они не перекликались в работе, т.к. по UART могут идти разные "отладочные" и "рабочие" данные не связанные с измерениями АЦП. :?: :roll:
имеется в виду адрес, например, источника данных: DMA может брать их из памяти (тогда нужен автоинкремент) или из регистра внешнего устройства (например, FIFO, хотя никто не запрещает по DMA читать регистр состояния).


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

Зарегистрирован: 2014-июн-25 09:29
Сообщения: 121
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
Сообщения: 183
Откуда: Саратов
andelie писал(а):
В обработчике прерываний от DMA нужно будет анализировать, от какого канала возникло прерывание.
как? Ничего умнее чем у каждого канала смотреть код режима канала (0 - обработка завершена) не придумал.


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

Зарегистрирован: 2014-июн-25 09:29
Сообщения: 121
Вот обработчик прерываний от 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
Сообщения: 183
Откуда: Саратов
andelie писал(а):
Вот обработчик прерываний от DMA из одного моего старого проекта. Здесь используется сразу три канала DMA.
интересно поведение такого обработчика, если при входе в обработчик обслуживание генератора еще не завершилось, а завершится при обработке второго АЦП.


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

Зарегистрирован: 2014-июн-25 09:29
Сообщения: 121
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
Сообщения: 121
Можно одновременно использовать и несколько каналов 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
Сообщения: 734
Откуда: АО "ПКК Миландр"
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+03:00


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

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 4 гостя


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

Перейти: 

Создано на основе phpBB® Forum Software © phpBB Limited
Русская поддержка phpBB