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...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!
pFlex->setClockSettings(3, 1, 0); // (480 MHz source, 1+1, 1+0) >> 480/2/1 >> 240Mhz
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
//**************************************************************//
// 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;
}
#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) ;
}
pFlex->setIOPinToFlexMode(12); // For /RD signal
pFlex->setIOPinToFlexMode(10); // For /WR signal
//**************************************************************//
// 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;
}
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
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...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
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.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 ?
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: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.
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
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
drawGauge(100,100,100);
while(1);
DrawCircle Center/Radius: 100, 100, 100
Xstart: -1, Ystart: 199, Xend: 198, Yend: -2
drawGauge(100,100,99);
DrawCircle Center/Radius: 100, 100, 99
Xstart: 0, Ystart: 198, Xend: 197, Yend: -1
drawGauge(100,100,98);
DrawCircle Center/Radius: 100, 100, 98
Xstart: 1, Ystart: 197, Xend: 196, Yend: 0
// 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;
}
drawGauge(100,100,100);
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.Ideas...
// 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;
No worries I just adjusted: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.
//const int16_t posy[6] = {63, 63, 63, 63, 63, 63};
const int16_t posy[6] = {65, 65, 65, 65, 65, 65}; // Must be 2 pixels more than radius.
Sorry posted to wrong thread = seems to be working now using the gauge exampledon'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
Thanks a good idea - would simplify things a lot.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.