/**
* ECE 315 Computer Interfacing
* Assignment 3
*
* @file main.c
* @details Samples a pseudo-random analogue voltage from the `noise-maker`
* custom chip once per second using the Pico's built-in ADC (GPIO26 /
* ADC0). The 12-bit ADC result is formatted as a decimal string and
* transmitted byte-by-byte over SPI to the `my-output-display` custom
* chip, terminated with a newline so the display chip knows when to
* flush its buffer. The same value is also printed locally via
* printf() so that the Wokwi serial console shows progress.
*
* Hardware connections
* --------------------
* noise-maker OUT --> GPIO26 (ADC0)
* my-output-display:
* SCK --> GPIO18 (SPI0 SCK)
* SDI --> GPIO19 (SPI0 TX / MOSI)
* nCS --> GPIO17 (SPI0 CS, driven manually)
*
* @author Komaldeep Taggar, CCID ktaggar
* @date 2025
* @copyright 2025, University of Alberta
* @version 1.0
* @licence MIT
*/
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/spi.h"
// Pin / peripheral configuration
#define ADC_PIN 26
#define ADC_CHANNEL 0
#define SPI_PORT spi0
#define SPI_BAUDRATE 1000000
// GPIO numbers for the SPI bus
#define PIN_SCK 18
#define PIN_MOSI 19
#define PIN_CS 17
// Sample period in milliseconds (1000 ms = 1 second)
#define SAMPLE_PERIOD_MS 1000
// The following function sends a null-terminated string via SPI
static void spi_send_string(const char *str) {
gpio_put(PIN_CS, 0);
size_t len = strlen(str);
for (size_t i = 0; i < len; i++) {
uint8_t byte = (uint8_t)str[i];
spi_write_blocking(SPI_PORT, &byte, 1);
}
gpio_put(PIN_CS, 1);
}
int main(void) {
stdio_init_all();
// Setup the ADC
adc_init();
adc_gpio_init(ADC_PIN);
adc_select_input(ADC_CHANNEL);
// Setup SPI
spi_init(SPI_PORT, SPI_BAUDRATE);
// Assign SPI functions to GPIO pins
gpio_set_function(PIN_SCK, GPIO_FUNC_SPI);
gpio_set_function(PIN_MOSI, GPIO_FUNC_SPI);
// Chip-select is driven as a plain GPIO
gpio_init(PIN_CS);
gpio_set_dir(PIN_CS, GPIO_OUT);
gpio_put(PIN_CS, 1);
printf("ECE 315 Assignment 3 - noise sampler ready\n");
// Main sampling loop
while (true) {
// Read 12-bit ADC value (0 – 4095)
uint16_t raw = adc_read();
/*
* Convert to voltage. The Pico ADC reference is 3.3 V over 12 bits,
* so each count = 3.3 / 4096 V. The noise-maker outputs 0–1 V,
* which maps to the lower portion of that range.
*/
float voltage = raw * (3.3f / 4096.0f);
// Print to the serial monito
printf("main.c ADC raw=%-5u voltage=%.4f V\n", raw, voltage);
// Build the message string to forward to the display
char msg[64];
snprintf(msg, sizeof(msg), "ADC raw=%-5u voltage=%.4f V\n", raw, voltage);
// Send over SPI to my-output-display
spi_send_string(msg);
// Wait one second before the next sample
sleep_ms(SAMPLE_PERIOD_MS);
}
return 0;
}