|
stm32f030. некорректно работает DMA в sleep mode (решено) |
|
|
|
Apr 12 2017, 19:07
|
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]-для короткого!!!
|
|
|
|
|
 |
Ответов
(1 - 9)
|
Apr 12 2017, 20:42
|
Administrator
  
Группа: Свой
Сообщений: 400
Регистрация: 10-05-04
Пользователь №: 1

|
Это понятно. Я к тому что контроллер DMA корректно работает с адресацией и прерываниями (именно DMA же определяет заполненность буфера), но не пишет в память. В документации про упоминание особенностей работы периферии АЦП или DMA в sleep режиме ничего интересного не нашел. Про sleep режим указано, что он лишь останавливает клоки процессора, но вся остальная периферия (в т.ч. и память) продолжают штатно работать. В разделе памяти про спячку тоже ничего нет. Ура, нашел в чем проблема  Есть такой бит - "sram interface clock enable during sleep mode". Включил, все заработало.
|
|
|
|
|
Apr 17 2017, 06:33
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(Alechek @ Apr 14 2017, 19:29)  Мои изыскания показывают, что особо сэкономить на остановке только тактовой процессора не получается. Куда выгодней ее просто снижать. Интересно. А как же изыскания Atmel, к примеру. Которые рекомендуют прямо противоположное. То есть быстро проснуться выполнить кусочек и заснуть глубоким сном. )) Я не экспериментировал. На это надо пол жизни потратить, но делал пару устройств малого потребления на MSP430. Последнее устройство вообще непонятно себя ведёт. Потребление намного выше , чем заявленное. Перерыл всё. Проект факультативный, поэтому тратить на него кучу времени не могу. Но, было бы любопытно сделать аналогичный проект на st32l0.
|
|
|
|
|
Apr 17 2017, 09:21
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
Цитата(SasaVitebsk @ Apr 17 2017, 11:33)  Интересно. А как же изыскания Atmel, к примеру. Которые рекомендуют прямо противоположное. То есть быстро проснуться выполнить кусочек и заснуть глубоким сном. )) ... Но, было бы любопытно сделать аналогичный проект на st32l0. Глубоким сном - да! Но если нужна работающая периферия, глубоким сном тут и не пахнет. Фишка, видимо, в том, что хоть ядро проца и стоит, но всякие NVIC работают, и жрут просто дофига! C STM32L сказка, там многое что можно напрямую от генератора запитать, а общую тактовую снизить. С STM32F0x0 хуже, там только UART может работать от генератора.
|
|
|
|
|
Apr 19 2017, 18:17
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Alechek @ Apr 17 2017, 11:21)  Глубоким сном - да! Но если нужна работающая периферия, глубоким сном тут и не пахнет. Фишка, видимо, в том, что хоть ядро проца и стоит, но всякие NVIC работают, и жрут просто дофига! Мои изыскания на этой ниве (но с LPC1758) дали похожий результат: я выяснил, что если выключить всю периферию, а также PLL, выключить кварц, затактироваться от внутреннего RC, и ещё включить после него максимальный делитель, так что тактовая проца составляет десятки кГц, то в таком режиме МК потребляет почти как в самом глубоком сне. И ещё и ОЗУ при этом остаётся целым. Правда один таймер я оставлял работать. Для побудки.
|
|
|
|
|
Apr 20 2017, 09:00
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Kabdim @ Apr 20 2017, 10:07)  А время пробудки не замеряли в том и в др. случае? У меня устройство в таком режиме (ожидания) периодически ложилось спать, потом просыпалось, включало периферию, опрашивало её несколько мсек (определяло нажатость кнопки, наличие подключения USB-хоста, ставило CTS Bluetooth-модулю, чтобы он мог выплюнуть накопленные за время сна данные), и, если можно оставаться в режиме ожидания, укладывалось спать опять. Этот период был == 300мсек. Для такого периода время просыпания не играет роли. Да там собственно оно должно быть быстрым: процессор выполняет WFI (на малой тактовой), таймер генерит сигнал прерывания (но входа в ISR нет), процессор переходит на след. команду после WFI и сразу сбрасывает делитель своей тактовой в 1 (до этого был выставлен максимум ==256), и дальнейшее выполнение уже должно идти на полной частоте IRC (4МГц если склероз не изменяет). Соответственно когда проц спит у него тактовая ~15.6кГц. По потреблению это почти то же самое, что глубокий сон.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|