Yet another post about interrupts.

Status
Not open for further replies.

vindar

Well-known member
Hello,

I have been a long time lurker of this (great) forum and I have usually found answers by searching old posts but I must admit I am stuck on this one... If anyone can point me in the right direction, I would be very grateful :)

I am using a teensy 3.2 to generate a 40khz signal using the IntervalTimer class. I need a very precise timing: each interrupt should not be delayed by more than a few cycles.
What the interrupt routine does is mostly switching the state of 4 digital pins simultaneously to create 4 similar waves. Yet, I cannot use PWN to do that because I do not generate a perfectly periodical signal: sometime, a given pin may is not be switched depending on other external variables.

If the teensy do only that, all is fine..

But then, at the same time, I am driving a SSD1306 screen via I2C (for monitoring). As you have probably guessed, its messes with my interrupt routine and, when communicating with the I2C device, the timer becomes irregular.

I did set the priority of the IntervalTimer routine to 0 using the setPriority() method and I thought that this would enable my interrupt (it is very short) to get called even during an I2C interrupt. I guess I do not understand how interrupt nesting works !

I also tried to use the i2c_t3 library instead of Wire and I tried the IRQ and DMA modes. Still no luck... The immediate transfer mode of i2c_t3 does not seem to be working with the adafruit library for SSD1306.

Does anyone know how I could fix my problem. I do not mind if a i2c transfer sometimes fails.. but I need the timer interrupt to stay fairly regular.

Thank you !
 
Thank you Paul for the link. It is indeed somewhat similar to what I am doing...

In my case, I can generate the data to output a little bit in advance. So, it seems that my best option might be, as mentioned in the other thread, to buffer some data in advance and use a DMA channel triggered by a timer to set the pins (all 4 output pins on the same port). By using double buffering and chaining two DMA channels, I should be able to create a regular continuous signal.

Before, I start wasting several hours trying to implement this and understand how DMA works, can you tell me if this strategy can (at least theoretically) works ? If I understand correctly, DMA transfer should make the signal "interrupt proof" w.r.t. I2C since it does not use the processor. However, how long does it take between the end of a DMA transfer and the start on next chained one ? Is is possible that I will miss a tick of the timer (which will be between 40khz and 400Khz) ?

Thanks!
 
I think, the most important is to understand that even when using the i2c_t3 library with DMA, the endTransmission() function remains blocking. To get a non-blocking i2c send, use the sendTransmission() function which is documented on the i2c_t3 GitHub page.
 
Yes, I looked at the code of the i2c_t3 library. However, I do not really care that the method is blocking here since I generate the signal from an interrupt. The problem is that, during an i2c transaction, the timer interrupt is sometime delayed. I guess this must happen either because interrupts are currently disabled or because another 0 priority interrupt is already running.
 
That's exactly what is called blocking. That's why I suggested that you do a non blocking transfer which allows your interrupts to launch in time while the i2c transfer would continue in the background.
 
That's exactly what is called blocking. That's why I suggested that you do a non blocking transfer which allows your interrupts to launch in time while the i2c transfer would continue in the background.

Ok! Well, there is something I do not understand :) So, I tried using i2c_t3 with DMA transfer in non-blocking mode. It is indeed better but there is still an annoying perturbation of the signal...

On the other hand, I just adapted the DMA + FTM timer approach of the Octo library for a quick test and the signal is perfect (much better than the interrupt generated version, even without i2c interference). So I will use this method (and, in the process, learn how to use DMA).

Thank you both very much for your help !
 
The interrupt handler runs with interrupts disabled. Thus, doing anything blocking in that function will cause other same- or lower-priority interrupts to be delayed until the blocking operation is completed. (I think the Teensy library just lumps all interrupts into a single priority level, btw -- letting some interrupt handlers pre-empt other interrupt handlers would not be Arduino compatible.)
 
Status
Not open for further replies.
Back
Top