|
DAC + DMA в STM32F2xx |
|
|
|
Feb 14 2012, 07:21
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Пытаюсь запустить DAC STM32f217 в режиме работы от DMA. В некую переменную int ForDAC2Value (переменная в памяти) переносятся данные преобразования ADC (по прерываниям конца преобразования). Инициализирую DAC2 + DMA1 для того, чтобы с помощью DMA1 перенести значение ForDAC2Value в DAC2 CODE __IO uint16_t ForDAC2Value = 0;
void DAC_Config(void) { DAC_InitTypeDef DAC_InitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure;
/* Enable DAC2, DMA1 and GPIO clocks ****************************************/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 | RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
/* Configure DAC2 pin as analog input ***************************************/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure);
/* DMA1 Stream6 channel7 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_Channel_7; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(DAC->DHR12R2); DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ForDAC2Value; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 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(DMA1_Stream6, &DMA_InitStructure); DMA_Cmd(DMA1_Stream6, ENABLE);
// конфигурируем ЦАП DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable; DAC_Init(DAC_Channel_2, &DAC_InitStructure); /* Enable DAC */ DAC_Cmd(DAC_Channel_2, ENABLE);
DAC_DMACmd(DAC_Channel_2, ENABLE); }
Не работает. Если сделать в прерываниях по концу преобразования ADC просто DAC->DHR12R2 = ForDAC2Value; (перенос данных с пом. процессора) Все работает нормально. Просмотрите код please, кому не лень. В чем тут проблема?
Сообщение отредактировал Acvarif - Feb 14 2012, 08:05
|
|
|
|
|
Feb 15 2012, 08:48
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Полная ерунда получается с DAC. Без DMA работает. Стоит подключить DMA все виснет. И вообще не понятно какая все же stream для DAC2 stream5 или 6? В даташите stream6, в примере с библиотекой stream5. Но ни стой ни с другой не работает. Может там и канал другой (не 7)? Просто гайка. Еррату почитать, что ли. Вот инициализация DAC2 + DMA1 канал 7 stream5 (с таймером) для формирования синуса. Не работает... CODE #define DAC_DHR12R2_ADDRESS 0x40007414 const uint16_t Sine12bit[32] = { 2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056, 3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909, 599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647};
void DAC_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; DAC_InitTypeDef DAC_InitStructure; DMA_InitTypeDef DMA_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; // NVIC_InitTypeDef NVIC_InitStructure;
/* Enable DAC reset state */ RCC_APB1PeriphResetCmd(RCC_APB1Periph_DAC, ENABLE); /* Release DAC from reset state */ RCC_APB1PeriphResetCmd(RCC_APB1Periph_DAC, DISABLE);
/* Enable DAC2, DMA1 and GPIO clocks ****************************************/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1 | RCC_AHB1Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM6, ENABLE);
/* Configure DAC2 pin as analog input ***************************************/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Time base configuration */ TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); TIM_TimeBaseStructure.TIM_Period = 0xFF; TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); /* TIM6 TRGO selection */ TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update); /* TIM6 enable counter */ TIM_Cmd(TIM6, ENABLE);
/* DAC channel2 Configuration */ DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO; DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None; DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; DAC_Init(DAC_Channel_2, &DAC_InitStructure);
/* DMA1_Stream5 channel7 configuration **************************************/ DMA_DeInit(DMA1_Stream5); DMA_InitStructure.DMA_Channel = DMA_Channel_7; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)DAC_DHR12R2_ADDRESS; DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&Sine12bit; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_BufferSize = 32; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 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(DMA1_Stream5, &DMA_InitStructure); /* Enable DMA1_Stream5 */ DMA_Cmd(DMA1_Stream5, ENABLE); /* Enable DAC Channel2 */ DAC_Cmd(DAC_Channel_2, ENABLE); /* Enable DMA for DAC Channel2 */ DAC_DMACmd(DAC_Channel_2, ENABLE);
}
|
|
|
|
|
Feb 21 2012, 19:15
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(Acvarif @ Feb 17 2012, 09:39)  Откликнитесь кто запускал DAC stm32f2xx от DMA. DAC + DMA stm32f1xx наверняка работает. Почему связка DAC + DMA stm32F2xx мертвая? Даже фирменный пример из библиотеки периферии не работает. Где там напутано с каналами и стримами? Похоже с Dac stm32f2xx через DMA никто не работал. Ну да ладно... По ходу возник довольно актуальный вопрос по поводу DMA. Возможно ли с помощью DMA по внешнему событию читать в память 16 бит данных с GPio порта? Согласно документации похоже, что такое не предусмотрено. Но может я невнимательно читал доку? И такой вариант както возможен?
|
|
|
|
|
Feb 21 2012, 19:35
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Acvarif @ Feb 21 2012, 23:15)  Похоже с Dac stm32f2xx через DMA никто не работал. Ну да ладно... Наверняка кто-то работал. Я имел дело и с DMA, и с DAC. Только в Ваш код влазить не стану, ибо страдаю аллергией на STишные библиотеки. Цитата(Acvarif @ Feb 21 2012, 23:15)  По ходу возник довольно актуальный вопрос по поводу DMA. Возможно ли с помощью DMA по внешнему событию читать в память 16 бит данных с GPio порта? Согласно документации похоже, что такое не предусмотрено. Но может я невнимательно читал доку? И такой вариант както возможен? Подтверждаю: невнимательно читал. Внешние события могут регистрироваться множеством способов: через USART, SPI, TIMER. Все они могут вызывать транзакцию DMA. Если под "внешним событием" подразумевается просто фронт на входе, то см. в сторону таймеров.
|
|
|
|
|
Feb 22 2012, 06:12
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(scifi @ Feb 21 2012, 23:35)  Подтверждаю: невнимательно читал. Внешние события могут регистрироваться множеством способов: через USART, SPI, TIMER. Все они могут вызывать транзакцию DMA. Если под "внешним событием" подразумевается просто фронт на входе, то см. в сторону таймеров. Спасибо. Да, именно фронт на входе. Адрес приемника установить нет проблем. Но как тогда установит адрес источника? Получается, что в качестве адреса источника периферии будет адрес какого либо GPIO. Но в таблице стримов нет такой периферии как GPIO. На какой канал-стрим все подключать? Получается, что на канал и стрим используемого таймера? Так разве пойдет? Работать будет?
|
|
|
|
|
Feb 22 2012, 07:14
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(scifi @ Feb 22 2012, 10:49)  В регистр DMA_SxPAR пишем &GPIO_xDR. В регистр DMA_SxM1AR пишем &buffer (адрес приёмного буфера). Стрим выбираем такой, чтобы мог запускаться от выбранного таймера. Всё. Понял. Спасибо. Если это заработает тогда STM_у цены нету. Цитата Вот рабочий код для генераци треугольника или шума: Возврвщаясь к теме: Какой все же стрим у DAC2 stm32f217 - 5 или 6 (в демках ставят 5, в юсер мануале 6) В приведенном коде нет DMA
|
|
|
|
|
Feb 22 2012, 07:23
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(Acvarif @ Feb 22 2012, 11:14)  Понял. Спасибо. Если это заработает тогда STM_у цены нету. Конечно заработает. И не такое работало. Предвидя дальнейшие вопросы, даю подсказку: таймеры могут формировать запросы DMA по событию Capture, которое может вызываться фронтом на входе таймера. И вообще таймеры в STM32 весьма мощные и позволяют творить чудеса. При условии, что не запутаетесь и правильно их запрограммируете. Цитата(Acvarif @ Feb 22 2012, 11:14)  Какой все же стрим у DAC2 Вопрос не имеет смысла и вскрывает глубинное непонимание принципа работы DMA. Номер стрима определяет выбор источников сигнала запроса DMA. Он не определяет адрес источника и приёмника данных.
|
|
|
|
|
Feb 22 2012, 07:39
|
Знающий
   
