Arduino pro micro + adafruit 16x8 led matrix driver ht16k33

Tengo hecho un tablero de ajedrez con con arduino pro micro, que lo que hace es enviar el movimiento como texto al ordenador (p.ej.: e2e4). Funciona correctamente: El ordenador recibe la string, realiza el movimiento, entonces el motor de ajedrez calcula su respuesta (p.ej.: e7e5). Lo envio por serie y la placa arduino la recibe,

El diseño está copiado de :

Ahora lo que quiero es poner un array de leds 9x9 (un led por cada esquina del cada escaque), que gestionará la placa adafruit ht16k33 de acuerdo con este diagrama

Ahora viene la pregunta:
¿Como conecto las dos placas?

Solo tendría que enviar por el pin Arduino-TX (creo que es ese) el movimiento (en nuestro caso e7e5), y entonces la placa Adafruit recibe la string (pienso que es la SDA), iluminaría entonces los leds, indicando que debemos mover fisicamente la pieza contraria sobre el tablero (desde-hasta). Una vez terminado el movimientos se apagaránn los leds. Ese es el algoritmo básico. La Adafruit no tendría que retornar nada, porque el movimiento lo controlo con la placa arduino.
Quizas la energia tambien debe pasarse VCC (Arduino) a VDD(Adafruit)

Quedan libres en la placa Adafruit los pines : A11-A15, SDA y SCL, VDD y GND

Bueno tendras que replantear algunas cosas pero no demasiadas.
Los pines I2C deben liberarse para controlar el HT16K33

Esta es una librería enfocada al manejo de displays (lo cual es lógico) pero que puedes usar para tu proyecto.

Lo primero, gracias por tu contestación, y comentar que soy esencialmente solo un programador (prácticamente un primerizo en cuestiones electrónicas):
No acabo de entender lo de dejar los I2C libres... En el diagrama de arriba, en la ADAFRUIT,los pines SDA y SCL están libres.

Según
https://docs.circuitpython.org/projects/ht16k33/en/latest/examples.html
los pines SDA y SCL son los I2C.

En el diagrama de arriba las filas/columnas (ánodos/Cátodos) están asignadas a los pines C0 al C7 y los A0 al A9 (El A10 aperece ocupado, pero sobra.)

Pero la pregunta persiste:
¿Cómo conecto FISICAMENTE las dos placas entre si para transferir datos de ARDUINO a ADAFRUIT?

EDITO:
No quiero que interactúen las dos placas. Simplemente enviar desde ARDUINO la jugada ("e2e4") al ADAFRUIT y luego aqui decodificar mediante un HashMap, o similar, y obtener los leds que el ADAFRUIT debe encender/apagar. No se si la terminología que uso es la adecuada pero sería como pasar por "serial" un texto y luego transformarlo dentro de la ADAFRUIT.

Así es como tengo la placa ARDUINO :

Chess ……….. Arduino
——————————-
Column A –> Pin 9
Column B –> Pin 8
Column C –> Pin 7
Column D –> Pin 6
Column E –> Pin 5
Column F –> Pin 4
Column G –> Pin 3
Column H –> Pin 2

Row 1 –> Pin 10
Row 2 –> Pin 16
Row 3 –> pin 14
Row 4 –> Pin 15
Row 5 –> Pin A0
Row 6 –> Pin A1
Row 7 –> Pin A2
Row 8 –> Pin A3

y este es el programa:

#include <Keyboard.h>

// outcomment one of the above
// a) debug via serial (for developing / testing)
// #define BOARD_DEBUG

// b) create a virtual USB keyboard (for final use)
#define USB_KEYBOARD

// the arduino micro pin connections
// layout depends on the wiring
// for the files, ranks and the ky-012 buzzer
int FILE_A = 9;
int FILE_B = 8;
int FILE_C = 7;
int FILE_D = 6;
int FILE_E = 5;
int FILE_F = 4;
int FILE_G = 3;
int FILE_H = 2;

int RANK_8 = 21;
int RANK_7 = 20;
int RANK_6 = 19;
int RANK_5 = 18;
int RANK_4 = 15;
int RANK_3 = 14;
int RANK_2 = 16;
int RANK_1 = 10;


// array of ranks and files
int FILES[8] = {FILE_A, FILE_B, FILE_C, FILE_D, FILE_E, FILE_F, FILE_G, FILE_H};
int RANKS[8] = {RANK_1, RANK_2, RANK_3, RANK_4, RANK_5, RANK_6, RANK_7, RANK_8};


