# ILI948x_t41_p - a parallel display driver for Teensy 4.1

Been playing around with it - got a partial read to work and it’s writing some odd stuff to the display.
The issue is the bit shifting from the data point to the buffers - my skills with bitwise operators are somewhat limited and while I know exactly how each operator works, I just can’t get it to play right. Even chatGPT is way off at this stuff many times.

Anyways, will try debug more with the logic analyzer when I get a chance!

Let me know if I can help with the bitwise puzzle.
It’s also not my strongest suit but I may get lucky :-D

Let me know if I can help with the bitwise puzzle.
It’s also not my strongest suit but I may get lucky :-D

Sorry for the late reply, was on vacation the whole week!

I pushed an update that semi works - you can try it out, although something broke my 9486 and I can no longer test on the bench.

Here is the bit shifting logic:
The FlexIO buffer is 32 bits long
We are using bits 0,1,2,3 and 6,7,8 and 9 for the data (same pins as well)

So when writing a command (8 bits in length) we need to shift the upper 4 bits to FlexIO bits 0-3 and the lower 8 bits to FlexIO bits 6-9
When writing pixel data (16 bits in length) we need to use the same approach as the command, but we need to split the 16 bit integer into two 8 bit integers - the lower byte and the upper byte

When reading, we do the opposite, we read bits 0-3 from FlexIO and push them into an 8 bit integer, and then we read bits 6-9 from FlexIO and write them into the 8 bit integer from bit #4.

So in theory this is all fairly simple, but I just can't get it to work properly for some reason.

Thanks for the explanation.
I will try to get it to work early next week and share my findings.

Sorry for the late reply, was on vacation the whole week!

I pushed an update that semi works - you can try it out, although something broke my 9486 and I can no longer test on the bench.

Here is the bit shifting logic:
The FlexIO buffer is 32 bits long
We are using bits 0,1,2,3 and 6,7,8 and 9 for the data (same pins as well)

So when writing a command (8 bits in length) we need to shift the upper 4 bits to FlexIO bits 0-3 and the lower 8 bits to FlexIO bits 6-9
When writing pixel data (16 bits in length) we need to use the same approach as the command, but we need to split the 16 bit integer into two 8 bit integers - the lower byte and the upper byte

When reading, we do the opposite, we read bits 0-3 from FlexIO and push them into an 8 bit integer, and then we read bits 6-9 from FlexIO and write them into the 8 bit integer from bit #4.

So in theory this is all fairly simple, but I just can't get it to work properly for some reason.

I'm gonna take a look at this but wanted to check if I understand the goal correctly.
Let's assume command = 1101 1001

Then the high nibble is 1101
The low nibble is 1001

Must the FlexIO integer then be:

0000 0010 0100 1101

Just want to know sure I have the bit positions correct before I work on solving the bit shifting.
If my example is off, then please supply values for the correct example and I'll try to fix it.

If the command value is 1101 1001 then FlexIO shifter buffer needs to receive 0000 0011 0100 1001
Basically between the 4 high bits and 4 low bits we insert two empty bits as can be seen between the highlighted bits above

Fixed the shifting and created a pull request.
Still nothing on the screen though...

Maybe the shift into the FlexIO buffer needs to be the opposite way around
Eg shift 4 bits in from bit 22 to bit 26 and then another 4 bits from bit 28-31

@Rezo
Now that I finished for the most part with PXP wanted to try your parallel display library. So picked up this display from amazon: https://www.amazon.com/dp/B073R7Q8FF?psc=1&ref=ppx_yo2ov_dt_b_product_details
Wired it up to a Micromod breakout wire lenght about 6inches but using the ILI9488 initialization got an outer limits style image:

If I try a ILI9486:

Any ideas?

EDIT: Did try to use the UTFT initialization for the ILI9486 image clarity got better but still BLUE all over. Will double check the wiring i the morning but think I am done for the night

Last edited:
@mjs513 are you using the Micromod version or the T4.1 version?

This would be the right one.

Can you share your setup code for the display?

@mjs513 are you using the Micromod version or the T4.1 version?

This would be the right one.

Can you share your setup code for the display?
First here are the pinouts for the display:

1st image posted was using the ILI9488 define
Code:
``//#define ILI9488``

2nd image posted was using:
//#define ILI9486

Third think I tried was the initialization from UTFT:

