103 lines
2.6 KiB
C
103 lines
2.6 KiB
C
#include <stdio.h>
|
|
|
|
#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;
|
|
|
|
const uint I2C_PIN_SDA = 0;
|
|
const uint I2C_PIN_SCL = 1;
|
|
const uint I2C_SLAVE_ADDRESS = 0x17;
|
|
const uint I2C_RATE = 100 * 1000;
|
|
|
|
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);
|
|
}
|
|
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);
|
|
gpio_put(i, 0);
|
|
}
|
|
for (uint i = PIN_SEGMENT_BASE; i < PIN_SEGMENT_BASE + 8; i++) {
|
|
gpio_init(i);
|
|
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;
|
|
|
|
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();
|
|
}
|