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

 
 
> stm32f030. некорректно работает DMA в sleep mode (решено)
jeka
сообщение Apr 12 2017, 19:07
Сообщение #1


Administrator
***

Группа: Свой
Сообщений: 400
Регистрация: 10-05-04
Пользователь №: 1



Несколько раундов борьбы с косяком, пока безуспешно. Суть следующая:
Оцифровываю данные так: АЦП -> DMA -> прерывание half transfer и full transfer.
Если процессор всегда в активном режиме, все работает прекрасно.
Но как только в холостой основной цикл добавляю остановку процессора (WFI), то начинает твориться следующее:

DMA генерирует прерывания как положено, с той же частотой и вовремя, т.е. как и без WFI. Но как только активирую WFI, то в RAM, куда DMA должна сохранять результат оцифровки, данные не записываются.
Точнее, экспериментально определено, что в буфере DMA обновляется только та часть данных, которая оцифровалась в моменты времени, когда процессор был в активном режиме (т.е. вертелся в обработчиках прерываний). Определил это добавлением холостого цикла в конце обработчика прерываний. И от величины задержки зависит, какие значения запишутся в RAM.
При этом все счетчики контроллера DMA работают корректно, что в sleep mode, что без него, т.е. нужный канал АЦП записывается всегда по нужному адресу. Счетчики DMA считывал в обработчике DMA, и делаю вывод что прерывания DMA вызываются вовремя (без задержек).

Вероятно, я что-то упустил в настройках или еще где, но по работе DMA в sleep mode ничего интересного не нашел. В errata также ничего полезного нет.
Слабо верится что такой косяк до ST до сих пор не дошел.


Куски кода:
CODE
ADC1->CFGR1=ADC_CFGR1_AWDSGL|ADC_CFGR1_CONT|ADC_CFGR1_DMACFG|ADC_CFGR1_DMAEN;
ADC1->CFGR2=ADC_CFGR2_CKMODE_0;

ADC1->CHSELR=0x02FF|ADC_CHSELR_CHSEL16;
ADC1->SMPR=6;// скоростью оцифровки также игрался
ADC->CCR|=ADC_CCR_TSEN;

// ADC DMA
DMA1_Channel1->CCR&=~DMA_CCR_EN;
DMA1_Channel1->CCR=DMA_CCR_PL_0*3 | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_HTIE | DMA_CCR_TCIE | DMA_CCR_TEIE;
DMA1_Channel1->CNDTR=20;
DMA1_Channel1->CPAR=(uint32_t)&(ADC1->DR);
DMA1_Channel1->CMAR=(uint32_t)&adcbuf;
DMA1_Channel1->CCR|=DMA_CCR_EN;

...

ADC1->CR=ADC_CR_ADSTART;


---------------- Основной цикл:
...
__enable_irq();

while (1) {
__WFI();// WFI cause DMA fill error in ADC bufer
};

------------------ И обработчик:

// Для фиксации позиции буфера DMA при обработке.
volatile int bp1, bp2;
volatile int bp1a, bp2a;

__irq void DMA1_Channel1_IRQHandler() {
int di=DMA1->ISR;

if (di & DMA_ISR_TEIF1) {
DMA1->IFCR=DMA_IFCR_CTEIF1;
}

if (di & DMA_ISR_HTIF1) {// нечетный вызов (первая половина буфера готова)
bp1=DMA1_Channel1->CNDTR;
DMA1->IFCR=DMA_IFCR_CHTIF1;
adc_new_data(&adcbuf[0]);
bp1a=DMA1_Channel1->CNDTR;
tc_cnt1++;
}

if (di & DMA_ISR_TCIF1) {// четный вызов (вторая половина буфера готова)
bp2=DMA1_Channel1->CNDTR;// Зафиксируем позицию DMA перед съемом данных
DMA1->IFCR=DMA_IFCR_CTCIF1;
adc_new_data(&adcbuf[1]);
bp2a=DMA1_Channel1->CNDTR;// Зафиксируем позицию DMA после съема данных
tc_cnt2++;
}

//for (int i=0; i<80; i++) __NOP();// Цикл, который влияет на количество байт, которые обновляются в буфере DMA
//(соответственно, появляется больше правильных выборок от начала буфера и от середины буфера)

}


Сообщение отредактировал IgorKossak - Apr 13 2017, 09:16
Причина редактирования: [codebox] для длинного кода. [code]-для короткого!!!
Go to the top of the page
 
+Quote Post



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

 


RSS Текстовая версия Сейчас: 15th August 2025 - 09:39
Рейтинг@Mail.ru


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