ST7796 Teensyduino support

Right, OK, so I now have a demo. And have fixed a bug. And the DMAChannel fixes needed updating. It's just amazing (and a bit embarrassing...) how the software has rotted since last summer.
  • new DMAChannel code attached;
    • the source repo is here, and should be regarded as definitive - the zip file is just today's snapshot
    • copy the DMAChannel.* and imxrt.h files to your Teensy 4 cores
  • the dev/big-screen-T4 branch has had a bug fix
And here's a demo that works for me; you will need to modify to suit your setup (audio hardware, SPI pins):
C++:
/*
 * Example of correct setup of ST7796 DMA to avoid audio conflicts
 * during asynchronous partial updates
 */
#include <ST7796_t3.h>
#include <Audio.h>

//=========================================================
// GUItool: begin automatically generated code
AudioSynthWaveform       wav1;      //xy=672,229
AudioSynthWaveform       wav2; //xy=698,269
AudioOutputI2S           i2sOut;           //xy=950,241

AudioConnection          patchCord1(wav1, 0, i2sOut, 0);
AudioConnection          patchCord2(wav2, 0, i2sOut, 1);

AudioControlSGTL5000     audioShield;     //xy=943,324
// GUItool: end automatically generated code


//---------------------------------------------------------
void randomWav(AudioSynthWaveform& wav)
{
  wav.begin(0.5f,110.0f*random(1,7),WAVEFORM_SINE);
}

//=========================================================
// Change pin numbers to suit your hardware!
//                        CS DC RST
ST7796_t3 tft = ST7796_t3{29,10,33};
#define TFT_BL 34 // backlight pin
//---------------------------------------------------------
void randomRect(void)
{
  if (!tft.asyncUpdateActive())
  {
    // choose new rectangle dimensions
    int16_t x=999,y=999,w,h;
    w = random(tft.width() / 2);
    h = random(tft.height() / 2);
    while (x+w >= tft.width())
      x = random(tft.width());
    while (y+h >= tft.height())
      y = random(tft.height());

    // write to frame buffer
    tft.clearChangedArea();
    tft.fillRect(x,y,w,h,random(65536));   
    tft.changeAsyncClipArea();

    // update changed area only to screen
    tft.updateScreenAsync(false,true);
  }
}


//=========================================================
void setup()
{
  AudioMemory(20);
  audioShield.enable();
  audioShield.volume(0.05f); // low volume

  // standard TFT display setup
  tft.begin();
  pinMode(TFT_BL,OUTPUT);
  digitalWriteFast(TFT_BL,HIGH);
  tft.fillScreen(0);
  tft.setRotation(1);
  tft.print("Hello world");

  // now prepare to use async area updates
  tft.setAsyncInterruptPriority(224);
  tft.useIntermediateBuffer(tft.width() * 2 * 2);
  tft.useFrameBuffer(true);
  tft.updateChangedAreasOnly(true);
}

//=========================================================
elapsedMillis audioTimer;
void loop()
{
  if (audioTimer >= 250)
  {
    audioTimer = 0;
    if (random(2))
      randomWav(wav2);
    else     
      randomWav(wav1);
  }
  randomRect();
}
 

Attachments

  • pre-emptible DMA v2.zip
    75.2 KB · Views: 13
Great thanks for your help. I didn't understand what I was supposed to do with the file pre-emptible DMA v2.zip :unsure:
 
I copied the files DMAChannel.* and imxrt.h into the Teensy 4 cores folder under Win11 and copied the new library ST7735_t3/tree/dev/big-screen-t4 into the Lib folder of my platformIO project. Unfortunately, I'm not getting any sound.
 
Have you successfully run my example using the Arduino IDE? I know, from admittedly limited experience, that getting PlatformIO to pick up cores and library changes is not trivial. Though maybe it’s easier for you with your greater experience of that.

If you can get the example working OK, using Arduino, and with changes made to suit your audio and display hardware, then we know it should be possible also to get it working with PlatformIO.
 
