Teensy 4.1 DMA based UART for Serial6, for both tx and rx

I have no idea why you're experiencing this problem. In fact, I don't really even know quite what the problem is, other than you have several different high priority interrupts on a tight timing schedule and when you add use of HardwareSerial (which ought to be at a lower priority) somehow your high priority interrupts miss their timing requirements. Is that about right?

Even if I could see all your code, figuring out these sorts of problems can be quite challenging. But without seeing the code, best I can do is completely blind guessing.

First of all, the HardwareSerial class is meant for the main program to call the functions like Serial3.print(). If you are calling these from interrupts, it must be from a lower priority that the priority level the serial interrupt uses. Best to instead put the data into an array and set a volatile flag or index which the main program polls.

Likewise, all sort of other data sharing or interaction between interrupts and main program is based on the concept that the public API functions are only called from main program, not from an interrupt. My guess is you may have code somewhere that's violating that intended design?

My next guess would be some sort of similar "unsafe" data sharing problem. Crafting interrupt based code is extremely difficult to do reliably because keeping data sharing between interrupts and lower priority code is a very hard problem. Only a few "safe" ways are well known which don't require blocking the interrupt while access shared data. The queue with head and tail indexes is the most commonly used.

When not using those known-safe ways, usually you must disable interrupts briefly while accessing data. If you have any such code, maybe it's playing havoc with the timing?

Now for some guesswork of things I believe are quite improbable, which are all variation of the theme that your code is flawless and some aspect of the hardware usage is adding timing problems. I would be quite surprised if that's the case, but I'm guessing you probably want to hear some of these ideas, so here goes....

Base hardware overhead for an interrupt is about 24 cycles (except when tail chain optimization gets used). That gives you half the CPU's integer registers. If other integer registers or the float registers are used, more cycles are used to save them onto the stack and restore before returning. If you're extremely pressed for tight timing, maybe those extra cycles just push everything over the edge.

Likewise on timing, access the DTCM memory (RAM1) is very fast and isn't cached because it's basically the same speed as the CPU cache. But access to RAM2 is cached, and cache misses are about 4X slower. If you're using RAM2 (either DMAMEM or memory you got from malloc or C++ new) maybe code running one way is suffering more cache misses than running another way?

And for an extremely unlikely scenario, one of the many things the hardware does to run so fast is branch prediction. Maybe running different code is evicting branch history, which later affects the speed other code which could have run faster if more of its branches were predicted?

But again, flawless code that suffers from these rather slight timing changes is pretty unlikely, especially if you have timing slack measured in a few microseconds range. Almost always with interrupt-based programs, things appear to work perfectly in one scenario but then fail mysteriously in other usage cases, due to unsafe sharing data between the interrupt and other code running at lower priority. These problems are insidious because they usually manifest when you make some unrelated change or simply have different timing of when the interrupts happen, where focusing on the thing you changed yields no benefit because it's not really the problem. Unsafe data sharing is the really hard aspect of designing interrupt-based code.
 
Difficult to say without seeing the full code.

If you toggle a digital output pin on your 25 us ISR entry and exit, and look at that with a scope, does it then ever miss a cycle?

You can also timestamping with ARM_DWT_CYCCNT, that gets you the most accurate timestamping, running at (i think) 150 MHz when Teensy is clocked at 600 MHz. Build an array of say 16k events of ISR entry and exit times, and check for jitter, mis-firings etc.

Another thought: setting the RTC (write accessing SNV registers) also freezes the CPU for ~30 us or so. So also the highest priority interrupts have to wait then. Are you doing that by any chance?
 
Thanks Paul and Sicco....

All the serial comms is instigated in the main loop. The priorities of the DMA_Serial interrupts and DMA are set in the DMA_serial code/library, and are set as the library was delivered, at 32.

Paul, by measure of elaspedMicros, my high prio interrupt does not overrun. Even if I remove reference to the shared volatile variables in the serial receive packet handling code, so that teensy's reaction to the received data is nothing other than having read the bytes, the disturbance to the interrupt still occurs. I have tried noInterrupts(), interrupts() before/after accessing shared volatile vars in the main loop. It makes no difference.

I will try to measure the toggling of a digital output, and also try to cut down the rather large program to be able to share it.
 
ARM_DWT_CYCCNT
Is good for time measure. It counts with each CPU cycle - so 600 MHz. And reads in 3 cycles so 12-13 times faster than micros() and higher resolution.

if the PWM output is just a Toggle from known states - use digitalToggleFast perhaps. Then no logic is needed to think HI or LO output.

The GPIO are cycled at 150 MHz (IIRC when at 600 MHz) as they run from alt part from CPU speed. That and ISR jitter would be common to USB Serial test, so should be the same effect.

Using the PJRC supplied USB Serial - it runs on DMA as well, but may use alternate bus paths from USB hardware?

How does UART DMA versus standard interrupt UART HardwareSerial compare in this same test?
 
The reason I started to try dma_serial is because stf serial6 was exhibiting the problem as well.

I can't use digitalfasttoggle because I need definitive control of the output state.
 
I solved this problem.

Unlike Serial, Serial1 to Serial8 generate considerable noise back through the Teensy 4.1's 5V supply, which was getting back to my sensitive analog & ADC circuitry.
 
I solved this problem.

Unlike Serial, Serial1 to Serial8 generate considerable noise back through the Teensy 4.1's 5V supply, which was getting back to my sensitive analog & ADC circuitry.
Does the standard PJRC ISR UART code work the same then when the ADC noise gets cleaned up?
 
The std USB Serial never caused a problem.

Both, for example, Serial6 and DMA_Serial6 exhibit the problem of producing copious noise. By hardening the ADC supply and ADC grounding, both Serial6 and DMA_Serial6 problems were alleviated.
 
Back
Top