Почему функция обработчика NVIC_EnableIRQ запускается только один раз?

У меня есть код, который выплевывает случайное число, когда регистр ISR готов:

#define TRNG_KEY  0x524E47
uint8_t lut[10] = {0xF6, 0x12, 0xAE, 0xEC, 0xD8, 0x7C, 0x7E, 0xE0, 0xFE, 0xFC};
uint32_t msk = 0x1FE;

void setup()
{
  Serial.begin(9600);
  PIOC->PIO_PER = msk;
  PIOC->PIO_OER = msk;
  PIOC->PIO_OWDR = ~msk;

  PMC->PMC_PCER1 = PMC_PCER1_PID41;
  TRNG->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY(TRNG_KEY);
  TRNG->TRNG_IER = 1 << 0;
}

void loop()
{
  if (TRNG->TRNG_ISR == 1) {
  PIOC->PIO_ODSR = lut[REG_TRNG_ODATA % 10];
  }
  delay(500);
}

Приведенный выше код работает. Однако, когда я попытался переключиться на внутреннее прерывание:

#define TRNG_KEY  0x524E47
uint8_t lut[10] = {0xF6, 0x12, 0xAE, 0xEC, 0xD8, 0x7C, 0x7E, 0xE0, 0xFE, 0xFC};
uint32_t msk = 0x1FE;

void setup()
{
  Serial.begin(9600);
  PIOC->PIO_PER = msk;
  PIOC->PIO_OER = msk;
  PIOC->PIO_OWDR = ~msk;

  PMC->PMC_PCER1 = PMC_PCER1_PID41;
  TRNG->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY(TRNG_KEY);
  TRNG->TRNG_IER = 1 << 0;

  NVIC_EnableIRQ(TRNG_IRQn);
}

void loop()
{

}

void TRNG_Handler(void) {
  PIOC->PIO_ODSR = lut[REG_TRNG_ODATA % 10];
}

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

Заранее спасибо !

, 👍0

Обсуждение

Я предполагаю, что "задержка" будет внутренне ждать увеличения какой-то миллисекундной переменной, и это происходит только в каком-то таймере ISR, который вы можете блокировать, задерживая в первую очередь. Возможно, вы захотите настроить аппаратный таймер на необходимый интервал или использовать флаг внутри "цикла" для переключения логического значения "можно обновлять" каждые 500 мс, которое затем сбрасывается в TRNG_Handler., @Maximilian Gerhardt

Хм, на самом деле я могу быть частично неправ. В [datasheet](https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf) говорит: Это прерывание устанавливается при наличии нового случайного значения и очищается при считывании регистра состояния(регистр TRNG_SR). SR, вероятно, является опечаткой и означает "ISR". Можете ли вы попробовать прочитать регистр состояния так же, как в https://github.com/davecheney/trng/blob/master/arduino-due-trng/arduino-due-trng.ino#L16 ?, @Maximilian Gerhardt

Эта задержка() была опечаткой, извините. Этого нет в моем реальном коде., @7E10FC9A


1 ответ


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

2

Две вещи:

  1. Никогда не используйте функцию delay() внутри ISR. В некоторых системах он может работать, но в большинстве случаев он просто блокируется. Это плохая практика, когда ваши ISR работают больше времени, чем абсолютно необходимо в любом случае.
  2. Вам нужно прочитать регистр состояния TRNG, чтобы снять флаг прерывания. Вы делаете это в своем первом примере кода с помощью if (TRNG->TRNG_ISR == 1) {.
,

Разве if (TRNG->TRNG_ISR = 1) {. не является назначением? TRNG->TRNG_ISR не читается - ему присваивается 1. Я думаю, что это должно быть сравнение. Это ошибка в первом примере. Но условие всегда было верным, и генератор достаточно быстр, чтобы гнить число каждые 500 мс ;-)., @Peter Paul Kiefer

@PeterPaulKiefer, возможно, ты и прав... Конечным результатом, вероятно, будет чтение регистра перед записью измененного содержимого обратно., @Majenko