Buydisplay 10.1" TFT in parallel 8080 mode and Teensy FlexIO

For a full 1024*600 @ 2bpp frame on an 8 bit bus with a 40Mhz baud rate you should get up to 16fps.
No super fast, but for such a high resolution and narrow bus, that's as good as it will get!
 
For a full 1024*600 @ 2bpp frame on an 8 bit bus with a 40Mhz baud rate you should get up to 16fps.
No super fast, but for such a high resolution and narrow bus, that's as good as it will get!
Awesome. Now to cover any leftover SPI calls with 8080 calls and then onto the MicroMod. I am really trying keep it all in one library...
 
The MicroMod is working with the ER-TFTM101-1 display.
MM8080.png


MM8080-1.png


Still have to get the DMA portion working on the MicroMod. The images were produced in 8-bit mode none DMA, 100ms to display both pictures. I'm sure DMA will speed things up. By the time I am done with the Ra8876LiteTeensy library it will be big and bulky. Not quite sure how I want to approach it. Right now RA8876_t3.cpp is coming up on 300kB. It now supports SPI, 8080 parallel, 8-bit and 16-bit on the T4x and MicroMod.

As @KurtE would say "Now back to playing"
 
I am trying to find the answer to why doing a FlexIO parallel read results in the /RD signal showing 4 pulses as apposed to the /WR signal showing just one pulse. I have looked all over the net and reference manual with no luck. It's probably obvious but not for me :)

Screenshot at 2024-03-29 18-04-30.png



Screenshot at 2024-03-29 18-16-45.png


Appreciate any help...
 
what clock source are you using? And prescalers?

When I was playing with FlexIO initially I found that the clock speed had to be half of the clock source speed.
Eg if the clock source is 480Mhz, the maximum FlexIO clock speed can be 240Mhz.
When the it was set above, I was getting multiple WR pulses for a single beat transfer
 
