wwatson4506 / Ra8876LiteTeensy

Teensy RA8876 Driver
14 stars 7 forks source link

8080 and DMA and MicroMod #16

Closed leutholl closed 2 months ago

leutholl commented 3 months ago

Thank you very much looking into an 8080 type interface. I wanted to do the same by myself also with a RA8876-compatible controller for a 400x1280 screen address in portrait mode, but mounted in landscape mode. I use SPI with DMA and max out at 45 MHz which is very close to be "usable" for lvgl widget refreshes such as the scrolling of a roller control. In addition to DMA-out the lvgl buffer I use the BLE overlay functions on an other canvas for high-fps primitives drawn over the lvgl. I then combine multiple canvas by the black key color. This works nice but 8080 would make it much smoother - I hope.

I looked into the FlexIO and was wondering:

Many thanks for your effort! Highly appreciated and very helpful.

wwatson4506 commented 3 months ago

First off this is WIP and I am learning the FlexIO system myself. What I put up on GitHub is just the beginning of development for using the 8080 interface. There is a lot more to do as well as housekeeping. On the Teensy 4.1 I am using both 8-bit and 16-bit bus widths. To use 16-bit mode, FlexIO 3 must be used to get 16 consecutive FlexIO pins and FlexIO 3 does not support DMA. I just got the MicroMod working. Again WIP. It will use DMA but in 8-bit mode. I have been using examples from @Rezo's ILI948x libraries which can be found here: https://github.com/david-res Also this thread from the Teensy forum: https://forum.pjrc.com/index.php?threads/ili948x_t41_p-a-parallel-display-driver-for-teensy-4-1.72660/ At this point in time I do not plan on restructuring this library. Nothing in the 8080 parallel version is guaranteed to stay the same. Good luck...

leutholl commented 3 months ago

Thanks. I managed to get it working on a Teensy 4.1 in both 8 bit and 16 bit mode but not using Multibeat. When using Multibeat, the timing was off and the display BLE picture showed diagonal black lines or rendered only half or 1/3 of the picture. Playing around with the clock shoed different results. I'm still on the breadboard thou.

I got my MicroMod today and changed the pins to be using FlexIO2 with has DMA. It's strange: I can control the internal PWM for the backlight, colorize the whole screen but I can't draw a Line yet only any BLE stuff. This is all using SingleBeat.

So I have less progress on the MicroMod and I'm lost now. the T4.1 setup was better but MultiBeat didn't work (using IRQs) and the MicroMod with the ATP board is not drawing any lines....

I'm using a RA8876. You mentioned that you have ti with MicroMod working but I can't see your code that uses the pins of FlexIO2 - I only see a T4.1 setup. Did I miss anything? Or is it a misunderstanding?

As for the T4.1 setup using SingleBeat, I can provide the code to integrate it with lvgl and in my case (for my odd screen which is portrait mode addressed but picture should be in landscape) I can rotate the lvgl buffer between taking it from lvgl and ROPing it out. I get around 25 fps with 1280x400 SingleBeat 8 Bit. That's why I want to get it working on MicroMod - to use DMA or revert back to T4.1 and get IRQ working.

Can you set me on the right path on either T4.1 or MM? Where is your MM code you mentioned? Was it really for the RA8876?

Many thanks.

PS: I know this is all WIP, so it my code. I'm happy to provide my version of the library which is very much stripped down but MM and T4.1 optimized and will be using lvgl and does the buffer rotation.

wwatson4506 commented 3 months ago

I had not tried to use multibeat yet on the T41. I just now have the MicroMod doing Multibeat DMA writes. But there is a problem with what is displayed. I think it is a handshake problem with the RA8876. Not sure yet. Also having problems with reading from display memory. I can read from the registers but not the display RAM. Writing to the display RAM works ok in singlebeat mode. There is a lot more testing to be done

leutholl commented 3 months ago

Thanks - what you write is close to my observation. While digging deeper I stumbled across: lcdStatusRead(). In contrast to SPI the Status Register is never selected, instead the code just expects data to be read but this won't happen as the register isn't selected in parallel mode. I'd expect that write the command to the status register and then read the data (the status value). But the first bit seems to be missing. Right?

