[solved] Changing pins to use a ILI9486

Hello all,

I have a TFT 3.5" en 8BIT that working with a 'Arduino micro' (ATMEGA32U4)
via this lib 3.5inch Arduino Display-UNO - LCD wiki

The arduino is linked to the TFT card with 8BIT using pins 2,3,4,5,6,7,8,9.
It's working well.

Now i want to free the I2C bus.
I2C is using pins 2 and 3:

  • pin 2 -> SDA
  • pin 3 -> SCL

I want to use pins 14 and 15 for the TFT instead of 2 and 3.

I've found this macro that's writing 8bits data:

#define BMASK 0x30 
#define CMASK 0x40 
#define DMASK 0x93 
#define EMASK 0x40 

#define write8old(d) {\
        uint8_t dr1 = (d) >> 1, dl1 = (d) << 1;\
 PORTB = (PORTB & ~BMASK) | (((d) & 0x3)<<4);\
 PORTC = (PORTC & ~CMASK) | (dl1 & (0x1<<6));\
 PORTD = (PORTD & ~DMASK) | (dl1 & (0x1<<7)) | (dr1 & (0x1<<1)) | (((d) & (0x1<<3))>>3) | ((d) & (0x1<<4));\
    PORTE = (PORTE & ~EMASK) | (dr1 & (0x1<<6));\
 WR_STROBE;  }

PORTB, PORTC, PORTD, PORTE are used to write directly in the ATMEGA32U4's registers

Via the chipset doc (chapitre 10.4) i've found that each PORT is 8bits and each bit controling a pin.

On this schema with can find the bits number corresponding to a pin.

Then i'va made this table:

that confirm the mask used in the code:

#define BMASK 0x30 //00110000
  #define CMASK 0x40 //01000000
  #define DMASK 0x93 //10010011
  #define EMASK 0x40 //01000000

I've rewrited the method like this to extract variables:

#define write8(d) {\
    uint8_t dr1 = (d) >> 1, dl1 = (d) << 1;\
 uint8_t PB4_5_ = (((d) & 0x3)<<4);\
    uint8_t PC6_ = (dl1 & (0x1<<6));\
 uint8_t PD1_ = (dr1 & (0x1<<1));\
 uint8_t PD0_ = (((d) & (0x1<<3))>>3);\
 uint8_t PD4_ = ((d) & (0x1<<4));\
 uint8_t PD7_ = (dl1 & (0x1<<7));\
 uint8_t PE6_ = (dr1 & (0x1<<6));\
 PORTB = (PORTB & ~BMASK) | PB4_5_;\
 PORTC = (PORTC & ~CMASK) | PC6_;\
 PORTD = (PORTD & ~DMASK) | PD7_ | PD1_ | PD0_ | PD4_;\
    PORTE = (PORTE & ~EMASK) | PE6_;\
 WR_STROBE;  }

and tried to see how the data send to the write method are used on the pins, using a 'd' value of like 'abcdefgh' (8bits)

d = 'abcdefgh'
dl1 = (d) << 1 gives 'bcdefgh0'
dr1 = (d) >> 1 gives 'aabcdefg'

PB4_5 = (((d) & 0x3)<<4)
0x03 << 4 gives 00110000
& abcdefgh
=> 00cd0000

PC6_ = (dl1 & (0x1<<6))
0x01 << 6 gives 01000000
& bcdefgh0
=> 0c000000

PD1_ = (dr1 & (0x1<<1))
0x01 << 1 gives 00000010
& aabcdefg
=> 000000f0

PD0_ = (((d) & (0x1<<3))>>3)
00x01 << 3 gives 00001000
& abcdefgh
gives 0000e000 then >>3
=> 0000000e

PD4_ = ((d) & (0x1<<4))
0x01 << 4 gives 00010000
& abcdefgh
=> 000d0000

PD7_ = (dl1 & (0x1<<7))
0x01 << 7 gives 10000000
& bcdefgh0
=> b0000000

PE6_ = (dr1 & (0x1<<6))
0x01 << 6 gives 01000000
& aabcdefg
=> 0a000000

finally

PORT B = 00cd0000
PORT C = 0c000000
PORT D = b00d00fe
PORT E = 0a000000

I need to move pin2 (PD1) to pin15 (PB1) and pin3 (PD0) to pin14 (PB3)

the mask are now:

