Table of Contents

Objectives Timeline Individual Assignment Group Assignment Conclusion References Design Files

Week 11: Networking & Communications

Objectives

These are the tasks for this week:

Timeline

Wednesday

Thursday

Friday

Saturday

Sunday

Monday

Tuesday

Wednesday

Individual Assignment

This week we learnt about different kinds of communication protocols. I decided to learn to use I2C to communicate between a master and two node boards. If time allows, I would like to make each node control a servo.

Using the Attiny 412

For this week, I will be referencing Midhun's (FA2023) and Adrian Torress' documentation, but I will be modifying it for the Attiny 1614 chip for the nodes and a development board I made during Electronics Poduction Week as my master board. I wanted to use I2C and UART communication protocol

These is the pinmapping of Attiny1614

The datasheet for the Attiny can be seen here

Communication Protocols

Using I2C

I2C is a serial communication protocol primarily used for short-distance communication between multiple devices. It uses two wires SDA (Serial Data; for transfer data) and Serial Clock (SCL; for timing) apart from Power and Ground to communicate between two or more devices.

The Main/Master board communicates with each of its nodes using unique 7 bit I2C addresses. The Master board does not need a I2C address, whereas seperate addresses can be set for each node. This means that a device can be cnnected to a total of 27-1= 127 devices at a time using I2C.

Both SDA and SCL lines can be pulled low by individual nodes, but to pull it back to high, you need pull-up resistors that are connected to PWR. This is both SCL and SDA lines are called open drain

I2C
Source: How To Mechatronics

Using UART

UART
Source: Electronics Stack Exchange

Designing the Servo Driver Nodes

This week I wanted to design modular servo driver boards that can each use 4 servos. I used KiCAD to design my PCBs.

PCBDesign Schematic

Schematic

For this week I wanted to design boards that can accept both I2C and UART communication protocols.

A tip by Abin: You can simply use Ctrl+C > Ctrl+V to copy and paste pictures into KiCAD

For I2C communication I will be using Midhun's (FA2023) documentation, but adapting for Attiny 1614 (he used ATtiny 412) I tried improving on the original design by adding UART connections following the convention followed by FTDI to be able to debug the code if required.

Schematic

I wanted to make connections for both I2C and UART to in my boards. Since we have 02x03 IDC connectors, based on instructor input, I tried designing a hybrid connector for both I2C and UART connections

This is how the completed schematic for my servo driver board looks like

PCB Designing

Since I want to make multiple copies, ideally the node PCB should be small. So, once I was able to get the connections right, I took a screenshot of the mock PCB for reference and proceeded to remove the trace,compress the space in between and add the traces again to make the PCB smaller

Since my board had to be designed in such a way that it is easily milled in a repeatable manner, I wanted to avoid using wired vias for connections that I used previously. This increased design time by a lot, and in the end I had to add a 0 ohm resistor to make one connection to GND. This is how my node PCB looks like once done.

PCBDesign

Making the PCB

Assembled Board

Milling

Just like previous weeks, I milled the boards. This included two nodes and one FTDI programer board to be able to program and debig the Attiny 1614.

But later I realized that the programmer board I had milled was wrong, and I had to discard it because of lack of time

Bill of Materials

Just like before, I used the interactive BOM plugin to create a rough draft of required components, which was then used to create the final BOM sheet

These are the BOM sheets for the two nodes (Node 1 has additional 4.99 K resistors for SDA and SCL pins of I2C connection, since I do not have them pulled up in the master board) and the new programmer desiigned by out instructor Saheen.

Soldering

These are how my node boards look like after soldering:

Verification

Using the Benchtop Power Supply

Safety
Testing for short circuiting for Node 1
Testing for short circuiting for Node 1

Now to make the connectors for wired connections. My instructor helped make a connector using 2 02x03 IDC connectors for each node and a 02x02 IDC connector (for I2C) and a 1x02 connector (for RX, TX) at the master board.

The picture shown below shows a diagram of how the connector was designed:

Programming

I will be using I2C communication, with the XiaoESP32 acting as the master and the Attiny 1614 acting as the node.

Program 1: Testing I2C Connection

I will be using this Xiao ESP32 C6 Development Board I made in Electronics Production Week

Master Board

Code for master board