ru8 RA8876_8080::lcdStatusRead(bool finalize) { // startSend(); // ru8 data = _pspi->transfer16(RA8876_SPI_STATUSREAD16); // endSend(finalize); while(WR_IRQTransferDone == false) {} //Wait for any DMA transfers to complete CSLow(); / De-assert RS pin / DCLow(); FlexIO_Config_SnglBeat_Read(); uint16_t dummy; uint16_t data = 0; while (0 == (p->SHIFTSTAT & (1 << 3))) {} dummy = p->SHIFTBUFBYS[3]; while (0 == (p->SHIFTSTAT & (1 << 3))) {} data = p->SHIFTBUFBYS[3]; DCHigh(); CSHigh(); // Serial.printf("Dummy 0x%x, data 0x%x\n", dummy, data); //Set FlexIO back to Write mode FlexIO_Config_SnglBeat(); if(BUS_WIDTH == 16) return data >> 8; else return data; }

wwatson4506 commented 3 months ago

That's because reading the status register is a special case. As per the reference manual for the RA8876 you set "cs"," rs" and "rd" low to read the status register. The read signal is set low by FlexIO. Any other RA8876 registers are accessed by writing the register number first and then reading/writing to the register. I would suggest downloading the RA8876 reference manual if you don't already have it😉

On Tue, Mar 26, 2024 at 8:42 AM leutholl @.***> wrote:

Thanks - what you write is close to my observation. While digging deeper I stumbled across: lcdStatusRead(). In contrast to SPI the Status Register is never selected, instead the code just expects data to be read but this won't happen as the register isn't selected in parallel mode. I'd expect that write the command to the status register and then read the data (the status value). But the first bit seems to be missing. Right?

ru8 RA8876_8080::lcdStatusRead(bool finalize) { // startSend(); // ru8 data = _pspi->transfer16(RA8876_SPI_STATUSREAD16); // endSend(finalize); while(WR_IRQTransferDone == false) {} //Wait for any DMA transfers to complete CSLow(); / De-assert RS pin / DCLow(); FlexIO_Config_SnglBeat_Read(); uint16_t dummy; uint16_t data = 0; while (0 == (p->SHIFTSTAT & (1 << 3))) {} dummy = p->SHIFTBUFBYS[3]; while (0 == (p->SHIFTSTAT & (1 << 3))) {} data = p->SHIFTBUFBYS[3]; DCHigh(); CSHigh(); // Serial.printf("Dummy 0x%x, data 0x%x\n", dummy, data); //Set FlexIO back to Write mode FlexIO_Config_SnglBeat(); if(BUS_WIDTH == 16) return data >> 8; else return data; }

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2020785046, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7WQ5KCY3YUQMBK3PWDY2GCPFAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRQG44DKMBUGY . You are receiving this because you commented.Message ID: @.***>

leutholl commented 3 months ago

Thanks again! I missed that point despite having the manual. I was mislead to that point in code as I was reading back the register value to verify that indeed all bits are correctly sent. But then I realized that I can write and read all values and even the Color Bar is shown (there is a SSD MIPI Bridge chip which needs initialization, so that part works). I can also fill the screen with a color but then I realized there is something very strange whenever it comes to setting coordinates (start point / endpoint). Thus I can't draw. It only sort of accepts a startX and startY of 0,0 and will then show any shape by flooding the screen height to "infinity" rather than respecting the set y values. So I need to dig deeper in the coordinate and this Active Window thing, I guess. What puzzles me is that the init code to the RA8876 is exactly the same as done in T4.1 where everything worked with SingleBeat. There must be a mistake when I migrated the code to the MM FLEXIO part. So I guess the Shifters work (at least in SingleBeat) and the cabling is right, but logically somewhere a register is set wrong or overwritten or whatever.

Do you know anything to keep in mind when it comes to drawing with coordinates. BTW: the color is set correctly - just the coordinates are off, way off ;)

Many thanks again!

leutholl commented 3 months ago

UPDATE: It works now. There was a problem with lcdHorizontalWidthVerticalHeight(HDW,VDH); setting incorrect values. I can now draw at any place and I can even ROP a picture using SingleBeat and(!) using MultiBeat with DMA. However with DMA the picture is distorted. I played with clock speed etc which helped a bit but I don't know how to lower the clock to a very slow speed so I can rule out my breadboard setup (with 15cm wires). I also do not know if my picture must be in the DMAMEM section? It looks like DMA is somehow "too fast" either for the screen or for reading the memory.

The picture has sometimes diagonal lines in the first section and always some random noise in the last section.

I also had to undo the byte reversal of the shifters of the code used to drive another display which needed it. Not sure if I did it correctly but I get the colors right now. The length variable for the multibeat is set to the number of 16bit pixels memory aligned to 32bit.

So after a very long period of frustration, I finally can get on.... As soon as I have the drawing quality right, I can then add lvgl (which is already prepared) and push a minimum set of my library version using the micromod with DMA or T4.1 in 8 bit or 16 bit without DMA but (hopefully) with IRQs which shouldn't be too bad either.

wwatson4506 commented 3 months ago

Glad to hear you are making progress. I ran into the same problem with DMA drawing a picture. Seemed like every other vertical line was wrong. Right now I am stumped with reading from the display ram. I write a byte to a location (usually location 0 written with 0xFF) and when I read it back it is always 0. If I do a fillScreen(0xffff) then all locations will read 0xff??? I think I need to walk away from this for a while and come back to it with fresh eyes😀 There is an internal wait function "check2dBusy()" that is called quite often and that does not do any good with DMA access. There is also an external wait signal available "WINT" that does the same thing as "ccheck2dBusy()". I don't know if the DMA engine can monitor an external wait signal or not, but that would allow pacing the MicroMod. That is also why "writeRect()" function works ok when drawing a picture. It uses "check2dBusy()".

On Tue, Mar 26, 2024 at 5:46 PM leutholl @.***> wrote:

UPDATE: It works now. There was a problem with lcdHorizontalWidthVerticalHeight(HDW,VDH); setting incorrect values. I can now draw at any place and I can even ROP a picture using SingleBeat and(!) using MultiBeat with DMA. However with DMA the picture is distorted. I played with clock speed etc which helped a bit but I don't know how to lower the clock to a very slow speed so I can rule out my breadboard setup (with 15cm wires). I also do not know if my picture must be in the DMAMEM section? It looks like DMA is somehow "too fast" either for the screen or for reading the memory.

The picture has sometimes diagonal lines in the first section and always some random noise in the last section.

I also had to undo the byte reversal of the shifters of the code used to drive another display which needed it. Not sure if I did it correctly but I get the colors right now. The length variable for the multibeat is set to the number of 16bit pixels memory aligned to 32bit.

So after a very long period of frustration, I finally can get on.... As soon as I have the drawing quality right, I can then add lvgl (which is already prepared) and push a minimum set of my library version using the micromod with DMA or T4.1 in 8 bit or 16 bit without DMA but (hopefully) with IRQs which shouldn't be too bad either.

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2021720886, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7XAHU3FIOAM4GFKFCTY2ICEZAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRRG4ZDAOBYGY . You are receiving this because you commented.Message ID: @.***>

K7MDL2 commented 3 months ago

I have a PCB that plugs onto the back of a RA8875 4.3" and RA8876 7" display with 40 pin connector. Uses Teensy 4.1 and SPI. Also i2c for touch. Designed for my Teensy SDR. See user account K7MDL2 on github. I have some v2.1 pcbs left. Gets rid of the long cable.

Mike K7MDL.

Sent from my T-Mobile 4G LTE Device Get Outlook for Androidhttps://aka.ms/ghei36


From: leutholl @.> Sent: Tuesday, March 26, 2024 5:46:21 PM To: wwatson4506/Ra8876LiteTeensy @.> Cc: Subscribed @.***> Subject: Re: [wwatson4506/Ra8876LiteTeensy] 8080 and DMA and MicroMod (Issue #16)

UPDATE: It works now. There was a problem with lcdHorizontalWidthVerticalHeight(HDW,VDH); setting incorrect values. I can now draw at any place and I can even ROP a picture using SingleBeat and(!) using MultiBeat with DMA. However with DMA the picture is distorted. I played with clock speed etc which helped a bit but I don't know how to lower the clock to a very slow speed so I can rule out my breadboard setup (with 15cm wires). I also do not know if my picture must be in the DMAMEM section? It looks like DMA is somehow "too fast" either for the screen or for reading the memory.

The picture has sometimes diagonal lines in the first section and always some random noise in the last section.

I also had to undo the byte reversal of the shifters of the code used to drive another display which needed it. Not sure if I did it correctly but I get the colors right now. The length variable for the multibeat is set to the number of 16bit pixels memory aligned to 32bit.

So after a very long period of frustration, I finally can get on.... As soon as I have the drawing quality right, I can then add lvgl (which is already prepared) and push a minimum set of my library version using the micromod with DMA or T4.1 in 8 bit or 16 bit without DMA but (hopefully) with IRQs which shouldn't be too bad either.

— Reply to this email directly, view it on GitHubhttps://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2021720886, or unsubscribehttps://github.com/notifications/unsubscribe-auth/APLVE7ETBLPUT6N43TSBPITY2ICE3AVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRRG4ZDAOBYGY. You are receiving this because you are subscribed to this thread.Message ID: @.***>

wwatson4506 commented 3 months ago

@KurtE also has something similar. My connecting wires are 3" long.

On Tue, Mar 26, 2024 at 7:01 PM K7MDL @.***> wrote:

I have a PCB that plugs onto the back of a RA8875 4.3" and RA8876 7" display with 40 pin connector. Uses Teensy 4.1 and SPI. Also i2c for touch. Designed for my Teensy SDR. See user account K7MDL2 on github. I have some v2.1 pcbs left. Gets rid of the long cable.

Mike K7MDL.

Sent from my T-Mobile 4G LTE Device Get Outlook for Androidhttps://aka.ms/ghei36


From: leutholl @.> Sent: Tuesday, March 26, 2024 5:46:21 PM To: wwatson4506/Ra8876LiteTeensy @.> Cc: Subscribed @.***> Subject: Re: [wwatson4506/Ra8876LiteTeensy] 8080 and DMA and MicroMod (Issue #16)

UPDATE: It works now. There was a problem with lcdHorizontalWidthVerticalHeight(HDW,VDH); setting incorrect values. I can now draw at any place and I can even ROP a picture using SingleBeat and(!) using MultiBeat with DMA. However with DMA the picture is distorted. I played with clock speed etc which helped a bit but I don't know how to lower the clock to a very slow speed so I can rule out my breadboard setup (with 15cm wires). I also do not know if my picture must be in the DMAMEM section? It looks like DMA is somehow "too fast" either for the screen or for reading the memory.

The picture has sometimes diagonal lines in the first section and always some random noise in the last section.

I also had to undo the byte reversal of the shifters of the code used to drive another display which needed it. Not sure if I did it correctly but I get the colors right now. The length variable for the multibeat is set to the number of 16bit pixels memory aligned to 32bit.

So after a very long period of frustration, I finally can get on.... As soon as I have the drawing quality right, I can then add lvgl (which is already prepared) and push a minimum set of my library version using the micromod with DMA or T4.1 in 8 bit or 16 bit without DMA but (hopefully) with IRQs which shouldn't be too bad either.

— Reply to this email directly, view it on GitHub< https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2021720886>, or unsubscribe< https://github.com/notifications/unsubscribe-auth/APLVE7ETBLPUT6N43TSBPITY2ICE3AVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRRG4ZDAOBYGY>.

You are receiving this because you are subscribed to this thread.Message ID: @.***>

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2021784371, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7TJR6UFDOM5WGCDIFDY2ISA7AVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRRG44DIMZXGE . You are receiving this because you commented.Message ID: @.***>

leutholl commented 3 months ago

Great inputs - together we can make it work! the check2DBusy() is only needed once before ROPing (in my case) as soon as the pixels are streamed out, there shouldn't be any wait conditions and if it was, that would be relevant to the subsequent graphics call, not for writing the SDRAM. After writing the picture, I don't access the screen anymore - as of now. I played around with settings, got rid of the byte swapping of the DMA, tried different clocks, tried to read from DMAMEM, tried memory alignment to 32bit, increased DMA size to be 32 bit on source etc.... I can now have a reproducable picture without the random noise blocks but as you were saying earlier, I also get vertical lines (see below). I think they are repeated from an earlier color (some pixels prior to the x-axis of where the vertical line starts). It could actually be exactly 8 pixels offset which could correlate to the beat of the minorLoop. Every now and then, I get a perfect picture so that would indicate a RF/grouning-related problem with my jump wires. I tried to lower the clock to an extreme slow speed but then, the picture doesn't show up at all, looks like the RA8876 kind of times-out or my clock settings are invalid.

Since I'd like to base my system on DMA I must use the MicroMod. I'm using KiCad but couldn't find the symbols and footprint to host a MicroMod on my custom board which I'd like to design. Another plus of the MicroMod is that the DEBUG SWD pins are available but I didn't look into that too far as the Teensy is officially not debuggable.

It's time to get my scope and look at the signals before loosing too much time with the FlexIO/DMA/Shifter config. But this vertical line offset is extremely well reproducable (at the same location), might be the code and not the interconnection. I changed from longer to shorter Duponds jumper wire => no difference.

I'd appreciate you looking into the vertical line issue when you're convenient. Similar to my coordinate issue earlier one tends to overlook thinks, this is where we need each other.

IMG_5813

KurtE commented 3 months ago

@KurtE also has something similar. My connecting wires are 3" long.

I had a couple versions, both were setup around the T4.1. I use DipTrace... image

When necessary I hack up my own symbols. I probably won't do another one for the MicroMod, as my eyes and hands are not good enough to solder those pins...

I have done a couple of MMOD boards, not geared toward these displays. I had them partially assembled at PCBWAY... Which are my goto boards. image

Although right now for playing with the different cameras, my goto for MMOD is a quick and dirty "shield" I did for the Sparkfun ATP board, which I have setup for ILI9341/9488 (or Adafruit displays)... The camera connection is using FLEXIO with DMA and the like... image Note: the board toward bottom left is my MMOD board. With the camera, I could not use the display connector I have on it as the IO pins conflicted with the FlexIO pins I am using for a camera. The one on the right is the shield on the ATP board. Currently it has an ILI9341 on it as well as an HM0360 camera

Not sure if you were asking about the boards I have or not, but just in case...

K7MDL2 commented 3 months ago

Resend, pics were too large.

@KurtE, your board is more compact and thus likely more economical and better targeted to this stuff. Good to have that option.

Mine is larger as it is targeted at SDR radio use with Teensy Audio module and lots of IO connectors for I2C, GPIO, and power supplies. Of course only need to populate what is required but the larger size cost more and take more space. Mine is in EasyEDA.

@.*** [A close-up of a computer Description automatically generated][A blue circuit board with many small chips and wires Description automatically generated]

I also use a AdaFruit I2C bus current booster module to help deal wit the long I2C cables rung to some panel mounted RGB I2C encoders form DUPPA in Europe seen along the right side in the picture above. Battery added for RTC.

Just FYI, Please carry on with the main topic!

From: KurtE @.**@.>> Sent: Wednesday, March 27, 2024 6:13 PM To: wwatson4506/Ra8876LiteTeensy @.**@.>> Cc: K7MDL @.**@.>>; Comment @.**@.>> Subject: Re: [wwatson4506/Ra8876LiteTeensy] 8080 and DMA and MicroMod (Issue #16)

@KurtEhttps://github.com/KurtE also has something similar. My connecting wires are 3" long.

I had a couple versions, both were setup around the T4.1. I use DipTrace... image.png (view on web)https://github.com/wwatson4506/Ra8876LiteTeensy/assets/1558080/850f3c8a-8ddb-4a9e-ae1f-1b57249f6abe

When necessary I hack up my own symbols. I probably won't do another one for the MicroMod, as my eyes and hands are not good enough to solder those pins...

I have done a couple of MMOD boards, not geared toward these displays. I had them partially assembled at PCBWAY... Which are my goto boards. image.png (view on web)https://github.com/wwatson4506/Ra8876LiteTeensy/assets/1558080/8ad0f53e-d53d-42bf-8042-bf0e8627e6de

Although right now for playing with the different cameras, my goto for MMOD is a quick and dirty "shield" I did for the Sparkfun ATP board, which I have setup for ILI9341/9488 (or Adafruit displays)... The camera connection is using FLEXIO with DMA and the like...

Not sure if you were asking about the boards I have or not, but just in case...

- Reply to this email directly, view it on GitHubhttps://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2024228196, or unsubscribehttps://github.com/notifications/unsubscribe-auth/APLVE7H3ILMKSQDDX76OBM3Y2NVC3AVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRUGIZDQMJZGY. You are receiving this because you commented.Message ID: @.**@.>>

mjs513 commented 3 months ago

@wwatson4506 - Probably before the lib gets too unmanageable maybe you should consider 2 versions of the library.

One that supports SPI and another that supports parallel bus coms. As you said its already at 300K.

Mike

wwatson4506 commented 3 months ago

Agreed...

On Thu, Mar 28, 2024 at 4:36 AM Mike S @.***> wrote:

@wwatson4506 https://github.com/wwatson4506 - Probably before the lib gets too unmanageable maybe you should consider 2 versions of the library.

One that supports SPI and another that supports parallel bus coms. As you said its already at 300K.

Mike

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2024971951, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7XN542GWAFVUWI4KDDY2P6CVAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMRUHE3TCOJVGE . You are receiving this because you were mentioned.Message ID: @.***>

leutholl commented 3 months ago

Thanks for showing your boards. When I get rid of the vertical lines I‘m going to build one myself. Any ideas of the vertical lines issue? They are pixel-perfect reproducable and I think it’s a loading issue into the SHIFTBUF or memory speed or alignment or something and not relates to electronics. but not 100% sure.

leutholl commented 3 months ago

I think I got it - or at least I'm pretty close. Will post some code later but I can now put pixels as I want. Multibeat + DMA. There are still the first 16 or 32 pixels and the last 8 pixels or so noisy (per transfer) but no vertical lines or any noise block in the ROP transfer. For whatever reason it didn't like iterating through the image array of 16bit RGB565 values but creating my own "pattern image" was working. all the buffers are now in uint32_t, as soon as one iterates through a uint16_t sources to copy from the noise, diagonal lines and (not sure) vertical lines appears. I'm still not 100% sure if the c-array containing the test picture is correct on its own (hard to test).

I'm no back to regular speed and can minimise the library for lvgl use and hopefully confirm everything....

wwatson4506 commented 3 months ago

That's awsome:) I have not had such good luck with doing reads from video ram. Reading from registers works great though. I am convinced it has to do with wait states in the RA8876. Just not sure yet...

wwatson4506 commented 3 months ago

I think I just solved the read problem. I took some well placed nano second delays and moving "CSLow()" after the first delay. Here is the data read function: `//**// // 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);

delayNanoseconds(500); CSHigh();

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

return data; } ` This does a consistent read of video memory...

leutholl commented 3 months ago

Thanks. Using SingleBeat it was always working. I'm now on the MultiBeat with DMA but still get the vertical lines. CS is low all transaction, DC is high all transaction. I was testing with single coloured rectangles where the lines are not visible but now using shapes they re-appear. Do you think it's a timing issue? If so, how can that be handled with DMA? I also see you are reading from pin3 are you now listening for the Ready pin of the RA8876?

wwatson4506 commented 3 months ago

I Don't know if you have seen this PJRC forum thread or not so here is a link just in case: https://forum.pjrc.com/index.php?threads/buydisplay-10-1-tft-in-parallel-8080-mode-and-teensy-flexio.74658/ I just posted an update and brought up the issue with DMA writes. I am going to continue with this issue...

leutholl commented 3 months ago

I mad some progress and thanks for the link. Turned out DMA and SHIFTERs are setup correctly but the screen is adding stuff that shouldn't be there. This has to do with the Active Window function of the RA8876 which needs to be set correctly as otherwise the announced number of pixels doesn't match what DMA pushes out and the screen "invents" colors and pixels. I hooked up my 16ch digital anaylzer and found out that the data on the bus is actually correct. So I guess I can now focus again on software. Because of the speed the digital analyzer shows wrong states on neoghbouring lines (ground / crosstalk), but from what I see I think the WAIT pin never is asserted once the BTE is setup correctly meaning we can stream data as we want as long as we are within the bounds. I had to use the Byte reversal DMA filling using:

sourceAddress = (uint16_t)value + minorLoopBytes/sizeof(uint16_t) - 1; // last 16bit address within current minor loop sourceAddressOffset = -sizeof(uint16_t); // read values in reverse order minorLoopOffset = 2minorLoopBytes; // source address offset at end of minor loop to advance to next minor loop sourceAddressLastOffset = minorLoopOffset - TotalSize; // source address offset at completion to reset to beginning destinationAddress = (uint32_t*)&p->SHIFTBUFBYS[SHIFTNUM-1]; // last 32bit shifter address (with reverse byte order) destinationAddressOffset = -sizeof(uint32_t); // write words in reverse order destinationAddressLastOffset = 0;

and used #define LV_COLOR_16_SWAP 1 on lvgl to get the colors back to right. the RA8876 has regular order of the MSB in contrast to the ILI used in this repo. But even when trying the fill the DMA in forward fashion something wasn't right so I kind of double reverse the MSBs for now.

Will report later when I have a better version and can slowly approach pushing some code that works.

wwatson4506 commented 3 months ago

Man, you are a busy person😄 Glad to hear you are making progress. I lost a pin on the MicroMod. Not sure why yet. Hopefully I did not smoke it☹️ I have the LA setup on the T4.1 right now and I think I have narrowed down why we are getting multiple pulses on the /RD signal. When I run just the "FlexIO_Config_SnglBeat_Read()" function I see two pulses on the /RD signal. Doing the same thing with "FlexIO_Config_SnglBeat()" there is no pulse on the /WR signal. So I need to dig further into this to find out why. It's one of those things I can't walk away from without knowing why...

On Thu, Apr 4, 2024 at 2:15 PM leutholl @.***> wrote:

I mad some progress and thanks for the link. Turned out DMA and SHIFTERs are setup correctly but the screen is adding stuff that shouldn't be there. This has to do with the Active Window function of the RA8876 which needs to be set correctly as otherwise the announced number of pixels doesn't match what DMA pushes out and the screen "invents" colors and pixels. I hooked up my 16ch digital anaylzer and found out that the data on the bus is actually correct. So I guess I can now focus again on software. Because of the speed the digital analyzer shows wrong states on neoghbouring lines (ground / crosstalk), but from what I see I think the WAIT pin never is asserted once the BTE is setup correctly meaning we can stream data as we want as long as we are within the bounds. I had to use the Byte reversal DMA filling using:

sourceAddress = (uint16_t*)value + minorLoopBytes/sizeof(uint16_t) - 1; // last 16bit address within current minor loop sourceAddressOffset = -sizeof(uint16_t); // read values in reverse order minorLoopOffset = 2

minorLoopBytes; // source address offset at end of minor loop to advance to next minor loop sourceAddressLastOffset = minorLoopOffset - TotalSize; // source address offset at completion to reset to beginning destinationAddress = (uint32_t)&p->SHIFTBUFBYS[SHIFTNUM-1]; // last 32bit shifter address (with reverse byte order) destinationAddressOffset = -sizeof(uint32_t); // write words in reverse order destinationAddressLastOffset = 0;

and used #define LV_COLOR_16_SWAP 1 on lvgl to get the colors back to right. the RA8876 has regular order of the MSB in contrast to the ILI used in this repo. But even when trying the fill the DMA in forward fashion something wasn't right so I kind of double reverse the MSBs for now.

Will report later when I have a better version and can slowly approach pushing some code that works.

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2038236263, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7SNDY5ZTVXGN6NLJILY3W7IFAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMZYGIZTMMRWGM . You are receiving this because you were mentioned.Message ID: @.***>

leutholl commented 3 months ago

some updates here: I have smooth animation working: The animation sample program of lvgl (the red ball that ping pongs and changes in size) incl. antialiasing in RGB565 with 30 fps on a rather larger screen (400 * 1280) with 6% CPU load (when the ball is small) and 15 % (when the ball is biggest which is half of the screen width). This is even using the slowest clock of 4 MHz and waiting tin the lvgl callback until DMA is finished (so nulling any DMA advantage as of now). When using async mode so that DMA is running while lvgl renders into the next buffer CPU load goes down to only 2% max but I get black pixels from buffer edge to buffer edge. Still, things are very fast!

I managed to undo the MSB swap on lvgl colors by using destinationAddress = (uint32_t*)&p->SHIFTBUFHWS[SHIFTNUM-1]; But I still must fill the DMA in reverse words. I played around with something like: `sourceAddress = (uint16_t*)value; // Start from the beginning of the data //sourceAddressOffset = sizeof(uint32_t); // Increment to read values in forward order sourceAddressOffset = sizeof(uint16_t); // Increment to read values in forward order minorLoopOffset = 0; // No offset needed for the beginning of the minor loop sourceAddressLastOffset = 0; //TotalSize - sizeof(uint16_t); // Offset at completion to reset to the beginning

// Adjust destination address calculation for correct byte order
destinationAddress = (uint32_t*)&p->SHIFTBUF[SHIFTNUM-1]; // Last 32-bit shifter address (without reverse byte order)
destinationAddressOffset = sizeof(uint32_t); // Increment to write words in forward order
destinationAddressLastOffset = 0; // No offset needed for the last address); // write words in reverse order`

but I get diagonal offsets....

There is one last visual residue that must be related with your observation on the multiple pulses. For every next pixel buffers the RA8876 expects a BTE/ROP command which includes reading from the Status Register. The pixel buffer is visualized having the first exactly 6 pixels black (not inserted as in additional pixels but overwritten to black). See picture which is a photo through my magnifying glass. writing goes left to right and you see the first 6 pixels black on the very corner of the background rectangle (white) and another 6 pixels black of the buffer that drew the red ball.

Using SingleBeats with Polling, this black 6-pixel line doesn't appear and I see the correct picture. What could that be?

It's either the first beat is wrong or the WR clock runs too early - I don't know. Maybe its's related what you are saying above as yes, reading is involved. Reading is SIngleBeat and after it, FlexIO is reconfigued to MultiBeat. I the data lines are low and WR has a rising edge then I could explain why this black line is appearing.

Still, I'm happy I got so far. Will push the code after all these effects are solved and my library edits are clean.

IMG_5842

leutholl commented 3 months ago

again an update. I'm chasing down the 6 black pixels for every buffer and my LA says that the WD clock strobes 12 times (rising edge) which would perfectly explain 6 black pixels before the data (here white) comes. Why does WD start running before the data is ready? My buffer is filled correctly as least before DMA picks up.

RigolDS15

wwatson4506 commented 3 months ago

I am fighting pretty much the same thing right now with the reads. Unfortunately I don't have a working MicroMod right now but it should be the same on the T41. I'm in the manual again...

On Sat, Apr 6, 2024 at 5:41 AM leutholl @.***> wrote:

again an update. I'm chasing down the 6 black pixels for every buffer and my LA says that the WD clock strobes 12 times (rising edge) which would perfectly explain 6 black pixels before the data (here white) comes. Why does WD start running before the data is ready? My buffer is filled correctly as least before DMA picks up.

RigolDS15.png (view on web) https://github.com/wwatson4506/Ra8876LiteTeensy/assets/5789698/03b2115a-d8c1-4585-a21a-8c09e40e90d4

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2041072079, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7Q3NLPZ7YHH6OBW2D3Y37URDAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGA3TEMBXHE . You are receiving this because you were mentioned.Message ID: @.***>

leutholl commented 3 months ago

sorry for my correction. The number of WR strobes is according to the buffer size and is correct. the first 12 strobes are just happening with no data thus black which explains the 6 black pixels (1 pixel = 16bit = 2 strobes at 8 bit). As soon as the data is ready from DMA (which I don't seems to have any control of) a mini pulse is happening. It is as if the memory is too slow for FlexIO. I placed the buffer in DMA (or at least I think I did) - should I look at that aspect again? How can DMAMEM be allocated when the buffer size is changing everytime which places the buffer in the stack I guess? RigolDS16

leutholl commented 3 months ago

And again me ;-) This time with a very dirty hack...

It seems that the first transaction when switching from SingeBeat to MultiBeat has the issue of sending 12 clock strobes without data. A 2nd use of the DMA+FLEXIO system seems to be working correctly. As dirty as this is, let's SHIFT out some values keeping CS on the display de-asserted, then assert CS and continue with the 2nd (correct) MultiBeat transaction which is the first seen by the display. At least I now know that this has something to do with the switching from SingleBeat to MultiBeat.

` FlexIO_Config_MultiBeat();

MulBeatCountRemain = length % BeatsPerMinLoop;
MulBeatDataRemain = (uint16_t*)value + ((length - MulBeatCountRemain)); // pointer to the next unused byte (overflow if MulBeatCountRemain = 0)
TotalSize = ((length*2) - MulBeatCountRemain);               /* in bytes */
minorLoopBytes = SHIFTNUM * sizeof(uint32_t);
majorLoopCount = TotalSize/minorLoopBytes;
//Serial.printf("Length(16bit): %d, Count remain(16bit): %d, Data remain: %d, TotalSize(8bit): %d, majorLoopCount: %d \n",length, MulBeatCountRemain, MulBeatDataRemain, TotalSize, majorLoopCount );

/* Setup DMA transfer with on-the-fly swapping of MSB and LSB in 16-bit data:
 *  Within each minor loop, read 16-bit values from buf in reverse order, then write 32bit values to SHIFTBUFBYS[i] in reverse order.
 *  Result is that every pair of bytes are swapped, while half-words are unswapped.
 *  After each minor loop, advance source address using minor loop offset. */
int destinationAddressOffset, destinationAddressLastOffset, sourceAddressOffset, sourceAddressLastOffset, minorLoopOffset;
volatile void *sourceAddress;
volatile void *destinationAddress;

DMA_CR |= DMA_CR_EMLM; // enable minor loop mapping

flexDma.begin();
arm_dcache_flush_delete((void*)value, length * 128);

/* this is a very dirty hack to use the SHIFTERS after SingleBeat mode to MultiBeat mode.
   The first transaction is always wrong (12 beats without data), so we do a dummy transaction here.
   Not that CS is de-asserted as this hack should not be seen by the display */
CSHigh();
flexDma.sourceBuffer((const uint32_t*)value, length);
flexDma.destinationCircular((uint32_t*)&p->SHIFTBUF[SHIFTNUM-1], sizeof(uint32_t) * SHIFTNUM);
flexDma.transferCount(length/SHIFTNUM);
flexDma.transferSize(SHIFTNUM);
flexDma.triggerAtHardwareEvent(hw->shifters_dma_channel[SHIFTER_DMA_REQUEST]);
flexDma.disableOnCompletion();
flexDma.clearComplete();
flexDma.enable();
delayMicroseconds(1);
CSLow();

/* From now on, the SHIFTERS in MultiBeat mode are working correctly... */
flexDma.begin();
sourceAddress = (uint16_t*)value + (minorLoopBytes)/sizeof(uint16_t) - 1; // last 16bit address within current minor loop
sourceAddressOffset = -sizeof(uint16_t); // read values in reverse order
minorLoopOffset = 2*minorLoopBytes; // source address offset at end of minor loop to advance to next minor loop
sourceAddressLastOffset = minorLoopOffset - TotalSize; // source address offset at completion to reset to beginning
destinationAddress = (uint32_t*)&p->SHIFTBUFHWS[SHIFTNUM-1]; // last 32bit shifter address (with reverse byte order)
destinationAddressOffset = -sizeof(uint32_t); // write words in reverse order
destinationAddressLastOffset = 0;

flexDma.TCD->SADDR = sourceAddress;
flexDma.TCD->SOFF = sourceAddressOffset;
flexDma.TCD->SLAST = sourceAddressLastOffset;
flexDma.TCD->DADDR = destinationAddress;
flexDma.TCD->DOFF = destinationAddressOffset;
flexDma.TCD->DLASTSGA = destinationAddressLastOffset;
flexDma.TCD->ATTR =
    DMA_TCD_ATTR_SMOD(0U)
  | DMA_TCD_ATTR_SSIZE(DMA_TCD_ATTR_SIZE_16BIT) // 16bit reads
  | DMA_TCD_ATTR_DMOD(destinationModulo)
  | DMA_TCD_ATTR_DSIZE(DMA_TCD_ATTR_SIZE_32BIT); // 32bit writes
flexDma.TCD->NBYTES_MLOFFYES = 
    DMA_TCD_NBYTES_SMLOE
  | DMA_TCD_NBYTES_MLOFFYES_MLOFF(minorLoopOffset)
  | DMA_TCD_NBYTES_MLOFFYES_NBYTES(minorLoopBytes);
flexDma.TCD->CITER = majorLoopCount; // Current major iteration count
flexDma.TCD->BITER = majorLoopCount; // Starting major iteration count

flexDma.triggerAtHardwareEvent(hw->shifters_dma_channel[SHIFTER_DMA_REQUEST]);
flexDma.disableOnCompletion();
flexDma.interruptAtCompletion();
flexDma.clearComplete();

flexDma.attachInterrupt(dmaISR);

digitalWriteFast(36, LOW);
digitalWriteFast(36, HIGH);
flexDma.enable();
dmaCallback = this;

}`

leutholl commented 3 months ago

maybe I can help you as I'm also wondering how to clear FlexIO from SingleBeat to MultiBeat in a "clean" way. I stumbled across this: https://github.com/ARMmbed/mbed-os/blob/baf6a3022a328b91713e03fd88f65126a9a53f01/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/drivers/fsl_flexio_mculcd.c#L546

wwatson4506 commented 3 months ago

That is very interesting. I wonder if that is what I am seeing with the reads. There should only be two /RD pulses, one for the dummy read and one for the actual data. I am getting three pulses.

On Sat, Apr 6, 2024 at 8:59 AM leutholl @.***> wrote:

And again me ;-) This time with a very dirty hack...

It seems that the first transaction when switching from SingeBeat to MultiBeat has the issue of sending 12 clock strobes without data. A 2nd use of the DMA+FLEXIO system seems to be working correctly. As dirty as this is, let's SHIFT out some values keeping CS on the display de-asserted, then assert CS and continue with the 2nd (correct) MultiBeat transaction which is the first seen by the display. At least I now know that this has something to do with the switching from SingleBeat to MultiBeat.

` FlexIO_Config_MultiBeat();

MulBeatCountRemain = length % BeatsPerMinLoop; MulBeatDataRemain = (uint16_t)value + ((length - MulBeatCountRemain)); // pointer to the next unused byte (overflow if MulBeatCountRemain = 0) TotalSize = ((length2) - MulBeatCountRemain); / in bytes / minorLoopBytes = SHIFTNUM * sizeof(uint32_t); majorLoopCount = TotalSize/minorLoopBytes; //Serial.printf("Length(16bit): %d, Count remain(16bit): %d, Data remain: %d, TotalSize(8bit): %d, majorLoopCount: %d \n",length, MulBeatCountRemain, MulBeatDataRemain, TotalSize, majorLoopCount );

/* Setup DMA transfer with on-the-fly swapping of MSB and LSB in 16-bit data:

  • Within each minor loop, read 16-bit values from buf in reverse order, then write 32bit values to SHIFTBUFBYS[i] in reverse order.
  • Result is that every pair of bytes are swapped, while half-words are unswapped.
  • After each minor loop, advance source address using minor loop offset. / int destinationAddressOffset, destinationAddressLastOffset, sourceAddressOffset, sourceAddressLastOffset, minorLoopOffset; volatile void sourceAddress; volatile void *destinationAddress;

DMA_CR |= DMA_CR_EMLM; // enable minor loop mapping

flexDma.begin(); arm_dcache_flush_delete((void)value, length 128);

/ this is a very dirty hack to use the SHIFTERS after SingleBeat mode to MultiBeat mode. The first transaction is always wrong (12 beats without data), so we do a dummy transaction here. Not that CS is de-asserted as this hack should not be seen by the display / CSHigh(); flexDma.sourceBuffer((const uint32_t)value, length); flexDma.destinationCircular((uint32_t)&p->SHIFTBUF[SHIFTNUM-1], sizeof(uint32_t) * SHIFTNUM); flexDma.transferCount(length/SHIFTNUM); flexDma.transferSize(SHIFTNUM); flexDma.triggerAtHardwareEvent(hw->shifters_dma_channel[SHIFTER_DMA_REQUEST]); flexDma.disableOnCompletion(); flexDma.clearComplete(); flexDma.enable(); delayMicroseconds(1); CSLow();

/ From now on, the SHIFTERS in MultiBeat mode are working correctly... / flexDma.begin(); sourceAddress = (uint16_t)value + (minorLoopBytes)/sizeof(uint16_t) - 1; // last 16bit address within current minor loop sourceAddressOffset = -sizeof(uint16_t); // read values in reverse order minorLoopOffset = 2minorLoopBytes; // source address offset at end of minor loop to advance to next minor loop sourceAddressLastOffset = minorLoopOffset - TotalSize; // source address offset at completion to reset to beginning destinationAddress = (uint32_t*)&p->SHIFTBUFHWS[SHIFTNUM-1]; // last 32bit shifter address (with reverse byte order) destinationAddressOffset = -sizeof(uint32_t); // write words in reverse order destinationAddressLastOffset = 0;

flexDma.TCD->SADDR = sourceAddress; flexDma.TCD->SOFF = sourceAddressOffset; flexDma.TCD->SLAST = sourceAddressLastOffset; flexDma.TCD->DADDR = destinationAddress; flexDma.TCD->DOFF = destinationAddressOffset; flexDma.TCD->DLASTSGA = destinationAddressLastOffset; flexDma.TCD->ATTR = DMA_TCD_ATTR_SMOD(0U) | DMA_TCD_ATTR_SSIZE(DMA_TCD_ATTR_SIZE_16BIT) // 16bit reads | DMA_TCD_ATTR_DMOD(destinationModulo) | DMA_TCD_ATTR_DSIZE(DMA_TCD_ATTR_SIZE_32BIT); // 32bit writes flexDma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE | DMA_TCD_NBYTES_MLOFFYES_MLOFF(minorLoopOffset) | DMA_TCD_NBYTES_MLOFFYES_NBYTES(minorLoopBytes); flexDma.TCD->CITER = majorLoopCount; // Current major iteration count flexDma.TCD->BITER = majorLoopCount; // Starting major iteration count

flexDma.triggerAtHardwareEvent(hw->shifters_dma_channel[SHIFTER_DMA_REQUEST]); flexDma.disableOnCompletion(); flexDma.interruptAtCompletion(); flexDma.clearComplete();

flexDma.attachInterrupt(dmaISR);

digitalWriteFast(36, LOW); digitalWriteFast(36, HIGH); flexDma.enable(); dmaCallback = this;

}`

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2041124916, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7VVPYKAZSVENJJ4BRTY4ALUPAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGEZDIOJRGY . You are receiving this because you were mentioned.Message ID: @.***>

wwatson4506 commented 3 months ago

This is the same file I am studying right now😆

On Sat, Apr 6, 2024 at 12:27 PM leutholl @.***> wrote:

maybe I can help you as I'm also wondering how to clear FlexIO from SingleBeat to MultiBeat in a "clean" way. I stumbled across this: https://github.com/ARMmbed/mbed-os/blob/baf6a3022a328b91713e03fd88f65126a9a53f01/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/drivers/fsl_flexio_mculcd.c#L546

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2041173620, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7TM6Q3ABUFCREIVOHLY4BECTAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGE3TGNRSGA . You are receiving this because you were mentioned.Message ID: @.***>

leutholl commented 3 months ago

Be careful with interpreting the Logic Analyzer. Depending on Impedance, Cable Length, Clips and Grounds you might see a false pulse (oftentimes shorter than the real ones) because of the hi-impedance transition. Just wanted to mention that to be on the safe side. On my side: still 12 real wrong pulses despite reseting Single Beat before doing Multi Beat.... hmm....

wwatson4506 commented 3 months ago

Thanks for the tip!

On Sat, Apr 6, 2024 at 12:40 PM leutholl @.***> wrote:

Be careful with interpreting the Logic Analyzer. Depending on Impedance, Cable Length, Clips and Grounds you might see a false pulse (oftentimes shorter than the real ones) because of the hi-impedance transition. Just wanted to mention that to be on the safe side. On my side: still 12 real wrong pulses despite reseting Single Beat before doing Multi Beat.... hmm....

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2041176324, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7SPGM4PYFZ33ACKGHLY4BFSPAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGE3TMMZSGQ . You are receiving this because you were mentioned.Message ID: @.***>

wwatson4506 commented 3 months ago

I disconnected the LA and there was no difference. What I was seeing was when it failed the LA showed the T41 was just missing the valid data. I was writing 0x0102 to video memory and reading it back. At least 80% of the time I read back the correct value, 0x102. But occasionally it reads back 0x0001 which shows it missing the low byte and that is what the LA is showing. It appears to be a timing issue with the signals. I THINK... Anyway, I tried slowing down the CPU with no luck and tried all of the different optimizations with now luck. So I think it back to the ref manual and examples. Maybe start from scratch.

leutholl commented 3 months ago

I solved it. Had to add this before setting up MultiBeat DMA p->SHIFTBUFHWS[0] = *(uint32_t*)value; uint32_t* value32 = (uint32_t*)value; value32++; p->SHIFTBUFHWS[1] = *(uint32_t*)value32; value32++; p->SHIFTBUFHWS[2] = *(uint32_t*)value32;

...and then working with value in reset position (ignore the value32 pointer increments) - no number of beats of DMA is correct.

The 12 beats without data were the actual data of the first 3 (note not 4 despite working with 4) SHIFTERBUF. If not set the value is assumed 0x00 but WR runs including the first 3 SHIFTERSBUFs worth of data. From that point on any next minor Loop is just happy retrieving the data from the SHIFTERS. I think this is related to the reverse loading from pixel buffer to the SHIFTER buffers by DMA. I tried forward mode as best as I can understand it but had other display issues - so reverse mode and working with SHIFTBUFHWS is the correct way for the RA8876 (on contrast to the ILI display). An expert might be laughing as I just might need an additional 12 beats and could add that somewhere in the address logic but I couldn't do it. To be honest the exact way of the reverse loading is a bit too complex to me.

Don't know if that helps on your read issue. If you can hand me a snippet of code to do the reading I can see what my Read is doing in terms of the addtional RD strobe you are observing. I still have my LA on the table for now ;-)

Can finally test everything, finish the minimum set of the library, work on double buffering + DMA locks, add the touch screen, add the rotation that I need (the RA8876 addresses in portrait mode) and can then give back to the community as I think my screen is very attractive to be working with lvgl in 8080 mode. I had it in my product with DMA SPI but it's a bit too slow.

just for my ego: THAT WAS A VERY DEEP RABBIT HOLE. ufff....

wwatson4506 commented 3 months ago

You have really been working it😀 Glad you have it working now. Here is output of what I am seeing:

Press anykey to continue rslt = 0x0102 Press anykey to continue rslt = 0x0102 Press anykey to continue rslt = 0x0001 <--------------- Very wrong and sporadic. Press anykey to continue rslt = 0x0102 Press anykey to continue rslt = 0x0102 Press anykey to continue

This is the current almost working lcdDataRead() function. //**// // Read RA8876 parallel Data (8bit read) //**// ru8 RA8876_t3::lcdDataRead(bool finalize) { uint8_t dummy = 0; uint8_t data = 0;

while(WR_IRQTransferDone == false) {} //Wait for any DMA transfers to complete // while(digitalReadFast(33) == 0); // If monitoring XnWAIT signal from RA8876. CSLow(); // Must to go low after config and delay above. DCHigh(); // Should already be HIGH

FlexIO_Config_SnglBeat_Read();

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

delayNanoseconds(500); // Stretch /CS signal a little. CSHigh(); // Serial.printf("Dummy 0x%4.4x, data 0x%4.4x\n", dummy, data);

//Set FlexIO back to Write mode FlexIO_Config_SnglBeat(); // Not sure if this is needed. return data; }

Here is how I am calling "lcdDataRead()":

include "RA8876_t3.h"

//#include "teensy41.c" //#include "Teensy41_Cardlike.h" //#include "t4.h"

include "flexio_teensy_mm.c"

uint8_t dc = 13; uint8_t cs = 11; uint8_t rst = 5; // 5 for MicroMod, 12 for T41;

uint8_t busSpeed = 12;

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); delay(100);

lcd.Memory_Select_SDRAM(); lcd.selectScreen(PAGE1_START_ADDR); Serial.print("\nBus speed: "); Serial.print(busSpeed,DEC); Serial.println(" MHZ");

lcd.fillScreen(0x0000); // lcd.pushPixels16bitDMA(flexio_teensy_mm,0,0,480,320); // 480x320 // lcd.writeRect(0, 0, 480, 320, flexio_teensy_mm); }

uint8_t rData = 0; uint16_t rslt = 0;

void loop() { lcd.drawLine(0x0000,0x0000,0x0002, 0x0000,0x0102); // Draw 3 16-bit pixels. lcd.graphicMode(true); // Set Graphics mode lcd.setPixelCursor(0x0000,0x0000); // Set to first pixel in display ram. lcd.ramAccessPrepare(); //Turn on Read/write access to display ram. rData = lcd.lcdDataRead(false); // Dummy read. rslt = (lcd.lcdDataRead() & 0xff); // read low byte rslt |= lcd.lcdDataRead()<<8; // add 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) ; }

This basically what I have been playing with for the last coupe of weeks...

On Sun, Apr 7, 2024 at 7:19 AM leutholl @.***> wrote:

I solved it. Had to add this before setting up MultiBeat DMA p->SHIFTBUFHWS[0] = (uint32_t)value; uint32_t value32 = (uint32_t)value; value32++; p->SHIFTBUFHWS[1] = (uint32_t)value32; value32++; p->SHIFTBUFHWS[2] = (uint32_t)value32;

...and then working with value in reset position (ignore the value32 pointer increments) - no number of beats of DMA is correct.

The 12 beats without data were the actual data of the first 3 (note not 4 despite working with 4) SHIFTERBUF. If not set the value is assumed 0x00 but WR runs including the first 3 SHIFTERSBUFs worth of data. From that point on any next minor Loop is just happy retrieving the data from the SHIFTERS. I think this is related to the reverse loading from pixel buffer to the SHIFTER buffers by DMA. I tried forward mode as best as I can understand it but had other display issues - so reverse mode and working with SHIFTBUFHWS is the correct way for the RA8876 (on contrast to the ILI display). An expert might be laughing as I just might need an additional 12 beats and could add that somewhere in the address logic but I couldn't do it. To be honest the exact way of the reverse loading is a bit too complex to me.

Don't know if that helps on your read issue. If you can hand me a snippet of code to do the reading I can see what my Read is doing in terms of the addtional RD strobe you are observing. I still have my LA on the table for now ;-)

Can finally test everything, finish the minimum set of the library, work on double buffering + DMA locks, add the touch screen, add the rotation that I need (the RA8876 addresses in portrait mode) and can then give back to the community as I think my screen is very attractive to be working with lvgl in 8080 mode. I had it in my product with DMA SPI but it's a bit too slow.

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2041486161, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7WENRVZLUKP6DLUVHLY4FIX3AVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGQ4DMMJWGE . You are receiving this because you were mentioned.Message ID: @.***>

leutholl commented 3 months ago

Not sure I understand your problem exactly.

I tried this: ` TFT.drawLine(0, 0, 30, 0, 0x6789); TFT.drawLine(31, 0, 70, 0, 0xABCD); while (true) { Serial.printf("\n\ntimestamp: %d\n", millis()); TFT.graphicMode(true); TFT.ramAccessPrepare();

  TFT.lcdDataRead();
  TFT.lcdDataRead();
  TFT.lcdDataRead();
  TFT.lcdDataRead();
  TFT.lcdDataRead();
  TFT.lcdDataRead();
  //pointer to ramAccess buffer continues in bulck read mode even writing to a register will not reset it.
  //TFT.lcdRegWrite(0x02);
  delay(1000);
}`

and got this in a very reliable way:

drawLine x0=0 y0=0 x1=30 y1=0 color=6789 drawLine x0=31 y0=0 x1=70 y1=0 color=abcd

timestamp: 2198 1st read(dummy) 0x0000, 2nd read(data) 0x0000 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089

timestamp: 3198 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089

timestamp: 4198 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd

timestamp: 5199 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd

timestamp: 6199 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd

timestamp: 7199 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd

timestamp: 8199 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010

timestamp: 9199 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010

which matched the color: 30 pixels of value 0x6789 but the first read is dummy read, then 40 pixels of value 0xABCD, then it auto-increments to my background color which is Blue 0x0010. I can't manage to reset the RAM pointer it just goes on and on even if I write to another register or draw something new. Note all reads or 4 byte aligned.

using `ru8 RA8876_8080::lcdDataRead(bool finalize) { // ru16 _data = (RA8876_SPI_DATAREAD16 | 0x00); // startSend(); // ru8 data = _pspi->transfer16(_data); // endSend(finalize); while(WR_IRQTransferDone == false) {} //Wait for any DMA transfers to complete CSLow(); / De-assert RS pin / DCHigh(); FlexIO_Config_SnglBeat_Read(); uint16_t dummy; uint16_t data = 0; while (0 == (p->SHIFTSTAT & (1 << 3))) {} dummy = p->SHIFTBUFBYS[3]; while (0 == (p->SHIFTSTAT & (1 << 3))) {} data = p->SHIFTBUFBYS[3]; //Set FlexIO back to Write mode FlexIO_Config_SnglBeat(); CSHigh(); Serial.printf("1st read(dummy) 0x%4.4x, 2nd read(data) 0x%4.4x\n", dummy, data);

if(BUS_WIDTH == 8) { return data; } else { return dummy = (data >> 8) | (data & 0xff); // High byte to low byte and mask. } }`

Rotation was set to 0. The PixelCursor command you're having is a bit strange. What RAM_Reads return after it is determined by register 0x03 [1-0]. Not sure this is reset correctly by the drawing function. Just to let you know.

But my results are always the same. If you can find a way to reset the RAM_reads back to pixels 0 I can let it run for some minutes to watch for variance.

Would you like me to look into the LA picture of that read? You mentioned 3 RD strobes. Was that always or only when you get wrong data reads? Does that mean that your RD strobes vary from time to time? please let me know soon if I should look into the LA for you. my cats are a bit tempted to play with the probes during night and I can't move my setup that easily.

wwatson4506 commented 3 months ago

To set a pixel address you use:

lcd.graphicMode(true); lcd.setPixelCursor(0x0000,0x0000); // Set to first pixel. X,Y coords. lcd.ramAccessPrepare();

If you have time it would be interesting to see if you get the same 3 /RD pulses I did...

On Sun, Apr 7, 2024 at 2:01 PM leutholl @.***> wrote:

Not sure I understand your problem exactly.

I tried this: ` TFT.drawLine(0, 0, 30, 0, 0x6789); TFT.drawLine(31, 0, 70, 0, 0xABCD); while (true) { Serial.printf("\n\ntimestamp: %d\n", millis()); TFT.graphicMode(true); TFT.ramAccessPrepare();

TFT.lcdDataRead(); TFT.lcdDataRead(); TFT.lcdDataRead(); TFT.lcdDataRead(); TFT.lcdDataRead(); TFT.lcdDataRead(); //pointer to ramAccess buffer continues in bulck read mode even writing to a register will not reset it. //TFT.lcdRegWrite(0x02); delay(1000); }`

and got this in a very reliable way:

drawLine x0=0 y0=0 x1=30 y1=0 color=6789 drawLine x0=31 y0=0 x1=70 y1=0 color=abcd

timestamp: 2198 1st read(dummy) 0x0000, 2nd read(data) 0x0000 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089

timestamp: 3198 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089

timestamp: 4198 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x0067, 2nd read(data) 0x0089 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd

timestamp: 5199 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd

timestamp: 6199 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd

timestamp: 7199 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd 1st read(dummy) 0x00ab, 2nd read(data) 0x00cd

timestamp: 8199 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010

timestamp: 9199 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010 1st read(dummy) 0x0000, 2nd read(data) 0x0010

which matched the color: 30 pixels of value 0x6789 but the first read is dummy read, then 40 pixels of value 0xABCD, then it auto-increments to my background color which is Blue 0x0010. I can't manage to reset the RAM pointer it just goes on and on even if I write to another register or draw something new. Note all reads or 4 byte aligned.

using `ru8 RA8876_8080::lcdDataRead(bool finalize) { // ru16 _data = (RA8876_SPI_DATAREAD16 | 0x00); // startSend(); // ru8 data = _pspi->transfer16(_data); // endSend(finalize); while(WR_IRQTransferDone == false) {} //Wait for any DMA transfers to complete CSLow(); / De-assert RS pin / DCHigh(); FlexIO_Config_SnglBeat_Read(); uint16_t dummy; uint16_t data = 0; while (0 == (p->SHIFTSTAT & (1 << 3))) {} dummy = p->SHIFTBUFBYS[3]; while (0 == (p->SHIFTSTAT & (1 << 3))) {} data = p->SHIFTBUFBYS[3]; //Set FlexIO back to Write mode FlexIO_Config_SnglBeat(); CSHigh(); Serial.printf("1st read(dummy) 0x%4.4x, 2nd read(data) 0x%4.4x\n", dummy, data);

if(BUS_WIDTH == 8) { return data; } else { return dummy = (data >> 8) | (data & 0xff); // High byte to low byte and mask. } }`

Rotation was set to 0. The PixelCursor command you're having is a bit strange. What RAM_Reads return after it is determined by register 0x03 [1-0]. Not sure this is reset correctly by the drawing function. Just to let you know.

But my results are always the same. If you can find a way to reset the RAM_reads back to pixels 0 I can let it run for some minutes to watch for variance.

Would you like me to look into the LA picture of that read? You mentioned 3 RD strobes. Was that always or only when you get wrong data reads? Does that mean that your RD strobes vary from time to time? please let me know soon if I should look into the LA for you. my cats are a bit tempted to play with the probes during night and I can't move my setup that easily.

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2041607761, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7QK5GUCRS2NKSUIUV3Y4GXZPAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGYYDONZWGE . You are receiving this because you were mentioned.Message ID: @.***>

leutholl commented 3 months ago

yes 3 pulses on RD on my LA.

leutholl commented 3 months ago

correction and interesting finding: This has something to do with using Serial

uint16_t dummy; uint16_t data = 0; /* while (0 == (p->SHIFTSTAT & (1 << 3))) {} dummy = p->SHIFTBUFBYS[3]; */ while (0 == (p->SHIFTSTAT & (1 << 3))) {} //data = p->SHIFTBUFBYS[3]; uint32_t data32 = p->SHIFTBUFBYS[3]; //as soon as I use Serial - I see 3 RD cycles - DMA intereferenece? Serial.printf("data32: 0x%x\n", data32);

Without Serial only 2x RD with Serial 3x RD. Serial is using DMA - is there a DMA channel interference?

EDIT: This only occurs if the read back data of the SHIFERBUF is actually used on Serial.print(). Otherwise the compile optimizes the statement away. Also using Serial without reference to the read back data will not add a RD cycle.

wwatson4506 commented 3 months ago

I have run out of time for today but will check it out tomorrow. Thanks for confirming and the curious observation with Serial.printf()...

On Sun, Apr 7, 2024 at 2:44 PM leutholl @.***> wrote:

correction and interesting finding: This has something to do with using Serial

uint16_t dummy; uint16_t data = 0; / while (0 == (p->SHIFTSTAT & (1 << 3))) {} dummy = p->SHIFTBUFBYS[3]; / while (0 == (p->SHIFTSTAT & (1 << 3))) {} //data = p->SHIFTBUFBYS[3]; uint32_t data32 = p->SHIFTBUFBYS[3]; //as soon as I use Serial - I see 3 RD cycles - DMA intereferenece? Serial.printf("data32: 0x%x\n", data32);

Without Serial only 2x RD with Serial 3x RD. Serial is using DMA - is there a DMA channel interference?

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2041618630, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7T7ELKPVDV7ONPXSPDY4G44TAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGYYTQNRTGA . You are receiving this because you were mentioned.Message ID: @.***>

leutholl commented 2 months ago

I need some help on rotation. I think you can help me. The lvgl buffer needs to be rotated by 90 degrees (actually 270 in my product). I saw the rotating feature of the RA8876 but I'm not sure if that is somehow related when doing BTE&ROP. I see that the memory read direction changes to bottom up, but I have a hard time to understand if this will influence BTE&ROP and if by that any rotation can be made. Before I must rotate the buffer in memory [sofware rotation]] (and I again stumbled across the Active Window and coordinate rotation issue because LVGL can rotate, RA8876 can "pseudo-rotate" and my buffer manipulate for-loop can rotate....), I want to be sure that this can't be solved without software rotation to spare memory and increase performance. I see some aspects here:

1) rotation of coordinate for BTE placement and Active Window 2) swapping width&height for the BTE command 3) swapping screenWidth of the BTE command 4) rotating the buffer itself (which is lvgl writing at any dimension at any place to "make" the full screen updated) 5) mirroring it for 90 to 270 degrees

