[Résolu] PORT/PIN mapping ATMEGA32U4 for 3.5" TFT

Bonjour tout le monde,

J'ai acquis un écran TFT 3.5" en 8BIT que j'arrive à interfacer avec mon 'Arduino micro' (ATMEGA32U4)
via la bibiliothèque (et autres infos) ici: 3.5inch Arduino Display-UNO - LCD wiki

L'arduino et relié à la carte du TFT en 8BIT et utilise les pins 2,3,4,5,6,7,8,9.
Cela fonctionne parfaitement ainsi.

J'aimerais maintenant libérer le canal I2C pour ajouter des contrôles.
Hors ce sont les pins 2 et 3 qui servent au canal I2C:

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

J'ai a ma disposition les pins 14 et 15.

En fouillant dans le code, j'ai trouvé la macro qui sert à l'envoi des données sur le bus 8bits:

#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 servent à écrire directement dans les registres de l'ATMEGA32U4

Via la doc (chapitre 10.4) j'ai trouvé que que chaque PORT fait 8bits et chaque bit contrôle un pin.

Sur ce schéma on retrouve les numéros des bits et les pins liés.

J'ai donc construit le tableau suivant:

qui confirme l'utilisation des masques, la traduction des masques en bits correspond au tableau:

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

J'ai ensuite décomposé un peu le code pour le lire plus facilement:

#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;  }

Et pris les variables une par une en me basant sur le paramètre 'd' qui vaudrait 'abcdefgh' (8bits)

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

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

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

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

PD0_ = (((d) & (0x1<<3))>>3)
00x01 << 3 nous donnes 00001000
& abcdefgh
donnes 0000e000 que l'on >>3
=> 0000000e

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

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

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

Soit au final

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

Avec tout ça je doit donc déplacer le pin2 (PD1) vers le pin15 (PB1) et le pin3 (PD0) vers le pin14 (PB3)

Je commence par mettre à jour les masques:

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

Puis je sais que PD0_ devient PB3_ donc que 'e' doit venir en bit 3 de PORTB soit 0000e000
Je fais donc

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

à la place de PD0_

et que PD1_ devient PB1_ donc que 'f' doit venir en bit 1 de PORTB soit 000000f0
Je fais donc

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

Avec un final un write8:

#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;  }

Mais cela ne fonctionne pas!
Je pense que je ne suis pas loin mais que j'ai fait une erreur dans tout ces bit shifting et que je ne la trouve plus après toutes ces heures les yeux rivé dessus...

Pouvez vous me confirmer la démarche ? confirmer/corriger les calculs svp ?

DANS LE FORUM EN ANGLAIS (vive le bit shifting!)

bonjour,

je pense qu'il y a une confusion dans ta lecture des brochages :

tu veux récupérer les pins de l'I2C

3 = SCL = PD0
2 = SDA = PD1

et les remplacer par les pin "arduino" 14 et 15, qui correspondent aux fonctions SCLK et MISO du SPI

14 = SCLK = PB1
15 = MISO = PB2

et non PB0 et PB1.

revois tes masquages et décalages, et bon courage.

perso, j'ai fait tout le contraire par fainéantise : un ATMega2560 et tout (les 8 bits de la donnée) sur le même port, plus facile et plus rapide.

En effet j'ai vu ça après avoir posté:

MISO = pin 14 = PB3 donc je passe de (pin 2 SDA) PD1 à PB1
SCLK = pin 15 = PB1 donc je passe de (pin 3 SCL) PD0 à PB3

du coup je crois que ta remarque est bonne (je me suis gourré) mais ton mapping n'est pas bon non plus :stuck_out_tongue_closed_eyes:

J'ai vu aussi que dans une autre méthode, celle qui définir le mode output des pins, on utilise les masques, j'ai donc corrigé pour utiliser le même masque partout.

Bref en corrigeant tout ça, cela ne marche toujours pas mieux...

Tu utilise la même carte TFT ?

Le 2560 à aussi deux USB (cela fait partie d'un projet USB HID)

Voilà ce que j'ai pour le moment:

Pour limiter la casse je ne change pour l'instant que PD1_ vers PB1_

//========================================================================================================================
//========================================================================================================================
// 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

re-

exact, j'ai inversé MISO et MOSI ... mais le mappage reste chiant à faire, ça ne simplifie toujours pas le découpage de la donnée ...

le 2560 ne possède pas d'USB natif, il passe par un circuit type FTDI, et communique par RX0/TX0.

j'ai bien le même afficheur (même carte, même driver) câblé en filaire, donnée/8bits sur le port A (broches 22 à 29) ce qui me permet de m'affranchir du découpage/remappage.

sur ton 32U4 tu pourrais peut-être utiliser (presque) tout le port B (bits 1~7) sur les broches "arduino" 15,16,14,28,29,30,11 (si je ne me suis pas encore gouré), et mettre le bit 0 sur un autre port, ou (si c'est possible) tirer un fil de la sortie pour la DEL RX (PB0) et utiliser cette sortie "en hard" en configurant le port B à la main ... mais tu perds la fonction de visu en émission.

bon courage pour les manips.

J'ai besoin d'USB, c'est un projet de HID.

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))

avecdr1 = (d) >> 1

avecdl1 = (d) << 1

I've tried that with masks

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

Ne marche toujours pas!

Je pense que le mapping est bon, niveau logiciel mais ça ne fonctionne toujours pas...
Alors soit il y a autre chose dans le code que je n'ai pas vu.
soit c'est mon hardware qui est mal branché...

Il me reste une option, je voulais libérer le I2C pour utiliser un MCP23017 et ajouter des GPIOs.
Je pourrais mettre un MCP23S17 pour faire la même chose en SPI...

Mais je voulais essayer ça avant de racheter du matériel...

re-

(je ne connais pas le 32U4, mais il doit être semblable aux 328 et 2560 ...)

apparemment, tu as compris comment se fait l'écriture de la donnée sur le port du LCD : découpage des 8 bits et présentation de chacun d'entre eux sur le bon bit du bon port.

si tu peux "remapper" tes E/S il se peut que tu puisse réorganiser ta donnée 8 bits de façon à ne pas "trop" la manipuler ?
et récrire la partie écriture de donnée plus facilement.

donc :

quelles sont les E/S que tu peux "réorganiser" ?
(je veux dire : hormis celles dédiées à une fonction "hard" comme RX/TX par exemple ?)
ce dans le but de n'avoir à manipuler que le minimum de bits, voire aucun si possible ?

Alors, j'ai ecris une routine pour mettre à 1 chaque PORT chacun leurs tours...
J'ai branché une LED sur chaque port. Elle doit s'allumer quand le bit du PORT est à 1.

Et bim, avec PB1 à 1 -> pas de LED...

J4ai également vérifié avec un digitalWrite du port 15... ne marche pas non plus!

J'ai finalement une soudure qui est pourrie!

Et en effet ça marche mieux quand le signal passe...

Désolé pour le dérangement.

En tout cas j'aurai appris beaucoup de chose avec cette 'bidouille'. Merci!

Code final:

        #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; }