Skip to content

Week 6 – Electronics Design (Group Assignment)

Overview

This week’s group assignment focused on understanding and using essential electronic test equipment to analyze and debug a microcontroller-based circuit. The aim was to develop practical skills in measuring electrical parameters and visualizing signal behavior in real-time.

By working with standard lab instruments, we learned how electronic systems behave physically, beyond theoretical knowledge.


Group Assignment Objective

  • Use electronic test equipment to analyze a working microcontroller circuit
  • Measure voltage, current, and signal characteristics
  • Visualize digital signals using an oscilloscope
  • Understand basic debugging techniques in embedded systems

Equipment Used

Multimeter

ZOYI ZT301 Digital Multimeter | Functionality and Usage Guide

zoyi.jpg

The ZOYI ZT301 Digital Multimeter is a handheld instrument used to measure voltage, current, resistance, continuity, and frequency. It is one of the most important diagnostic tools in electronics, used to verify circuits, test components, and debug PCBs.


Purpose

A multimeter helps determine:

  • If power is present
  • If two points are connected
  • If a component has the correct value
  • If there is a short circuit

FabAcademy uses:

  • Verify PCB traces after milling
  • Check 5 V and 3.3 V power rails
  • Test resistors and LEDs
  • Debug microcontroller boards

Main Parts

Display – shows measured value and unit (V, Ω, A, Hz)

Rotary Dial – selects measurement mode

Input Ports

Probes – used to touch circuit points.


How to Use (Basic PCB Testing)

1. Check continuity (before powering PCB)

Purpose: detect broken traces or shorts

Steps:

  1. Black probe → COM
  2. Red probe → VΩHz
  3. Turn dial → continuity symbol (sound wave)
  4. Touch probes to two points

Beep = connected

No beep = not connected

Use to check:

  • Trace connections
  • Solder joints
  • No short between VCC and GND

2. Measure voltage (after powering PCB)

Purpose: confirm correct power supply

Steps:

  1. Black probe → COM
  2. Red probe → VΩHz
  3. Turn dial → V
  4. Touch black probe to GND
  5. Touch red probe to VCC

Expected:

  • 5 V
  • or 3.3 V

3. Measure resistance (component testing)

Purpose: verify resistor value

Steps:

  1. Turn dial → Ω
  2. Touch probes across resistor
  3. Read value

Example:

1000 Ω = 1 kΩ resistor


Why it is essential

The multimeter is the primary tool for verifying, troubleshooting, and validating electronic circuits. It allows quick identification of power issues, broken traces, and faulty components.


Digital Oscilloscope

OWON TAO3104A Digital Oscilloscope | Functionality and Usage Guide

OWON TAO3104A Oscilloscope

The OWON TAO3104A is a 4-channel digital storage oscilloscope with a 100 MHz bandwidth and a 1 GSa/s sample rate. Unlike a multimeter which only shows static values, an oscilloscope displays how signals change over time — making it essential for analyzing waveforms, timing, and signal behavior in electronic circuits.


Purpose

An oscilloscope helps determine:

  • The shape of a signal (sine, square, triangle, sawtooth, etc.)
  • The frequency and period of a signal
  • The amplitude (voltage level) of a signal
  • The duty cycle of a PWM signal
  • Whether a signal is noisy, distorted, or behaving unexpectedly

FabAcademy uses:

  • Visualize PWM output from microcontrollers
  • Verify signal waveforms from function generators
  • Debug timing issues in digital circuits
  • Measure frequency and duty cycle of signals
  • Observe real-time behavior of sensor outputs

Key Specifications

ParameterValue
Bandwidth100 MHz
Channels4
Sample Rate1 GSa/s
Display8-inch TFT color LCD
Input Impedance1 MΩ
Probe Attenuation1X / 10X

Main Parts

Display – color screen showing waveforms, grid, and measurements

Channel Inputs (CH1–CH4) – BNC connectors where probes are connected

Rotary Knobs – adjust vertical scale (V/div) and horizontal scale (time/div)

Trigger Controls – set the conditions for when the oscilloscope begins capturing

AUTOSET Button – automatically configures settings to display a stable waveform

RUN/STOP Button – starts or freezes the waveform capture

Probes – connect to circuit points; typically have a 1X/10X switch


How to Use (Basic Signal Measurement)

1. Calibrate the probe (before measuring)

Purpose: compensate the probe to ensure accurate measurements

