Group Assignment Individual Assignment SPI with SAMD21 NFC+Motor Board NFC Control MQTT Morse Code Device Design Files
Week 11

Networking and Communications

This week, I focused on designing, fabricating, and assembling a custom PCB. I used KiCad for schematic and PCB design, then fabricated the board using milling and laser etching, and finally assembled and tested it.

Learning Objectives

  • Select and use software for circuit board design
  • Demonstrate workflows used in circuit board design

  • Assignments

    Group Assignments

  • Send a message between two projects
  • Document your work to the group work page and reflect on your individual page what you learned

    Individual Assignments

  • design, build and connect wired or wireless node(s) with network or bus addresses and a local input and/or output devices

  • Group Assignment

    The group assignment was to communicate between any 2 projects already made. For the assignment purpose, we communicated between my and Ancy's project. The commnication between the two projects was done by ESP-NOW as both are boards were XIAO ESP32s. You can find the group assignment on the below page.

    Group Assignment

    SPI ESP32C6-SAMD21

    SERCOM

    Generally a microcontroller will have separate serial communication modules with different pinouts for each module. Separate dedicated peripherals and user registers will be available for each module. For example, USART will be a separate peripheral with dedicated pins for its function and I2C will be a separate peripheral with its own dedicated pins.

    In SAM D microcontrollers, all the serial peripherals are designed into a single module as serial communication interface (SERCOM). A SERCOM module can be configured either as USART, I2C, or SPI, selectable by the user. Each SERCOM will be assigned four pads from PAD0 to PAD3. The functionality of each pad is configurable depending on the SERCOM mode used. Unused pads can be used for other purposes and the SERCOM module will not control them unless they are configured to be used by the SERCOM module.

    SERCOM SPI

    Photo credit: Microchip

    For example, SERCOM0 can be configured as USART mode with PAD0 as transmit pad and PAD1 as receive pad. Other unused pads (PAD2 and PAD3) can be used either as GPIO pins or be assigned to some other peripherals. The assignment of SERCOM functionality for different pads is highly flexible making the SERCOM module more advantageous compared to the typical serial communication peripheral implementation

    Sercom SPI Slave Library

    I used this library for my SAMD21 Borad to communicate it as a slave

    SAMD21 SPI Slave Code

    I took this example code from the above given github repository to initialize the SAMD21 Board as the Slave in the SPI Communication. I have edited the code for the correct pins in my case for my SAMD21 Board. You can find the detailed documentation of the TouchNav SAMD21 Board in the input week assignment.

    
    /*  
      Copyright (C) 2022 lenvm
    
      This program is free software: you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
      the Free Software Foundation, either version 3 of the License, or
      (at your option) any later version.
    
      This program is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      GNU General Public License for more details.
    
      For the GNU General Public License see https://www.gnu.org/licenses/
    
      Contact Information
      -------------------
      lenvm
      GitHub   : https://github.com/lenvm
    */
    
    /*
      Example code for the SercomSPISlave library.
      This code initializes a SERCOM1 SPI Slave and prints the data received.
    
      Written 2020 July 15 
      by lenvm
      Updated 2021 June 8
      by lenvm
      Updated 2022 November 1
      by lenvm
    */
    
    #include <SercomSPISlave.h>
    Sercom1SPISlave SPISlave; // to use a different SERCOM, change this line and find and replace all SERCOM1 with the SERCOM of your choice
    
    #define DEBUG // uncomment this line to print debug data to the serial bus
    #define INTERRUPT2BUFFER // uncomment this line to copy the data received in the Data Received Complete interrupt to a buffer to be used in the main loop
    //#define INTERRUPT2SERIAL // uncomment this line to print the data to the serial bus whenever the Data Received Complete interrupt is triggered
    
    // initialize variables
    byte buf[1]; // initialize a buffer of 1 byte
    
    void setup()
    {
      Serial.begin(115200);
      Serial.println("Serial started");
      SPISlave.SercomInit(SPISlave.MOSI_Pins::PA16, SPISlave.SCK_Pins::PA17, SPISlave.SS_Pins::PA18, SPISlave.MISO_Pins::PA19);
      Serial.println("SERCOM1 SPI slave initialized");
    }
    
    void loop()
    {
      #ifdef INTERRUPT2BUFFER
        Serial.println(buf[0]); // Print latest data written into the buffer by the interrupt
        delay(1); // Delay of 1 ms
      #endif
      #ifdef INTERRUPT2SERIAL
        delay(1000); // Delay of 1 s to keep the main loop running, while data is written to the serial every time the Data Received Interrupt is triggered
      #endif
    }
    
    void SERCOM1_Handler()
    /*
    Reference: Atmel-42181G-SAM-D21_Datasheet section 26.8.6 on page 503
    */
    {
      #ifdef DEBUG
        Serial.println("In SPI Interrupt");
      #endif
      uint8_t data = 0;
      data = (uint8_t)SERCOM1->SPI.DATA.reg;
      uint8_t interrupts = SERCOM1->SPI.INTFLAG.reg; // Read SPI interrupt register
      #ifdef DEBUG
        Serial.print("Interrupt: "); Serial.println(interrupts);
      #endif
      
      // Slave Select Low interrupt
      if (interrupts & (1 << 3)) // 1000 = bit 3 = SSL // page 503
      {
        #ifdef DEBUG
          Serial.println("SPI Slave Select Low interupt");
        #endif
        SERCOM1->SPI.INTFLAG.bit.SSL = 1; // Clear Slave Select Low interrupt
      }
      
      // Data Received Complete interrupt: this is where the data is received, which is used in the main loop
      if (interrupts & (1 << 2)) // 0100 = bit 2 = RXC // page 503
      {
        #ifdef DEBUG
          Serial.println("SPI Data Received Complete interrupt");
        #endif
        data = SERCOM1->SPI.DATA.reg; // Read data register
        SERCOM1->SPI.INTFLAG.bit.RXC = 1; // Clear Receive Complete interrupt
      }
      
      // Data Transmit Complete interrupt
      if (interrupts & (1 << 1)) // 0010 = bit 1 = TXC // page 503
      {
        #ifdef DEBUG
          Serial.println("SPI Data Transmit Complete interrupt");
        #endif
        SERCOM1->SPI.INTFLAG.bit.TXC = 1; // Clear Transmit Complete interrupt
      }
      
      // Data Register Empty interrupt
      if (interrupts & (1 << 0)) // 0001 = bit 0 = DRE // page 503
      {
        #ifdef DEBUG
          Serial.println("SPI Data Register Empty interrupt");
        #endif
        SERCOM1->SPI.DATA.reg = 0xAA;
      }
      
      #ifdef INTERRUPT2BUFFER
        // Write data to buffer, to be used in main loop
        buf[0] = data;
      #endif
      #ifdef INTERRUPT2SERIAL
        // Print data received during the Data Receive Complete interrupt
        char _data = data;
        Serial.print("DATA: ");
        Serial.println(_data); // Print received data
      #endif
    
    }
    
    ESP32 Master Code

    This is the master code for the XIAO ESP32C6 Board that I used for communicating with the TouchNav SAMD21 Board. I used ChatGPT to write this code.

    ChatGPT Prompt: I want to communicate between a SAMD21 and a XIAO ESP32-C6 using SPI. The ESP32-C6 will act as the SPI master and send integer data to the SAMD21 (SPI slave). The data should be sent when I type a number into the Serial Monitor and press Enter.

    
    #include 
    
    #define SCK  D8
    #define MISO D10
    #define MOSI D9
    #define CS   D0
    
    void setup() {
      Serial.begin(115200);
    
      SPI.begin(SCK, MISO, MOSI, CS);
      pinMode(CS, OUTPUT);
      digitalWrite(CS, HIGH);
    }
    
    void loop() {
      delay(1000);  // Every 1 sec send data
    
      
    
        if (Serial.available()) {
        String inputString = Serial.readStringUntil('\n');  // read till Enter key
        int response = inputString.toInt();  // convert to integer
        digitalWrite(CS, LOW);  
        SPI.transfer(response);  // Send 0x55 and read response
      
        Serial.print("You entered: ");
        Serial.println(response);
        
        digitalWrite(CS, HIGH);
      }
    
    
    }
    
    

    Individual Assignments

    NFC + Motor Board

    I wanted to design a board which used RFID communication as it was required for my final project. This week was the best time to try the MRFC522 RFID Reader Module. I also wanted to control a motor according to the RFID Input. This would help me to integrate in the final project.

    I also wanted to try using my boards to communicate using Morse Code. That's why I added a push button and a speaker/buzzer to the board.

    Designing the board

    Components Used

    RFID-RC522 Development Kit

    This RC522 RFID Development kit is based on NXP's a highly integrated reader/writer IC MFRC522 for contactless communication at 13.56 MHz. The MFRC522 reader supports ISO/IEC 14443 A/MIFARE and NTAG. The MFRC522's internal transmitter is able to drive a reader/ writer antenna designed to communicate with ISO/IEC 14443A cards and transponders without additional active circuitry. The receiver module provides a robust and efficient implementation for demodulating and decoding signals from ISO/IEC 14443A compatible cards and transponders.

    RFID RC522 Pinout

    Photo credit: handsontec

    RC522 RFID Development kit - Documentation

    I used the SPI protocol to communicate with the RFID RC522 Development Board as it offered maximum speed. I have used a 1x8 Through Hole Header Array to connect the RC522 Board.

    Schematic RC522

    DC Motor with N Channel Mosfet

    For my final project, I need a motor to rotate the record to mimic the turntable effect of the classic Vinyl Record Player. I didn't need any complex motor control, so I decide to make a simple DC Motor circuit driven by a simple N Channel Mosfet.

    I refered to Akash's documentation to design my motor driver circuit

    DC Motor with N Channel MOSFET

    Speaker

    For this week's assignment , I wanted to make a Wifi based Morse Code communication board. For a typical Morse Code Machine the sound is very essential, that's why I wanted to use a speaker/buzzer for the board. So I decide to use the speaker that Namita used for her last week's assignment as it required a simple driver circuit which is MOSFET based unlike my I2S DAC+Amplifier Based Circuit which used for my assignment last week. The AST0927MW-3.6Q Speaker is an electromagnetic transducer which is specifically designed for audio indication, with a resonant frequency of 2.73 kHz and a sound pressure level (SPL) of 85 dB. I used the footprint provided by Namita which she made last week. You can refer to her documentation for more information about the speaker and how she made the footprint.

    The footprint of the AST0927MW-3.6Q Speaker is attached here - Speaker Footprint

    The speaker also uses a N Channel Mosfet as a driver. I have attached a Red LED to the Speaker-In pin through a resistor, this makes it light up by default everytime the speaker is on, making it easier for me. I didn't have to use a pin or program the LED Separately.

    Speaker - N Channel Mosfet Driver Circuit

    WS2812B and Push Button

    The WS2812B Addressable RGB LED is also used to signify the status of the board and the push button is used to send morse code messages. The push button is pulled up hy by a resistor to avoid floating values.

    NFC Motor Board Schematic

    The schematic and PCB design was doen in the KiCad Software.

    NFC XIAO ESP32C6 Board Schematic

    NFC Motor Board PCB Design

    This is the PCB Design of the board. I edited the trace width of the 12V and GND lines to carry more current. The trace width of those power lines is 0.8mm whiile rest of the trace widths are 0.4 mm.

    NFC XIAO ESP32C6 Board: PCB Design

    PCB Milling using Milling Machine

    I used the Modela RDX Milling Machine for milling the PCB

    Traces milled

    The traces were clean and the board was ready to be assembled using all the components.

    Assembly

    I setup the board on the PCB holder setup and requested all the components from the Fab Stash and collected it from the inventory.

    NFC XIAO ESP32C6 Board
    NFC XIAO ESP32C6 Board
    Components

    Hero Shots

    After soldering all the components on the PCB, I attached the motor and the RC522 RFID Reader Module to the board. Below are some hero shots of the board.

    NFC XIAO ESP32C6 Board
    NFC XIAO ESP32C6 Board
    NFC XIAO ESP32C6 Board
    NFC XIAO ESP32C6 Board
    NFC XIAO ESP32C6 Board

    PCB Milling using XTools F1 Ultra

    After the milling the board on the Modela RDX Milling machine, I wanted to try using another process for my next PCB. I used the XTools F1 Ultra for my next board.

    Electroncis Production: Group Assignment

    You can refer to the above documentation on the process of PCB engraving using the XTools F1 Ultra in the 'Using the XTool F1 Ultra for PCB Engraving' section.

    You can see the video of the Xtools engraving the FR4 Board. It is not possible to engrave on the FR1 board as the board would burn eventually in the process. The FR4 is heat resistant as compared to the FR1.

    The output looks really nice with really tight tolerances and neat traces as compared to the milling process

    NFC XIAO ESP32C6 Board
    NFC XIAO ESP32C6 Board
    NFC XIAO ESP32C6 Board

    Programming

    I tested the NFC Module using the example code from the library. You need to install the MFRC522 library by Github to use this code.

    The library and the step by step process is mentioned in the documentation

    The example is called "ReadNUID" in the MFRC522 library. It will read the NUID of the MIFARE Classic Tag and print it to the Serial Monitor. The code is given below.

    
    #include <SPI.h>
    #include <MFRC522.h>
    
    #define SS_PIN D7
    #define RST_PIN D6
     
    MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
    
    // Init array that will store new NUID 
    byte nuidPICC[4];
    
    void setup() { 
      Serial.begin(9600);
      SPI.begin(); // Init SPI bus
      rfid.PCD_Init(); // Init MFRC522 
    
      Serial.println(F("This code scan the MIFARE Classsic NUID."));
    }
     
    void loop() {
    
      // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
      if ( ! rfid.PICC_IsNewCardPresent())
        return;
    
      // Verify if the NUID has been readed
      if ( ! rfid.PICC_ReadCardSerial())
        return;
    
      Serial.print(F("PICC type: "));
      MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
      Serial.println(rfid.PICC_GetTypeName(piccType));
    
      // Check is the PICC of Classic MIFARE type
      if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&  
        piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
        piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
        Serial.println(F("Your tag is not of type MIFARE Classic."));
        return;
      }
    
      if (rfid.uid.uidByte[0] != nuidPICC[0] || 
        rfid.uid.uidByte[1] != nuidPICC[1] || 
        rfid.uid.uidByte[2] != nuidPICC[2] || 
        rfid.uid.uidByte[3] != nuidPICC[3] ) {
        Serial.println(F("A new card has been detected."));
    
        // Store NUID into nuidPICC array
        for (byte i = 0; i < 4; i++) {
          nuidPICC[i] = rfid.uid.uidByte[i];
        }
       
        Serial.println(F("The NUID tag is:"));
        Serial.print(F("In hex: "));
        printHex(rfid.uid.uidByte, rfid.uid.size);
        Serial.println();
        Serial.print(F("In dec: "));
        printDec(rfid.uid.uidByte, rfid.uid.size);
        Serial.println();
      }
      else Serial.println(F("Card read previously."));
    
      // Halt PICC
      rfid.PICC_HaltA();
    
      // Stop encryption on PCD
      rfid.PCD_StopCrypto1();
    }
    
    
    /**
     * Helper routine to dump a byte array as hex values to Serial. 
     */
    void printHex(byte *buffer, byte bufferSize) {
      for (byte i = 0; i < bufferSize; i++) {
        Serial.print(buffer[i] < 0x10 ? " 0" : " ");
        Serial.print(buffer[i], HEX);
      }
    }
    
    /**
     * Helper routine to dump a byte array as dec values to Serial.
     */
    void printDec(byte *buffer, byte bufferSize) {
      for (byte i = 0; i < bufferSize; i++) {
        Serial.print(' ');
        Serial.print(buffer[i], DEC);
      }
    }
    
    								

    I wanted to try something basic for my final project progress. So I made the motor run when the NFC ID was detected and to stop the motor when the ID was detected again

    
    #include <SPI.h>
    #include <MFRC522.h>
    
    #define SS_PIN D7
    #define RST_PIN D6
    
    #define motor D1
     
    MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
    
    // Init array that will store new NUID 
    byte nuidPICC[4];
    
    void setup() { 
      pinMode(motor,OUTPUT);
      Serial.begin(9600);
      SPI.begin(); // Init SPI bus
      rfid.PCD_Init(); // Init MFRC522 
    
      Serial.println(F("This code scan the MIFARE Classsic NUID."));
    }
     
    void loop() {
    
      // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
      if ( ! rfid.PICC_IsNewCardPresent())
        return;
    
      // Verify if the NUID has been readed
      if ( ! rfid.PICC_ReadCardSerial())
        return;
    
      Serial.print(F("PICC type: "));
      MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
      Serial.println(rfid.PICC_GetTypeName(piccType));
    
      // Check is the PICC of Classic MIFARE type
      if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI &&  
        piccType != MFRC522::PICC_TYPE_MIFARE_1K &&
        piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
        Serial.println(F("Your tag is not of type MIFARE Classic."));
        return;
      }
    
      if (rfid.uid.uidByte[0] != nuidPICC[0] || 
        rfid.uid.uidByte[1] != nuidPICC[1] || 
        rfid.uid.uidByte[2] != nuidPICC[2] || 
        rfid.uid.uidByte[3] != nuidPICC[3] ) {
        Serial.println(F("A new card has been detected."));
        analogWrite(motor, 30);
    
        // Store NUID into nuidPICC array
        for (byte i = 0; i < 4; i++) {
          nuidPICC[i] = rfid.uid.uidByte[i];
        }
       
        Serial.println(F("The NUID tag is:"));
        Serial.print(F("In hex: "));
        printHex(rfid.uid.uidByte, rfid.uid.size);
        Serial.println();
        Serial.print(F("In dec: "));
        printDec(rfid.uid.uidByte, rfid.uid.size);
        Serial.println();
      }
      else 
      {
        Serial.println(F("Card read previously."));
        analogWrite(motor, 0);
      }
      // Halt PICC
      rfid.PICC_HaltA();
    
      // Stop encryption on PCD
      rfid.PCD_StopCrypto1();
    }
    
    
    /**
     * Helper routine to dump a byte array as hex values to Serial. 
     */
    void printHex(byte *buffer, byte bufferSize) {
      for (byte i = 0; i < bufferSize; i++) {
        Serial.print(buffer[i] < 0x10 ? " 0" : " ");
        Serial.print(buffer[i], HEX);
      }
    }
    
    /**
     * Helper routine to dump a byte array as dec values to Serial.
     */
    void printDec(byte *buffer, byte bufferSize) {
      for (byte i = 0; i < bufferSize; i++) {
        Serial.print(' ');
        Serial.print(buffer[i], DEC);
      }
    }
    
    

    MQTT Communication with Rico

    Using the board that I designed in this week, I communicated with Rico Kanthatham at Skylab Workshop. I used Message Query Telemetry Transportation (MQTT) for this purpose. I have documented about MQTT and the whole process in the week 14 Interface and Application assignment. You can refer to the same.

    This is the video of Rico sending and recieving the morse code to our lab

    Design Files

    You can download my design files from below

    x