Sorry. Its my bug. I used my old example. Your example works fine. I'll try it in my project :)

Display ST7796S FrameBuffer and Audio Test
 
Last edited:
Houston, i have a problem!
I'm using Wire.h and the Adafruit_MCP23X17.h library for my key and encoder query. The system crashes after initializing Adafruit_MCP23X17.h.

C:
/*
Test with Display ST7796S FrameBuffer with DMA and Audio
*/

#include <Arduino.h>
#include <Audio.h>
#include <ST7796_t3.h> // Hardware-specific library
#include <st7735_t3_font_OpenSans.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_MCP23X17.h>


// TFT Display ST7796S
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 8
#define TFT_CS 10
#define TFT_RST 9
#define TFT_BL 28 // TFT Backlight
#define TFT_height 320
#define TFT_width 480

// For 3.5" TFT with ST7796S
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);

// GPIO Expander for Encoders and Keys
Adafruit_MCP23X17 mcp0;     // 1st MCP Key 1-16
uint8_t PIN_KEY_INT = 25;   // Keys Interrupt


//=========================================================
// GUItool: begin automatically generated code
AudioSynthWaveform wav1;
AudioSynthWaveform wav2;
AudioOutputI2S i2sOut;
AudioConnection patchCord1(wav1, 0, i2sOut, 0);
AudioConnection patchCord2(wav2, 0, i2sOut, 1);

// TFT FrameBuffer is located in Teensy4.1 512MB Ram2
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];

//---------------------------------------------------------
void randomWav(AudioSynthWaveform &wav)
{
  wav.begin(0.5f, 110.0f * random(1, 7), WAVEFORM_SINE);
}

// random rectangle ------------------------------------------
void randomRect(void)
{
  if (!tft.asyncUpdateActive())
  {
    // choose new rectangle dimensions
    int16_t x = 999, y = 999, w, h;
    w = random(tft.width() / 2);
    h = random(tft.height() / 2);
    while (x + w >= tft.width())
      x = random(tft.width());
    while (y + h >= tft.height())
      y = random(tft.height());

    // write to frame buffer
    tft.clearChangedArea();
    tft.fillRect(x, y, w, h, random(65536));
    tft.changeAsyncClipArea();

    // update changed area only to screen
    tft.updateScreenAsync(false, true);
  }
}

// Setup -------------------------------------------------------
void setup(void)
{
  Serial.begin(9600);

  AudioMemory(20);

  // Waveform-Einstellungen
  wav1.amplitude(0.5); // Lautstärke 0.0 - 1.0
  wav2.amplitude(0.5); // Lautstärke 0.0 - 1.0
  wav1.frequency(440); // Frequenz in Hz (A4)
  wav2.frequency(440); // Frequenz in Hz (A4)

  // init TFT Backlight
  pinMode(TFT_BL, OUTPUT);    // TFT Backligth
  digitalWrite(TFT_BL, HIGH); // TFT_BL on

  // init TFT ST7796S
  tft.begin();
  // tft.setFrameBuffer(FrameBuffer);
  tft.setRotation(1);
  tft.invertDisplay(true);
  tft.setAsyncInterruptPriority(224);
  tft.useIntermediateBuffer(tft.width() * 20 * sizeof(uint16_t)); // intermediate buffer
  // tft.useIntermediateBuffer(tft.width() * 2 * 2);
  tft.useFrameBuffer(true);
  tft.updateChangedAreasOnly(true);
 
  // init Wire1 for Keys
    Wire1.begin();
    Wire1.setClock(400000UL); // I2C speed 400KHz
 
    // init MPC23017 GPIO Expander
    mcp0.setupInterrupts(true, false, LOW);
    /*
    for (size_t i = 0; i < 16; i++)
    {
        mcp0.pinMode(i, INPUT_PULLUP);
        mcp0.setupInterruptPin(i, CHANGE);
    }
    mcp0.getCapturedInterrupt();
    mcp0.readGPIOAB();
    mcp0.clearInterrupts();
    */

}