First we plug the master board and prepare the IDE and upload the following code


    // Wire Master Writer
    // by Nicholas Zambetti  < http://www.zambetti.com> and modified by Noel Joseph Saji 09/04/2022
    
    // Demonstrates use of the Wire library
    // Writes data to an I2C/TWI slave device
    // Refer to the "Wire Slave Receiver" example for use with this
    
    // Created 29 March 2006
    
    // This example code is in the public domain.
    
    
    #include <Wire.h>
    
    void setup() {
        Wire.begin();  // join i2c bus (address optional for master)
    }
    
    byte x = 0;
    
    void loop() {
        Wire.beginTransmission(8);  // transmit to device #8
        Wire.write((const uint8_t*)"x is ", 5);      // sends five bytes
        Wire.write(x);              // sends one byte
        Wire.endTransmission();     // stop transmitting
    
        x++;
        delay(500);
    }
                
                        

To make it for my Xiao, I had replaced Wire.write("x is "); in the original code with Wire.write((const uint8_t*)"x is ", 5); to avoid this error: Compilation error: invalid conversion from 'const char*' to 'uint8_t' {aka 'unsigned char'} [-fpermissive] For more explanation, click here.

The Wire library will be used to initate I2C communication. We initate I2C communication using the Wire.begin() function, Since I have not added a 7 bit address, the Xiao is set up as the master.

Wire.beginTransmission(8) initiates I2C communication with a node with the address 8

Wire.write("") writes data to a node in response to a request from the master

Wire.endTransmission() cuts communication with the specific node, allowing other masters to communicate with it

Code for Nodes

Then we plug in one of the nodes plugged with the programmer are the IDE. Then we set the following in tools in the Arduino IDE

Additionally we set the supply side voltage to 3.3 V if it does not work at 5V using the toggle switch in the programmer. Then we add the following code:


    // Slave-reader
    //
    // Wire Slave Receiver
    //
    // by Nicholas Zambetti < http://www.zambetti.com> and modified by Saheen Palayi 06/06/2022
    //
    // This work may be reproduced, modified, distributed,
    // performed, and displayed for any purpose, but must
    // acknowledge this project. Copyright is retained and
    // must be preserved. The work is provided as is; no
    // warranty is provided, and users accept all liability.
    //
    
    
    // Demonstrates use of the Wire library
    // Receives data as an I2C/TWI slave device
    // Refer to the "Wire Master Writer" example for use with this
    
    // Created 29 March 2006 by Nicholas Zambetti
    
    // This example code is in the public domain.
    
    
    //Added software serial for Attiny84
    // #include <SoftwareSerial.h>
    #include <Wire.h>
    
    
    // Software serial rx,tx pins of Attiny84
    const byte rxPin = 0;
    const byte txPin = 1;
    
    
    //declaring mySerial as SoftwareSerial
    // SoftwareSerial mySerial(rxPin, txPin);
    
    
    void setup() {
    
        Wire.begin(8);                 // join i2c bus with address #8
        Wire.onReceive(receiveEvent);  // register event
        Serial.begin(9600);          // start serial for output
    }
    
    void loop() {
        // Serial.println("hello");
        delay(100);
    }
    
    // function that executes whenever data is received from master
    // this function is registered as an event, see setup()
    void receiveEvent(int howMany) {
        while (1 < Wire.available()) {  // loop through all but the last
        char c = Wire.read();         // receive byte as a character
        Serial.print(c);            // print the character
        }
        int x = Wire.read();  // receive byte as an integer
        Serial.println(x);  // print the integer
    }        
                        

Wire.begin(8) allows the Attiny 1614 to be set up as a node in I2C communication with the address '8'

Wire.onReceive(receiveEvent) sets up a function receiveEvent to be called when the node receives a transmission from a master.

Wire.available() checks the number of bytes that can be read by the node

Wire.read() reads the incoming data from the master

Connecting Different Boards

I connected the boards as shown below using the connector I made previously

Program 2: Controlling LEDs using a Switch through I2C

Due to some issues with UPDI initialisation with the Attiny boards, I made some new node boards using Attiny 1614s where the signal lines were as straight and short as possible. The master board is the same as before.

The schematic and PCB layout are shown below