I am using this:
Code:
pFlex->setClockSettings(3, 1, 0); // (480 MHz source, 1+1, 1+0) >> 480/2/1 >> 240Mhz
and here is the FlexIO read setup:
Code:
FASTRUN void RA8876_t3::FlexIO_Config_SnglBeat_Read() {
#if defined(USE_MM)

    p->CTRL &= ~FLEXIO_CTRL_FLEXEN;
    p->CTRL |= FLEXIO_CTRL_SWRST;
    p->CTRL &= ~FLEXIO_CTRL_SWRST;

    gpioRead();

    /* Configure the shifters */
    p->SHIFTCFG[3] =
        //FLEXIO_SHIFTCFG_INSRC                                                  /* Shifter input */
        FLEXIO_SHIFTCFG_SSTOP(0)                                              /* Shifter stop bit disabled */
       | FLEXIO_SHIFTCFG_SSTART(0)                                             /* Shifter start bit disabled and loading data on enabled */
       | FLEXIO_SHIFTCFG_PWIDTH(7);                                            /* Bus width */
   
    p->SHIFTCTL[3] =
        FLEXIO_SHIFTCTL_TIMSEL(0)                                              /* Shifter's assigned timer index */
      | FLEXIO_SHIFTCTL_TIMPOL*(1)                                             /* Shift on posedge of shift clock */
      | FLEXIO_SHIFTCTL_PINCFG(0)                                              /* Shifter's pin configured as input */
      | FLEXIO_SHIFTCTL_PINSEL(4)  //4                                            /* Shifter's pin start index */
      | FLEXIO_SHIFTCTL_PINPOL*(0) //0                                            /* Shifter's pin active high */
      | FLEXIO_SHIFTCTL_SMOD(1);                                               /* Shifter mode as recieve */

    /* Configure the timer for shift clock */
    p->TIMCMP[0] =
        (((1 * 2) - 1) << 8)                                                   /* TIMCMP[15:8] = number of beats x 2 – 1 */
      | (((_baud_div)/2) - 1);       //30             /* TIMCMP[7:0] = baud rate divider / 2 – 1 ::: 30 = 8Mhz with current controller speed */
   
    p->TIMCFG[0] =
        FLEXIO_TIMCFG_TIMOUT(0)                                                /* Timer output logic one when enabled and not affected by reset */
      | FLEXIO_TIMCFG_TIMDEC(0)                                                /* Timer decrement on FlexIO clock, shift clock equals timer output */
      | FLEXIO_TIMCFG_TIMRST(0)                                                /* Timer never reset */
      | FLEXIO_TIMCFG_TIMDIS(2)                                                /* Timer disabled on timer compare */
      | FLEXIO_TIMCFG_TIMENA(2)                                                /* Timer enabled on trigger high */
      | FLEXIO_TIMCFG_TSTOP(1)                                                 /* Timer stop bit disabled */
      | FLEXIO_TIMCFG_TSTART*(0);                                              /* Timer start bit disabled */
   
    p->TIMCTL[0] =
        FLEXIO_TIMCTL_TRGSEL((((3) << 2) | 1))                                 /* Timer trigger selected as shifter's status flag */
      | FLEXIO_TIMCTL_TRGPOL*(1)                                               /* Timer trigger polarity as active low */
      | FLEXIO_TIMCTL_TRGSRC*(1)                                               /* Timer trigger source as internal */
      | FLEXIO_TIMCTL_PINCFG(3)                                                /* Timer' pin configured as output */
      | FLEXIO_TIMCTL_PINSEL(1)                                                /* Timer' pin index: RD pin */
      | FLEXIO_TIMCTL_PINPOL*(1)                                               /* Timer' pin active low */
      | FLEXIO_TIMCTL_TIMOD(1);                                                /* Timer mode as dual 8-bit counters baud/bit */

 
    /* Enable FlexIO */
   p->CTRL |= FLEXIO_CTRL_FLEXEN;    
}
#else
and the actual read command:
Code:
//**************************************************************//
// Read RA8876 parallel Data (8bit read)
//**************************************************************//
ru8 RA8876_t3::lcdDataRead(bool finalize)
{
  uint16_t dummy = 0;
  uint16_t data = 0;
  while(WR_IRQTransferDone == false) {} //Wait for any DMA transfers to complete

// Check WINT pin (33) active low.
//  while(digitalReadFast(33) == 0);

  FlexIO_Config_SnglBeat_Read();

  CSLow();

  DCHigh(); // Should already be HIGH
delayMicroseconds(1);

  while (0 == (p->SHIFTSTAT & (1 << 3))) {}
  dummy = p->SHIFTBUFBYS[3];

  while (0 == (p->SHIFTSTAT & (1 << 3))) {}
  data = p->SHIFTBUFBYS[3];

delayMicroseconds(1);
  CSHigh();

  //Set FlexIO back to Write mode
  FlexIO_Config_SnglBeat();

//Serial.printf("dummy = %d, data = %d\n",dummy,data);
  return data;
//  return dummy;
}
Lastly the sketch:
Code:
#include "RA8876_t3.h"
#include "flexio_teensy_mm.c"

uint8_t dc = 13;
uint8_t cs = 11;
uint8_t rst = 5;
uint32_t start = 0;
uint32_t end =  0;

uint8_t busSpeed = 8;

RA8876_t3 lcd = RA8876_t3(dc,cs,rst); //(dc, cs, rst)

void setup() {
  while (!Serial && millis() < 3000) {} //wait for Serial Monitor
  Serial.printf("%c Teensy and RA8876 parallel 8080 mode testing (8/16)\n",12);
  Serial.print(CrashReport);
  pinMode(33, INPUT); // For XnWAIT signal if connected and used.

  lcd.begin(busSpeed);
  Serial.print("\nBus speed: ");
  Serial.print(busSpeed,DEC);
  Serial.println(" MHZ");
  lcd.fillScreen(0x0000);
}

uint16_t  rslt = 0;

