Здравствуйте, уткнулся в проблему, не знаю куда копать. Первый проект на STM, и идеи кончились.
Задача: измерение напряжения на 4х аналоговых входах. 100х4 раз в секунду достаточно.
Проблема: Из-за опроса нескольких входов использую DMA. Данные идут, но отсутствует однозначность
Канал№х -> Ячейка[x].
Как бы отсутствие синхронизации в работе ADC и DMA.
Крайний вариант решения: Отключить DMA и запускать ADC однократно, по-канально. Каждый раз переконфигурируя на следующий канал и ожидая прерывания готовности результата. Т.е. симулировать DMA программно.
Плата Discovery со стекляшкой.
- Код: Выделить всё • Развернуть
- uint16_t recv_array[6];
 ...........................................................................
 // Adjust system clock prescaler
 CLK_CKDIVR = 0; // no system clock prescaler (16 MHz)
 
 // Configure timer 1
 ********** не важно, думаю. ********************
 // Configure timer 4
 ********** не важно, думаю. ********************
 
 // Configure DMA
 CLK->PCKENR2 |= CLK_PCKENR2_DMA1; //Тактирование
 
 DMA1_Channel0->CNBTR = sizeof(recv_array)-1; //Размер буфера
 
 DMA1_Channel0->CPARH = (ADC1_BASE+4)>>8; //Адрес регистра АЦП (старший байт)
 DMA1_Channel0->CPARL = (uint8_t)(ADC1_BASE+4); //Младший
 DMA1_Channel0->CM0ARH = (uint8_t)((uint16_t)(recv_array)>>8); //Адрес буфера
 DMA1_Channel0->CM0ARL = (uint8_t)(recv_array);
 DMA1_Channel0->CSPR |= DMA_CSPR_16BM | DMA_CSPR_PL; //Режим работы с 16и битными числами. | HighPriority
 DMA1_Channel0->CCR |= DMA_CCR_IDM | DMA_CCR_CE | DMA_CCR_TCIE | DMA_CCR_ARM; //Включаем канал и разрешаем прерывание
 DMA1->GCSR |= DMA_GCSR_GE; //Включаем DMA
 
 // Coinfigure ADC
 CLK->PCKENR2 |= CLK_PCKENR2_ADC1; //Тактирование
 ADC1->CR1 |= ADC_CR1_ADON | ADC_CR1_CONT; //Пинаем АЦП, чтобы он проснулся + Continious
 ADC1->CR2 |= (uint8_t)0x02; // 16 cycles per samle period
 ADC1->CR3 |= (uint8_t)0x02; // 16 cycles per samle period
 
 ADC1->TRIGR[0] |= ADC_TRIGR1_TSON | (1<<0); //Подаем питание на датчик
 ADC1->TRIGR[2] |= (1<<2) | (1<<1) | (1<<0); // Disable triggers on inputs
 ADC1->TRIGR[3] |= (1<<7); // Disable triggers on inputs
 ADC1->SQR[0] |= (1<<5) | (1<<0); //Measure temperatire + ch24
 ADC1->SQR[2] |= (1<<2) | (1<<1) | (1<<0); //Measure ext channels 10,9,8
 ADC1->SQR[3] |= (1<<7); //Measure ext channel 7
 
 SomeDelay(); // let sensor to startup
 
 // Enable interrupts
 asm("RIM");
 ADC1->CR1 |= ADC_CR1_START; //Поехали!
 
 
 while (1) //В цикле будем мигать светодиодом
 {
 
 PC_ODR_bit.ODR7 = 1; //Переключаем пин в высокий уровень - светодиод горит
 SomeDelay(); //Задержка в 0.5 сек
 PC_ODR_bit.ODR7 = 0; //Пин в низкий уровень - светик тухнет
 SomeDelay();
 };
 
 return 0;
 }
 ISR(TIM1_OVF, TIM1_OVR_UIF_vector)
 {
 TIM1_SR1_bit.UIF = 0; //Сброс флага прерывания
 };
 ISR(TIM4_OVF, TIM4_UIF_vector)
 {
 TIM4_SR1_bit.UIF = 0; //Сброс флага прерывания
 };
 ISR(ADC_IRQ, COMP_EF1_vector)
 {
 //Забираем результат
 x=x; //ТУТ СТОИТ BREAKPOINT
 //TIM4_SR1_bit.UIF = 0; //Сброс флага прерывания
 };
 ISR(DMA_IRQ, DMA1_CH0_TC_vector) //INTERRUPT_HANDLER(DMA_IRQ, 2)
 {
 DMA1_Channel0->CSPR &= ~DMA_CSPR_TCIF;
 }
Прерывание вызывается только вот это. Все аналоговые входа на напряжении питания, измеряется только температурный датчик. При этом в "recv_array" находится вот что (последовательные breakpoint-ы):
- Код: Выделить всё • Развернуть
- 4095 4095 4095 712_ 712_ 4095 ...
 4095 4095 4095 4095 708_ 4095 ...
 4095 4095 4095 4095 4095 4095 ...
 711_ 4095 4095 4095 709_ 4095 ...
 4095 4095 4095 4095 4095 708_ ...
 4095 4095 706_ 708_ 4095 4095 ...
 "_" - это просто для форматирования в колонки добавил
А ожидались 7хх в одну строчку.
Подскажите, пожалуйста, куда копать. Перфекционист не разрешает симулировать DMA программно ((. Пока что.
ПС: Да, проверял что будет если снимать DMA_CCR_ARM, ADC_CR1_CONT, делать массив больше/меньше количества опрашиваемых каналов - все одно: входа один раз оцифровываются, данные в буфере, прерывания не вызываются и все...
Добавлено спустя 17 секунд:
Вчера весь вечер провертел, медитировал на регистры ADC и DMA, ясность не появилась.
Менял время выборки АЦП, картина не поменялась - значит все таки только ADC пинает DMA. Только както странно.
Пробовал выключить CONT в ADC и тыцать START в прерывании ADC_CR1, но он тогда опрашивает только первый по порядку канал (
В режиме отладки, нажав паузу, могу ли я по состоянию регистров какнибудь понять какой канал ADC сейчас оцифровывается? Чтобы хоть понять что он делает?
Еще совсем непонятно, в референце написано, что если не взвести CONT=1 и запустить ADC с несколькими выбранными каналами, то он оцифрует всю очередь (если выключить DMA - то останется результат только последнего канала), и после обработки последнего канала вызовет прерывание EOC. А у меня оцифровывается первый канал и ничего не происходит дальше. ЧЯДНТ?




