13. Networking and Communications

On this week I learned to communicate different microcontrollers using some protocols. In my case I used the I2C communication, the same one used for controlling the OLED display. To fully understand this week, you should check the week4 and the week8. To visit the group website, click here.

I2C

The I2C (Inter-Integrated Circuit) protocol is a synchronous, multi-master, multi-slave, packet-switched communication interface designed to allow multiple microcontrollers to communicate with each other or with various devices over a common bus. I2C uses two bidirectional lines, Serial Data Line (SDA) and Serial Clock Line (SCL), pulled up with resistors. Each device connected to the bus is software-addressable by a unique address and simple master/slave relationships can be established.

The connection process includes the master microcontroller initializing communication by sending a start condition, followed by the address of the slave device. The address is succeeded by a read/write bit that signals the desired operation. When a slave device is on the bus, it responds by pulling the data line low, indicating that the request has been received. It proceeds to send or receive data according to the operation that has been indicated. Subsequently, the communication ends after the master generates a stop condition. In this addressing method, many slave devices can be independently controlled by one bus. In this way, resources are saved and the wiring aspect is eased in complex systems.

The I2C protocol supports different data transfer rates, from the standard speed of 100 kbps to a high-speed mode of 3.4 Mbps. It also includes features such as clock stretching, where a slower slave can keep the line low of the clock to delay the master until he is ready to board, and officiate. If two masters start transmission at the same time, the one sending the highest priority address (lowest numerical value) wins the bus.

PCB

For this week, I designed a new PCB in order to connect the Quentorres, my PCB from the week8 and this new PCB. For this PCB, I used an Attiny45, a push-button and a lot of pins. The pins used for the PCB were the programming ones (MISO, MOSI, SCK, Reset, Vcc, and Ground) and two pairs of the I2C pins. Here's the pinout of the Attiny45:

This is an image of the schematic of my PCB:

This is an image of the Kicad design of my PCB:

I need to specify that I made a big fail designing the PCB. When I made the schematic, I connected the ground pin of the LED to voltage, something that would have probably burned out the led. Fortunately, I realized this before soldering the components and didn't burn anything.

After the soldering proccess of the PCB, I also added some pins to my old PCBs in order to get enough I2C pins for the connections. The images below show the new PCB and the way I connected the 3 PCBs:

For programming the Attiny44 and the Attiny45, I used an Arduino NANO in order to use the Arduino IDE for the codes. I have a short tutorial of how to program the Attiny using the Arduino on my week8.

The Codes

I decided to use the PCB from week4 as the master and the week8 and the new one PCBs as the slaves. I decided to make something simple just to understand how the communication works. The master was in charge of printing in the Serial Monitor a button state, the Attiny44 was in charge of turning on a LED and the Attiny45 was in charge of sending the button signal. These are the codes:

XIAO RP2040 Code:

    
    #include < Wire.h >
    
    void setup() {
      Serial.begin(9600);
      Wire.begin();
    }
    
    
  • Libraries and Setup: First, I included the library used for the I2C communication ("Wire.h"). I also started the Serial Monitor and I set the Xiao as the master.
  • 
    void loop() {
      int estadoBoton = 0;
    
      // Solicitar el estado del botón al ATtiny45 en la dirección 3
      Wire.requestFrom(3, 1);
      if (Wire.available()) {
        estadoBoton = Wire.read();
      }
    
      // Envía el estado del botón al ATtiny44 en la dirección 2
      Wire.beginTransmission(2);
      Wire.write(estadoBoton);
      Wire.endTransmission();
    
      // Debugging por Serial
      Serial.print("Estado del botón: ");
      Serial.println(estadoBoton);
    
      delay(500);
    }
    
  • The Loop: On the loop, first, I requested the information from the "3" address. If I am receiving information, the Xiao saves the information obtained on "estadoBoton". Then, I sent the same information obtained to the "2" address. Finally, I printed the button state (information received) on the Serial Monitor next to the words "Buttons State:".

You can copy the code right here:

Attiny44 Code:

    
    #include < Wire.h >
    
    #define led1 9
    
    void setup() {
      pinMode(led1, OUTPUT);
      digitalWrite(led1, LOW); 
      Wire.begin(2);
      Wire.onReceive(receiveEvent);
    }
    
    
  • Libraries and Setup: First, I included the library used for the I2C communication ("Wire.h"). I also defined the pin from the LED (the ninth pin), I set it as an output, I turned it off, I set the Attiny44 as an slave on the address "2" and finally, I set the the function the Attiny44 would make when it receices a signal.
  • 
    void loop() {
      delay(1000); 
    }
    
    void receiveEvent(int howMany) {
      while (Wire.available()) {
        int estado = Wire.read();
        if (estado == HIGH) {
          digitalWrite(led1, HIGH);
        } else {
          digitalWrite(led1, LOW);
        }
      }
    }
    
  • The Loop and The Function: On the loop, I just had a delay of 1000ms. I created the function "receiveEvent", this is the function the Attiny44 will make when it receives information. This function enters when a data is received, this functions saves this data on "estado" and changes the state of the LED depending on the data received.

You can copy the code right here:

Attiny45 Code:

    
    #include < Wire.h >
    
    #define boton1 3  // Asegúrate de que este es el pin correcto para el botón
    int estadoBoton = 0;
    
    void setup() {
      pinMode(boton1, INPUT);
      Wire.begin(3);  // Configura como esclavo en dirección 3
      Wire.onRequest(requestEvent);  // Responde cuando el maestro solicite datos
    }
    
    
    
  • Libraries and Setup: First, I included the library used for the I2C communication ("Wire.h"). I also defined the pin from the button (the third pin), created the variable "estadoBoton", I set the button pin as an input, I set the Attiny45 as an slave on the address "3" and finally, I set the the function the Attiny45 would make when it receices a signal.
  • 
    void loop() {
      estadoBoton = digitalRead(boton1);  // Lee el estado del botón constantemente
    }
    
    void requestEvent() {
      Wire.write(estadoBoton);  // Envía el estado del botón al maestro
    }
    
  • The Loop and The Function: On the loop, I only saved the button state on "estadoBoton". I created the function "requestEvent", in which I only sent the button state to the master (Xiao RP2040). This function is the one called on the setup when the master requests information.

You can copy the code right here:

Here is the video of the all the PCBs and microcontrollers working together:

Get in touch

Follow