void loop() {
  lcd.drawLine(0x0000,0x0001,0x00ff, 0x0001,0x0102);
  lcd.graphicMode(true);
//    activeWindowXY(x,y);
//    activeWindowWH(width,height);
  lcd.setPixelCursor(0x0000,0x0001);
  lcd.ramAccessPrepare();
  rslt = lcd.lcdDataRead(false);//RA8876 dummy read
  rslt = (lcd.lcdDataRead(false) << 8); // Read low byte
  rslt |= (lcd.lcdDataRead(false) & 0xff); // or in high byte
  Serial.printf("rslt = 0x%4.4X\n",rslt);
  waitforInput();
}

void waitforInput()
{
  Serial.println("Press anykey to continue");
  while (Serial.read() == -1) ;
  while (Serial.read() != -1) ;
}
The read command works fine when reading the RA8876 registers. But it is inconsistent when trying to read from the RA8876 video memory. One other thing that might be a problem is that there is an external wait pin that is asserted by the RA8876 when it is busy internally. I had this hooked up to pin #33 on the MicroMod and monitored it in the above code but it did not make a difference.
It should be returning 0x0102 and it does most of the time. But sometimes it is returning 0x0201 or 0x0202.
 
Actually you still need these parts in place of gpioRead() and gpioWrite():
Code:
  pFlex->setIOPinToFlexMode(12); // For /RD signal
  pFlex->setIOPinToFlexMode(10); // For /WR signal