So how are 1) 2) 3) 4) 5) related to each other, what must be considered.

I will play around with that thing now but I see that you might have some shortcuts to speed up my thinking progress.

K7MDL2 commented 2 months ago

I use BTE and ActiveWindow for my spectrum display and use rotation, usually 0 or 180. I do not change my X or Y coordinates in my code, correction is taken care of in the display controller. I use SPI interface.

From: leutholl @.> Sent: Monday, April 8, 2024 1:36 PM To: wwatson4506/Ra8876LiteTeensy @.> Cc: K7MDL @.>; Comment @.> Subject: Re: [wwatson4506/Ra8876LiteTeensy] 8080 and DMA and MicroMod (Issue #16)

I need some help on rotation. I think you can help me. The lvgl buffer needs to be rotated by 90 degrees (actually 270 in my product). I saw the rotating feature of the RA8876 but I'm not sure if that is somehow related when doing BTE&ROP. I see that the memory read direction changes to bottom up, but I have a hard time to understand if this will influence BTE&ROP and if by that any rotation can be made. Before I must rotate the buffer in memory [sofware rotation]] (and I again stumbled across the Active Window and coordinate rotation issue because LVGL can rotate, RA8876 can "pseudo-rotate" and my buffer manipulate for-loop can rotate....), I want to be sure that this can't be solved without software rotation to spare memory and increase performance. I see some aspects here:

  1. rotation of coordinate for BTE placement and Active Window
  2. swapping width&height for the BTE command
  3. swapping screenWidth of the BTE command
  4. rotating the buffer itself (which is lvgl writing at any dimension at any place to "make" the full screen updated)
  5. mirroring it for 90 to 270 degrees

So how are 1) 2) 3) 4) 5) related to each other, what must be considered.

