prenticedavid / MCUFRIEND_kbv

MCUFRIEND_kbv Library for Uno 2.4, 2.8, 3.5, 3.6, 3.95 inch mcufriend Shields
Other
361 stars 181 forks source link

STROBE_16BIT delays only for SAM3X8E #51

Closed AdiGitalEU closed 5 years ago

AdiGitalEU commented 6 years ago

I'm sorry if this isn't the proper way to deal with the issue but I still can't get my head around GITHUB. Since I resolved the problem by editing code outside the mcufriend_special.h file I thought it might be worth reporting.

After two days of cracking the library I managed to get it working on Teensy 3.6 in 16bit mode on SSD1963 (800x480) by adding the necessary section in the mcufriend_special.h. I couldn't get above 96MHz and was playing with the read and write delays and signal analysis on oscilloscope (short cables and signals looked good). The graphictest_kbv draws lines and other elements but there seems to be garbage left after each test. I tracked the issue to the #if USING_16BIT_BUS #if defined(SAM3X8E) section (fillRect method) in the cpp. It looks the longer delays in 16bit mode are ony for DUE. I've changed it and now got up to 216MHz and the whole test takes 1.12s. I know the library is mainly for the shields so if the custom code is worth sharing please let me know how.

prenticedavid commented 6 years ago

What have you done? Please send a Pull Request. Or just add the code snippet to your message.

I do not have a Teensy3.6. I only have a Teensy3.2. I have never considered anyone doing a 16BIT SPECIAL on anything other than Mega2560 or Due. I have a 16BIT SPECIAL for a BluePill. I think that I wrote one for ZinggJM but I doubt if he ever tried it.

The library was designed for 8080-8 interface on Shields. This generally involves random Port pins. Most AVR and M0 targets are slower than the TFT controller.

Fast M3 and M4 targets are quicker than TFT controllers. So require some delays. I have simplified the delays on the current Beta. But only for mcufriend_shield targets.

You can trim the WR_ACTIVEs to avoid glitches on the Adafruit Tests. You can trim the RD_ACTIVEs to avoid glitches in Software Scroll and readID()

If you have contiguous Port bits, you might need to worry about the length of the IDLE phase.

Life is much easier if you show your SPECIAL entry.

The SSD1963 is pretty quick. I only have a 40-pin SSD1963 module. If you have a 40-pin SSD1289 or ILI9341 screen, it would be interesting. The SSD1289 is pretty slow. The ILI9341 can go faster than the datasheet says.

David.

AdiGitalEU commented 6 years ago

Hello David, apologies for not including the code. Will add it below with videos showing achieved speed and the problem. But first let me say: what an amazing piece of work!

Yes, I'm using the two lower bytes of the port C and D, as explained in the Teensy's edition of the UTFT. It took a while before I got my head around all the macros ;) but eventually it worked (I began with 24MHz). So now with the code below it works up to 216MHz. I will try to tweak it even more after I put the two on the final PCB.

I do have SSD1289 but I believe it's something wrong with it. On the DUE and the 16bit DUE shield it kind of works but with lots of lines during communication. On the Teensy it's just garbage or nothing. I would be curious to see smaller TFT on the combo but that's all I have with 16bits bus.

I added/changed the following: __In MCUFRIEND_kbv.cpp I switched to this init as the default was giving reduced/wrong colors:__ table8_ads = SSD1963_800ALT_regValues, table_size = sizeof(SSD1963_800ALT_regValues);

__Removed INVERT_SS as the screen was mirrored:__

#if defined(SUPPORT_1963) && USING_16BIT_BUS 
    case 0x1963:
        _lcd_capable = AUTO_READINC | MIPI_DCS_REV1 | READ_NODUMMY | INVERT_RGB; //INVERT_SS | INVERT_RGB;

Then added the define for Teensy 3.6 and copied delays from the DUE:

#if USING_16BIT_BUS
    #if defined(__SAM3X8E__)
        #define STROBE_16BIT {WR_ACTIVE;WR_ACTIVE;WR_ACTIVE;WR_IDLE;WR_IDLE;}
    #elif defined(__MK66FX1M0__)
        #define STROBE_16BIT {WR_ACTIVE;WR_ACTIVE;WR_ACTIVE;WR_IDLE;WR_IDLE;}
    #else
        #define STROBE_16BIT {WR_ACTIVE; WR_IDLE;}

And at last added the following to the mcufriend_special.h: At the top: #define USE_TEENSY_36_PORT_CD ...and at the end:

//####################################### TEENSY ############################
#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) // regular UNO shield on a Teensy 3.x
#warning "Teensy 3.6 16bit port C & D only (for now)"
// Note: Port usage explained in UTFT Teensy edition ...\libraries\UTFT\hardware\arm\HW_Teensy3.h"