//--------------------------------------------------------------
// Main loop
//--------------------------------------------------------------
elapsedMillis audioTimer;
void loop()
{
  if (audioTimer >= 250)
  {
    audioTimer = 0;
    if (random(2))
      randomWav(wav2);
    else
      randomWav(wav1);
  }
  randomRect();
}


Crash report

Screenshot 2026-04-16 201054.png
 
Last edited:
:unsure:
Small objects with a black background are flickering. Is that normal
Another thing I've noticed: I can no longer disable the frame buffer by setting it to false.
One more thing. If I turn off (comment out) all audio, then the screen output no longer works.


Screen flickering bar

C:
// init TFT ST7796S
  tft.begin();
  tft.setRotation(1);
  tft.invertDisplay(true);
  tft.setAsyncInterruptPriority(224);
  tft.useIntermediateBuffer(tft.width() * 8 * sizeof(uint16_t)); // intermediate buffer
  tft.useFrameBuffer(true);
  tft.updateChangedAreasOnly(true);




// draw Envelope delay-time ------------------------------------
void draw_env_delay(int value)
{
    if (!tft.asyncUpdateActive())
    {
       tft.clearChangedArea();
      
        tft.fillRect(16, 193, 129, 12, ST7735_BLACK);
        tft.drawRect(16, 193, 129, 12, light_grey);
        tft.fillRect(17, 194, value + 1, 10, bar_color_1);
      
        tft.setCursor(80, 181);
        tft.setTextColor(ST7735_GREEN);
        tft.setFont(OpenSans_8);
        tft.print(F("time"));

        // print values
        tft.fillRoundRect(102 + 45 - 91, 220, 35, 25, 2, tab_color_3);
        tft.setTextColor(ST7735_BLACK);
        tft.setFont(OpenSans_13);
        tft.setCursor(102 + 50 - 91, 226);
        tft.print(Enc_Pos[4][0]);

        // screen update
        tft.changeAsyncClipArea();
        tft.updateScreenAsync(false, false);
    }
}
 
Last edited:
Small objects with a black background are flickering. Is that normal
Not that I’m aware of. Obviously I can’t run the code you posted because it’s incomplete, but I wouldn’t expect that flickering. I’d expect screen updates to be quite slow because you’ve called updateScreenAsync(false,false) rather than (false,true), so it should be updating the whole screen, not just the area you’ve changed.
Another thing I've noticed: I can no longer disable the frame buffer by setting it to false.
No code … no idea
One more thing. If I turn off (comment out) all audio, then the screen output no longer works.
Still no code … still no idea
 
Flickering with horizontal bargraph. ST7796S framebuffer and dma is enabled. Audio is on.
Automatic fading without encoder.


My code
C:
/*
Test with Display ST7796S FrameBuffer with DMA and Audio
*/

#include <Arduino.h>
#include <Audio.h>
#include <ST7796_t3.h> // Hardware-specific library
#include <SPI.h>
#include <st7735_t3_font_OpenSans.h>

// TFT Display ST7796S
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 8
#define TFT_CS 10
#define TFT_RST 9
#define TFT_BL 28 // TFT Backlight
#define TFT_height 320
#define TFT_width 480

// For 3.5" TFT with ST7796S
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);

// init Audio
AudioSynthWaveform wav1;
AudioSynthWaveform wav2;
AudioOutputI2S i2sOut;
AudioConnection patchCord1(wav1, 0, i2sOut, 0);
AudioConnection patchCord2(wav2, 0, i2sOut, 1);

// TFT FrameBuffer is located in Teensy4.1 512MB Ram2
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];

// draw horizontal bargraph. -----------------------------------
void draw_bar(int value)
{
    if (!tft.asyncUpdateActive())
    {
        tft.clearChangedArea();

        tft.fillRect(16, 193, 129, 12, ST7735_BLACK);
        tft.drawRect(16, 193, 129, 12, ST7735_WHITE);
        tft.fillRect(17, 194, value, 10, ST7735_RED);

        tft.setCursor(65, 170);
        tft.setTextColor(ST7735_WHITE);
        tft.setFont(OpenSans_12);
        tft.print(F("value"));

        // print values
        tft.fillRect(76, 220, 35, 25, ST7735_BLACK);
        tft.setCursor(76, 226);
        tft.print(value);

        // screen update
        tft.changeAsyncClipArea();
        tft.updateScreenAsync(false, true);
    }
}