I will play around with that thing now but I see that you might have some shortcuts to speed up my thinking progress.

- Reply to this email directly, view it on GitHubhttps://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#issuecomment-2043598706, or unsubscribehttps://github.com/notifications/unsubscribe-auth/APLVE7CB6LKYZPXMKH4QULDY4L5SVAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBTGU4TQNZQGY. You are receiving this because you commented.Message ID: @.**@.>>

wwatson4506 commented 2 months ago

@KurtE and @mjs513 did the majority of the work with rotation. If I remember right the RA8876 only rotates 90 and 180 degrees counterclockwise. Check out section 11.4 starting at page #52. Kurt and Mike set it up to rotate a full 270 degrees. check out the RA8876Rotate.ino sketch. It demonstrates rotation in all directions counter clockwise and is working with the 8080 IF.

KurtE commented 2 months ago

Sorry I know very little about using LVGL. Other than I see a lot of people having issues with it when they try to use it with the Arduino GIGA Display Shield. Something about they changed a bunch of the APIs from version 8.x to 9.x in an incompatible way. Also that was unclear about what is going to happen now the LVGL and ... broke up...

As for rotation. yes @mjs513 and myself did a lot of it something like 4 years ago. It looks like Mike gets most of the github Blame 😉 but we probably bounced code back and forth and he was probably the one who did the main pull requests.