Группа: Участник
Сообщений: 998
Регистрация: 27-08-08
Пользователь №: 39 850

|
Цитата(scifi @ Feb 22 2012, 11:23)  Номер стрима определяет выбор источников сигнала запроса DMA. Он не определяет адрес источника и приёмника данных. Еще раз спасибо. Дошло. С таймером надеюсь разберусь. По поводу DMA и GPIO: пытаюсь определиться как stm32+DMA будет успевать читать данные (16 бит) поступающие на один из портов (от ПЛИС) с частотой 120 кГц (92.16 Мбит/сек) c дальнейшей их передачей по Ethernet на ПК Похоже, что должен справиться.
|
|
|
|
|
Feb 22 2012, 07:54
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(Acvarif @ Feb 22 2012, 13:14)  В приведенном коде нет DMA Вот с DMA: Код Pin<'A', 4>::Mode(ANALOGINPUT); Pin<'A', 5>::Mode(ANALOGINPUT);
// init timer: RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; TIM2->CR1 = 0; // count up, no divisor TIM6->PSC = timer_prescaler; // prescaler TIM6->ARR = timer_period; // period TIM6->CR2 |= TIM_CR2_MMS_1; // MMS = 010 : update event is selected as a trigger output (TRGO)
// init DAC: DAC->CR &= ~DAC_CR_EN1; // DAC disable RCC->APB1ENR |= RCC_APB1ENR_DACEN; DAC->CR = 0 | DAC_CR_BOFF1 // disable output buffer | DAC_CR_TEN1 // trigger enable ;
RCC->AHBENR |= RCC_AHBENR_DMA2EN;
// configure DMA channel DMA2_Channel3->CCR = 0 | DMA_CCR1_DIR // Direction = read from memory | DMA_CCR1_CIRC // Circular mode | DMA_CCR1_MINC // Memory increment mode | DMA_CCR1_PSIZE_0 // Peripheral size = halfword | DMA_CCR1_MSIZE_0 // Memory size = halfword | DMA_CCR1_PL_1 // Channel Priority level ; DMA2_Channel3->CNDTR = sizeof(sine_table) / sizeof(sine_table[0]); // count DMA2_Channel3->CPAR = (uint32_t)&DAC->DHR12R1; // Peripheral address DMA2_Channel3->CMAR = (uint32_t)&sine_table; // Memory address
// enable DMA channel. DMA2_Channel3->CCR |= DMA_CCR1_EN;
// enable DAC DAC->CR |= DAC_CR_EN1;
// enable DAC DMA DAC->CR |= DAC_CR_DMAEN1;
// Run timer TIM6->CR1 |= TIM_CR1_CEN;
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|