Таймер в обычном режиме для запуска прерывания на AVR128DB48

#c #embedded #avr #clock

#c #встроенный #avr #часы

Вопрос:

Я пытаюсь установить таймер для запуска прерывания 8 тыс. раз в секунду на AVR128DB48. Код инициализации, который я использую для инициализации часов, приведен ниже.

 //clock init
//24Mhz/64 = 375k
//(1/375k)*top=(1/8000)
//top = 46
TCA0.SINGLE.PER = 46;
//enables overflow interrupt
TCA0.SINGLE.INTCTRL |= 0x1;
//sets clock divider to 64 enables clock
TCA0.SINGLE.CTRLA |= TCA_SINGLE_RUNSTDBY_bm | TCA_SINGLE_ENABLE_bm | (5<<1);
  

Это почти точно то, что в документации указано, что код инициализации должен быть. Для проверки прерывания я использую эту функцию в качестве обработчика прерываний

 ISR(TCA0_OVF_vect)
{
    outputval = !outputval;
    if (outputval){
        PORTC.OUT |= 2;
    }
    else{
        PORTC.OUTCLR |= 2;
    }    
    return;
}
  

Когда я подключаю этот вывод к своему осциллографу и измеряю частоту, он считывает выходную частоту 35 кб. Если я изменяю значение per на что угодно, оно также всегда считывает 35 кб. Я тестировал со значениями, такими как 100 и 200, все те же результаты. Я также меняю делитель тактовой частоты, и я все равно получаю тот же результат в 35 тыс. Если я не установлю бит включения, я не получу никакого вывода. Я чего-то не хватает? OVF прерывания не выполняет то, что я думаю, что он делает? Я несколько раз просматривал документацию и считаю, что все делаю правильно.

Комментарии:

1. Вам нужно очистить источник прерывания в обработчике прерывания, чтобы прерывание не повторялось немедленно?

2. @kkrambo да, это была проблема. большое вам спасибо.

3. Если проблема была решена, поделитесь решением. 🙂

Ответ №1:

Как указал kkrambo, проблема заключалась в том, что с AVR128DB48 этот флаг прерывания не сбрасывается автоматически контроллером прерываний, поэтому вам необходимо сбросить флаг в конце обработчика прерываний перед возвратом. Если вы этого не сделаете, он будет постоянно пытаться обслуживать прерывание снова и снова. Это делается путем записи 1 во флаг прерывания, который для этого периферийного устройства и для этого прерывания (OVF) выполняется следующим кодом ниже:

 TCA0.SINGLE.INTFLAGS |= 0x1;
  

Таким образом, для пересмотренного кода для всего прерывания будет:

 ISR(TCA0_OVF_vect)
{
    outputval = !outputval;
    if (outputval){
        PORTC.OUT |= 2;
    }
    else{
        PORTC.OUTCLR |= 2;
    }
    TCA0.SINGLE.INTFLAGS |= 0x1;
    return;
}