Due direct port manipulation for Mega2560 shield

:o I have a 3.2" TFT which is a snap to use with the Mega2560 as most drivers including mine utilize the standard shield pin arrangement.

I really wanted to use on my Due but found the port pins for db0-7 and db8-15 were totally uncool. By saying this the ports and pin mapping on the Due was all over the place where the pins connect to the TFT.

The 1289 TFT I have is 16 bit parallel so it has 2x the connection fun as the 8 bit version.

For quick testing of my graphics library etc I needed to be able to use the shield on the Due and the Mega2560.

I have a few standard macros my routines use for reading and writing to the 2 8 bit locations. On the Mega2560 (off memory) these just end up being PORTC and PORTA.

#pragma message("** SHIELD POS - DIB 8/16 bit interface pins 37-30(0-7) 22-29(8-15)  (PORTA & PORTC)")

#define fastDigitalWrite8_1(val8) PORTC = (val8)
#define fastDigitalWrite8_2(val8) PORTA = (val8)
 
#define fastPinMode8_1_INPUT() DDRC = 0
#define fastPinMode8_2_INPUT() DDRA = 0

#define fastPinMode8_1_OUTPUT() DDRC = 255
#define fastPinMode8_2_OUTPUT() DDRA = 255

#define fastDigitalRead8_1() (PORTC)
#define fastDigitalRead8_2() (PORTA)

For the due it's a lot more complicated but still ends up fast. The macro below is for for the Due and reads from what would be the same as the Mega2560 PORTA and PORTC locations. Verified as working and I hope it can save others a lot of time. A lot of the bit manipulation gets optimized by the compiler but it's a lot easier to make changes the way it is.

#pragma message("** SHIELD - DIB 8/16 bit interface pins 37-30(0-7) 22-29(8-15) MEGA2560 mapping")


#define fastDigitalWrite8_1(val8) REG_PIOC_CODR = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) ; \
								  REG_PIOD_CODR = (1 << 10) | (1 << 9); \
								  REG_PIOA_CODR = (1 << 7); \
								  REG_PIOC_SODR =  ((val8 & 1) << 5) | \
                                                   ((val8 & 2) << 3) | \
                                                   ((val8 & 4) << 1) |  \
								                   ((val8 & 8) >> 1) |  \
								                   ((val8 & 16) >> 3);  \
								  REG_PIOD_SODR =  ((val8 & 32) << 5) |  \
												   ((val8 & 128) << 2); \
								  REG_PIOA_SODR = (val8 & 64) << 1;  

#define fastDigitalRead8_1() ((REG_PIOC_PDSR >> 5) & 1) | \
							 ((REG_PIOC_PDSR >> 3) & 2) | \
							 ((REG_PIOC_PDSR >> 1) & 4) | \
							 ((REG_PIOC_PDSR << 1) & 8) | \
							 ((REG_PIOC_PDSR << 3) & 16) | \
						     ((REG_PIOD_PDSR >> 5) & 32) | \
							 ((REG_PIOD_PDSR >> 2) & 128) | \
							 ((REG_PIOA_PDSR >> 1) & 64) 



#define fastDigitalWrite8_2(val8) REG_PIOD_CODR = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 6) ; \
								  REG_PIOA_CODR = (1 << 14) | (1 << 15); \
								  REG_PIOB_CODR = (1 << 26); \
								  REG_PIOB_SODR =  (val8 & (1 << 0)) << 26; \
								  REG_PIOA_SODR =  (val8 & ((1 << 1) | (1 << 2))) << 13; \
								  REG_PIOD_SODR =  ((val8 & ((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6))) >> 3) |  \
								                   ((val8 & (1 << 7)) >> 1);  

#define fastDigitalRead8_2() ((REG_PIOB_PDSR  >> 26) & (1 << 0)) | \
							 ((REG_PIOA_PDSR  >> 13) & ((1 << 1) | (1 << 2))) | \
							 ((REG_PIOD_PDSR   << 3) & ((1 << 3) | (1 << 4) | (1 << 5) | (1 << 6))) | \
							 ((REG_PIOD_PDSR  << 1) & (1 << 7))



#define fastPinMode8_1_INPUT() pinMode(37, INPUT);pinMode(36, INPUT);pinMode(35, INPUT);pinMode(34, INPUT);pinMode(33, INPUT);pinMode(32, INPUT);pinMode(31, INPUT);pinMode(30, INPUT);  //REG_PIOC_ODR = (0x000000FF << 1);
#define fastPinMode8_2_INPUT() pinMode(22, INPUT);pinMode(23, INPUT);pinMode(24, INPUT);pinMode(25, INPUT);pinMode(26, INPUT);pinMode(27, INPUT);pinMode(28, INPUT);pinMode(29, INPUT); //REG_PIOC_ODR = (0x000000FF << 12);