Steps:

  1. Connect probe to CH1 input
  2. Attach probe tip to the built-in 5V calibration output on the oscilloscope panel
  3. Clip the ground lead to the adjacent GND terminal
  4. Press AUTOSET — the oscilloscope will automatically scale and display a square wave
  5. Check that the square wave has flat tops and sharp edges
    • Rounded corners → under-compensated, adjust probe trimmer
    • Peaked/spiky corners → over-compensated, adjust probe trimmer

✅ A properly calibrated probe shows a clean, flat-topped square wave


2. Measure a signal

Purpose: observe and analyze a waveform from a circuit

Steps:

  1. Connect probe ground clip to circuit GND
  2. Touch probe tip to the signal point
  3. Press AUTOSET for automatic scaling
  4. Use V/div knob to adjust vertical zoom
  5. Use time/div knob to adjust horizontal zoom
  6. Read frequency, period, and amplitude from the on-screen measurements

3. Measure PWM / Duty Cycle

Purpose: verify PWM output percentage from a microcontroller

Steps:

  1. Connect probe to the PWM output pin
  2. Press AUTOSET
  3. Enable on-screen measurements: frequency, period, duty cycle (+Width)
  4. Compare measured duty cycle to expected value

What We Did — XIAO RP2040 Function Generator

We used a Seeed Studio XIAO RP2040 microcontroller as a simple software-defined function generator, outputting waveforms via its PWM peripheral. The oscilloscope was used to visualize and verify each waveform.

Setup

  1. Connected oscilloscope probe to the 5V calibration output on the oscilloscope
  2. Pressed AUTOSET to calibrate and verify probe compensation
  3. Connected CH1 probe to the PWM output pin of the XIAO RP2040
  4. Connected probe ground to the board's GND

Wiring Schematic

XIAO RP2040 Wiring Schematic


XIAO RP2040 Code

cpp
/*
  PWM Signal Generator — Seeed Studio XIAO RP2040
  ================================================
  Libraries needed (install via Arduino Library Manager):
    - Adafruit SSD1306
    - Adafruit GFX Library

  XIAO RP2040 Wiring:
    OLED SDA  → D4 (GPIO6)   I2C
    OLED SCL  → D5 (GPIO7)   I2C
    PWM OUT   → D0 (GPIO26)  → DSO probe tip
    Up button → D1 (GPIO27)  → to GND
    Down btn  → D2 (GPIO28)  → to GND
    Sel btn   → D6 (GPIO0)   → to GND
    DSO GND   → GND pin

  Navigation:
    Home screen       : double-press SELECT → open menu
    Menu              : Up/Down scroll, SELECT to choose waveform
    Running screen    : Up/Down change frequency, double-press SELECT → back to menu
*/

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// ── OLED ──────────────────────────────────────────────────────────────────────
#define SCREEN_W   128
#define SCREEN_H    64
#define OLED_RESET  -1
Adafruit_SSD1306 display(SCREEN_W, SCREEN_H, &Wire, OLED_RESET);

// ── Pins (XIAO RP2040) ────────────────────────────────────────────────────────
#define PIN_PWM_OUT  D0   // GPIO26
#define PIN_UP       D1   // GPIO27
#define PIN_DOWN     D2   // GPIO28
#define PIN_SEL      D6   // GPIO0

// ── Waveforms & Frequencies ───────────────────────────────────────────────────
const char* WAVEFORMS[] = {"Sine", "Square", "Triangle", "Sawtooth", "Ramp Down", "Pulse 25%", "Pulse 10%"};
const int   NUM_WAVES   = 7;

const uint32_t FREQ_STEPS[] = {10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000};
const int      NUM_FREQS    = 9;

// ── State ─────────────────────────────────────────────────────────────────────
enum AppState { HOME, MENU, RUNNING };
AppState appState = HOME;

int  menuIdx  = 0;
int  waveIdx  = 0;
int  freqIdx  = 4;   // default 1 kHz

// ── LUT & Timer ───────────────────────────────────────────────────────────────
#define SAMPLES 64
uint16_t lut[SAMPLES];
volatile int lutPos = 0;

// RP2040 has hardware PWM slice — we use analogWrite + repeating timer
struct repeating_timer waveTimer;

bool timerCallback(struct repeating_timer* t) {
  analogWrite(PIN_PWM_OUT, lut[lutPos] >> 8);  // scale 16-bit → 8-bit (0-255)
  lutPos = (lutPos + 1) % SAMPLES;
  return true;
}