// Setup -------------------------------------------------------
void setup(void)
{
    Serial.begin(9600);

    AudioMemory(20);

    // Waveform settings
    wav1.amplitude(0.5); // Lautstärke 0.0 - 1.0
    wav2.amplitude(0.5); // Lautstärke 0.0 - 1.0
    wav1.frequency(440); // Frequenz in Hz (A4)
    wav2.frequency(440); // Frequenz in Hz (A4)

    // init TFT Backlight
    pinMode(TFT_BL, OUTPUT);    // TFT Backligth
    digitalWrite(TFT_BL, HIGH); // TFT_BL on

    // init TFT ST7796S
    tft.begin();
    tft.setRotation(1);
    tft.invertDisplay(true);
    tft.setAsyncInterruptPriority(224);
    tft.useIntermediateBuffer(tft.width() * 20 * sizeof(uint16_t)); // intermediate buffer
    tft.useFrameBuffer(true);
    tft.updateChangedAreasOnly(true);

    // clear screen
    tft.fillScreen(ST7735_BLACK);
    tft.updateScreenAsync();
}

//--------------------------------------------------------------
// Main loop
//--------------------------------------------------------------
elapsedMillis barTimer;
void loop()
{
    static int value = 0;

    if (barTimer >= 25)
    {
        barTimer = 0;
        draw_bar(value++);

        if (value == 127)
        {
            value = 0;
        }
    }
}

TFT_SCK Signal with audio
 
Last edited:
No screen flickering without audio. ST7796S framebuffer and dma is enabled.


My code
C:
/*
Test with Display ST7796S FrameBuffer with DMA. Audio is disabled
*/

#include <Arduino.h>
#include <Audio.h>
#include <ST7796_t3.h> // Hardware-specific library
#include <SPI.h>
#include <st7735_t3_font_OpenSans.h>

// TFT Display ST7796S
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 8
#define TFT_CS 10
#define TFT_RST 9
#define TFT_BL 28 // TFT Backlight
#define TFT_height 320
#define TFT_width 480

// For 3.5" TFT with ST7796S
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);

/*
// init Audio
AudioSynthWaveform wav1;
AudioSynthWaveform wav2;
AudioOutputI2S i2sOut;
AudioConnection patchCord1(wav1, 0, i2sOut, 0);
AudioConnection patchCord2(wav2, 0, i2sOut, 1);
*/

// TFT FrameBuffer is located in Teensy4.1 512MB Ram2
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];

// draw horizontal bargraph. -----------------------------------
void draw_bar(int value)
{
    if (!tft.asyncUpdateActive())
    {
        tft.clearChangedArea();

        tft.fillRect(16, 193, 129, 12, ST7735_BLACK);
        tft.drawRect(16, 193, 129, 12, ST7735_WHITE);
        tft.fillRect(17, 194, value, 10, ST7735_RED);

        tft.setCursor(65, 170);
        tft.setTextColor(ST7735_WHITE);
        tft.setFont(OpenSans_12);
        tft.print(F("value"));

        // print values
        tft.fillRect(76, 220, 35, 25, ST7735_BLACK);
        tft.setCursor(76, 226);
        tft.print(value);

        // screen update
        tft.changeAsyncClipArea();
        tft.updateScreenAsync(false, true);
    }
}

