From 32849eab29ecad88b7a49452e38211027ac6b374 Mon Sep 17 00:00:00 2001 From: Jack O'Sullivan Date: Sat, 11 May 2024 03:27:05 +0100 Subject: [PATCH] Working I2C-controlled digits --- mcu/CMakeLists.txt | 2 +- mcu/main.c | 89 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 74 insertions(+), 17 deletions(-) diff --git a/mcu/CMakeLists.txt b/mcu/CMakeLists.txt index 4c8f2c9..1f2671e 100644 --- a/mcu/CMakeLists.txt +++ b/mcu/CMakeLists.txt @@ -16,4 +16,4 @@ pico_enable_stdio_usb(qclk 1) pico_enable_stdio_uart(qclk 0) pico_add_extra_outputs(qclk) -target_link_libraries(qclk pico_stdlib) +target_link_libraries(qclk pico_stdlib hardware_i2c pico_i2c_slave) diff --git a/mcu/main.c b/mcu/main.c index aafa7c8..bb78db8 100644 --- a/mcu/main.c +++ b/mcu/main.c @@ -1,27 +1,33 @@ #include #include "hardware/gpio.h" +#include "hardware/i2c.h" #include "pico/stdlib.h" #include "pico/binary_info.h" +#include "pico/i2c_slave.h" const uint PIN_DIGIT_BASE = 18; const uint PIN_SEGMENT_BASE = 2; const uint N_DIGITS = 4; -uint8_t digit_states[4] = { 0b11001100, 0b11111111, 0b10101010, 0b00101001 }; +const uint I2C_PIN_SDA = 0; +const uint I2C_PIN_SCL = 1; +const uint I2C_SLAVE_ADDRESS = 0x17; +const uint I2C_RATE = 100 * 1000; -void write_digit(uint8_t digit) { +uint8_t digit_states[4] = { 0 }; +static struct { + bool digit_written; + uint digit; +} i2c_context; + +static void write_digit(uint8_t digit) { const uint mask = (0xffffffff << PIN_SEGMENT_BASE) ^ (0xffffffff << PIN_SEGMENT_BASE + 8); gpio_put_masked(mask, (~digit & 0xff) << PIN_SEGMENT_BASE); gpio_put_masked(mask, digit << PIN_SEGMENT_BASE); } - -int main() { - bi_decl(bi_program_description("qCLK driver.")); - - stdio_init_all(); - +static void setup_io() { for (uint i = PIN_DIGIT_BASE; i < PIN_DIGIT_BASE + N_DIGITS; i++) { gpio_init(i); gpio_set_dir(i, GPIO_OUT); @@ -32,14 +38,65 @@ int main() { gpio_set_dir(i, GPIO_OUT); } write_digit(0); +} +static void display_loop() { + for (uint i = 0; i < N_DIGITS; i++) { + uint prev = i == 0 ? N_DIGITS - 1 : i - 1; - while (1) { - for (uint i = 0; i < N_DIGITS; i++) { - uint prev = i == 0 ? N_DIGITS - 1 : i - 1; - gpio_put(PIN_DIGIT_BASE + prev, 0); - write_digit(digit_states[i]); - gpio_put(PIN_DIGIT_BASE + i, 1); - sleep_ms(1); - } + gpio_put(PIN_DIGIT_BASE + prev, 0); + sleep_us(100); + + write_digit(digit_states[i]); + gpio_put(PIN_DIGIT_BASE + i, 1); + sleep_ms(1); } } + +static void i2c_slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event) { + switch (event) { + case I2C_SLAVE_RECEIVE: // master has written some data + if (!i2c_context.digit_written) { + // writes always start with the memory address + uint8_t addr = i2c_read_byte_raw(i2c); + i2c_context.digit = addr < N_DIGITS ? addr : -1; + i2c_context.digit_written = true; + } else if (i2c_context.digit != -1) { + // save into memory + digit_states[i2c_context.digit] = i2c_read_byte_raw(i2c); + } + break; + case I2C_SLAVE_REQUEST: // master is requesting data + // load from memory + uint8_t data = i2c_context.digit != -1 ? digit_states[i2c_context.digit] : 0; + i2c_write_byte_raw(i2c, data); + break; + case I2C_SLAVE_FINISH: // master has signalled Stop / Restart + i2c_context.digit_written = false; + break; + default: + break; + } +} +static void setup_i2c() { + gpio_init(I2C_PIN_SDA); + gpio_set_function(I2C_PIN_SDA, GPIO_FUNC_I2C); + gpio_pull_up(I2C_PIN_SDA); + + gpio_init(I2C_PIN_SCL); + gpio_set_function(I2C_PIN_SCL, GPIO_FUNC_I2C); + gpio_pull_up(I2C_PIN_SCL); + + i2c_init(i2c0, I2C_RATE); + // configure I2C0 for slave mode + i2c_slave_init(i2c0, I2C_SLAVE_ADDRESS, &i2c_slave_handler); +} + +int main() { + bi_decl(bi_program_description("qCLK driver.")); + + stdio_init_all(); + setup_io(); + setup_i2c(); + + while (1) display_loop(); +}