Здравствуйте, уткнулся в проблему, не знаю куда копать. Первый проект на 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. А у меня оцифровывается первый канал и ничего не происходит дальше. ЧЯДНТ?