void buildLut(int wave) {
  for (int i = 0; i < SAMPLES; i++) {
    float t = (float)i / SAMPLES;   // 0.0 … <1.0
    float v = 0.5f;
    switch (wave) {
      case 0: v = (sinf(2 * PI * t) + 1.0f) / 2.0f; break;          // Sine
      case 1: v = (t < 0.5f)  ? 1.0f : 0.0f;         break;          // Square
      case 2: v = (t < 0.5f)  ? 2*t  : 2-2*t;        break;          // Triangle
      case 3: v = t;                                   break;          // Sawtooth
      case 4: v = 1.0f - t;                            break;          // Ramp Down
      case 5: v = (t < 0.25f) ? 1.0f : 0.0f;          break;          // Pulse 25%
      case 6: v = (t < 0.10f) ? 1.0f : 0.0f;          break;          // Pulse 10%
    }
    lut[i] = (uint16_t)(v * 65535);
  }
}

void startWave(int wave, uint32_t freq) {
  cancel_repeating_timer(&waveTimer);
  lutPos = 0;
  buildLut(wave);
  // Period in µs: 1,000,000 / (freq * SAMPLES)
  int32_t period_us = (int32_t)(1000000L / ((long)freq * SAMPLES));
  if (period_us < 1) period_us = 1;
  add_repeating_timer_us(-period_us, timerCallback, NULL, &waveTimer);
}

void stopWave() {
  cancel_repeating_timer(&waveTimer);
  analogWrite(PIN_PWM_OUT, 0);
}

// ── Display helpers ───────────────────────────────────────────────────────────
void drawHome() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(8, 0);  display.print("PWM Generator");
  display.drawFastHLine(0, 10, 128, SSD1306_WHITE);
  display.setCursor(0, 20); display.print("Double-press SEL");
  display.setCursor(16,32); display.print("to open menu");
  display.setCursor(0, 52); display.print("OUT:D0   GND:GND");
  display.display();
}

void drawMenu(int idx) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(16, 0); display.print("< Waveform >");
  display.drawFastHLine(0, 10, 128, SSD1306_WHITE);

  int visible = 4;
  int start   = (idx >= visible) ? idx - visible + 1 : 0;
  for (int row = 0; row < visible && (start + row) < NUM_WAVES; row++) {
    int wi = start + row;
    int y  = 14 + row * 12;
    if (wi == idx) {
      display.fillRect(0, y - 1, 128, 11, SSD1306_WHITE);
      display.setTextColor(SSD1306_BLACK);
      display.setCursor(4, y); display.print(WAVEFORMS[wi]);
      display.setTextColor(SSD1306_WHITE);
    } else {
      display.setCursor(4, y); display.print(WAVEFORMS[wi]);
    }
  }
  display.display();
}

// Mini waveform preview (60px wide, 20px tall)
void drawPreview(int wave, int xOff, int yOff, int w = 60, int h = 20) {
  for (int x = 0; x < w; x++) {
    float t = (float)x / w;
    float v = 0.5f;
    switch (wave) {
      case 0: v = (sinf(2 * PI * t) + 1.0f) / 2.0f; break;
      case 1: v = (t < 0.5f)  ? 1.0f : 0.0f;         break;
      case 2: v = (t < 0.5f)  ? 2*t  : 2-2*t;        break;
      case 3: v = t;                                   break;
      case 4: v = 1.0f - t;                            break;
      case 5: v = (t < 0.25f) ? 1.0f : 0.0f;          break;
      case 6: v = (t < 0.10f) ? 1.0f : 0.0f;          break;
    }
    int y = yOff + (int)((1.0f - v) * (h - 1));
    display.drawPixel(xOff + x, y, SSD1306_WHITE);
  }
}

String freqLabel(uint32_t freq) {
  if (freq >= 1000) {
    if (freq % 1000 == 0)
      return String(freq / 1000) + "kHz";
    else
      return String(freq / 1000.0f, 1) + "kHz";
  }
  return String(freq) + "Hz";
}

void drawRunning(int wave, uint32_t freq) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0); display.print(WAVEFORMS[wave]);
  display.drawFastHLine(0, 10, 128, SSD1306_WHITE);
  drawPreview(wave, 34, 13);
  display.drawFastHLine(0, 35, 128, SSD1306_WHITE);
  display.setCursor(0, 39); display.print("Freq: " + freqLabel(freq));
  display.setCursor(0, 52); display.print("U/D:freq");
  display.setCursor(68,52); display.print("2xSEL:menu");
  display.display();
}