#define USES_16BIT_BUS

#if defined(__MK20DX128__) || defined(__MK20DX256__) // Teensy3.0 || 3.2 96MHz
// #define WRITE_DELAY { WR_ACTIVE; WR_ACTIVE; }
// #define READ_DELAY  { RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; }
#elif defined(__MK64FX512__) // Teensy3.5 120MHz thanks to PeteJohno
// #define WRITE_DELAY { WR_ACTIVE; WR_ACTIVE; WR_ACTIVE; WR_ACTIVE; }
// #define READ_DELAY  { RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; }
#elif defined(__MK66FX1M0__) && defined(USE_TEENSY_36_PORT_CD)// Teensy3.6 180MHz untested.   delays can possibly be reduced.

#define WRITE_DELAY { WR_ACTIVE; WR_ACTIVE; WR_ACTIVE; WR_ACTIVE; WR_ACTIVE; WR_ACTIVE; WR_ACTIVE; WR_ACTIVE; }
#define READ_DELAY  { RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; RD_ACTIVE; }

#else
#error unspecified delays
#endif

#define RD_PORT GPIOA
#define RD_PIN 16       //28 RD
#define WR_PORT GPIOA
#define WR_PIN 5        //25 WR
#define CD_PORT GPIOE
#define CD_PIN 26       //24 RS 
#define CS_PORT GPIOA
#define CS_PIN 14       //26 CS
#define RESET_PORT GPIOA
#define RESET_PIN 15    //27 Reset

#define write_8(d) { GPIOC_PDOR = d; } 
#define write_16(d) { GPIOC_PDOR = d; GPIOD_PDOR = (d >> 8);}

#define read_8() (GPIOC_PDIR)
#define read_16() (GPIOC_PDIR | GPIOD_PDIR << 8)

#define setWriteDir() {GPIOC_PDDR |=  0xFF; GPIOD_PDDR |=  0xFF; }
#define setReadDir()  {GPIOC_PDDR &= ~0xFF; GPIOD_PDDR &= ~0xFF; }

#define write8(x)     {write_8(x); WRITE_DELAY; WR_STROBE }
#define write16(x)    {write_16(x); WRITE_DELAY; WR_STROBE }

#define READ_8(dst) { RD_STROBE; READ_DELAY; dst = read_8(); RD_IDLE; } 
#define READ_16(dst) { RD_STROBE; READ_DELAY; dst = read_16(); RD_IDLE;}

//Data: Teensy pins -> D0-D15 :
#define GPIO_INIT() { pinMode( 15, OUTPUT); \
                    pinMode( 22, OUTPUT); \
                    pinMode( 23, OUTPUT); \
                    pinMode(  9, OUTPUT); \
                    pinMode( 10, OUTPUT); \
                    pinMode( 13, OUTPUT); \
                    pinMode( 11, OUTPUT); \
                    pinMode( 12, OUTPUT); \
                    pinMode(  2, OUTPUT); \
                    pinMode( 14, OUTPUT); \
                    pinMode(  7, OUTPUT); \
                    pinMode(  8, OUTPUT); \
                    pinMode(  6, OUTPUT); \
                    pinMode( 20, OUTPUT); \
                    pinMode( 21, OUTPUT); \
                    pinMode(  5, OUTPUT); \
                    pinMode( 24, OUTPUT); \
                    pinMode( 25, OUTPUT); \
                    pinMode( 26, OUTPUT); \
                    pinMode( 27, OUTPUT); \
                    pinMode( 28, OUTPUT);}

#define PASTE(x, y) x ## y

#define PIN_LOW(port, pin) PASTE(port, _PCOR) = (1<<(pin))
#define PIN_HIGH(port, pin) PASTE(port, _PSOR) = (1<<(pin))
#define PIN_OUTPUT(port, pin) PASTE(port, _PDDR) |= (1<<(pin))

//=========================== end of teensy

The videos: Speed demo: https://youtu.be/GSWkkS039lw

Delay problem: https://youtu.be/wznlmC8UtIs

prenticedavid commented 6 years ago

Yes, it is impressive. It is a similar speed with a Due (using CTE Adapter Shield for Due).

You have written your SPECIAL correctly.

Look at the current Master Branch: mcufriend_shield.h The delay macros are a lot easier to manage. You do not need pinMode() statements. This is simpler.

#define DMASK  0xFFFF
#define setWriteDir() {GPIOD_PDDR |= DMASK; }
#define setReadDir() {GPIOD_PDDR &= ~DMASK; }

I like your Teensy Adapter. I did a similar thing with BluePill and small piece of Protoboard. The BluePill sits underneath the 5 inch SSD1963. I am horrified by flying jumper wires. Soldering a custom Adapter is a bit fiddly but you can swap it between screens and MCU boards.

