ST7735_T3 Library - does it block or use interrupts?

Status
Not open for further replies.

cebersp

Well-known member
Hi,
in my project with T4.1 I try to use Audio Library, ST7735_T3, SDFat, and TeensyThreads. Recently I run into timing problems, which only occur, if I activate a thread, which is dealing with a ST7735 display. There are some Text outputs and tft.fillRect(). I am wondering about reasons...

Is it true/possible, that ST7735_T3 blocks interrupts or uses interrupts? I have read, that TeensyThreads does not switch tasks, if the switch interrupt falls into an ISR.
What would be good ideas to cut the display handling into smaller slices, which can be interrupted?

Many thanks in advance!
Christof

Edit, this silly peace of code seems to work:
Code:
void slowFillRect(int x, int y, int w, int h, int col) {
  for(int i=0;i<w;i++) {
    tft.fillRect(x+i,y, 1,h, col);
  }
}
 
Last edited:
By default, if you tell it to fill a rectangle, lets say 128x128, the code is setup to do it all in one chunk...
That is the code boils down to:
Code:
		beginSPITransaction();
		setAddr(x, y, x+w-1, y+h-1);
		writecommand(ST7735_RAMWR);
		for(y=h; y>0; y--) {
			for(x=w; x>1; x--) {
				writedata16(color);
			}
			writedata16_last(color);		
		}
		endSPITransaction();
	}
Which outputs a few fields at the start to tell the display the bounding rectangle, and then set it into RAM write mode
and then we output that many 128*128 uint16_t values to the display, before we return.

No interrupts or the like involved.

However this library does have the option, of creating a logical frame buffer for the display, in which case this call simply sets memory associated with this buffer with these colors, and only if you
call updateScreen will it output. However this again does the same, However there is updateScreenAsync() which will start up a DMA operation to do the transfer, which will go on in the background.

But this depends on which teensy you are using and if there is enough memory and the like.
 
Thanks for your answer!
Is it perhaps possible that beginSPITransaction() might block the access of the SD card? On this T4. 1 I use the builtin SD-card holder.
 
...still wondering, if "beginSPITransaction" can block access of an SD-card, which is not tied to the same pins? I did not find the source of this routine.
 
Which player do you use? It might a problem there.

For example, there is code like this:
Code:
#if defined(HAS_KINETIS_SDHC)
    if (!(SIM_SCGC3 & SIM_SCGC3_SDHC)) AudioStartUsingSPI();
#else
    AudioStartUsingSPI();
#endif
This was never good, but somehow worked on the T3 - it was a workaround I added a few years ago. It was never good - it works with the assumption that if the SDHC hardware is enabled, it will be used for the file. This can be wrong. I mentioned that several times but never got an answer.
Since on the T4 HAS_KINETIS_SDHC is not defined, it always calls AudioStartUsingSPI() regardless of whether SD uses SPI or not.
Since there is no way to tell if SPI is used for a file or not, there is no solution. All suggestions on how to solve this problem have been rejected, all questions unanswered.
It would be nice to have a better solution for T3 as well. It was a temporary solution... usually, "temporary" really means "forever" (in 99%)
 
Last edited:
Ok, thank you Frank,
I am not using an existing player, but made my own simple one outside of the Audio Library. Code is here: https://forum.pjrc.com/threads/69362-Core-of-a-Multitrack-Looper

At the moment, I just assume, that "beginSPITransaction" does block ALL SPI channels, as it has no parameter, which one is meant. At least this could explain, why my stupid way of splitting up the fillRect did help....
(I have read somewhere, that Micropython would give up to use SPI hardware. Micropython has -as far as I know- still issues with multithreading. I wonder if it is too complex to maintain hardware SPI for multiple controllers and many drivers build on it.)
 
Again should warn, I have not done anything with Teensy threads (except play once or twice) and very little with Audio...

But have done a few things with SPI...

One of the nice things about Arduino/Teensy is almost all of the source code is on your computer, so sometimes when you have questions like this, it is easier and faster to take a look at the sources... At least for me it is...

SPI.beginTransaction does nothing to keep your code from calling other SPI functions, especially on other SPI busses.
That there is no such thing like a semaphore or mutex that says this code owns SPI now. Everything is sort of Cooperative.

What it logically does is if you have specified some interrupt masks to be used it sets those up, it then checks to see if the SPISettings are the same as previous time called, if not it recomputes the register settings. Unlike T3.x it recomputes them as enough people were changing the underlying clock setting. Regardless if it say any changes in settings, it sets the SPI registers to those computed register settings. It does it each time as enough people were mucking with the registers without going through the beginTransaction... Then it returns.

Again there are no locks or anything that keeps anyone else from using SPI anything. endTransaction does nothing if you have not specified any interruptMasks... One exception is you can set a define in the library that will blink a pin if you have a mismatch of calls...

So unless there is some external code that like in teensy threads that say this thread owns SPI... there is nothing keeping the different threads from doing stuff.. However if for example the display is being updated with lets say a fillRect and that thread gets interrupted and the new thread starts writing to the same SPI, there is very likely going to be some corruption going to happen.

But again not sure if the thread code will interrupt a thread a thread that is actively doing something (like by timer) or if it in this case is cooperative, like only when you call something like yield...

But if it does not interrupt, the fillRect code is mostly atomic. That is it keeps stuffing data out on the SPI output queue, spinning while the queue is full, before putting the next word onto the queue, and then waits for the queue to empty, before it returns.

Sorry, not sure if this helped or not.
 
Thank you, Kurt for your answer!
I do know, that writing such long answers takes time, and I appreciate your and Frank's help!
At the moment I am baffled, what went wrong. Doing some tests with an oscilloscope and some testprogram, to find out more about the threads library.
Christof
 
Ok, so I have now found out how to assign priorities for threads. See here: https://forum.pjrc.com/threads/6947...d-Priority-and-Cycle-Time?p=299622#post299622
So I do now assign 10 us time slices for everything including graphics except 100us for high priority handling of audio frames and buffer handling for the SD-card.
The following picture shows in black the position repeated musical loop, this means that all file handling repeats within one black cycle which is perhaps 10 Seconds. The orange line shows the minimum cycle time for all threads and the red line shows the maximum cycle time. There are 4 threads with 10us and 2 high priority threads with 100us, so from the threading system a maximum of 240us is possible. It is very astonishing for me, that maximum cycle time seems to vary up to 470us (seldom). I cannot see the regularity here. This must come from some interrupt activity. (?) At least there seems be enough safety to catch every next audio frame and it seems to work stable now....
task4.JPG

Has anybody an overview list of interrupts and how often they occur and for what time they are active?
Christof
 
Status
Not open for further replies.
Back
Top