// holds the current state of the buttons and records
// if a button was pressed
bool STATUS[8][8] = {
  {false, false, false, false, false, false, false, false},
  {false, false, false, false, false, false, false, false},
  {false, false, false, false, false, false, false, false},
  {false, false, false, false, false, false, false, false},
  {false, false, false, false, false, false, false, false},
  {false, false, false, false, false, false, false, false},
  {false, false, false, false, false, false, false, false},
  {false, false, false, false, false, false, false, false}
};

int DEBOUNCE_TIMER[8][8] = {
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0},
  {0, 0, 0, 0, 0, 0, 0, 0}
};


void setup()
{
  // put your setup code here, to run once:

  /*
    Approach that was used in Berger's Solus chess (but here for tactile switches)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    - Connect the rows to 8 pins of the microcontroller, setting them as OUTPUT, and initializing them all to '1' (High).
    - Connect the columns to 8 pins of the microcontroller, setting them all as INPUT with pull-up resistor enabled.
    - Set to '0' (Low) one row and read the value of all columns. Do the same with the other seven rows, one by one.
    - In every full sampling of the board (of the 8 rows), we obtain a matrix of 8 x 8 bits.
    - Detecting changes that occur in the matrix at every sampling, we can know what piece was moved.
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
  pinMode(RANK_1, OUTPUT);
  pinMode(RANK_2, OUTPUT);
  pinMode(RANK_3, OUTPUT);
  pinMode(RANK_4, OUTPUT);
  pinMode(RANK_5, OUTPUT);
  pinMode(RANK_6, OUTPUT);
  pinMode(RANK_7, OUTPUT);
  pinMode(RANK_8, OUTPUT);

  pinMode(FILE_A, INPUT_PULLUP);
  pinMode(FILE_B, INPUT_PULLUP);
  pinMode(FILE_C, INPUT_PULLUP);
  pinMode(FILE_D, INPUT_PULLUP);
  pinMode(FILE_E, INPUT_PULLUP);
  pinMode(FILE_F, INPUT_PULLUP);
  pinMode(FILE_G, INPUT_PULLUP);
  pinMode(FILE_H, INPUT_PULLUP);
#ifdef BOARD_DEBUG
  Serial.begin(115200);
  Serial.println("Arduino Chess Board");
#endif
#ifdef USB_KEYBOARD
  Keyboard.begin();
#endif
}

int reset_timer = 0;

void loop()
{
  for (int i = 0; i < 8; i++)
  {
    int rank_i = RANKS[i];
    digitalWrite(rank_i, LOW);
    for (int j = 0; j < 8; j++)
    {
      int file_j = FILES[j];
      int val = digitalRead(file_j);
      if (val == HIGH)
      {
        // val == HIGH: field is not pressed
        if (STATUS[i][j]) {
          // active, check if we are below threshold
          if (DEBOUNCE_TIMER[i][j] - 1 < 2) {
            STATUS[i][j] = false;
          }
        }
        if (DEBOUNCE_TIMER[i][j] > 0) {
          DEBOUNCE_TIMER[i][j] = DEBOUNCE_TIMER[i][j] - 1;
        }
      }
      if (val == LOW)
      {
        // val == LOW: field is pressed
        // val == HIGH: field is not pressed
        if (!STATUS[i][j]) {
          // not active, check if we are above threshold
          if (DEBOUNCE_TIMER[i][j] + 1 > 6) {
            STATUS[i][j] = true;
            char s[] = "a1\n";
            s[0] = 97 + j;
            s[1] = 49 + i;
#ifdef USB_KEYBOARD
            for (int m = 0; m < 2; m++)
            {
              Keyboard.write(s[m]);
            }
#endif
#ifdef BOARD_DEBUG
            Serial.println("button press");
            Serial.println(s);
#endif
          }
        }
        if (DEBOUNCE_TIMER[i][j] + 1 < 9) {
          DEBOUNCE_TIMER[i][j] = DEBOUNCE_TIMER[i][j] + 1;
        }
      }
    }
    digitalWrite(rank_i, HIGH);
  }

}

Listo, si lo estan nada de qué preocuparse, por eso dos pines ademas de GND y VCC se comunica el integrado.
Yo veo que

columnas[] = {A1, B1, C1, D1, E1, F1, G1, H1}
filas[] = {A2, A3, A4, A5, A6, A7, A8, A9, I8}

No me queda claro H9, I8 e I9
el led que esta entre A1 columna e I9 fila esta digamos claro
La fila que supuestamente es I8 puede que tmb

Conectas GND, VCC (5V), SDA y SCL nada mas.

Lo de la conexión entre Chess y Arduino no la entiendo.

El tablero tiene 8 filas y 8 columna 1-8 y A-H, pero estamos haciendo una matriz 9x9. Alguna nombre le tengo que dar. Hay que tener en cuenta que quiero poner un led en cada esquina de cada casilla/escaque. Imaginemos un tablero 2x2:
o----o---o
|A2|B2|
o----o---o
|A1|B1|
o----o---o
Si nos fijamos en lugar de una matriz 2x2 (un led por cada casilla), tenemos una matriz 3x3 (cuatro leds rodeando cada casilla). Por lo tanto tenemos que añadir una fila y columna más. Las columnas de leds serían a, b, (c añadida); y las filas serían 1, 2, (3 añadida)

Es una manera de explicarme a mi mismo la nomenclatura ajedrecistica y la terminología de Arduino. Es que si no me organizo un poco ... al final es todo un "totum revolutum"; esto es: la columna A del tablero la asigno al Pin 9 de la ARDUINO, etc...

La SDA y SCL en la placa ARDUINO están ocupados. Fíjate en mi post anterior a qué pines he asignado las filas y columnas del tablero
¿Los GND y VCC (creo que ambas tarjetas van a 5V) del ARDUINO las conecto a las GND y VCC del ADAFRUIT?

El HT16k33 es un dispositivo I2C.
So comunica x 2 cables ademas de VCC y GND.
Por ahi debes enviarle que quieres encender.
Usando la librería que te pasé y encontrando como hacer que se encienda lo que quieres.
Esta mas pensado para displays.

Perdona que sea tan torpe. Entiendo que el cableado va asi:

ARDUINO - ADAFRUIT
-------------------------------
GND <-------> GND
VCC <--------> VDD
SDA <--------> SDA
SCL <---------> SCL

Si no hay nada en contrario, entiendo que es así. Gracias por tu ayuda.

Si, asi va.

Si, funciona con diodos led simples. El esquema del primer post es válido : las filas (catodos) con sus resistencias a los pines C0, C1, .... y las columnas a los pines A1, A2, ...
Pongo un código de ejemplo en circuitpython.
Al final el hardware que he elegido es la Pi Pico con un level shifter (Adafruit [BSS138]), en lugar de la Arduino Pro (Python me resulta más asequible).

"""
# Averiguar la direección del dispositivo HTK1633

# Import all board pins and bus interface.
import board
import busio
import time

# Import the HT16K33 LED matrix module.
from adafruit_ht16k33 import matrix

# To use default I2C bus (most boards)
#i2c = board.I2C()  # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller

# To create I2C bus on specific pins
# import busio
# i2c = busio.I2C(board.SCL1, board.SDA1)  # QT Py RP2040 STEMMA connector
i2c = busio.I2C(board.GP1, board.GP0)    # Pi Pico RP2040

while not i2c.try_lock():
    pass

try:
    while True:
        print(
            "I2C addresses found:",
            [hex(device_address) for device_address in i2c.scan()],
        )
        time.sleep(2)

finally:  # unlock the i2c bus when ctrl-c'ing out of the loop
    i2c.unlock()
"""

import time
# Import all board pins and bus interface.
import board
import busio

# Import the HT16K33 LED matrix module.
from adafruit_ht16k33 import matrix

# Create the I2C interface.
#i2c = busio.I2C(board.SCL, board.SDA)
i2c = busio.I2C(board.GP1, board.GP0)    # Pi Pico RP2040


"""
EJEMPLO 1 - Matriz 3x3
# Create the matrix class.
# This creates a 16x8 matrix:

#matrix = matrix.Matrix16x8(i2c)

# Or this creates a 16x8 matrix backpack:
# matrix = matrix.MatrixBackpack16x8(i2c)
# Or this creates a 8x8 matrix:
# matrix = matrix.Matrix8x8(i2c)
# Or this creates a 8x8 bicolor matrix:
# matrix = matrix.Matrix8x8x2(i2c)
# Finally you can optionally specify a custom I2C address of the HT16k33 like:
# matrix = matrix.Matrix16x8(i2c, address=0x70)

# creates a 8x8 matrix:
matrix = matrix.Matrix8x8(i2c, address=0x70)

# edges of an 3x3 matrix
col_max = 3
row_max = 3

# Clear the matrix.
matrix.fill(0)
col = 0
row = 0

q = True

while q:
        # Run through each pixel individually and turn it on.
        for xled in range(1,10):   # anodes numbers starts 1

            x =int((xled-1)/3)+1   # anodes numbers starts 1
            y =  (2+xled)%3   # cathodes number start 0

            matrix[x, y] = 1    #2
            col += 1
            time.sleep(1)

            # Print Square Location
            print ("Square " ,xled, x, y)

            # Delay for half a second.
            time.sleep(1)

            if xled == row_max:

                q = False


# Clear the display buffer.

matrix.fill(0)
"""

matrix = matrix.Matrix16x8(i2c)

# Clear the matrix.
matrix.fill(0)

# Set a pixel in the origin 0,0 position.
matrix[0, 0] = 1
# Set a pixel in the middle 8, 4 position.
matrix[4, 4] = 1
# Set a pixel in the opposite 15, 7 position.
#matrix[15, 7] = 1
matrix.show()

# Change the brightness
matrix.brightness = 0.8

# Set the blink rate
matrix.blink_rate = 2

time.sleep(5)
# Clear the matrix.
matrix.fill(0)

# e4
matrix[0, 0] = 1
matrix[0, 1] = 1
matrix[1, 0] = 1
matrix[1, 1] = 1
matrix.brightness = 1.0
matrix.blink_rate = 3   #parpadeo lento
time.sleep(5)
matrix.fill(0)

# Definición de casillas y leds correspondientes
# Suponemos un tablero 4x4 e4-h1 y por tanto
# una matriz de leds 5x5 (la coord. (0,0) es la esquina superior izqda. )
# O--O--O--O--O
# |E4|F4|G4|H4|
# O--O--O--O--O
# |E3|F3|G3|H3|
# O--O--O--O--O
# |E2|F2|G2|H2|
# O--O--O--O--O
# |E1|F1|G1|H1|
# O--O--O--O--O
casillas = {
    "e1" : [(3,0), (3,1), (4,0), (4,1)],    # las cuatro esquinas de cada casilla
    "e2" : [(2,0), (2,1), (3,0), (3,1)],
    "e3" : [(1,0), (1,1), (2,0), (2,1)],
    "e4" : [(0,0), (0,1), (1,0), (1,1)],
    "f1" : [(3,1), (3,2), (4,1), (4,2)],
    "f2" : [(2,1), (2,2), (3,1), (3,2)],
    "f3" : [(1,1), (1,2), (2,1), (2,2)],
    "f4" : [(0,1), (0,2), (1,1), (1,2)],
    "g1" : [(3,2), (3,3), (4,2), (4,3)],
    "g2" : [(2,2), (2,3), (3,2), (3,3)],
    "g3" : [(1,2), (1,3), (2,2), (2,3)],
    "g4" : [(0,2), (0,3), (1,2), (1,3)],
    "h1" : [(3,3), (3,4), (4,3), (4,4)],
    "h2" : [(2,3), (2,4), (3,3), (3,4)],
    "h3" : [(1,3), (1,4), (2,3), (2,4)],
    "h4" : [(0,3), (0,4), (1,3), (1,4)]
}

errores = {
    "ErrMov0" : [(4,0), (3,1), (2,2), (1,3), (0,4)]
}

def ilumina_movimiento(uci_mov):
    global matrix
    desde = uci_mov[0:2]
    hasta = uci_mov[2:4]
    matrix.blink_rate = 0   #sin parpadeo
    for led in casillas[desde]:
        matrix[led[0], led[1]] = 1
    for led in casillas[hasta]:
        matrix[led[0], led[1]] = 1
        print(led[0], led[1], led)
    if uci_mov == "e1g1":    #emulamos un enroque
        # dormimos 1 seg. y luego ponemos a parpadear
        # las casillas f1 y h1 que es el movimiento de la
        # torre en el enroque
        time.sleep(1)   # hace falta tiempo para que el Ht16K33 "respire"
        matrix.fill(0)  #limpiamos la matriz
        matrix.blink_rate = 2
        time.sleep(1)
        for led in casillas["f1"]:
            matrix[led[0], led[1]] = 1
        for led in casillas["h1"]:
            matrix[led[0], led[1]] = 1
        

def ilumina_error(err):
    global matrix
    matrix.blink_rate = 1   #parpadeo rápido
    #matrix.brightness = 1.0 # maximo brillo
    for led in errores["ErrMov0"]:
        # iluminamos la diagonal e1h4
        # para marcar el error
        matrix[led[0], led[1]] = 1


for _ in range(0,1):
    mov = "e1g1"
    matrix.blink_rate
    ilumina_movimiento(mov)
    time.sleep(5)

matrix.blink_rate = 0
matrix.fill(0)

ilumina_error("cualquiera")
time.sleep(5)
matrix.fill(0)

Moderador:
Este es un foro de arduino no de Pi y MicroPython.
A veces se permite el Python, PHP, Android y otros lenguajes cuando interactúan con Arduino pero este no es el caso.
Cierro el tema porque se desvirtuó.