// Setup -------------------------------------------------------
void setup(void)
{
    Serial.begin(9600);

    /*
    AudioMemory(20);

    // Waveform settings
    wav1.amplitude(0.5); // Lautstärke 0.0 - 1.0
    wav2.amplitude(0.5); // Lautstärke 0.0 - 1.0
    wav1.frequency(440); // Frequenz in Hz (A4)
    wav2.frequency(440); // Frequenz in Hz (A4)
    */

    // init TFT Backlight
    pinMode(TFT_BL, OUTPUT);    // TFT Backligth
    digitalWrite(TFT_BL, HIGH); // TFT_BL on

    // init TFT ST7796S
    tft.begin();
    tft.setRotation(1);
    tft.invertDisplay(true);
    tft.setAsyncInterruptPriority(224);
    tft.useIntermediateBuffer(tft.width() * 20 * sizeof(uint16_t)); // intermediate buffer
    tft.useFrameBuffer(true);
    tft.updateChangedAreasOnly(true);

    // clear screen
    tft.fillScreen(ST7735_BLACK);
    tft.updateScreenAsync();
}

//--------------------------------------------------------------
// Main loop
//--------------------------------------------------------------
elapsedMillis barTimer;
void loop()
{
    static int value = 0;

    if (barTimer >= 25)
    {
        barTimer = 0;
        draw_bar(value++);

        if (value == 127)
        {
            value = 0;
        }
    }
}


TFT_SCK Signal without audio

I don't understand why the TFT_CLK signal is longer when audio is disabled ?
 
Last edited:
OK, I'm looking at this now.

It looks as if there's something weird that's triggering async updates on every write to the frame buffer, not just when we ask for them. The longer TFT_CLK is probably because you're updating the whole area of "value" / bar / number, whereas the buggy auto update is writing them separately (though the bar is getting updated three times).

Leave it with me, though it may be a while as I'm struggling to understand what on earth is going on here!
 
OK, found it. You don't have a frame buffer, so actually all the screen updates are synchronous.

But, I hear you say, I called tft.useFrameBuffer(true);! Indeed you did, but you failed to tell it that you'd already allocated the frame buffer, so it tried to allocate one from the heap. Which failed, because a frame buffer for a 320x480 screen is 307200 bytes, and you can't fit two of those into RAM2...

Try adding tft.setFrameBuffer(FrameBuffer); just before tft.useFrameBuffer(true);, and things will look a lot better.
 
Sorry.. I've changed it now. Screen without flickring but no sound :unsure:

C:
/*
Test with Display ST7796S FrameBuffer with DMA and Audio
*/

#include <Arduino.h>
#include <Audio.h>
#include <ST7796_t3.h> // Hardware-specific library
#include <SPI.h>
#include <st7735_t3_font_OpenSans.h>

// TFT Display ST7796S
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 8
#define TFT_CS 10
#define TFT_RST 9
#define TFT_BL 28 // TFT Backlight
#define TFT_height 320
#define TFT_width 480

// For 3.5" TFT with ST7796S
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);

// init Audio
AudioSynthWaveform wav1;
AudioSynthWaveform wav2;
AudioOutputI2S i2sOut;
AudioConnection patchCord1(wav1, 0, i2sOut, 0);
AudioConnection patchCord2(wav2, 0, i2sOut, 1);



// TFT FrameBuffer is located in Teensy4.1 512MB Ram2
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];

// draw horizontal bargraph. -----------------------------------
void draw_bar(int value)
{
    if (!tft.asyncUpdateActive())
    {
        tft.clearChangedArea();

        tft.fillRect(16, 193, 129, 12, ST7735_BLACK);
        tft.drawRect(16, 193, 129, 12, ST7735_WHITE);
        tft.fillRect(17, 194, value, 10, ST7735_RED);

        tft.setCursor(65, 170);
        tft.setTextColor(ST7735_WHITE);
        tft.setFont(OpenSans_12);
        tft.print(F("value"));

        // print values
        tft.fillRect(76, 220, 35, 25, ST7735_BLACK);
        tft.setCursor(76, 226);
        tft.print(value);

        // screen update
        tft.changeAsyncClipArea();
        tft.updateScreenAsync(false, true);
    }
}