#define fastPinMode8_1_OUTPUT() pinMode(37, OUTPUT);pinMode(36, OUTPUT);pinMode(35, OUTPUT);pinMode(34, OUTPUT);pinMode(33, OUTPUT);pinMode(32, OUTPUT);pinMode(31, OUTPUT);pinMode(30, OUTPUT); // REG_PIOC_OER = (0x000000FF << 1);
#define fastPinMode8_2_OUTPUT() pinMode(22, OUTPUT);pinMode(23, OUTPUT);pinMode(24, OUTPUT);pinMode(25, OUTPUT);pinMode(26, OUTPUT);pinMode(27, OUTPUT);pinMode(28, OUTPUT);pinMode(29, OUTPUT); // REG_PIOC_OER = (0x000000FF << 12);

I guess you have a port mapping like this on the Due:

  Display port to Mega and Due pin mapping:

 TFT Mega Due
 D15 PA7 D.6
 D14 PA6 D.3
 D13 PA5 D.2
 D12 PA4 D.1
 D11 PA3 D.0
 D10 PA2 A.15
 D9 PA1 A.14
 D8 PA0 B.26

 D7 PC7 D.9
 D6 PC6 A.7
 D5 PC5 D.10
 D4 PC4 C.1
 D3 PC3 C.2
 D2 PC2 C.3
 D1 PC1 C.4
 D0 PC0 C.5
 
 RS PD7 C.6
 WR PG2 C.7
 CS PG1 C.8
 RST PG0 C.9

In this case you can use code like this which is much easier to read and get right since the bit shift is the same as the bit number. The compiler codes this efficiently so it runs just as fast.

  //                |       |       |       |         Ruler for byte MS bits 31, 23, 15 and 7
  //                     B          AA   DD AD  DDDD  Marker for register bits used
  REG_PIOA_CODR = 0b00000000000000001100000010000000; // Clear bits
  REG_PIOB_CODR = 0b00000100000000000000000000000000; // Clear bits
  //                                        W CCCCC   // WR bit
  REG_PIOC_CODR = 0b00000000000000000000000010111110; // Clear WR bit as well
  REG_PIOD_CODR = 0b00000000000000000000011001001111; // Clear bits

  // Now set the 16 data bits of the word as required
  //                                         Port.bit
  if (word&0x8000) REG_PIOD_SODR = 0x1 << 6;  // D.6
  if (word&0x4000) REG_PIOD_SODR = 0x1 << 3;  // D.3
  if (word&0x2000) REG_PIOD_SODR = 0x1 << 2;  // D.2
  if (word&0x1000) REG_PIOD_SODR = 0x1 << 1;  // D.1
  if (word&0x0800) REG_PIOD_SODR = 0x1 << 0;  // D.0
  if (word&0x0400) REG_PIOA_SODR = 0x1 << 15; // A.15
  if (word&0x0200) REG_PIOA_SODR = 0x1 << 14; // A.14
  if (word&0x0100) REG_PIOB_SODR = 0x1 << 26; // B.26

  if (word&0x0080) REG_PIOD_SODR = 0x1 << 9;  // D.9
  if (word&0x0040) REG_PIOA_SODR = 0x1 << 7;  // A.7
  if (word&0x0020) REG_PIOD_SODR = 0x1 << 10; // D.10
  if (word&0x0010) REG_PIOC_SODR = 0x1 << 1;  // C.1
  if (word&0x0008) REG_PIOC_SODR = 0x1 << 2;  // C.2
  if (word&0x0004) REG_PIOC_SODR = 0x1 << 3;  // C.3
  if (word&0x0002) REG_PIOC_SODR = 0x1 << 4;  // C.4
  if (word&0x0001) REG_PIOC_SODR = 0x1 << 5;  // C.5

Often used graphics commands like PASET, CASET and RAMWR can be hard coded and this makes the graphics libraries run faster too, e.g.:

void TFT_HX8357_Due::caset(void)
{
  //                |       |       |       |         Ruler for byte MS bits 31, 23, 15 and 7
  REG_PIOA_CODR = 0b00000000000000000000000010000000; // Clear bits in A
  REG_PIOD_CODR = 0b00000000000000000000011000000000; // Clear bits in D
  REG_PIOD_SODR = 0b00000000000000000000010000000000; // Set common bits in D
  //                                        WR        // Set WR and RS low
  REG_PIOC_CODR = 0b00000000000000000000000011111110; // Clear RS and bits in C

  REG_PIOC_SODR = 0b00000000000000000000000000010100; // Write the CASET specific bits

  WR_H;
  RS_H;
}

All these approached and more are used in the library here (relevant code is at end of TFT_HX8357_Due.cpp)