As mentioned, it looks like the hardware supports a couple of different orientations, but not all 4 that most of our libraries support , for 0, 90, 180, 270 degrees.

So we did a lot of this through software. Look at the setRotation method that is part of this library. In some cases changes the scan direction and likewise some other settings.

But then we also had to catch it in most of the primitives and do things like swap coordinates. So for example if you look at the simple primitive: fillRect, you will see code that handles it like:


void RA8876_t3::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,uint16_t color) {
    x += _originx;
    y += _originy;
    int16_t x_end = x+w-1;
    int16_t y_end = y+h-1;
    if((x >= _displayclipx2)   || // Clip right
         (y >= _displayclipy2) || // Clip bottom
         (x_end < _displayclipx1)    || // Clip left
         (y_end < _displayclipy1))      // Clip top 
    {
        // outside the clip rectangle
        return;
    }
    if (x < _displayclipx1) x = _displayclipx1;
    if (y < _displayclipy1) y = _displayclipy1;
    if (x_end > _displayclipx2) x_end = _displayclipx2;
    if (y_end > _displayclipy2) y_end = _displayclipy2;
  check2dBusy();
  graphicMode(true);
  foreGroundColor16bpp(color);
  switch (_rotation) {
    case 1: swapvals(x,y); swapvals(x_end, y_end); break;
    case 2: x = _width-x; x_end = _width - x_end;; break;
    case 3: rotateCCXY(x,y); rotateCCXY(x_end, y_end); break;
  }
  lcdRegDataWrite(RA8876_DLHSR0,x, false);//68h
  lcdRegDataWrite(RA8876_DLHSR1,x>>8, false);//69h
  lcdRegDataWrite(RA8876_DLVSR0,y, false);//6ah
  lcdRegDataWrite(RA8876_DLVSR1,y>>8, false);//6bh
  lcdRegDataWrite(RA8876_DLHER0,x_end, false);//6ch
  lcdRegDataWrite(RA8876_DLHER1,x_end>>8, false);//6dh
  lcdRegDataWrite(RA8876_DLVER0,y_end, false);//6eh
  lcdRegDataWrite(RA8876_DLVER1,y_end>>8, false);//6fh   
  lcdRegDataWrite(RA8876_DCR1,RA8876_DRAW_SQUARE_FILL, true);//76h,0xE0  

```'

Note: this only works fully correctly for our primitives. But does not work in all orientations for things like drawting text using a built in font.

How to do this with LVGL?  I don't know.  I know with the GIGA display, has had some support for this.  They have some basic driver that handles the screen, and a few other ones that use it.  Like you can use Adafruit_GFX with it.  But performance really sucks on it.  They have each primitive go down to things like draw a pixel, and when this happens it marks the screen dirty and starts up a high priority thread that refreshes the screen...   But if I remember correctly, they have an example that uses an IMU or the like built into the display shield, and reorients the LVGL screen depending on how the screen is orientated.   Not sure if it works, but maybe...

Good luck.
leutholl commented 2 months ago

Thanks for all your friendly inputs. I have a working sketch with lvgl in 270degrees using a combination of Reverse Scanning und Reverse RAM Writing but still needing to rotate the buffers of lvgl dirty zones by software. This is something I don’t understand. Why do I need to rotate the buffer in software when the RAIO has support to reverse scanning and memory write direction. I mean this is available for BTE/ROP graphics, I‘m not talking about primitives or text mode. lvgl fires the callback for any region of the screen that has changed. it’s that buffer that I still need to rotate in software. Is this related that the Video Page Memory Address needs to be doubled in size because the working area is temporarily squared?

This software rotation and waiting for the RAIO to do some additional ROPs that I have to do, drops the framerate quite heavily. But I still can get full screen refresh rate if about 11 FPS. If only a part of the screen needs to be updated (eg a button press) and I can avoid my additional ROPs (I‘m working with multiple canvas/layers) this is butter smooth and much faster than DMA SPI. I also added Capacitative Touch with rotation and lvgl even understands gestures. PWM for Backlight is done in the RAIO and working. The SSD2828 needed some care as well as sometimes the screen would interlace after Reset but power on was working. Also instead of polling the status register I‘m listening on the WAIT pin.

I‘m very close to push my own version of the library which is meant for lvgl. I‘m very grateful of all your contributions. It’s just that the software rotation still bug me.

Will show you my rotation code soon.

leutholl commented 2 months ago

Here is my repo that wraps this thread. Many thanks for all your contributions. I will close the issue.

https://github.com/leutholl/TFT0784_mm

wwatson4506 commented 2 months ago

Thanks for the link. I will definitely check it out. Glad it is working for you...

wwatson4506 commented 2 months ago

Unbelievably AWESOME work Leutholl😂 I updated my "MulBeatWR_nPrm_DMA()" function and it works perfectly. Thanks so much for all your hard work on this. Oh, and your scope. I will update my drivers on GitHub. Not sure if you are going to introduce your library yet so I won't say anything to the forum until you do. Thanks again...

On Tue, Apr 23, 2024 at 9:26 AM leutholl @.***> wrote:

Closed #16 https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16 as completed.

— Reply to this email directly, view it on GitHub https://github.com/wwatson4506/Ra8876LiteTeensy/issues/16#event-12578393410, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAH2Q7SQVEYAZ7ESYTHDO2LY62DTFAVCNFSM6AAAAABE6JBZNCVHI2DSMVQWIX3LMV45UABCJFZXG5LFIV3GK3TUJZXXI2LGNFRWC5DJN5XDWMJSGU3TQMZZGM2DCMA . You are receiving this because you were mentioned.Message ID: @.***>

leutholl commented 3 weeks ago

Please announce the library on the forums you find relevant. I'm not too practiced writing on forums when it comes to contribute code - so be my guest. I should have the same username on the pjrc forum so you can link to me.