// Setup -------------------------------------------------------
void setup(void)
{
    Serial.begin(9600);

    AudioMemory(20);

    // Waveform settings
    wav1.amplitude(0.5); // Lautstärke 0.0 - 1.0
    wav2.amplitude(0.5); // Lautstärke 0.0 - 1.0
    wav1.frequency(440); // Frequenz in Hz (A4)
    wav2.frequency(440); // Frequenz in Hz (A4)

    // init TFT Backlight
    pinMode(TFT_BL, OUTPUT);    // TFT Backligth
    digitalWrite(TFT_BL, HIGH); // TFT_BL on

    // init TFT ST7796S
    tft.begin();
    tft.setRotation(1);
    tft.invertDisplay(true);
    tft.setAsyncInterruptPriority(224);
    tft.useIntermediateBuffer(tft.width() * 20 * sizeof(uint16_t)); // intermediate buffer
    tft.setFrameBuffer(FrameBuffer);
    tft.useFrameBuffer(true);
    tft.updateChangedAreasOnly(true);

    // clear screen
    tft.fillScreen(ST7735_BLACK);
    tft.updateScreenAsync();
}

//--------------------------------------------------------------
// Main loop
//--------------------------------------------------------------
elapsedMillis barTimer;
void loop()
{
    static int value = 0;

    if (barTimer >= 25)
    {
        barTimer = 0;
        draw_bar(value++);

        if (value == 127)
        {
            value = 0;
        }
    }
}
 
Well, it's working here, so there shouldn't be a problem with audio. I did have to add a couple of lines to enable my audio adaptor, but I'm guessing you're using something which doesn't need that.

On a slightly different note, your example's update strategy is terrible. You end up re-writing a lot of unchanged pixels, whereas if you broke the draw_bar() function into three separate asynchronous updates, you'd get a much shorter total update time. I just tried, and it went from 11ms down to 3.5ms - and that's leaving in the continuous re-drawing of "value", which never changes...

I can actually see an opportunity for improving the FB performance further; if we read back a pixel's value just before we write it, and it's going to end up the same colour, then it needn't expand the changed area.
 
You're right. It's just a simple example. But it should work with audio. Unfortunately, it doesn't.

I have no audio with tft.useFrameBuffer(true)
 
I don't know if this is the right way to go. So many problems with the graphics. And the audio processing for ADSR, filters, LFOs, and other things has to work too.. I'm considering using a second Teensy 4.0 for drawing graphics and menus on the display. I plan to send commands for drawing graphics and text from the first Teensy 4.1 (audio processing, filters, envelope) to the second Teensy 4.0 via a fast serial data bus. I'm also unsure if the DMA memory in the Teensy 4.1 is sufficient for both audio processing and graphics. Many questions :unsure:
 
Hallo again..
Okay. Back to the roots. But first, a big thanks on 'h4yn0nnym0u5e' for your great support 🙏

For my touchscreen (ST7796S 480 x 320 pixels), I'm now using the standard ST7796 library from Teensyduino, version 1.60. The display works very well with this library :)
What I don't quite understand logically is why the framebuffer is activated with `tft.useFrameBuffer(false)` and not with `true`.

C:
/*
Test with Display ST7796S FrameBuffer with DMA and Audio
ST7735_SPICLOCK 60 MHz #define in ST7735_t3.h
*/

#include <Arduino.h>
#include <Audio.h>
#include <ST7796_t3.h> // Hardware-specific library
#include <SPI.h>

// TFT Display ST7796S
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 8
#define TFT_CS 10
#define TFT_RST 9
#define TFT_BL 28 // TFT Backlight
#define TFT_height 320
#define TFT_width 480

// For 3.5" TFT with ST7796S
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);

//=========================================================
// GUItool: begin automatically generated code
AudioSynthWaveform wav1;
AudioSynthWaveform wav2;
AudioOutputI2S i2sOut;
AudioConnection patchCord1(wav1, 0, i2sOut, 0);
AudioConnection patchCord2(wav2, 0, i2sOut, 1);

// TFT FrameBuffer is located in Teensy4.1 512MB Ram2
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];