#define BMASK2 0x3A //00111010
#define DMASK2 0x90 //10010000

PD0_ to PB3_ is like moving 'e' to bit 3 of PORTB like 0000e000
then

uint8_t PB3_ = ((d) & (0x1<<3));\

and PD1_ to PB1_ is like moving 'f' to bit 1 of PORTB like 000000f0
then

uint8_t PB1_ = (dr1 & (0x1<<1));\

finally write8 is now:

#define write8(d) {\
    uint8_t dr1 = (d) >> 1, dl1 = (d) << 1;\
 uint8_t PB3_ = ((d) & (0x1<<3));\
 uint8_t PB4_5_ = (((d) & 0x3)<<4);\
    uint8_t PC6_ = (dl1 & (0x1<<6));\
 uint8_t PB1_ = (dr1 & (0x1<<1));\
 uint8_t PD4_ = ((d) & (0x1<<4));\
 uint8_t PD7_ = (dl1 & (0x1<<7));\
 uint8_t PE6_ = (dr1 & (0x1<<6));\
 PORTB = (PORTB & ~BMASK2) | PB1_ | PB3_ | PB4_5_;\
 PORTC = (PORTC & ~CMASK) | PC6_;\
 PORTD = (PORTD & ~DMASK2) | PD7_  | PD4_;\
    PORTE = (PORTE & ~EMASK) | PE6_;\
 WR_STROBE;  }

But it's not working!

Can you help me to found where i'm wrong please ?[

Install MCUFRIEND_kbv via the IDE Library Manager.
Buy a proper Leonardo.

Plug the Shield into the Leonardo. Everything should work. (the Leo has less Flash than a Uno so you must be careful with big sketches)

The Pro Micro is only a Leonardo without proper headers.

David.

Yes i could change the hardware but i want to try some code because it seems simpler (and it’s less expensive…)

I’ve found an error in my new mapping, then i’ve corrected this:
MISO = pin 14 = PB3 then i’m moving from (pin 2 SDA) PD1 to PB1
SCLK = pin 15 = PB1 then i’m moving from (pin 3 SCL) PD0 to PB3

This is the code i have now, trying only to change the pin 2 (PD1 to PB1) (easier to locate where i’m wrong i think):

//========================================================================================================================
//========================================================================================================================
// Original
//========================================================================================================================
//========================================================================================================================

#ifdef USE_ORG

  #define BMASK 0x30 //00110000
  #define CMASK 0x40 //01000000
  #define DMASK 0x93 //10010011
  #define EMASK 0x40 //01000000

  #define write8(d) {\
    uint8_t dr1 = (d) >> 1, dl1 = (d) << 1;\
 uint8_t PB4_5_ = (((d) & 0x3)<<4);\
    uint8_t PC6_ = (dl1 & (0x1<<6));\
 uint8_t PD1_ = (dr1 & (0x1<<1));\
 uint8_t PD0_ = (((d) & (0x1<<3))>>3);\
 uint8_t PD4_ = ((d) & (0x1<<4));\
 uint8_t PD7_ = (dl1 & (0x1<<7));\
 uint8_t PE6_ = (dr1 & (0x1<<6));\
 PORTB = (PORTB & ~BMASK) | PB4_5_;\
 PORTC = (PORTC & ~CMASK) | PC6_;\
 PORTD = (PORTD & ~DMASK) | PD7_ | PD1_ | PD0_ | PD4_;\
    PORTE = (PORTE & ~EMASK) | PE6_;\
 WR_STROBE;  }

#endif

//========================================================================================================================
//========================================================================================================================
//Déplacement du pin2 (PD1) vers pin15 (PB1) et pin3 (PD0) vers pin14 (PB3)
//========================================================================================================================
//========================================================================================================================
 
#ifdef USE_NEW 
 
  #define BMASK 0x32 //00110010
  #define CMASK 0x40 //01000000
  #define DMASK 0x91 //10010001
  #define EMASK 0x40 //01000000
 
  #define write8(d) {\
     uint8_t dr1 = (d) >> 1, dl1 = (d) << 1;\
 uint8_t PB4_5_ = (((d) & 0x3)<<4);\
    uint8_t PC6_ = (dl1 & (0x1<<6));\
 uint8_t PB1_ = (dr1 & (0x1<<1));\
 uint8_t PD0_ = (((d) & (0x1<<3))>>3);\
 uint8_t PD4_ = ((d) & (0x1<<4));\
 uint8_t PD7_ = (dl1 & (0x1<<7));\
 uint8_t PE6_ = (dr1 & (0x1<<6));\
 PORTB = (PORTB & ~BMASK) | PB4_5_ | PB1_ ;\
 PORTC = (PORTC & ~CMASK) | PC6_;\
 PORTD = (PORTD & ~DMASK) | PD7_ | PD0_ | PD4_;\
    PORTE = (PORTE & ~EMASK) | PE6_;\
 WR_STROBE;  }