// ── Button debounce & double-press detection ──────────────────────────────────
#define DEBOUNCE_MS  50
#define DOUBLE_MS   400

unsigned long lastSelMs = 0;
int           selCount  = 0;

// Returns: 'U'=up, 'D'=down, 'S'=single-sel, '2'=double-sel, 0=nothing
char readButtons() {
  if (digitalRead(PIN_UP) == LOW) {
    delay(DEBOUNCE_MS);
    while (digitalRead(PIN_UP) == LOW);
    return 'U';
  }
  if (digitalRead(PIN_DOWN) == LOW) {
    delay(DEBOUNCE_MS);
    while (digitalRead(PIN_DOWN) == LOW);
    return 'D';
  }
  if (digitalRead(PIN_SEL) == LOW) {
    delay(DEBOUNCE_MS);
    while (digitalRead(PIN_SEL) == LOW);
    unsigned long now = millis();
    if (selCount == 1 && (now - lastSelMs) < DOUBLE_MS) {
      selCount  = 0;
      lastSelMs = 0;
      return '2';           // double-press
    } else {
      selCount  = 1;
      lastSelMs = now;
      return 0;             // wait to see if double
    }
  }
  // Single-press timeout
  if (selCount == 1 && (millis() - lastSelMs) > DOUBLE_MS) {
    selCount = 0;
    return 'S';
  }
  return 0;
}

// ── Setup ─────────────────────────────────────────────────────────────────────
void setup() {
  // Buttons — input pull-up
  pinMode(PIN_UP,   INPUT_PULLUP);
  pinMode(PIN_DOWN, INPUT_PULLUP);
  pinMode(PIN_SEL,  INPUT_PULLUP);
  pinMode(PIN_PWM_OUT, OUTPUT);

  // I2C on XIAO RP2040: SDA=D4(GPIO6), SCL=D5(GPIO7)
  Wire.setSDA(D4);
  Wire.setSCL(D5);
  Wire.begin();

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    // OLED init failed — halt
    while (true);
  }

  display.clearDisplay();
  display.display();
  drawHome();
}

// ── Loop ──────────────────────────────────────────────────────────────────────
void loop() {
  char btn = readButtons();

  // ── HOME ──────────────────────────────────────────────────────────────────
  if (appState == HOME) {
    if (btn == '2') {
      appState = MENU;
      drawMenu(menuIdx);
    }
  }

  // ── MENU ──────────────────────────────────────────────────────────────────
  else if (appState == MENU) {
    if (btn == 'U') {
      menuIdx = (menuIdx - 1 + NUM_WAVES) % NUM_WAVES;
      drawMenu(menuIdx);
    } else if (btn == 'D') {
      menuIdx = (menuIdx + 1) % NUM_WAVES;
      drawMenu(menuIdx);
    } else if (btn == 'S' || btn == '2') {
      waveIdx = menuIdx;
      stopWave();
      startWave(waveIdx, FREQ_STEPS[freqIdx]);
      appState = RUNNING;
      drawRunning(waveIdx, FREQ_STEPS[freqIdx]);
    }
  }

  // ── RUNNING ───────────────────────────────────────────────────────────────
  else if (appState == RUNNING) {
    if (btn == 'U') {
      if (freqIdx < NUM_FREQS - 1) freqIdx++;
      stopWave();
      startWave(waveIdx, FREQ_STEPS[freqIdx]);
      drawRunning(waveIdx, FREQ_STEPS[freqIdx]);
    } else if (btn == 'D') {
      if (freqIdx > 0) freqIdx--;
      stopWave();
      startWave(waveIdx, FREQ_STEPS[freqIdx]);
      drawRunning(waveIdx, FREQ_STEPS[freqIdx]);
    } else if (btn == '2') {
      stopWave();
      appState = MENU;
      drawMenu(menuIdx);
    }
  }

  delay(10);
}

Waveforms Generated

The following waveforms were generated and observed on the oscilloscope:


Sine Wave

PWM-approximated sine using varying pulse widths (not a true analog sine)

Sine Wave


Square Wave

50% duty cycle, clean digital output

Square Wave


Triangle Wave

Linearly increasing then decreasing duty cycle

Triangle Wave


Ramp

Linearly increasing duty cycle only

Ramp Wave