//---------------------------------------------------------
void randomWav(AudioSynthWaveform &wav)
{
    wav.begin(0.5f, 110.0f * random(1, 7), WAVEFORM_SINE);
}

// random rectangle ------------------------------------------
void randomRect(void)
{
    if (!tft.asyncUpdateActive())
    {
        // choose new rectangle dimensions
        int16_t x = 999, y = 999, w, h;
        w = random(tft.width() / 2);
        h = random(tft.height() / 2);
        while (x + w >= tft.width())
            x = random(tft.width());
        while (y + h >= tft.height())
            y = random(tft.height());

        // write to frame buffer
        tft.fillRect(x, y, w, h, random(65536));
        // update changed area only to screen
        tft.updateScreenAsync();
    }
}

// Setup -------------------------------------------------------
void setup(void)
{
    Serial.begin(9600);

    // set audio Memory
    AudioMemory(20);

    // set Waveform and Amplitude
    wav1.amplitude(0.5); // Level 0.0 - 1.0
    wav2.amplitude(0.5); // Level 0.0 - 1.0
    wav1.frequency(440); // Frequenz in Hz (A4)
    wav2.frequency(440); // Frequenz in Hz (A4)

    // init TFT ST7796S
    tft.init(TFT_height, TFT_width);
    tft.setFrameBuffer(FrameBuffer);
    tft.setRotation(1);
    tft.invertDisplay(true);
    tft.useFrameBuffer(false);

    // clear screen
    tft.fillScreen(ST7735_BLACK);
    tft.updateScreenAsync();

    // set TFT Backlight on
    pinMode(TFT_BL, OUTPUT);    // TFT Backligth
    digitalWrite(TFT_BL, HIGH); // TFT_BL on

 
}

//--------------------------------------------------------------
// Main loop
//--------------------------------------------------------------
elapsedMillis audioTimer;
void loop()
{
    if (audioTimer >= 250)
    {
        audioTimer = 0;
        if (random(2))
        {
            randomWav(wav2);
        }

        else
        {
            randomWav(wav1);
        }
    }
    randomRect();
}

Audio and Graphics Demo ST7796S TouchDisplay
 
Last edited:
I'm using the ST7796_t3 library in Teensyduino, Version 1.60 for an ST7796S display (320x480 Pixel). When I set FrameBuffer to true, the image output doesn't work. When I set FrameBuffer to false, the image output works.

C:
/*
Test with Display ST7796S FrameBuffer with DMA
*/

#include <Arduino.h>
#include <ST7796_t3.h>
#include <SPI.h>

// TFT Display ST7796S
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 8
#define TFT_CS 10
#define TFT_RST 9
#define TFT_BL 28 // TFT Backlight
#define TFT_height 320
#define TFT_width 480

// For 3.5" TFT with ST7796S
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);


// TFT FrameBuffer is located in Teensy4.1 512MB Ram2
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];



// Setup -------------------------------------------------------
void setup(void)
{
    Serial.begin(9600);

    // init TFT Backlight
    pinMode(TFT_BL, OUTPUT);    // TFT Backligth
    digitalWrite(TFT_BL, HIGH); // TFT_BL on

    // init TFT ST7796S
    tft.init(320,480);
    tft.setFrameBuffer(FrameBuffer);
    tft.setRotation(1);
    tft.invertDisplay(true);
    tft.useFrameBuffer(true);
    tft.fillScreen(ST7735_BLACK);
    tft.updateScreen();
}

//--------------------------------------------------------------
// Main loop
//--------------------------------------------------------------
elapsedMillis loopTimer;
void loop()
{
  if (loopTimer >= 250)
  {
    loopTimer = 0;
    if (!tft.asyncUpdateActive())
    {
      int w = random(TFT_width);
      int h = random(TFT_height);
      if (w >= 380) w = 380;
      if (h >= 220) h = 220;
      tft.fillRect(w, h, 100, 100, random(65535));
      tft.updateScreenAsync();
    }
  }
}
 