Code for Master Board


    #include <Wire.h> // Include the Wire library for I2C communication

    #define LED D3
    #define Switch D2
    byte buttonNew; // To store the current button state
    byte buttonOld = 1; // To store the previous button state (initialized as 1)
    byte state = 0; // To toggle I2C device communication
    int dt = 100;

    void setup() {
    pinMode(Switch, INPUT);
    pinMode(LED, OUTPUT);
    Serial.begin(9600);
    Wire.begin();  // Initialize I2C communication
    }

    void loop() {
    buttonNew = digitalRead(Switch);

    //Button was released before (0) and now pressed (1)

    if (buttonOld == 0 && buttonNew == 1) {
        if (state == 0) {
        Wire.beginTransmission(8); Wire.write(1); Wire.endTransmission(); //Send 1 (signal to turn LED ON) to node with address '8'
        Wire.beginTransmission(9); Wire.write(0); Wire.endTransmission(); //Send 0 (signal to turn LED OFF) to node with address '9'
        state = 0;
        state = 1;
        Serial.println("8");
        } 

    //In all other cases

        else {
        Wire.beginTransmission(8); Wire.write(0); Wire.endTransmission(); //Send 0 (signal to turn LED OFF) to node with address '8'
        Wire.beginTransmission(9); Wire.write(1); Wire.endTransmission(); //Send 1 (signal to turn LED ON) to node with address '9'
        state = 0;
        Serial.println("9");
        }
    }
    buttonOld = buttonNew;
    delay(dt);

    //For debugging

    // Serial.print("buttonOld: ");
    // Serial.print(buttonOld);
    // Serial.print(" buttonNew: ");
    // Serial.print(buttonNew);
    // Serial.print(" state: ");
    // Serial.println(state);
    }

                                        
                        

Wire.beginTransmission(8) initiates I2C communication with nodes with the address 8.

Wire.beginTransmission(9) initiates I2C communication with nodes with the address 9.


Code for Node boards


    #include <Wire.h>
    #define LED A7

    void setup() {
    pinMode(LED, OUTPUT);
    Wire.swap(1);
    Wire.begin(9);                 // join i2c bus with address #8 or #9
    Wire.onReceive(receiveEvent);  // register event
    Serial.begin(9600);            // start serial for output

    //An inital blink to indicate the boards work as indicated

    digitalWrite(LED, HIGH);       
    delay(500);
    digitalWrite(LED, LOW);
    }

    void loop() {
    delay(100);
    }

    //I2C function that executes the Blink LED program

    void receiveEvent(int howMany) {
    while (Wire.available()) {
        byte val = Wire.read();

        //if '1' is received, turn the LED ON
        if (val==1){
        digitalWrite(LED,HIGH);
        }

        //if '0' is received, turn the LED OFF
        else if (val==0){
        digitalWrite(LED,LOW);
        }
    }
    }

                    

Wire.begin(9) allows the Attiny 1614 to be set up as a node in I2C communication with the address '9'

Group Assignment

In our group assignment, we sent messages between two different boards that used two different protocols (ESP_NOW & MQTT). The Time of Flight sensor measures distances between the sensor and an obstruction. If this distance is equal to 15 cm the onboard microcontroller sends a MQTT message to the network. When the distance is lower than 15 cm, the onboard microcontroller communicates via ESP-NOW to light up an LED on a different board in its network

To access our group assignment, click here

Conclusion

Mistakes & Solutions

  1. ProshPlay 3D model missing: If 3D models are not being updated even after attaching the correct link in 3D preview, try updating the footprint library and repeat the relinking process once again
  2. Not able to burn bootloader/upload program using SerialUPDI and Attiny1614: While trying to burn the bootloader, I got an error saying Failed to burn bootloader

    After consulting ChatGPT, I tried measuring voltage drop at the chip whch was measured at only 3V, even though at the supply side there was 5V drop. I tested the continuity at the GND line and found that I used a 1k resistor instead of a 0 ohm resistor, which I then replaced, but it still did not solve the problem bad solder joint in the 0 Ohm resistor which prevented current from flowing through it.

    The next morning, Akash (FA2025) helped solve the problem by changing the supply voltage to 3.3 V (from 5V) using the toggle switch on the programmer, and setting the clock speed to 16 MHz (instead of default 20MHz). The problem with the voltage supply is caused by problems with the old programmer board (which will be replaced by the new one I will use today), but I am unaware of what it has to do with clock speed, but based on ChatGPT prompts, higher clock speeds require more precise timing and tighter voltage requirements, and due to errors that crept in while designing the boards (or the programmer), the chip is not stable enough to be communicated to at this clock speed fo 20MHz, so you need to slow it down.

    The ChatGPT prompts I used have been listed below:

  3. Compilation error while using Wire.write() for I2C connection:Acccording to ChatGPT you cannot directly use strings in Wire.write() for I2C connection
  4. UPDI initialisation error

    Maybe because my UPDI lines were long and windy, instead of straight and short, I got this error that syas UPDI initialisation with Attiny 1614 has failed. So I had to redesign another board. While tracing, signal lines should come as first priority, and they should be as sraight and short as possible

References

  1. Wire (I2C) by Particle Docs
  2. Attiny 1614 datasheet
  3. What are I2C Pull-Up Resistors and How to Calculate their Values (Total Phase)

Design Files

Click here to access the design files