So here is a a version of lcdDataRead() that works:
Code:
//**************************************************************//
// Read RA8876 parallel Data (8bit read)
//**************************************************************//
ru8 RA8876_t3::lcdDataRead(bool finalize) {
  uint16_t dummy = 0;
  uint16_t data = 0;

  while(WR_IRQTransferDone == false) {} //Wait for any DMA transfers to complete

  FlexIO_Config_SnglBeat_Read();
  delayNanoseconds(1500); // Seems to be the optimal delay needed

  CSLow();  // Must to go low after config and delay above.
  DCHigh(); // Should already be HIGH

  while (0 == (p->SHIFTSTAT & (1 << 3))) {}
  dummy = p->SHIFTBUFBYS[3];

  while (0 == (p->SHIFTSTAT & (1 << 3))) {}
  data = p->SHIFTBUFBYS[3];

  while(digitalReadFast(3) == 0);  // If monitoring XnWAIT signal from RA8876.

  delayNanoseconds(500);
  CSHigh();

  //Set FlexIO back to Write mode
  FlexIO_Config_SnglBeat();

  return data;
}
and read config without gpioRead():
Code:
FASTRUN void RA8876_t3::FlexIO_Config_SnglBeat_Read() {
#if defined(USE_MM)

    p->CTRL &= ~FLEXIO_CTRL_FLEXEN;
    p->CTRL |= FLEXIO_CTRL_SWRST;
    p->CTRL &= ~FLEXIO_CTRL_SWRST;

//    gpioRead();  // Not used

    /* Configure the shifters */
    p->SHIFTCFG[3] =
        //FLEXIO_SHIFTCFG_INSRC                                                  /* Shifter input */
        FLEXIO_SHIFTCFG_SSTOP(0)                                              /* Shifter stop bit disabled */
       | FLEXIO_SHIFTCFG_SSTART(0)                                             /* Shifter start bit disabled and loading data on enabled */
       | FLEXIO_SHIFTCFG_PWIDTH(7);                                            /* Bus width */
    
    p->SHIFTCTL[3] =
        FLEXIO_SHIFTCTL_TIMSEL(0)                                              /* Shifter's assigned timer index */
      | FLEXIO_SHIFTCTL_TIMPOL*(1)                                             /* Shift on posedge of shift clock */
      | FLEXIO_SHIFTCTL_PINCFG(0)                                              /* Shifter's pin configured as input */
      | FLEXIO_SHIFTCTL_PINSEL(4)  //4                                            /* Shifter's pin start index */
      | FLEXIO_SHIFTCTL_PINPOL*(0) //0                                            /* Shifter's pin active high */
      | FLEXIO_SHIFTCTL_SMOD(1);                                               /* Shifter mode as recieve */

    /* Configure the timer for shift clock */
    p->TIMCMP[0] =
        (((1 * 2) - 1) << 8)                                                   /* TIMCMP[15:8] = number of beats x 2 – 1 */
      | (((_baud_div)/2) - 1);       //30             /* TIMCMP[7:0] = baud rate divider / 2 – 1 ::: 30 = 8Mhz with current controller speed */
    
    p->TIMCFG[0] =
        FLEXIO_TIMCFG_TIMOUT(0)                                                /* Timer output logic one when enabled and not affected by reset */
      | FLEXIO_TIMCFG_TIMDEC(0)                                                /* Timer decrement on FlexIO clock, shift clock equals timer output */
      | FLEXIO_TIMCFG_TIMRST(0)                                                /* Timer never reset */
      | FLEXIO_TIMCFG_TIMDIS(2)                                                /* Timer disabled on timer compare */
      | FLEXIO_TIMCFG_TIMENA(2)                                                /* Timer enabled on trigger high */
      | FLEXIO_TIMCFG_TSTOP(1)                                                 /* Timer stop bit disabled */
      | FLEXIO_TIMCFG_TSTART*(0);                                              /* Timer start bit disabled */
    
    p->TIMCTL[0] =
        FLEXIO_TIMCTL_TRGSEL((((3) << 2) | 1))                                 /* Timer trigger selected as shifter's status flag */
      | FLEXIO_TIMCTL_TRGPOL*(1)                                               /* Timer trigger polarity as active low */
      | FLEXIO_TIMCTL_TRGSRC*(1)                                               /* Timer trigger source as internal */
      | FLEXIO_TIMCTL_PINCFG(3)                                                /* Timer' pin configured as output */
      | FLEXIO_TIMCTL_PINSEL(1)                                                /* Timer' pin index: RD pin */
      | FLEXIO_TIMCTL_PINPOL*(1)                                               /* Timer' pin active low */
      | FLEXIO_TIMCTL_TIMOD(1);                                                /* Timer mode as dual 8-bit counters baud/bit */

  pFlex->setIOPinToFlexMode(12);  //           Added
 
    /* Enable FlexIO */
   p->CTRL |= FLEXIO_CTRL_FLEXEN;     

#else

The LA output reading a value of 0x01:
Screenshot at 2024-03-31 09-31-43.png

Marker "K" is the falling edge of the first /RD pulse. Marker "L" is rising edge of the first wait state applied by the RA8876. The data is valid between the "k" and "L" markers (D0 is high) but not valid between "N" and "M" markers. Then on the third /RD pulse is valid again. The correct value of 0x01 was returned. So which /RD pulse returned the correct value? The first or third? The second /RD pulse is invalid (0x00).
The WINT (XnWAIT) signal happens 42ns after the /RD signal goes low which makes sense but why is there three or sometimes four /RD pulses used for one 8-bit read? That is what is eluding me:confused: Cannot seem to find that information anywhere. As of right now I am getting consistent 8/16 bit reads.
Anyway the next challenge is figuring out why when displaying an image using DMA on the MicroMod shows missed or overlapped vertical lines every few vertical lines of the image.

Bad image displayed using MulBeatWR_nPrm_DMA():
Bad_image.jpg


Good image displayed using the writeRect() function:
Good_image.jpg


Possibly a timing issue again with DMA writes. Need to learn more about DMA usage.
I'll keep plugging away at it:D
 
I had issues just as you have above with the DMA write, but I can't recall what it was.
Worth reading though my comments in this FlexIO thread - my memory is just not good enough to recall what the root cause was. But I have a feeling it's the byte swap in the shifter buffer
 
I had issues just as you have above with the DMA write, but I can't recall what it was.
Worth reading though my comments in this FlexIO thread - my memory is just not good enough to recall what the root cause was. But I have a feeling it's the byte swap in the shifter buffer
Thanks, I'll take a look at it. So far it has been my lack of knowledge of FlexIO and DMA that has slowed me down but I'm starting to understand it more...
 
The WR PIN seems to be stuck...

//#define WR_PIN 36
//#define RD_PIN 37
#define WR_PIN 28 // Problem Pin stuck on 36
#define RD_PIN 29

... I can move the RD pin to 29 and that works fine but for the WR PIN no matter what I define it continues to use PIN 36. Only when WR is connected to PIN 36 on the teensy will the display work. I can't see anywhere else it is defined. Thoughts ?
 
The WR PIN seems to be stuck...

//#define WR_PIN 36
//#define RD_PIN 37
#define WR_PIN 28 // Problem Pin stuck on 36
#define RD_PIN 29

... I can move the RD pin to 29 and that works fine but for the WR PIN no matter what I define it continues to use PIN 36. Only when WR is connected to PIN 36 on the teensy will the display work. I can't see anywhere else it is defined. Thoughts ?
That's because the WR pin is controlled by FlexIO and cannot be easily changed where as the RD pin for this display type needs to be controlled manually.
 
That's because the WR pin is controlled by FlexIO and cannot be easily changed where as the RD pin for this display type needs to be controlled manually.
I see that now... I was trying to reclaim an SPI bus. It looks I'll have to resort to using SPI2 pads for an SPI bus. Thanks for the quick reply!
 
That's because the WR pin is controlled by FlexIO and cannot be easily changed where as the RD pin for this display type needs to be controlled manually.
Note: you should be able to use other FlexIO 3 pins for this. On T4.1 the pins are:
Code:
FlexIO3:
    Pin Order: Pin:flex
         7:17 8:16 14:2 15:3 16:7 17:6 18:1 19:0 20:10 21:11 22:8 23:9 26:14 27:15 34:29 35:28 36:18 37:19 38:12 39:13 40:4 41:5
    Flex Pin Order: flex:in
         0:19 1:18 2:14 3:15 4:40 5:41 6:17 7:16 8:22 9:23 10:20 11:21 12:38 13:39 14:26 15:27 16:8 17:7 18:36 19:37 28:35 29:34
The pins used are:
Code:
pFlex->setIOPinToFlexMode(19);
    pFlex->setIOPinToFlexMode(18);
    pFlex->setIOPinToFlexMode(14);
    pFlex->setIOPinToFlexMode(15);
    pFlex->setIOPinToFlexMode(40);
    pFlex->setIOPinToFlexMode(41);
    pFlex->setIOPinToFlexMode(17);
    pFlex->setIOPinToFlexMode(16);


#if (BUS_WIDTH == 16)
    pFlex->setIOPinToFlexMode(22);
    pFlex->setIOPinToFlexMode(23);
    pFlex->setIOPinToFlexMode(20);
    pFlex->setIOPinToFlexMode(21);
    pFlex->setIOPinToFlexMode(38);
    pFlex->setIOPinToFlexMode(39);
    pFlex->setIOPinToFlexMode(26);
    pFlex->setIOPinToFlexMode(27);
#endif
So from the flexIO order list we have:
0:19 1:18 2:14 3:15 4:40 5:41 6:17 7:16 8:22 9:23 10:20 11:21 12:38 13:39 14:26 15:27 16:8 17:7 18:36 19:37 28:35 29:34[/CODE]
The code needs 8 consecutive flexio pins and is hard coded to start at 0... So the ones in RED are required to be these pins.
The green ones are if you choose to go to 16 pin mode, again would be required to be these pins.
But if doing 8 bits only could be one of these or andy of the ones still in black...

Note: with our ILI948x_ Flexio version, We can start with any of the flexio pins as long as the next 7 are used... Also in that library both
RD and WR are required to be FlexIO pins, as we swap usage for read operations.
 
@mjs513 @KurtE - Working with the example "gauges.ino", I noticed that no outer circle was being drawn. I found that the radius has to be two pixels less than the x or y coordinates otherwise no circle is drawn.
Example:
Code:
drawGauge(100,100,100);
while(1);
results in:
bad_gauge.jpg

And debugs as:
Code:
DrawCircle Center/Radius: 100, 100, 100
Xstart: -1, Ystart: 199, Xend: 198, Yend: -2
With:
Code:
drawGauge(100,100,99);
No circle and:
Code:
DrawCircle Center/Radius: 100, 100, 99
Xstart: 0, Ystart: 198, Xend: 197, Yend: -1
With:
Code:
drawGauge(100,100,98);
Result:
good_gauge.jpg

and debug output:
Code:
DrawCircle Center/Radius: 100, 100, 98
Xstart: 1, Ystart: 197, Xend: 196, Yend: 0
If I comment out this clipping section of the drawCircle() method:
Code:
    // Rectangular clipping
    int16_t dia = 2 * r;
    int16_t x_start = x0 - r - 1;
    int16_t y_start = y0 + r - 1;
    int16_t x_end = x_start + dia - 1;
    int16_t y_end = y_start - dia - 1;
     Serial.printf("DrawCircle Center/Radius: %d, %d, %d\n", x0, y0, r);
     Serial.printf("Xstart: %d, Ystart: %d, Xend: %d, Yend: %d\n", x_start, y_start, x_end, y_end);
    //  Rectangular clipping
    if ((x_start >= _displayclipx2) || // Clip right
        (y_start >= _displayclipy2) || // Clip bottom
        (x_end < _displayclipx1) ||    // Clip left
        (y_end < _displayclipy1))      // Clip top
    {
        // outside the clip rectangle
        return;
    }
the circle is drawn with:
Code:
drawGauge(100,100,100);

Ideas...
 
Yeah - my clipping hack for circles is probably wrong. Haven;t really run through all the test cases yet - was busy getting SPI version hooked into ra8876_comon which I just finished but a bit tired now.

EDIT:
Replace what you have with

Code:
    // Rectangular clipping
    int16_t dia = 2 * r;
    int16_t x_start = x0 - r;
    int16_t y_start = y0 + r;
    int16_t x_end = x_start + dia;
    int16_t y_end = y_start - dia;
and you will get the outer ring back.
 
Yeah - my clipping hack for circles is probably wrong. Haven;t really run through all the test cases yet - was busy getting SPI version hooked into ra8876_comon which I just finished but a bit tired now.
No worries :) I just adjusted:
Code:
//const int16_t posy[6] = {63, 63, 63, 63, 63, 63};
to:
Code:
const int16_t posy[6] = {65, 65, 65, 65, 65, 65}; // Must be 2 pixels more than radius.
I don't even see a difference on the screen.
Onto the next...
 