I need help. I don't understand why FrameBuffer isn't working. I'm using the ST7796_t3.h library.
Because, if you’ve gone back to the Teensyduino 1.60 version of the library, the async updates are broken, as I found out last May.

It just occurred to me … can you try some different pin choices with my fixed library? It might be worth avoiding pin 8 as it’s used by I2S; I’ve been using 10 for DC as it’s an optimised choice for the LPSPI hardware, but it’ll just be slightly slower if you pick another pin instead. Anything will do for /CS, as long as it doesn’t clash with other peripherals you’re using. SCK and MOSI are obviously fixed; does MISO do anything? I seem to recall that it’s not functional on the ST7796.
 
I'm now using your corrected ST7735_t3-dev-big-screen-t4 library with the pinout you suggested and Teensyduino version 1.60 with the original DMA files. Graphics and sound are now working perfectly.

C:
/*
Test mit Display ST7796S FrameBuffer mit DMA und Audio
*/

#include <Arduino.h>
#include <Audio.h>
#include <ST7796_t3.h> // Hardwarespezifische Bibliothek
#include <SPI.h>
#include <st7735_t3_font_OpenSans.h>

// TFT-Display ST7796S
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_SCK 13
#define TFT_DC 10
#define TFT_CS 27
#define TFT_RST 9
#define TFT_BL 28 // TFT-Hintergrundbeleuchtung
#define TFT_height 320
#define TFT_width 480

// Für 3,5"-TFT-Bildschirme mit ST7796S
ST7796_t3 tft = ST7796_t3(TFT_CS, TFT_DC, TFT_RST);

// Audio initialisieren
AudioSynthWaveform wav1;
AudioSynthWaveform wav2;
AudioOutputI2S i2sOut;
AudioConnection patchCord1(wav1, 0, i2sOut, 0);
AudioConnection patchCord2(wav2, 0, i2sOut, 1);

// Der TFT-Framebuffer befindet sich im Teensy4.1 512MB RAM2
DMAMEM uint16_t FrameBuffer[TFT_height * TFT_width];

//=========================================================
void setup()
{
  AudioMemory(20);

  // Wellenform-Einstellungen
  wav1.amplitude(0.5); // Lautstärke 0,0 - 1,0
  wav2.amplitude(0.5); // Lautstärke 0,0 - 1,0
  wav1.frequency(440); // Frequenz in Hz (A4)
  wav2.frequency(440); // Frequenz in Hz (A4)

  // TFT-Hintergrundbeleuchtung initialisieren
  pinMode(TFT_BL, OUTPUT); // TFT-Hintergrundbeleuchtung
  digitalWrite(TFT_BL, HIGH); // TFT_BL an

  // Standard-TFT-Display-Konfiguration
  tft.begin();
  tft.setAsyncInterruptPriority(224);
  tft.useIntermediateBuffer(tft.width() * 2 * 2);
  tft.useFrameBuffer(true);
  tft.updateChangedAreasOnly(true);
  tft.setRotation(1);
  tft.invertDisplay(true);
  tft.fillScreen(ST7735_WHITE);
  tft.setCursor(200,150);
  tft.setTextColor(ST7735_BLACK);
  tft.setTextSize(2);
  tft.print("Hallo Welt");
  tft.updateScreenAsync(false,true);
  delay(2000);
}

//=========================================================

elapsedMillis loopTimer;
void loop()
{
  if (loopTimer >= 250)
  {
    if (!tft.asyncUpdateActive())
    {
      loopTimer = 0;
      int w = random(TFT_width);
      int h = random(TFT_height);

      falls (w >= 380)
        w = 380;
      falls (h >= 220)
        h = 220;

      tft.clearChangedArea();
      tft.fillRect(w, h, 100, 100, random(65535));
      tft.changeAsyncClipArea();
      tft.updateScreenAsync(false, true);
    }
  }
}

Drawing a 100 x 100 pixel rectangle takes 2.69 ms. A fillScreen() operation takes approximately 41 ms.

TFT_CLK signal with PCI speed of 60 MHz
RigolDS2.png
 
Last edited:
Back
Top