Code:
``````#elif defined (ILI9486_1)
Command = 0x01; //SW RST
SglBeatWR_nPrm_8(Command,0 ,0);
delay(120);

Command = 0x11; // Sleep out, also SW reset
SglBeatWR_nPrm_8(Command, 0, 0);
delay(20);

Command = 0xF2;        // ?????
CommandValue[0U] = 0x1C;
CommandValue[1U] = 0xA3;
CommandValue[2] = 0x32;
CommandValue[3] = 0x02;
CommandValue[4] = 0xb2;
CommandValue[5] = 0x12;
CommandValue[6] = 0xFF;
CommandValue[6] = 0x12;
CommandValue[8] = 0x00;
SglBeatWR_nPrm_8(Command, CommandValue, 9);

Command = 0xF1;        // ?????
CommandValue[0] = 0x36;
CommandValue[1] = 0xA4;
SglBeatWR_nPrm_8(Command, CommandValue, 2);

Command = 0xF8;        // ?????
CommandValue[0] = 0x21;
CommandValue[1] = 0x04;
SglBeatWR_nPrm_8(Command, CommandValue, 2);

Command = 0xF9;        // ?????
CommandValue[0] = 0x00;
CommandValue[1] = 0x08;
SglBeatWR_nPrm_8(Command, CommandValue, 2);

Command = 0xC0;        // Power Control 1
CommandValue[0U] = 0x0d;
CommandValue[1] = 0x0d;
SglBeatWR_nPrm_8(Command, CommandValue, 2);

Command = 0xC1;        // Power Control 2
CommandValue[0U] = 0x43;
CommandValue[1] = 0x00;
SglBeatWR_nPrm_8(Command, CommandValue, 2);

Command = 0xC2;        // Power Control 3
CommandValue[0U] = 0x00;
SglBeatWR_nPrm_8(Command, CommandValue, 1);

Command = 0xC5;        // VCOM Control
CommandValue[0U] = 0x00;
CommandValue[1] = 0x48;
SglBeatWR_nPrm_8(Command, CommandValue, 2);

Command = 0xB6;        // Display Function Control
CommandValue[0U] = 0x00;
CommandValue[1] = 0x22;        // 0x42 = Rotate display 180 deg.
CommandValue[2] = 0x3B;
SglBeatWR_nPrm_8(Command, CommandValue, 3);

Command = 0xE0;        // PGAMCTRL (Positive Gamma Control)
CommandValue[0U] = 0x0f;
CommandValue[1] = 0x24;
CommandValue[2] = 0x1c;
CommandValue[3] = 0x0a;
CommandValue[4] = 0x0f;
CommandValue[5] = 0x08;
CommandValue[6] = 0x43;
CommandValue[7] = 0x88;
CommandValue[8] = 0x32;
CommandValue[9] = 0x0f;
CommandValue[10] = 0x10;
CommandValue[11] = 0x06;
CommandValue[12] = 0x0f;
CommandValue[14] = 0x07;
CommandValue[15] = 0x00;
SglBeatWR_nPrm_8(Command, CommandValue, 16);

Command = 0xE1;        // NGAMCTRL (Negative Gamma Control)
CommandValue[0U] = 0x0F;
CommandValue[1] = 0x38;
CommandValue[2] = 0x30;
CommandValue[3] = 0x09;
CommandValue[4] = 0x0f;
CommandValue[5] = 0x0f;
CommandValue[6] = 0x4e;
CommandValue[7] = 0x77;
CommandValue[8] = 0x3c;
CommandValue[9] = 0x07;
CommandValue[10] = 0x10;
CommandValue[11] = 0x05;
CommandValue[12] = 0x23;
CommandValue[13] = 0x1b;
CommandValue[14] = 0x00;
SglBeatWR_nPrm_8(Command, CommandValue, 15);

Command = 0x20;        // Display Inversion OFF
CommandValue[0U] = 0x00;//C8
SglBeatWR_nPrm_8(Command, CommandValue, 1);

Command = 0x36;        // Memory Access Control
CommandValue[0U] = 0x0A;
SglBeatWR_nPrm_8(Command, CommandValue, 1);

Command = 0x3A;        // Interface Pixel Format
CommandValue[0U] = 0x55;
SglBeatWR_nPrm_8(Command, CommandValue, 1);

