UartEvent for Teensy 3.5

Status
Not open for further replies.

rwenck

Member
Has anybody ported Duff's UartEvent for Teensy 3.1 to the 3.5? Is a port of register names or functionality even necessary? I am occasionally loosing some data on the uart0 receive FIFO before it gets transferred to the ring buffer. I think it is due to interrupt blocking in my code preventing the uart0_status_isr from running in time. I know I haven't posted code, but my question isn't about code review. I just am hoping to get some assistance or advice from Duff or another super user to make the port so I can take advantage of DMA. FYI - the UartEvent examples appear to hang on my 3.5, so I'm pretty sure some massaging is required. Thanks in advance and thanks for all the assistance this forum has given me over the years...

Source code: UartEvent / examples / BufferSize_Event /
Error Message: None, processor appears to hang
Hardware: Custom board with Teensy 3.5 and Adafruit 2.8" display (using SPI)
Software: Teensyduino 1.41, Arduino 1.8.5

-Ryan
 
You should be using SerialEvent or EventResponder to see if you have those issues, you could also try giving UART0 a higher priority for interrupts, ex:

Code:
NVIC_SET_PRIORITY(IRQ_UART0_STATUS , 0);

where, 0 being highest priority
255 being lowest priority
default should be 64 if i remember right
 
Thanks for your response, Tonton81. I am using SerialEvent1() to fire the code that checks the ring buffer for data. My problem is that the ring buffer doesn't get the data in the first place. That is why I suspect the ISR isn't responding before the data gets pushed out by the next message. I also set IRQ_PRIORITY to 16 in serial1.c and this did not fix my problem. I also just think DMA is so eloquent.

I didn't se the IRQ priority to 0 because I don't want to interfere with the systick timer...
 
you can do the IRQ from your sketch, running Serial1.begin() would override it back to default, so better run it after Serial.begin
DMA shouldnt be needed with the FIFO uarts, they have 8 byte FIFO on S1 and S2, if your managing to loose any of the 8 entries, theres definately an issue, you'd need to pull the bytes as soon as theyre available
If you use SerialEvent, yield regularly calls it throught the code, not just at end of every loop like arduino, so you have many chances to get your events there
 
Tonton81,
I modified the core library file, "serial1.c", which sets the default IRQ priority for IRQ_UART0_STATUS. Therefore, I don't think the IRQ is getting changed back like you're saying. Am I wrong? Also, the issue I am running into is that I am talking to a control program that I cannot control or modify. It sometimes sends two messages back to back without the required delay (breaks Modbus protocol). The 1st message is 12 bytes, the 2nd is 8 bytes. After all 20 bytes are received, I am missing the last 4 bytes from the first message. My assumption is that the first 8 bytes get pulled by the UART ISR, but the last 4 don't because the 2nd message comes in right after without delay and pushes those last 4 bytes of message 1 out of the FIFO before the ISR runs.

With DMA and the rx watermark set to 1, I can avoid these issues altogether. Duff has already accomplished this for the Teensy 3.1.
 
The IRQ was if you didnt wanna modify the core, you'd simply override what the begin() did without touching the files

I have no background in DMA usage sorry, but because of the way Paul designed the way SerialEvents are triggered by having it call in many places of the core, It solved issues somewhat like your mentioning when I was doing 3 megabaud uart transfers of data blasts ranging from 10-100 bytes without loss, it's just a function you need to add to your sketch, it'll get triggered like a callback as soon (or as fast as possible) as data is received from uart
 
Tonton81,
I really appreciate your advice. Unfortunately, I am already using the serialEvents1() function to fire my comms library function that checks for and pulls data from the ring buffer that the uart0 ISR populates. I saw those forum posts about the yield() function and tried that first. This solution hasn't worked for me. I have found that allowing interrupts during SPI calls to the Adafruit ili9341 display library functions causes problems, so I disable interrupts during these code blocks. I think those code blocks and whatever delays are associated with the activities that occur within those code blocks cause the uart ISR to be delayed sufficiently that data gets lost. I guess I could try to set interrupt priorities appropriately to eliminate the need for blocking all interrupts. I just thought using DMA was a way to ensure I never have to think about this problem again...
 
ahh, dont disable interrupts, perhaps the time is disabled is the time you miss the uart interrupts,
the interrupts on the teensy have different levels of priority, try taking out that isr disabling code and allow the NVIC priority to be in charge :)

im running high speed spi transfers without disabling interrupts, and pushed the resources i need to higher priority, nested interrupts allow higher priority interrupts to interrupt the current interrupt and then return to it when done and continue from there, sort of like recursion
 
Tonton81,
Definitely going to try to do that. However, I still think letting the DMA take care of shuttling data from the uart to memory is superior. Any idea why the core doesn't already use DMA for this? Is there a drawback to DMA other than portability?
-R
 
not really sure, im not a dma expert sorry :)
the core doesnt do this itself because some teensies have different amount of DMA controllers, and adding it to the core would disallow the user from using it for other purposes (ex, SPI, I2C, fastled, etc), for it to be maintained in the core as well throughout different versions of teensy is not high on the to do list either i would imagine, which is why either the user enables it himself or someone writes a library to do it (like Duff)
 
I am not sure exactly what all your issues are, about losing input characters, maybe due to processing of ISRS or ISRs disabled?

If ISRs are completely disabled, then this won't help much.

But if the ISR routine is starving, you can raise it's priority.

Now assuming Serial1:

