Different problems

Hello,
I did just buy an arduino giga R1 and a have much problems.

  • Interrupt on digital pin locks the processor (blinking red 4 shot and 4 long). If I just put an increment of an int, it works, however if I add a Serial.print("a") it doesn't more work.
  • can't find any sample of programming interrupts on a timer.
    ...
    Thanks if you can help me.

Hi @freddydw

This is expected. You should never do things like serial in an ISR. Use the ISR to set a variable and then put the serial code in your loop function.

I'll provide an example of the correct way to do this:

volatile bool someFlag = false;

void setup() {
  Serial.begin(9600);
  byte interruptPin = 9;
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), interruptHandler, CHANGE);
}
void loop() {
  if(someFlag) {
    someFlag = false;
    Serial.println("Hello, world!");
  }
}
void interruptHandler() {
  someFlag = true;
}

That removes the advantages to have an interrupt. It is not limited to Serial.print, if you heve a look to samples given for encoder rotatif the same problem happens.

void setup()

{

Serial.begin(115200);

while (!Serial)

;

Serial.println("InterruptRotator example for the RotaryEncoder library.");

// setup the rotary encoder functionality

// use FOUR3 mode when PIN_IN1, PIN_IN2 signals are always HIGH in latch position.

// encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR3);

// use FOUR0 mode when PIN_IN1, PIN_IN2 signals are always LOW in latch position.

// encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::FOUR0);

// use TWO03 mode when PIN_IN1, PIN_IN2 signals are both LOW or HIGH in latch position.

attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, FALLING);

//attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);

pinMode(PIN_IN1,INPUT_PULLUP);

//pinMode(PIN_IN2,INPUT_PULLUP);

//encoder = new RotaryEncoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);

// register interrupt routine

} // setup()

// Read the current position of the encoder and print out when changed.

void loop()

{

static int pos = 0;

//encoder->tick(); // just call tick() to check the state.

/*int newPos = 0;//encoder->getPosition();

if (pos != newPos) {

Serial.print("pos:");

Serial.print(newPos);

Serial.print(" dir:");

Serial.println((int)(0));

pos = newPos;

}*/

//Serial.println(pos);

// if

} // loop ()

void checkPosition()

{

//noInterrupts();

//encoder->tick(); // just call tick() to check the state.

Serial.print('*');

//interrupts();

}

Regards

Freddy (Alfred) De Wachter

Clos des Champs, 1

1370 Jodoigne.

Freddy.dewachter@gmail.com

+32 479 37 48 53

This is simply how interrupts work. Interrupts are disabled while the interrupt service routine is being executed, so you can't do anything in it that uses interrupts (e.g., serial communication, reading a rotary encoder) and you also should make sure to not have any code that takes a significant amount of time to run. You just have to accept the limitations as a fact of life.

I did such things a lot on other devices (nano, every, mega, mega 2560, Uno, … and I did never have any problem with it. The example that I did show is an example given by arduino and works perfectly on an arduino mega 2560, but does not work on the Giga R1.

In any case, thank you for your help.

Regards.

moderator edit: PII removed

@freddydw @ptillisch - side note, most other boards I have worked with in the past will allow you to do things like Serial.write ... inside of things like interrupts.

They allow it, as the data you write out is typically put into a buffer that will be transferred later. The main exception to this is when you completely fill up the transfer buffers. Which I believe is why Arduino addeded the availableForWrite() method:
Serial.availableForWrite() - Arduino Reference

Unfortunately in some of the more recent core implementations, Arduino has not implemented and/or used buffered serial output...

I could be wrong, but I don't belite this is also totally accurate. That is the STM32H7 processors have a Nested Vectored Interrupt Controller (NVIC) (Chapter 20 of the RM). So unless something unusual has been setup, a higher priority Interrupt ( I believe lower numbers have higher priority).

16 programmable priority levels (4 bits of interrupt priority are used)

The RM does not give a whole lot of details on the NVIC, but refer you to reference manuals for M7 and M4 processros.

You will find some places in the code that update some interrupts to their non-default priority, for example in the camera library:

    NVIC_SetPriority(DCMI_DMA_IRQ, DCMI_DMA_IRQ_PRI);
    HAL_NVIC_EnableIRQ(DCMI_DMA_IRQ);

and the H7 Video (dsi.cpp)

	/** @brief NVIC configuration for LTDC interrupt that is now enabled */
	HAL_NVIC_SetPriority(LTDC_IRQn, 0x0F, 0);
	HAL_NVIC_EnableIRQ(LTDC_IRQn);

	/** @brief NVIC configuration for DMA2D interrupt that is now enabled */
	HAL_NVIC_SetPriority(DMA2D_IRQn, 0x0F, 0);
	HAL_NVIC_EnableIRQ(DMA2D_IRQn);

	/** @brief NVIC configuration for DSI interrupt that is now enabled */
	HAL_NVIC_SetPriority(DSI_IRQn, 0x0F, 0);
	HAL_NVIC_EnableIRQ(DSI_IRQn);

As for Timer interrupts. I know they are doable. When I needed something like that, I cheated and did a quick dirty and instead created a thread, or the like that waited for a timeout.

Specific example: I implemented a USBHost Serial device that implements the buffering and has a timeout, that if the buffer is not filled within a certain time after the last write, it then triggers to flush whatever data it has in the queue.

My object contains an mbed::Timeout object
that when I receive I new output to the queue I reset the timeout timer:
inline void startWriteTimeout() {

writeTO_.attach(mbed::callback(this, &USBHostSerialDevice::processTXTimerCB), std::chrono::microseconds(write_timeout_));}

The timeout callback sends an event to my objects mailbox:

void USBHostSerialDevice::processTXTimerCB() {
  USBHostSerialDevice::message_t * serobj_msg = mail_serobj_event.try_alloc();
  if (serobj_msg) {
    serobj_msg->event_id = LATENCY_TIMEOUT_MSG;
    mail_serobj_event.put(serobj_msg);    
  } else {
    startWriteTimeout();
  }
}

And the thread that I created for this device is then awakened and process the timeout:

There are probably cleaner/simpler ways to accomplish this. But that is what I using right now.
If you want to see it in more details it is up in:
KurtE/GIGA_USBHostMBed5_devices: Some USB Host device extension to Arduino_USBHostMBed5 library (github.com)

In the USBHostSerialDevice files.

Not sure if that helps you or not.

Good luck

Thank you for your intervention in this discussion. Serial.print is an axample for me in this case, most of the time, I use it for debug purposes. At the beginning, the problem happened whe I tried to connect a rotary encoder ky-040. It is locking very fast when you turn the button on the giga R1, but it works very good on the mega 2560. I tried even ther to use Available for write, but that does'nt change anything. I supposed it was a problem of glitches on the rotary switch. A capacitor on the input does not change the problem. I did go to the Giga for the availability of interrupts on any pin, but it does not work as expected. This reduces a lot the interrest of GIGA R1. I have still to make interrupts on timer working.
In any case, agin thank you for the reference to github.
Regards.

I've had no problems with Interrupts on my Giga.
It's worth reading the mbed documentation too on Interrupts: InterruptIn - API references and tutorials | Mbed OS 6 Documentation

1 Like