Port Expander

Come da titolo, ho diversi pca9555n della NXP. Sono dei port expander a 16bit i2c con 3 bit di indirizzo programmabili. Ovvero se metto A0=A1=A2 =0 l'indirizzo i2c di quell'integrato sarà 0100 000.
Detto questo sto cercando di far funzionare questo integrato, ma sto impazzendo!

Ho trovato questo sito http://www.neufeld.newton.ks.us/electronics/?p=241 con del codice utile. Guardiamolo insieme

#include <Wire.h>


//#define DEBUG_GPIO


//  I2C device address is 0 1 0 0   A2 A1 A0
#define DIP_ADDRESS (0x4 << 3 | 0x0)
#define LED_ADDRESS (0x4 << 3 | 0x7)

Si creano gli indirizzi, shiftando di 3 a sinistra e facendo un or con 07
Nel mio codice ho messo l'indirizzo grezzo
#define GPIO1(0x27) ovvero 0100111

void setup() {
  
#ifdef DEBUG_GPIO
  Serial.begin(9600);
  //Serial.println(DIP_ADDRESS); delay(2000);
#endif
//inizializza in uscita il port dei gpio
  Wire.begin();
  gpio_write(LED_ADDRESS, 0xffff);
  gpio_dir(LED_ADDRESS, 0x0000);
}

Qui non mi tornano 2-3 cose, sto #ifdef a cosa serve? Poi vabbè inizializza nel modo classico la i2c e inizializza il pca9555

void loop() {
  int bits;
  
#ifdef DEBUG_GPIO
  Serial.println(0xff & gpio_read(DIP_ADDRESS));
#endif

  bits = gpio_read(DIP_ADDRESS) & 0x0f;
  //  mirror direction of bits for output display
  gpio_write(LED_ADDRESS,
      (
        ((bits & 1) << 3) | ((bits & 2) << 1) |
        ((bits & 4) >> 1) | ((bits & 8) >> 3)
      ) << 12);

#ifdef DEBUG_GPIO
  delay(200);
#endif
}

Qui legge da DIP e scrive ciò che legge in LED. A dip sono collegati degli interruttori ed è configurato in modalità input, mentre l'altro è configurato in output.

#define REGISTER_INPUT (0)
#define REGISTER_OUTPUT (2)
#define REGISTER_CONFIG (6)

queste sono definizioni che vengono direttamente dal datasheet.

int gpio_read(int address) {
  int data = 0;
  
  //  Send input register address
  Wire.beginTransmission(address);
  Wire.send(REGISTER_INPUT);
  Wire.endTransmission();
  
  //  Connect to device and request two bytes
  Wire.beginTransmission(address);
  Wire.requestFrom(address, 2);
  
  if (Wire.available()) {
    data = Wire.receive();
  }
  if (Wire.available()) {
    data |= Wire.receive() << 8;
  }
  
  Wire.endTransmission();
  
  return data;
}

Funzione per leggere

void gpio_dir(int address, int dir) {
  //  Send config register address
  Wire.beginTransmission(address);
  Wire.send(REGISTER_CONFIG);
  
  //  Connect to device and send two bytes
  Wire.send(0xff & dir);  //  low byte
  Wire.send(dir >> 8);    //  high byte

  Wire.endTransmission();
}

Questo sinceramente non l'ho capito

void gpio_write(int address, int data) {
  //  Send output register address
  Wire.beginTransmission(address);
  Wire.send(REGISTER_OUTPUT);
  
  //  Connect to device and send two bytes
  Wire.send(0xff & data);  //  low byte
  Wire.send(data >> 8);    //  high byte

  Wire.endTransmission();
}

e in questa funzione scrive.

Io vorrei solo far blinkare qualche led. Avete un'idea?
dire REGISTER_OUTPUT(2); vuol dire che il port 0 è impostato come output mentre per impostare il port 1 il valore del registro di controllo è REGISTER_OUTPUT(3);.

void gpio_dir(int address, int dir) {
  //  Send config register address
  Wire.beginTransmission(address);
  Wire.send(REGISTER_CONFIG);
  
  //  Connect to device and send two bytes
  Wire.send(0xff & dir);  //  low byte
  Wire.send(dir >> 8);    //  high byte

  Wire.endTransmission();
}

questo è per la direzione del port (ingresso/uscita)

Ciao,
di solito il #ifdef viene utilizzato come "discriminatore".
A seconda dei vari #define puoi "configurare" il codice.
In pratica è la base della compilazione condizionata. :smiley:
In altre parole, se è "defined" che sei in debug .. spara sulla seriale del testo :smiley:
Non credo sia questo il tuo dubbio .... vero? ;D

uhm ok, non la sapevo questa cosa... io vorrei far blinkare un led con ste funzioni. Mi sembrano scritte giuste, compatibilmente al datasheet. Leggendo quello infatti le cose tornano solo che boh, imposto un port a 0 non succede nulla... si dovrebbe accendere il led rgb a anodo comune. Che ha l'anodo a VCC e i catodi sui 3 pin del port 1. Ho modificato un po' tutto ma nulla :S

ho capito faccio da me... :frowning:

chi fa da se fa per tre...
PCA9555n first try - YouTube ;D

Ciao Calamaro
Vuol dire allora che hai trovato il problema.
Sono curioso, ci dici cos'era.
Ciao Uwe

ho fatto un errore nabbissimo di cui mi vergogno! Non avevo letto che dal diecimila l'i2c esce dal 4,5 ANALOG IN non dal 4,5 OUT! poi ho cambiato 2 o 3 cose nel sw e ci siamo. son riuscito a pilotare 4,66 led rgb con un solo integrato! magari se dopo vo in treno dalla mi nonna mi metto a scrivermi una libreria!

Ciao Calamaro
Non preoccuparti. Tutti noi facciamo questi errori stupidi. Dopo quando hai tanta esperienza un po di meno.
Gli errori piú cretini sono quelli che si trovano piú dificilmente.
Nessuno poteva aiutarti, perché non avevi pensato al circuito e non avevi fatto vedere una foto del tuo progetto. Il Sw era giusto.
Poi solo qualcuno che aveva quel espander avrebbe potuto testare il tuo SW.
Ciao Uwe

Fico!!! Ci posti lo schema??
Sono curioso!!

Piu' che altro non sono sicuro che sia l'integrato migliore per i led rgb, ci vorrebbe un port expander pwm.

Detto questo, se fai una libreria e la documenti sul playground saro' ben felice di provare questo integrato e il tuo codice!

Federico

ciao
L'integrato indicato é il TLC5940: 16 uscite PWM a 12 bit. http://focus.ti.com/lit/ds/symlink/tlc5940.pdf
Cosí si puó regolare l' intensitá di ogni led e con i led RGB selezionare tutta la gamma di colore.
ciao Uwe

si ma io non devo pilotare i led rgb... quella era una prova. :smiley: io dovrò pilotare stepper ;D

@uwe ma io ho tanta esperienza :stuck_out_tongue:

ho richiesto come sample i TLC5940NT sul sito della TI mo vediamo cosa ne esce fuori! magari potrei utilizzarli per altre cose!