Обсуждаем контроллеры компании Atmel.
Ответить

АЦП в режиме Auto Triggering

Вс янв 07, 2024 12:58:31

Уважаемые форумчане, всех с праздниками!
Пытаюсь использовать АЦП AVR в режиме периодического автозапуска от таймера.
Код пытается работать, опрос АЦП осуществляется, но почему-то ровно 2 раза, а не до бесконечности, как планировалось.
После этого код висит в вечном цикле (проверял, тестовый код в вечном цикле корректно выполняется), а прерывание АЦП не вызывается более 2 раз.

Тестирую на ATmega16, тактовая частота 4МГц, на входе потенциометр, результат наблюдаю в программе-читалке COM-порта.
По задумке должно возникать событие Compare Match B таймера 1 с частотой 2Гц (проверял, возникает c нужной частотой),
которое автотриггерит АЦП, запуская прерывание АЦП по окончанию преобразования (запускается, но ровно 2 раза, если жать на Reset, то снова 2 раза и дальше тишина до Reset),
в прерывании АЦП результат отправляю по UART (результат корректный, по UART доходит)
Использую Microchip Studio 7.0, оптимизация отключена.

Помогите, товарищи! Сломал всю голову, скурил весь даташит, ничего не понимаю! Возможно, глаз замылился, но не настолько же! Четвертые сутки бьюсь с простеньким, вроде бы, кодом (

Код ниже:
Код:
#include <avr/io.h>
#include <avr/interrupt.h>

void init();
void uart_init();
void timer1_init();
void adc_init();
void uart_send( char x );

ISR( ADC_vect )
{
    uart_send( ADCH );
}

int main(void)
{
   init();
      
    while (1){}
}

void init()
{
    uart_init();
   timer1_init();
   adc_init();
   
   sei();
}

void uart_init()
{
    UBRRL = 25; // 9600bod at CLK = 4MHz
    UCSRB = 1 << TXEN;       
}

void timer1_init()
{
   OCR1A   = 31250;
   OCR1B   = OCR1A;
   TCCR1B  = ( 1 << WGM12 ) | ( 1 << CS11 ) | ( 1 << CS10 ); // /64 2Hz at CLK=4MHz
}

void adc_init()
{
    ADMUX  = ( 1 << REFS0 ) | ( 1 << ADLAR ); // PA0, AVCC, PA0
   SFIOR  = ( 1 << ADTS2 ) | ( 1 << ADTS0 ); // COMPB
   ADCSRA = ( 1 << ADEN )  | ( 1 << ADSC ) | ( 1 << ADATE ) | ( 1 << ADIE ) | ( 1 << ADPS2 ) | ( 1 << ADPS0 ); //COMPB, ADCclk=125kHz
   
}

void uart_send( char x )                           
{
    while ( !( UCSRA & ( 1 << UDRE ) ) );       
    UDR = x;                                     
}
Вложения
main.c
Исходник в виде файла
(978 байт) Скачиваний: 15

Re: АЦП в режиме Auto Triggering

Вс янв 07, 2024 15:01:40

первый запуск АЦП происходит потому, что ты при инициализации АЦП сразу задал ADSC - старт преобразования.
второй запуск, видимо, происходит по заданному триггеру.
убери (1 << ADSC), должен остаться один запуск.
но почему нет повторов "до бесконечности" я сказать не могу.

Re: АЦП в режиме Auto Triggering

Вс янв 07, 2024 15:23:43

Если убрать (1 << ADSC) при инициализации, то запуск только один, я пробовал. Что тоже странно, ибо, как я понимаю даташит, опрос АЦП стартует только после выставления start conversion (если не брать во внимание энергосберегающие режимы).
Попа какая-то, простите за физиологию.. Уже в errata полез от горя, но не нашел там поддержки(

Добавлено after 4 minutes 31 second:
Пробовал выставлять ADSC <- 1 в main(), после разрешения глобальных прерываний, давал длинные задержки перед этим (даташит говорит, что модули АЦП могут инициализироваться 1 * CLKadc + какое-то там время), результат идентичен

Добавлено after 8 minutes 5 seconds:
Можно, конечно, в прерывании таймера руками выставлять ADSC - режим однократного опроса, так работает, но какого x***, если есть заявленный автотриггер? Понять бы, кто тупой, я, или микрочип?! Начинаю сомневаться .. в микрочипе

Re: АЦП в режиме Auto Triggering

Вс янв 07, 2024 16:02:31

после задания (1 << ADSC) АЦП стартует сразу же, не ожидая запуска по триггеру.
у тебя же старт должен происходить по триггеру, без установки этого бита.
в даташите на АТмега16 я не нашел, чтобы бит ADATE сам сбрасывался. но по поведению похоже, что бит сбрасывается и запуск по триггеру происходит однократно.
но ты можешь попробовать в прерывании от АЦП заново установить этот бит ADATE, и посмотреть, будет ли автостарт повторяться.

Re: АЦП в режиме Auto Triggering

Вс янв 07, 2024 16:11:02

Флаг OC1B надо вручную сбрасывать, т.к. обработчик отсутствует.
Добавьте
Код:
TIFR |= (1 <<  OCF1B);
в обработчик ADC.
Иначе, OC1B так и продолжает висеть, и новый строб не проходит.

Re: АЦП в режиме Auto Triggering

Вс янв 07, 2024 16:45:14

Флаг OC1B надо вручную сбрасывать, т.к. обработчик отсутствует.
Добавьте
Код:
TIFR |= (1 <<  OCF1B);
в обработчик ADC.
Иначе, OC1B так и продолжает висеть, и новый строб не проходит.


Мать моя, женщина, точно, просохатил! Спасибо огромное, заработало! :)

Добавлено after 4 minutes 33 seconds:
после задания (1 << ADSC) АЦП стартует сразу же, не ожидая запуска по триггеру.
у тебя же старт должен происходить по триггеру, без установки этого бита.
в даташите на АТмега16 я не нашел, чтобы бит ADATE сам сбрасывался. но по поведению похоже, что бит сбрасывается и запуск по триггеру происходит однократно.
но ты можешь попробовать в прерывании от АЦП заново установить этот бит ADATE, и посмотреть, будет ли автостарт повторяться.


И тоже верно, я неправильно прочитал даташит, понял так, что на самое первое преобразование надо ставить ADSC, но нет

Вот верный код, если кого-то заинтересует:
Код:
#include <avr/io.h>
#include <avr/interrupt.h>

void init();
void uart_init();
void timer1_init();
void adc_init();
void uart_send( char x );

ISR( ADC_vect )
{
    uart_send( ADCH );
   
   TIFR |= (1 <<  OCF1B);
}

int main(void)
{
   init();
      
    while (1){}
}

void init()
{
    uart_init();
   timer1_init();
   adc_init();
   
   sei();
}

void uart_init()
{
    UBRRL = 25; // 9600bod at CLK = 4MHz
    UCSRB = 1 << TXEN;       
}

void timer1_init()
{
   OCR1A   = 31250;
   OCR1B   = OCR1A;
   TCCR1B  = ( 1 << WGM12 ) | ( 1 << CS11 ) | ( 1 << CS10 ); // /64 2Hz at CLK=4MHz
}

void adc_init()
{
    ADMUX  = ( 1 << REFS0 ) | ( 1 << ADLAR ); // PA0, AVCC, PA0
   SFIOR  = ( 1 << ADTS2 ) | ( 1 << ADTS0 ); // COMPB
   ADCSRA = ( 1 << ADEN )  | ( 1 << ADATE ) | ( 1 << ADIE ) | ( 1 << ADPS2 ) | ( 1 << ADPS0 ); //COMPB, ADCclk=125kHz
   
}

void uart_send( char x )                           
{
    while ( !( UCSRA & ( 1 << UDRE ) ) );       
    UDR = x;                                     
}


Добавлено after 2 minutes 10 seconds:
Спасибо всем огромное !
Да, Старик, прочитал, независимо от автотриггера можно ставить ADSC и будет лишь внеочередной опрос, все так! При автотриггере, действительно, устанавливать ADSC не требуется
Братцы, вы - мозг!

Re: АЦП в режиме Auto Triggering

Вс янв 07, 2024 20:32:17

Не забывайте, что у Вас время оцифровывания всего-лишь 1-го канала 124 микросекунды.
Изображение
Изображение
Это я хочу дополнить, к дальнейшему развитию Вашего проекта.
Вложения
Безымянный1.png
Calculator
(6.69 KiB) Скачиваний: 86
Безымянный.png
Conversion time
(20.42 KiB) Скачиваний: 88
Ответить