#endif

But it’s always not working

Write an accurate table for how you want to wire the Shield e.g.

//regular UNO shield on TEENSY++ 2.0 thanks tysonlt

//LCD pins  |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 | |RD |WR |RS |CS |RST|
//AVR   pin |PD7|PD6|PD5|PD4|PD3|PD2|PE1|PE0| |PF0|PF1|PF2|PF3|PF4|

or

//UNO shield on BOBUINO
//LCD pins  |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 | |RD |WR |RS |CS |RST|
//AVR   pin |PB3|PB2|PB1|PB0|PD3|PD2|PD6|PD5| |PA7|PA6|PA5|PA4|PA3|

or

//regular UNO shield on GRAND CENTRAL M4
//LCD pins   |D7  |D6  |D5  |D4  |D3  |D2  |D1 |D0  | |RD |WR |RS |CS |RST|
//SAMD51 pin |PD21|PD20|PC21|PC20|PC19|PC18|PB2|PB18| |PA2|PA5|PB3|PC0|PC1|

Note that your Pro Micro will not be able to use the SPI bus for a SD card, ...
You have to make compromises when there are not many pins available.

David.

Ok, i've this one for the original working system:

I've made this table from documentation.
Then i've compared to the code and it's in sync.

Then i've made the new one:

david_prentice:
Note that your Pro Micro will not be able to use the SPI bus for a SD card, ...
You have to make compromises when there are not many pins available.

David.

Yes, in the original configuration, the SPI pins are availlable.
I've choose to free the I2C and scrify the SPI because i need I2C extensions and not planned to use the SD card.
But it' seems difficult to find a TFT board like this one without SD card!

Please write in the style that I have illustrated. i.e. so I can copy-paste
And most importantly so that my eyes don't hurt..

oh, ok sorry :frowning:

Original

LCD|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0
AVR|PE6|PD7|PC6|PD4|PD0|PD1|PB5|PB4

New

LCD|D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0
AVR|PE6|PD7|PC6|PD4|PB3|PB1|PB5|PB4
avr |PE6                |PD7                 |PC6                 |PD4                 |PB3
    |E 01000000         |D 10000000          |C 01000000          |D 00010000          |B 00001000
    |E 0a000000         |D b0000000          |C 0c000000          |D 000d0000          |B 0000e000
    |(dr1 &  (0x1 << 6))|(dl1 & (0x1 <<7))   |(dl1 & (0x1<<6))    |(d & (0x1<<4))      |(d & (0x1<<3))


avr |PB1                 |PB5                 |PB4
    |B 00000010          |B 00100000          |B 00010000
    |B 000000f0          |B 00g00000          |B 000h0000
    |(dr1 & (0x1<<1))    |((d>>4)&(0x1<<5))   |((d>>4)&(0x1<<4))

with dr1 = (d) >> 1

with dl1 = (d) << 1

I’ve tried that with masks

#define BMASK 0x3A //00111010
#define CMASK 0x40 //01000000
#define DMASK 0x90 //10010000
#define EMASK 0x40 //01000000

But it’s still not working…

I have edited the MCUFRIEND_shield.h Leonardo conditional block to suit your wiring:

//################################### TOKAZIO on 32U4 ##############################
#elif defined(__AVR_ATmega32U4__) && defined(USE_TOKAZIO)       //
//LCD pins  |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 | |RD |WR |RS |CS |RST|
//AVR   pin |PE6|PD7|PC6|PD4|PB3|PB1|PB5|PB4| |PF7|PF6|PF5|PF4|PF1| tokazio
//AVR   pin |PE6|PD7|PC6|PD4|PD0|PD1|PB5|PB4| |PF7|PF6|PF5|PF4|PF1| Leonardo
#define RD_PORT PORTF
#define RD_PIN  7
#define WR_PORT PORTF
#define WR_PIN  6
#define CD_PORT PORTF
#define CD_PIN  5
#define CS_PORT PORTF
#define CS_PIN  4
#define RESET_PORT PORTF
#define RESET_PIN  1