Sawtooth

Linearly decreasing duty cycle (inverse ramp)

Sawtooth Wave


Pulse 25%

Square wave with 25% duty cycle

Pulse 25%


Pulse 10%

Narrow pulse with 10% duty cycle

Pulse 10%


Important Note on PWM-Based Waveforms

Since the XIAO RP2040 outputs digital PWM signals, non-square waveforms (sine, triangle, ramp, sawtooth) are approximations, not true analog signals. The shape is created by rapidly varying the pulse width over time — the oscilloscope time/div scale must be zoomed out enough to see the overall envelope shape rather than individual pulses.

A true sine wave requires a DAC or analog filter circuit. The PWM sine is a stepped approximation visible as a jagged or staircase-like waveform at high zoom.


Key Concepts

Time/div — controls how much time fits on screen horizontally. Lower value = zoomed in, higher value = zoomed out.

V/div — controls the voltage scale vertically. Adjust so the waveform fills ~60–80% of the screen height.

Trigger — determines when the oscilloscope starts drawing. A stable trigger = a stable waveform on screen. AUTOSET handles this automatically.

Duty Cycle — percentage of the period that the signal is HIGH. A 25% duty cycle means the signal is on for 25% and off for 75% of each cycle.


Why it is Essential

The oscilloscope is the primary tool for observing and understanding signal behavior over time. While a multimeter gives a single value, the oscilloscope reveals the full picture — shape, frequency, timing, and noise — making it indispensable for debugging analog and digital circuits, validating microcontroller outputs, and understanding real-world signal quality.


Saleae Logic 8

Saleae Logic 8 Channel Analyzer | Functionality and Usage Guide

saleae_1.jpg

The Saleae Logic 8 is a USB-connected logic analyzer and mixed-signal capture tool that lets you view and decode digital and analog electronic signals on your computer. It's widely used by embedded engineers and hobbyists to debug communication, timing, and logic problems in microcontroller-based systems.


Purpose

A logic analyzer helps determine:

  • Real-time digital signal capture across multiple channels
  • Communication protocol decoding (UART, SPI, I²C, etc.)
  • Timing relationships between signals
  • Waveform patterns and signal transitions
  • Data transmission sequences in embedded systems

FabAcademy uses:

  • Debug serial communication (UART) between microcontrollers
  • Analyze I²C display communication
  • Capture and decode multi-channel digital protocols
  • Troubleshoot timing issues in embedded systems
  • Understand real-world communication protocols

Specifications

ParameterValue
Channels8 Digital + 1 Analog
Sample RateUp to 100 MHz
MemoryDeep capture buffer
Analog Bandwidth5 MHz
Voltage Range1.8V to 5.5V
ConnectivityUSB 2.0
Protocol SupportUART, SPI, I²C, CAN, etc.

Main Parts

USB Port – connects to computer for data transmission and power

Channel Inputs (CH1–CH8 Digital) – where test probes attach for signal capture

Analog Input – dedicated analog channel for mixed-signal measurements

LED Indicators – show capture status and connection state

Logic Probes – connect to circuit test points; include ground reference

Software Interface – powerful Saleae Logic software for analysis and visualization


How to Use (Basic UART Capture)

Step 1: Connect the Analyzer

  1. Plug the Saleae Logic 8 into your computer via USB
  2. Open the Saleae Logic software
  3. Connect the ground probe to system GND
  4. Connect digital probes to TX/RX pins of the UART

Purpose: establish communication between the logic analyzer and your circuit


Step 2: Configure Capture Settings

Steps:

  1. Select the channels you want to capture (CH1 for TX, CH2 for RX)
  2. Set Sample Rate: 9600 for UART, use at least 10× the baud rate
  3. Click Start to begin capturing

Example for 9600 baud UART:

  • Minimum sample rate: 96 kHz
  • Recommended: 1-10 MHz

Step 3: Analyze with Protocol Decoder

Purpose: automatically decode the captured digital signals

Steps:

  1. From the Analyzer dropdown, select Async Serial (UART)
  2. Configure settings:
    • Baud Rate: 9600
    • Bits: 8
    • Stop Bits: 1
    • Parity: None
  3. The software displays decoded ASCII data
Example UART Capture

saleae_2.jpg

saleae_3.jpg

Data transmitted: "hello world!"

  • Transmitted every 2 seconds (matches code delay)
  • Each character appears as a distinct burst in the capture
  • Decoded to ASCII: 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!'