Command = 0x2A;        // Column Addess Set
CommandValue[0U] = 0x00;
CommandValue[1] = 0x00;
CommandValue[2] = 0x01;
CommandValue[3] = 0xDF;
SglBeatWR_nPrm_8(Command, CommandValue, 4);

Command = 0x002B;        // Page Address Set
CommandValue[0U] = 0x00;
CommandValue[1] = 0x00;
CommandValue[2] = 0x01;
CommandValue[3] = 0x3f;
SglBeatWR_nPrm_8(Command, CommandValue, 3);

delay(50);
Command = 0x0029;        // Display ON
SglBeatWR_nPrm_8(Command, 0, 0);

Command = 0x002C;        // Memory Write
SglBeatWR_nPrm_8(Command, 0, 0);

delay(120);
Serial.println("ILI9486 Initialized");``````

Did you setup some shield like setup for this or lots of jumper wires? Probably should wire mine up at some point.
It has been bouncing around in TFT bins for probably a few years now...

Did you setup some shield like setup for this or lots of jumper wires? Probably should wire mine up at some point.
It has been bouncing around in TFT bins for probably a few years now...
Lots of jumpers at least for now - would like to get it working with the camera but we will see.

Heres a quick image. Note the red wire to the pin on top of the screen - that goes to 3.3v while power on the shield goes to 5v. Took me a while to figure that out.

Are the display IM pins wired for 8 bit 8080?

Are the display IM pins wired for 8 bit 8080?
Be honest cant really tell if its 8080 but its set up for parallel. So far nothing I tried seems to work

@mjs513 I had a careful look at the info on the Amazon page - seems this display ONLY works in 16 bit 8080 mode, hence the bad results
You can modify the MM library to run on 16 bit mode on the dev board, but will require rework for DMA transfers.

Id suggest an ILI9486 Uno shield. Those run in 8 bit 8080 Mode/bus

@mjs513 I had a careful look at the info on the Amazon page - seems this display ONLY works in 16 bit 8080 mode, hence the bad results
You can modify the MM library to run on 16 bit mode on the dev board, but will require rework for DMA transfers.

Id suggest an ILI9486 Uno shield. Those run in 8 bit 8080 Mode/bus
Had a feeling you were going to say that you cant get there from here with that display.

Yes this is the one I have at home, and I used to develop the library initially.
Worked fine up to around 20Mhz bus speed with 10cm jumper wires, which can push around 65ish FPS if my math is right for a 20,000,000/(480*320)*2transfer_per_pxl for a 16bpp image
Thanks for the confirmation on that as well. Will be ordering one soon. Although was looking at this one from buydisplay:

Thanks for the confirmation on that as well. Will be ordering one soon. Although was looking at this one from buydisplay:

That is actually a good display!
I have two of the Buydisplay ILI9488 panels mounted on a custom PCB with a T4.1 running 16 bit parallel.

The advantage with the display you linked is that you can easily swap between SPI, 8080 and RGB with soldering or desoldering some pads.
It also has Capacitive touch which is neat and has drivers available online.

Here is that display driven on FlexIO3 with no DMA

That is actually a good display!
I have two of the Buydisplay ILI9488 panels mounted on a custom PCB with a T4.1 running 16 bit parallel.

The advantage with the display you linked is that you can easily swap between SPI, 8080 and RGB with soldering or desoldering some pads.
It also has Capacitive touch which is neat and has drivers available online.
Thats good because I already have one thats configured for SPI so should be able to reconfigure

@Rezo
Moded the board so that JP1, JP2 and JP6 are shorted, JP3, JP4 and JP5 are open. But all I get is a backlite screen - no image.

Rewired it a couple times will do again but think may be done for the afternoon now.

I have the same board... Will try later. Mine is also setup for SPI4

Looks like Would need to change J3 and J6... But also looks like might have to add or remove some resisters?

@KurtE - You beat me to it

Code:
``````8080 8-bit Interface
J1,J2,J6 Short and J3,J4,J5 Open.
R1~R10=0R,R20=0R and R17~R19,R21~R28 Not Soldering``````

I wonder what "0R" means?
EDIT: Probably 0 resistance (shorted)...

Last edited:
Looks like Would need to change J3 and J6... But also looks like might have to add or remove some resisters?
yeah thought about it - but probably easier to just order a new one,

Andyes 0R means just that