#define BMASK         ((1<<3)|(1<<1)|(1<<5)|(1<<4))
#define CMASK         (1<<6)
#define DMASK         ((1<<7)|(1<<4))
#define EMASK         (1<<6)
static inline                   //hope we use r24
void write_8(uint8_t x)
{
    PORTB &= ~BMASK;
    PORTC &= ~CMASK;
    PORTD &= ~DMASK;
    PORTE &= ~EMASK;
    PORTB |= (((x) & (3 << 0)) << 4);
    PORTB |= (((x) & (1 << 2)) >> 1);
    PORTB |= (((x) & (1 << 3)) >> 0);
    PORTD |= (((x) & (1 << 4)) << 0);
    PORTC |= (((x) & (1 << 5)) << 1);
    PORTD |= (((x) & (1 << 6)) << 1);
    PORTE |= (((x) & (1 << 7)) >> 1);
}

#define read_8()      ( ((PINB & (3<<4)) >> 4)\
| ((PINB & (1<<1)) << 1)\
| ((PINB & (1<<3)) << 0)\
| ((PIND & (1<<4)) >> 0)\
| ((PINC & (1<<6)) >> 1)\
| ((PIND & (1<<7)) >> 1)\
| ((PINE & (1<<6)) << 1)\
)
#define setWriteDir() { DDRB |=  BMASK; DDRC |=  CMASK; DDRD |=  DMASK; DDRE |=  EMASK;  }
#define setReadDir()  { DDRB &= ~BMASK; DDRC &= ~CMASK; DDRD &= ~DMASK; DDRE &= ~EMASK;  }
#define write8(x)     { write_8(x); WR_STROBE; }
#define write16(x)    { uint8_t h = (x)>>8, l = x; write8(h); write8(l); }
#define READ_8(dst)   { RD_STROBE; dst = read_8(); RD_IDLE; }
#define READ_16(dst)  { uint8_t hi; READ_8(hi); READ_8(dst); dst |= (hi << 8); }

#define PIN_LOW(p, b)        (p) &= ~(1<<(b))
#define PIN_HIGH(p, b)       (p) |= (1<<(b))
#define PIN_OUTPUT(p, b)     *(&p-1) |= (1<<(b))

Obviously untested. I have not even looked at how or when LCDWIKI hacked my library code.

You can see which 6 lines were changed

#define BMASK         ((1<<3)|(1<<1)|(1<<5)|(1<<4))
...
#define DMASK         ((1<<7)|(1<<4))
...
    PORTB |= (((x) & (1 << 2)) >> 1);
    PORTB |= (((x) & (1 << 3)) >> 0);
...
| ((PINB & (1<<1)) << 1)\
| ((PINB & (1<<3)) << 0)\
...

Obviously untested. Please let me know how you get on.

It is a bit fiddly to write the macros from scratch.
The Leonardo has really awkward pins.

However if you are hand-wiring the Pro Micro you could arrange the pins much more efficiently.

David.

After tried each PORT on a LED, i’ve found thant the pin15 (PB1) was not soldered correctly!!!

Thank you for your precious help and for all these explanation.
Now, I know how to directly write to registers, do bit shifting (and what for) and pin/port mapping.

Thanks a lot.

Final code:

#define BMASK         ((1<<3)|(1<<1)|(1<<5)|(1<<4))
 #define CMASK         (1<<6)
 #define DMASK         ((1<<7)|(1<<4))
 #define EMASK         (1<<6)
 static inline void write_8(uint8_t x){
 PORTB &= ~BMASK;
 PORTC &= ~CMASK;
 PORTD &= ~DMASK;
 PORTE &= ~EMASK;
 PORTB |= (((x) & (3 << 0)) << 4);
 PORTB |= (((x) & (1 << 2)) >> 1);
 PORTB |= (((x) & (1 << 3)) >> 0);
 PORTD |= (((x) & (1 << 4)) << 0);
 PORTC |= (((x) & (1 << 5)) << 1);
 PORTD |= (((x) & (1 << 6)) << 1);
 PORTE |= (((x) & (1 << 7)) >> 1);
 }
 #define write8(x)     { write_8(x); WR_STROBE; }