Setting Up UART on XIAO RP2040

Arduino Code Example

cpp
void setup() {
  Serial1.begin(9600);  // Hardware UART
  delay(1000);
}

void loop() {
  Serial1.println("hello world!");
  delay(2000);  // Transmit every 2 seconds
}

Why Serial1?

  • Serial (USB) is for debugging/monitoring
  • Serial1 (Hardware UART) transmits via TX/RX pins for external analysis

saleae_5.jpg


Decoding UART Data

Bit Order

UART transmits data Least Significant Bit (LSB) first

Example: Character 'o' (ASCII 111)

LSB order (transmitted): 11110110 MSB order (interpretation): 01101111

Binary: 0b01101111 Hex: 0x6F ASCII: 'o'

saleae_6.jpg


Understanding I²C Communication

I²C Protocol Overview

I²C uses two lines: SDA (data) and SCL (clock)

Protocol Sequence:

  1. START Condition – SDA goes low while SCL is high
  2. Address Byte – 7-bit device address + 1-bit R/W flag = 8-bit value
  3. ACK/NACK – Receiver acknowledges receipt
  4. Data Bytes – Actual data transmission
  5. STOP Condition – SDA goes high while SCL is high

Example: SSD1306 OLED Display (I²C Device)

  • 7-bit Address: 0x3C
  • Write Operation: Address left-shifted + R/W bit = 0x78
  • Open-drain bus: idle high due to pull-up resistors

Arduino Code for OLED Display

cpp
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

void setup() {
  Wire.begin();                           // SDA=D4, SCL=D5
  Wire.setClock(400000);                  // Fast mode I²C
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0, 0);
  display.println("Hello Saleae!");
  display.display();
}

void loop() {
}

Analyzing I²C Traffic in Saleae Logic

Step 1: Configure I²C Analyzer
  1. Select I²C from the Analyzer dropdown
  2. Set SDA Channel and SCL Channel
  3. Saleae automatically decodes the protocol
Step 2: Interpret the Capture

saleae_7.jpg

saleae_8.jpg

saleae_9.jpg

Transaction breakdown:

  • START → Address (0x78) → ACK → Control Byte (0x40) → ACK → Data Bytes → STOP
  • Data bytes represent pixel information for the display
  • Raw hex values shown instead of ASCII (unlike UART)

Understanding I²C Addressing

7-bit to 8-bit Address Conversion:

Given: 7-bit address 0x3C (binary: 0111100)

For Write Operation:

  • Left-shift: 01111000
  • R/W bit = 0 (write)
  • Result: 0x78

Bus Sequence: START → 0x78 → ACK → Data → STOP

Key Points:

  • Master always transmits 8-bit address on the bus
  • LSB is the R/W bit (0 = write, 1 = read)
  • All devices acknowledge (or NACK) receipt of their address
  • Pull-up resistors keep bus idle high

30V/5A Programmable DC Power Supply

https://www.bkprecision.com/products/model/9123A?region_code=eu

The bench power supply available in our lab is from B&K Precision, belonging to the 912xA series.

A 30V/5A programmable DC power supply is a machine that gives controlled DC (Direct Current) voltage and current to your circuit. DC means electricity that flows in one direction, like from a battery.

Instead of powering your project circuit directly from a PC or a battery (which gives fixed voltage ), this lets you set any voltage from 0–30V, control how much current flows from 0–5A, and protect both your circuit and your PC from damage. So, when testing a project, we use this adjustable DC power supply to safely power the circuit without risking burning components or harming the computer.

Data sheet - https://bkpmedia.s3.us-west-1.amazonaws.com/downloads/manuals/en-us/912xA_manual.pdf

User manual - https://bkpmedia.s3.us-west-1.amazonaws.com/downloads/manuals/en-us/912xA_manual.pdf

powersupply1.jpg

powersupply2.jpg

(img from datasheet)

powersupply3.jpg

(img from manual)

Usage:

It is used to power and test electronic circuits safely. You can use it to run Arduino, Pico, or ESP boards, check LEDs and motors, and test the PCB you designed.

It is also helpful for debugging—if a circuit is not working, you can gradually increase the voltage and set a current limit to prevent component damage.

It is very useful for learning electronics because it helps you understand voltage, current, and Ohm’s Law while allowing safe experimentation.