That is you could simply try changing your sketch or library like:
Code:
  Serial1.begin(...);
    NVIC_SET_PRIORITY(IRQ_UART0_STATUS, 0);
Sets the IRQ to priority 0 which is the highest.

As for the library you mentioned, I would think if it works on T3.2 it might work on T3.5 unless there is code looking for specific processors defined... MK20...
The main thing in the standard Serial1 code in core that was added for T3.5 was maybe a new valid pin number or two as alternatives (26, 27) and maybe the option of turning on 2 stop bit mode.

Another side note: for high speed Serial, you should stick with Serial1 or Seril2 as they have FIFO queues where as Serial2-6 don't have the FIFO but double buffer.
 
Kurt is right, Serial1 has the biggest hardware-fifo and should be preferred.
Disabling interrupts is the problem. The uart-code needs them, if you disallow them you will loose bytes for sure. What is the reason that you disable them? And why do you use the Adafruit ILI9341 libary and not the optimized Teensy lib?
 
I have found that allowing interrupts during SPI calls to the Adafruit ili9341 display library functions causes problems, so I disable interrupts during these code blocks. I think those code blocks and whatever delays are associated with the activities that occur within those code blocks cause the uart ISR to be delayed sufficiently that data gets lost.

Maybe you should focus your effort on why the display isn't working when you use serial communication?

Those displays use SPI which with a synchronous clock, so you really should not need to disable interrupts for the display. Something else is very wrong somewhere.

If you're stuck on the display problem, perhaps create a small program you can share that uses the display and a serial port to talk to another Teensy (and of course also post the code for that 2nd Teensy). Then any of us could connect the display and a couple Teensys together and see the problem. We're pretty good at helping with problems when code is shared. And when code isn't shared, we're also pretty good at (much less ineffective) blind guessing, like this thread....

I just thought using DMA was a way to ensure I never have to think about this problem again...

No, I can assure you this is a very wrong assumption! DMA will make everything more complicated and require *more* careful thought.

The general purpose DMA controller is also a poor fit for variable length protocols like modbus. It works very well for fixed length data like audio blocks. But it can't parse the data and adapt the length of transfers. It doesn't easily implement timeouts, which are commonly done for error handling with protocols like modbus.
 
Hi KurtE,
Thanks for your input. I was originally reluctant to set the priority to 0 due to worries about interference with the systick timer. I did try this, however, and it helps but does not completely eliminate my problem. BTW, I am using Serial1 to take advantage of the 8 word FIFO. I also set the rx watermark to 1 in serial1.c to make sure the uart0 interrupt fires as frequently as possible.
 
Frank B and Paul,
You have both raised good questions. I have a lot to say, but can't until I get home tonight. There was a reason I chose the Adafruit ili9341 library modified by Paul, but I can't remember why. There was something I could do with one that I couldn't do with the other and couldn't resolve. I will dig into that question when I get home this evening. To Paul's point: Why am I experiencing problems with serial comms and SPI? It isn't an issue with SPI and serial. My issue is if I don't block interrupts during ili9341 library function calls, the display does not function and of course blocking interrupts causes me to loose data. Clearly, without some code, you can't easily help me, I know. I will respond this evening with some code and a better description of my problem.

I am curious as to why Paul thinks that DMA won't work with variable length data though. All I want from the DMA functionality, built into the UART hardware, is to transfer each incoming word (UART0_RWFIFO set to 1) from uart0_d to the ring buffer. I take care of parsing and decoding the message with my Modbus library. Anyway, love the Teensy and really appreciate your help!
 
I am curious as to why Paul thinks that DMA won't work with variable length data though.

With enough fiddling, experimenting, "creative" coding and lots of troubleshooting, it probably can work.

But the DMA's TCD BITER & CITER fields need fixed values in advance. How you'd deal with variable length data is the sort of horribly ugly problem that in academia "is left as an exercise left to the reader". Who knows, maybe there's some relatively easy way I don't know?


My issue is if I don't block interrupts during ili9341 library function calls, the display does not function

Something definitely isn't right there. ILI9341 normally works fine with interrupts in play.

In this audio library tutorial video, you can see an ILI9341 display working while interrupts are enabled, where the audio library is generating *many* interrupts and accessing the SD card shared on the same SPI lines from its own interrupt.

Skip forward to 47:15 (near the end) in this video to see it in action. ILI9341 definitely is supposed to work with interrupts!

 
Paul,
That is good to know. I am excited to finally get this issue resolved and will respond once I have an example ready to post. Take care
 
I agree with Paul, that I don't see why you would need to disable interrupts? At least not for the screen code? Unless there are a few different caveats: Mainly that you have multiple places trying to update the screen. That is if your main line code does screen updates and something else like an Interval Timer also does updates... Then potentially the main line code could be part way through some screen update (in some transaction) and then the interrupt starts to blast something out, which could screw up the display...

Not sure if it would help here or not... But as of yesterday, with the current beta IDE that now gives the T3.5 256k of memory, I enabled the capability to use a Frame buffer: Note the frame buffer eats memory: 320x240x2 bytes...

With this update, it has the capability to do the screen updates asynch using DMA... It can do it two ways. My preferred way: is to do all of my screen updates and then call off to say update the screen now, which it will do the update in the background once. Or you can turn on Update continuous which in some cases like Frank's movie like updates, but it make it much more likely you can still get screen flashes or the like.
 
Status
Not open for further replies.
Back
Top