Ok guys created a new combined branch that has 3 libraries: https://github.com/mjs513/Ra8876LiteTeensy/tree/RA8896_combined
1719782041201.png


GFX has all the common functions across devices
t41_p: obviously for the t41 with flexio
t3 : is for SPI only

Probably still some issues but probably done for the day. Haven't run through all the examples been playing mainly with the test sketches. Eventually would like to combine somehow the device libraries, i.e., t41_p and t3 but not sure yet.

Cheers.
Mike
 
Ok guys created a new combined branch that has 3 libraries: https://github.com/mjs513/Ra8876LiteTeensy/tree/RA8896_combined
:D

What about MMOD or other boards who might enough FlexIO1 or 2 pins that are consecutive for DMA., like Micromod ..
Is there another branch we need to merge in? Or should we do like ILI948x and have a FlexIO implementation which
detects if it can use DMA and the low-level functions when necessary, uses Interrupt implementation or DMA.
 
What about MMOD or other boards who might enough FlexIO1 or 2 pins that are consecutive for DMA., like Micromod ..
Is there another branch we need to merge in? Or should we do like ILI948x and have a FlexIO implementation which
detects if it can use DMA and the low-level functions when necessary, uses Interrupt implementation or DMA.
Thanks a good idea - would simplify things a lot.
 
Back
Top