Safety Information:

  • Read the manual before operating the power supply.
  • Only trained users should use this equipment.
  • Use the device as instructed in the manual, or its safety protection may not work.
  • Always connect a proper earth (ground) connection.
  • Do not touch exposed live wires or circuits when powered ON.
  • Ensure all connections are properly insulated.
  • Turn OFF, unplug, and disconnect all test leads before cleaning or servicing.
  • Repairs must be done only by qualified service personnel.
  • Follow the safety symbols and warnings shown on the instrument.

Important Features/Buttons:

V-Set:

Used to set the output voltage.

I-Set:

Used to set the current limit (protection level).

On/Off:

Turns the output ON or OFF.

(Always keep it OFF before connecting the circuit.)

Knob:

Used to adjust values by rotating.

Numeric Key: Used to directly enter the required voltage or current value. If you type something wrong, press ESC to clear it, then re-enter the correct value.

🔴 Red Terminal (+)

Positive output (connect to circuit +).

Black Terminal (–)

Negative output (connect to circuit GND).

Usually, the circuit ground (GND) is connected here.

🟢 Green Terminal (⏚)

Earth/ ground reference.

Used for safety grounding, not normally needed for basic circuit testing.

Current Limit:

The current limit is a safety protection feature. It controls the maximum amount of current that can flow to your circuit.

For example, if your LED needs only 20mA, you can set:

  • Voltage: 5V
  • Current limit: 0.05A

If there is a short circuit or mistake, the power supply will not allow more current than the limit you set. This prevents components from burning or getting damaged.

Initially, we did not properly focus on setting the current limit during testing. While documenting, we realized this mistake, even though our instructor had clearly explained.

powersupply4.jpg

Don’ts:

  • Do not short the red (+) and black (–) terminals directly.
  • Do not reverse polarity (never connect + to – wrongly).
  • Do not exceed the rated voltage of your components.
  • Do not connect polarized components incorrectly.

Our instructor demonstrated what happens when a capacitor is connected with wrong polarity — it overheated and burst like a firecracker. This shows how dangerous incorrect connections can be.

Do’s:

  • Always set the current limit first before turning ON the output.
  • Start with a low voltage and increase slowly.
  • Double-check polarity before powering the circuit.
  • Turn OFF the supply before connecting or disconnecting components.

Experiment – Powering NB6 Boy (GameBoy 2) Using Bench Power Supply

We powered Nadec’s NB6 Boy GameBoy 2 using the bench power supply to observe its current consumption.

Hardware Used:

  • Microcontroller: Seeed Studio XIAO ESP32-C6
  • Display: NeoPixel Matrix & OLED Display
  • Audio: Passive Buzzer
  • Connectivity: WiFi

We connected the negative (–) terminal of the power supply to the GND of the board and the positive (+) terminal to the VCC (5V) pin. Then we pressed V-Set and set the voltage to 5V. After setting a safe current limit, we turned the output ON.

We connected:

  • Negative (–) terminal of the power supply → GND of the board
  • Positive (+) terminalVCC (5V) of the board

powersupply5.jpg

Then we pressed V-Set and set the voltage to 5V. After setting a safe current limit, we turned the output ON.

Observation:

Once the board started running, we observed how much current it was drawing. We monitored the current while the games were running, noted the normal operating current and also checked the maximum current it reached during gameplay.

Minimum current observed immediately after connecting the device.Minimum current

Minimum current observed immediately after connecting the device.Minimum current

Maximum current observed while the device was running.

Maximum current observed while the device was running.

This experiment helped us understand the power consumption of our device and ensured that it operates safely within the required voltage and current range.

Experiment 2 – Observing Current Change with LED Brightness

In this experiment, we programmed the XIAO RP2040 so that when the button is pressed, the LED brightness increases gradually from OFF to full brightness using PWM. (Pulse Width Modulation controls brightness by turning the LED ON and OFF very quickly and changing how long it stays ON in each cycle.)

Code:

// Pin Definitions
const int buttonPin = D5;     
const int ledPin = D6;        

void setup() {
  pinMode(ledPin, OUTPUT);
  
  // Use the internal 20k ohm resistor
  // This pulls the pin HIGH by default
  pinMode(buttonPin, INPUT_PULLUP); 
}

