0

I have a code that spit out random number when the ISR register is ready:

#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);
}

The code above works. However, when I tried to switch to internal interrupt:

#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];
}

The code only spit out one random number and then freezes, indicating TRNG_Handler(void) was only executed once. I cannot figure out why.

Thanks in Advance !

7E10FC9A
  • 209
  • 1
  • 6
  • I presume `delay` will internally wait on some millisecond variable to be incremented, and that only happens in some timer ISR, that you may be blocking by delaying in the first place. You might want to setup a hardware timer in the needed interval or use a flag inside `loop` to toggle a boolean "it's okay to update" value every 500ms, that is then reset in the TRNG_Handler. – Maximilian Gerhardt Jan 31 '21 at 15:40
  • Hm actually I may be partially wrong. The [datasheet](https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf) says `This interrupt is set when a new random value is available and is cleared when the status register is read(TRNG_SR register).` The `SR` is probably a typo and means `ISR`. Can you try and read the status register the same as in https://github.com/davecheney/trng/blob/master/arduino-due-trng/arduino-due-trng.ino#L16 ? – Maximilian Gerhardt Jan 31 '21 at 15:49
  • That delay() was a typo, sorry. It's not in my actual code. – 7E10FC9A Jan 31 '21 at 17:41

1 Answers1

2

Two things:

  1. Never use delay() inside an ISR. On some systems it may work, but on most it will just block. It's bad practice to have your ISRs run for more time that absolutely needed anyway.
  2. You need to read the status register for the TRNG to clear the interrupt flag. You're doing that in your first code sample with if (TRNG->TRNG_ISR == 1) {.
Majenko
  • 103,876
  • 5
  • 75
  • 133
  • Isn't `if (TRNG->TRNG_ISR = 1) {.` an assignment? `TRNG->TRNG_ISR` is not read - 1 is assigned to it. I think it is intended to be a comparisson. That's an error in the first example. But the condition was always true, and the generator is fast enough to gnerate a number every 500ms it seems ;-). – Peter Paul Kiefer Jan 31 '21 at 20:23
  • @PeterPaulKiefer You might be right... The end result would probably be reading the register before writing the changed content back. – Majenko Jan 31 '21 at 20:25