Почему Arduino Due останавливается после одного вызова ADC_Handler?

В приведенном ниже простом примере я просто программно запускаю прием АЦП, а затем устанавливаю цифровой выход встроенного светодиода в обработчике прерываний. Однако я не знаю, почему программа, похоже, останавливается.


void setup() {
  Serial.begin(115200);

  pinMode(13,OUTPUT);
  digitalWrite(13,LOW);

  adc_enable_channel(ADC, ADC_CHANNEL_6);
  adc_enable_interrupt(ADC, ADC_IER_EOC6);
  pmc_enable_periph_clk(ID_ADC);
  NVIC_EnableIRQ(ADC_IRQn);
    
  Serial.println("GO");     
}

void loop() 
{
  Serial.println("RUNNING");
  adc_start(ADC);
}

void ADC_Handler(void)
{
  digitalWrite(13,HIGH);  
  adc_get_status(ADC);
}

Я знаю, что вызывается обработчик, потому что загорается светодиод. Основные циклы, похоже, перестают работать после этого, так как они больше ничего не печатают. Если я не инициирую приобретение в главном цикле, оно будет длиться вечно. Аналогично, если я не включу прерывание или NVIC.

Я не могу объяснить такое поведение.

, 👍1

Обсуждение

В вашем коде настройки нет ссылки на "ADC_Handler", поэтому я сомневаюсь, что это действительно называется., @PMF

Возможный дубликат: https://arduinoprosto.ru/q/19924/arduino-due-interrupt-based-adc-hangs-processing?rq=1, @PMF

@PMF Как и в случае с другими ISR, он переопределяет слабую ссылку в "Arduino15\пакеты\arduino\оборудование\sam\1.6.12\ядра\arduino\coretex_handlers.c". Это определенно называется, потому что светодиод загорается, только если есть эта цифровая запись., @Adam V. Steele


1 ответ


Лучший ответ:

2

Замораживание произойдет, если только биты ADC_ISR 0-15 не будут равны 0 в конце обработчика прерываний. В этом случае ISR возвращает бит 6, установленный для включенного канала (6). Для многих прерываний бит может быть сброшен до 0, просто прочитав ADC_ISR. Однако для прерываний в конце преобразования необходимо прочитать преобразованный регистр данных для этого канала, чтобы бит ISR был установлен в 0.

Поэтому этот код не будет остановлен. (Я включил некоторые дополнительные распечатки, чтобы прояснить значения регистра в каждый момент времени.)

volatile uint32_t LAST = 0;
volatile uint32_t CHAN6 = 0;
volatile uint32_t ISR1 = 0;
volatile uint32_t ISR2 = 0;

void setup() {
  Serial.begin(115200);

  adc_enable_channel(ADC, ADC_CHANNEL_6);

  adc_enable_interrupt(ADC, ADC_IER_EOC6);

  pmc_enable_periph_clk(ID_ADC);
    
  NVIC_ClearPendingIRQ(ADC_IRQn);
  NVIC_EnableIRQ(ADC_IRQn);
    
  Serial.println("GO");
  adc_configure_trigger(ADC, ADC_TRIG_SW,0);
}

void loop() 
{
  Serial.println(ISR1,BIN); 
  Serial.println(ISR2,BIN); 

  adc_start(ADC);
  delay(1000);
}

void ADC_Handler(void)
{   
  ISR1 = adc_get_status(ADC); // chan 6 bit =1
  LAST = adc_get_latest_value(ADC); 
  ISR1 = adc_get_status(ADC); // chan 6 bit =1 (still)
  
  CHAN6 = adc_get_channel_value(ADC, ADC_CHANNEL_6);
  ISR2 = adc_get_status(ADC); // chan 6 bit = 0
}

Однако я отмечу, что в таблице данных для чипа на странице 1322 указано, что чтение одного из регистров ADC_CDR очищает соответствующий бит EOC. Чтение ADC_LCDR очищает бит DRDY и бит EOC, соответствующие последнему преобразованному каналу.

Это кажется ложным. Чтение ADC_LCDR не очищает бит состояния и приведет к зависанию. ADC_CDR6 необходимо прочитать специально, чтобы избежать зависания.

,