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

 
 
> stm32f407 + interleaved mode ADC + DMA
Sonya
сообщение Jun 1 2016, 09:16
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 15
Регистрация: 10-02-11
Пользователь №: 62 860



Нужно сделать вот что: запускать АЦП по внешнему сигналу (External trigger = EXTI line11). Режим работы АЦП при этом - interleaved mode с DMA (три АЦП подряд ацепируют один и тот же сигнал на входе).
Инициализация АЦП проходит так (под копирку из примеров библиотеки стандартной периферии):
CODE
static void ADC_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;

/* Enable peripheral clocks *************************************************/
RCC_AHB1PeriphClockCmd( ADC1_2_CHANNEL_GPIO_CLK , ENABLE);
RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA2 , ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1 , ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC2 , ENABLE);
RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC3 , ENABLE);

/* Configure ADC Channel 0 pin as analog input *****************************/
GPIO_InitStructure.GPIO_Pin = GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIO_PORT, &GPIO_InitStructure);

/* DMA2 Stream0 channel 0 configuration **************************************/
DMA_InitStructure.DMA_Channel = DMA_Channel_0;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC_CDR_ADDRESS;
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&aADCTripleConvertedValue[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
DMA_InitStructure.DMA_BufferSize = num; //сколько точек взять для преобразования
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(DMA_STREAMx, &DMA_InitStructure);

/* DMA2_Stream0 enable */
DMA_Cmd(DMA2_Stream0, ENABLE);

/* ADC Common configuration *************************************************/
ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
ADC_CommonInit(&ADC_CommonInitStructure);

/* ADC1 regular channel 0 configuration ************************************/
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Falling;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_Ext_IT11;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfConversion = 1;
ADC_Init(ADC1, &ADC_InitStructure);

ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);

ADC_DMACmd(ADC1, ENABLE);

/* ADC2 regular channel 0 configuration ************************************/
ADC_Init(ADC2, &ADC_InitStructure);
/* ADC2 regular channel 0 configuration */
ADC_RegularChannelConfig(ADC2,ADC_Channel_0, 1, ADC_SampleTime_3Cycles);

/* ADC3 regular channel 0 configuration ************************************/
ADC_Init(ADC3, &ADC_InitStructure);
/* ADC3 regular channel 0 configuration */
ADC_RegularChannelConfig(ADC3, ADC_Channel_0, 1, ADC_SampleTime_3Cycles);
}

Внешней командой (по Modbus на UARTе) инициализируется вход, на который приходит синхроимпульс, разрешаются прерывания и включается АЦП:
Код
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
    GPIOC->MODER &=~GPIO_MODER_MODER11;      
    GPIOC->PUPDR &=~GPIO_PUPDR_PUPDR11;      
    SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI11_PC;
    EXTI->IMR    |=(EXTI_IMR_MR11);          
    EXTI->FTSR   |=(EXTI_FTSR_TR11);                  
    DMA2_Stream0 -> CR |= DMA_SxCR_TCIE;
    NVIC_EnableIRQ(DMA2_Stream0_IRQn);
      
    ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
    ADC_Cmd(ADC1, ENABLE);
    ADC_Cmd(ADC2, ENABLE);
    ADC_Cmd(ADC3, ENABLE);


И что происходит в обработчике DMA:

Код
void DMA2_Stream0_IRQHandler(void){  
  DMA2 -> LIFCR |= DMA_LIFCR_CTCIF0; //обнуляем флаг Transfer Complete
  ADC_MultiModeDMARequestAfterLastTransferCmd(DISABLE);
  ADC_Cmd(ADC1, DISABLE);
  ADC_Cmd(ADC2, DISABLE);
  ADC_Cmd(ADC3, DISABLE);  
}



Синхронизация не работает при таком раскладе. Прерывание DMA срабатывает не связано с внешним сигналом: то до его спадающего фронта, то после.
Если эту ножку оторвать, то АЦП вообще не запускается (по крайней мере в обработчик DMA не входит). То есть как-то этот сигнал всё-таки действует.
Подскажите, пожалуйста, что я делаю не так? Я так понимаю, что секрет в этих двух строчках:
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Falling;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_Ext_IT11;

Выставление разных ADC_ExternalTrigConvEdge дает одинаковую картину (только если не выставить его в None).

Внешний сигнал с синхроимпульсом проверен - перепроверен: четко идет раз в 100мкс длительностью 50 мкс. Фронты адекватные.

Если в обработчике DMA не запрещать ADC, то это прерывание срабатывает каждые ~20мкс. Где-то в мануале было написано, что надо бы отрубать периферию от DMA каждый раз при срабатывания прерывания.

Если честно, не очень понимаю, как правильно инициализировать EXTI line11.
EXTI->IMR |=(EXTI_IMR_MR11); <- это пережитки прошлой программы, но вроде как и здесь как-то также должно быть или нет (внешний сигнал приходит на gpioc.11)?
EXTI->FTSR |=(EXTI_FTSR_TR11);

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

Раньше версия программы была немного иной: АЦП запускалось в обработчике прерывания по внешнему сигналу. Всё работало. Но потребовалось изменить код, чтобы АЦП запускалось триггером по этому внешнему сигналу. У меня возникло подозрение, что возможно эта опция запуска АЦП по триггеру внешним сигналом в режиме interleaved + DMA вообще не работает в stm...
Может ли такое быть? )



Внешняя команда, приходящая по Modbus, обрабатывалась прямо в обработчике по таймеру 5. Видимо, из-за этого неправильно синхронизировалось АЦП с первым приходом фронта внешнего импульса (т.к. прерывание tim5 приоритетней, чем dma2_stream0). Поэтому сейчас этот код добавлен после ADC_config(). А в обработчик по таймеру, где раньше выполнялись эти строчки, добавлено выставление флага flag = 1; , проверка которого идет в основном цикле программы.
CODE

ADC_Config();
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
GPIOC->MODER &=~GPIO_MODER_MODER11;
GPIOC->PUPDR &=~GPIO_PUPDR_PUPDR11;
SYSCFG->EXTICR[2] |= SYSCFG_EXTICR3_EXTI11_PC;
EXTI->IMR |=(EXTI_IMR_MR11);
EXTI->FTSR |=(EXTI_FTSR_TR11);
DMA2_Stream0 -> CR |= DMA_SxCR_TCIE;
NVIC_EnableIRQ(DMA2_Stream0_IRQn);

while(1){
if (flag ==1) {
flag =0;
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
ADC_Cmd(ADC1, ENABLE);
ADC_Cmd(ADC2, ENABLE);
ADC_Cmd(ADC3, ENABLE);
}
}


И всё же непонятно, почему по второй, третьей .... и т.д. команде DMA срабатывает в какие-то произвольные моменты времени, несинхронизированно с внешним сигналом.
И почему , если ADC не выключать или выключать и включать прямо в обработчике DMA, то DMA срабатывает каждые ~20мкс, а не раз в 100мкс...

Сообщение отредактировал Sonya - Jun 1 2016, 09:15
Причина редактирования: [codebox] для длинного кода. [code]-для короткого!!!
Go to the top of the page
 
+Quote Post



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

 


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


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