void loop() {
  // Logic is inverted: LOW means the button is pressed
  if (digitalRead(buttonPin) == LOW) {
    
    // Fade in
    for (int brightness = 0; brightness <= 255; brightness++) {
      // If user lets go mid-fade, we stop (optional safety check)
      if (digitalRead(buttonPin) == HIGH) break; 
      
      analogWrite(ledPin, brightness);
      delay(10); 
    }
    
    // Stay at max brightness while held
    while (digitalRead(buttonPin) == LOW) {
      analogWrite(ledPin, 255);
    }
    
  } else {
    // Turn off when released
    digitalWrite(ledPin, LOW);
  }
}

Hardware Used

  • Breadboard
  • Jumper wires
  • LED (white)
  • Resistor (220Ω or 330Ω)
  • Push button
  • Seeed Studio XIAO RP2040

White LEDs need a higher forward voltage (around 3V–3.3V) compared to red LEDs (~2V). So they draw current differently and brightness changes are more noticeable when powered with 5V.

Power Connection

  • Bench Power Supply + (Red)5V / VCC of XIAO RP2040
  • Bench Power Supply – (Black)GND of XIAO RP2040

The circuit was powered using a 5V bench power supply, and we observed the current variation while the brightness was changing. The aim was to understand how LED brightness affects current consumption through real-time measurement.

Function Generator

GW Instek AFG-2125 Function Generator | Functionality and Usage Guide

A function generator is an electronic test instrument that produces various waveforms, such as sine, square, triangle, sawtooth, and pulse waves, over a range of frequencies.


Purpose

A function generator helps:

  • Generate test signals for circuit analysis
  • Simulate sensor outputs during development
  • Test frequency response of amplifiers and filters
  • Provide clock signals for digital circuits

FabAcademy uses:

  • Provide known input signals to test circuit behavior
  • Generate audio frequencies for speaker/buzzer testing
  • Create trigger signals for oscilloscope synchronization

Main Parts

Function – Press this button to toggle between wave shapes (Sine, Square, Triangle). Frequency – Press this to set the speed of the oscillation. Amplitude – Press this to control the voltage "height" (strength) of the signal. The Knob – After pressing a variable button (like Freq or Ampl), rotate the knob to increase or decrease the value. Output – Press the Output button to send the signal to your probes.

function4.jpg


How to Use (Basic Operation)

1. Setup Waveform

The interface is designed for quick adjustments using a "Select and Modify" workflow.

  1. Press Function to select the desired wave shape.
  2. Press Frequency and rotate the knob to set the speed of the oscillation.
  3. Press Amplitude and rotate the knob to set the voltage.

2. Connect Output

  1. Connect probes to the output terminal.
  2. Press the Output button to send the signal to your probes.

What We Did — Testing with a Piezoelectric Crystal

To test the capabilities of the function generator, we connected the probes to a piezoelectric crystal. Unlike an LED, which just blinks, a piezo element converts electrical signals into physical movement (vibration).

The Process: We connected the BNC-to-alligator clips from the generator's output to the positive and negative terminals of the piezo disk.

1. Low-Frequency Vibration (1Hz - 10Hz)

We initially set the frequency to 1Hz - 10Hz using a Square wave. At this range, we could physically feel the crystal "clicking" or pulsing as the voltage jumped between high and low states.

function3.jpg

2. Audible Range Test (200Hz - 2kHz)

We then rotated the knob to increase the frequency into the 200Hz - 2kHz range. The mechanical vibrations became fast enough to create audible sound waves, turning the piezo into a buzzer.

Waveform Analysis:

  • Sine Wave: Produced a smooth, pure tone.
  • Square Wave: Produced a much harsher, "buzzier" sound because of the rapid voltage transitions.
  • Triangle Wave: Produced a softer, thinner sound compared to the square wave.

Observations

By varying the amplitude, we could control the volume of the sound. By adjusting the frequency, we could change the pitch. This experiment successfully demonstrated how the AFG-2125 precisely controls the timing and strength of electrical signals to drive hardware components.



Key Learnings

  • Logic analyzers are essential for protocol debugging
  • Multiple protocols (UART, I²C, SPI) can be captured and analyzed simultaneously
  • Timing information is critical for embedded system troubleshooting
  • Automatic decoding saves time compared to manual bit interpretation
  • Understanding bus protocols is fundamental for embedded system development

Conclusion

The Saleae Logic 8 is an indispensable tool for embedded engineers. By capturing and analyzing real communication protocols (UART, I²C, SPI), you gain deep insight into how embedded systems communicate. This week's assignment demonstrated practical protocol debugging, from simple serial output to complex display communication, building strong foundational skills for future embedded system work.