I will create a Branch with your SPECIAL. You could see how many WR_ACTIVEs are needed to get the SSD1289 working.

David.

AdiGitalEU commented 6 years ago

Thank you David.

I used the pinMode() as a safe shortcut just as I started - not knowing the required registers and not being sure what I'm doing ;) Thank you for the tip!

I've got a few BluePills and was thinking about using it as the GPU but because of the built-in SD card in Teensy I decided to stick with it (I need it in my project). Although I have no 16bit TFTs left but might get some in a future so will definitely be interested in the wide bus for the BluePill. The 8bit works with my RM68140 (320x480) and other 3.5 displays I've got so well, that it inspired me to experiment and switch to your library from the UTFT. So big thank you! I've learned a lot.

(I might actually try to desolder the RA display from the shield and try it in 16bit at some point)

Alek

P.S. Forgot to mention the orientation seems twisted but that's not an issue really.

prenticedavid commented 6 years ago

The SSD1963 is wider than it is high. I call it "Portrait" because Vertical Scroll works this way. Yes, I agree. It is confusing. "Natural mode" might be accurate but it would confuse everyone. Anyway 9 out 10 controllers are "Natural Portrait". Your SSD1963 is "Natural Landscape"

The SSD1963 only works in 8080-16. Most other controllers can do 8080-8 and SPI. Which is plenty sufficient for most applications. A BluePill does not have that many GPIO pins.

I do not have a read-write RM68140 to fit on a M4. I know that it is slower than a ILI9486. It would be nice to have some real results.
I hope to get an Arduino Forum member to test an 8080-8 RM68140 on a 180MHz Nucleo-F446. I have even created a Branch for him. He is not willing. I might do some begging to you shortly.

David.

AdiGitalEU commented 6 years ago

If there's anything I can help or contribute just please let me know.

On the BluePill side - I was hoping to use the entire PORT A on it. It seems to have all bits available. I know the A11-14 are occupied by USB and ST-LINK but was hoping they'd be free after programming's finished? Anyway - these were just my initial thoughts and project for later.

Hope you'll excuse me being lazy (or tired ;) ) and asking instead of trying. I'm interested in using the scroll functionality. Does it work only on entire line or is it possible to make it in a window? I'll want to make a scrolling graph.

prenticedavid commented 6 years ago

There is no great harm in splitting PORTs. The ARM has a barrel shifter. You do not need to have a single contiguous PORT. Most apps need TFT, SPI for SD and Touch controller. Possibly I2C and a couple of Analog pins.

This gets really tight on a BluePill. I prefer to keep SWD operational. You end up with mixed PORTs.

Regarding Scroll. The SSD1963 can scroll a Band or the whole screen. Only in Vertical direction. Look at the Demo.

David.

prenticedavid commented 6 years ago

I have created a Branch for you called "tidy_special" It should be configured for your Teensy3.6 SPECIAL Please let me know if it works with your SSD1963.

It is necessary to use pinMode() to configure Teensy GPIO. i.e. init_GPIO() macro. It is simpler to use pinMode() than accessing the specific hardware registers. But you should be able to adjust delays easily e.g. for slower controllers.

You can start with slow Clock Speeds from the Arduino IDE. This is a simple way to resolve speed problems.

My Arduino Forum colleague is mailing me a RM68140. So I will be able to see its Read and Write Cycle times for myself.

David.

AdiGitalEU commented 6 years ago

Hello David, thank you for the branch.

Apart from one typo in GPIO_INIT() The SPECIAL works great! I'm not sure if that's just my display but I had to make the 3 changes in the cpp:

Fix mirrored display: In line 1180 removed INVERT_SS from _lcd_capable

Fix wrong colors: Switch table8_ads to SSD1963_800ALT_regValues

Included Teensy in the delay condition: 580 #if defined(__SAM3X8E__) || defined(__MK66FX1M0__)

I got the same results going stable up to 216MHz (test completed in 1.11s) but now 240MHz (1.0s) produces only few glitches on the screen. I tried adding few more delay but without much difference. I believe this may be the temporary wiring. The connections are short but they vary in length and are tangled. At those frequencies this is most likely the cause. Shortly I will be making a proper prototyping pcb for further development of my project and will revise the delays. I'm expecting stable results at 240MHz.

prenticedavid commented 6 years ago

I have updated the typo. I could change the SS inversion in one of the tables. For the future, the delay condition would be better to use F_CPU > 120, F_CPU > 96, F_CPU > 72MHz, ...

Thanks for the feedback. The 8080-16 code is not well tested. I only have a SSD1963 with 40-pin header. My other 8080-16 displays are on Mega2560 Shields. Only fit Mega or Due.

David.