velxio/test/test_custom_chips/sdk/examples/eeprom-24lc256.c

99 lines
2.6 KiB
C

/*
* eeprom-24lc256.c — 32 KB I2C EEPROM (24LC256-class).
*
* Differences vs 24C01:
* - 32 KB capacity (vs 128 bytes)
* - Two-byte address (high then low) → 16-bit address space
* - Same 7-bit base I2C address 0x50, A0/A1/A2 set the low bits.
*
* Protocol on the bus (master writes):
* 1st byte = address high
* 2nd byte = address low
* 3rd+ = data, sequential write with auto-increment
* Master reads return memory at the current pointer, auto-incrementing.
*/
#include "velxio-chip.h"
#include <stdlib.h>
#include <string.h>
#define EEPROM_BASE_ADDR 0x50
#define EEPROM_SIZE 0x8000 /* 32768 = 32 KB */
typedef enum {
ST_IDLE,
ST_HAS_HIGH,
ST_HAS_FULL_ADDRESS,
} ee_state;
typedef struct {
vx_pin a0, a1, a2, wp;
uint16_t pointer;
uint8_t mem[EEPROM_SIZE];
ee_state state;
} chip_state_t;
static bool i2c_connect(void* ud, uint8_t addr, bool is_read) {
chip_state_t* s = (chip_state_t*)ud;
if (!is_read) s->state = ST_IDLE;
return true;
}
static uint8_t i2c_read(void* ud) {
chip_state_t* s = (chip_state_t*)ud;
uint8_t b = s->mem[s->pointer & (EEPROM_SIZE - 1)];
s->pointer = (uint16_t)((s->pointer + 1) & (EEPROM_SIZE - 1));
return b;
}
static bool i2c_write(void* ud, uint8_t byte) {
chip_state_t* s = (chip_state_t*)ud;
switch (s->state) {
case ST_IDLE:
s->pointer = (uint16_t)((byte & 0x7f) << 8);
s->state = ST_HAS_HIGH;
break;
case ST_HAS_HIGH:
s->pointer = (uint16_t)((s->pointer & 0xff00) | byte);
s->state = ST_HAS_FULL_ADDRESS;
break;
case ST_HAS_FULL_ADDRESS:
s->mem[s->pointer & (EEPROM_SIZE - 1)] = byte;
s->pointer = (uint16_t)((s->pointer + 1) & (EEPROM_SIZE - 1));
break;
}
return true;
}
static void i2c_stop(void* ud) {
chip_state_t* s = (chip_state_t*)ud;
s->state = ST_IDLE;
}
void chip_setup(void) {
chip_state_t* s = (chip_state_t*)calloc(1, sizeof(chip_state_t));
s->a0 = vx_pin_register("A0", VX_INPUT);
s->a1 = vx_pin_register("A1", VX_INPUT);
s->a2 = vx_pin_register("A2", VX_INPUT);
s->wp = vx_pin_register("WP", VX_INPUT);
uint8_t addr = EEPROM_BASE_ADDR
| ((vx_pin_read(s->a2) & 1) << 2)
| ((vx_pin_read(s->a1) & 1) << 1)
| ((vx_pin_read(s->a0) & 1));
vx_i2c_config cfg = {
.address = addr,
.scl = vx_pin_register("SCL", VX_INPUT),
.sda = vx_pin_register("SDA", VX_INPUT),
.on_connect = i2c_connect,
.on_read = i2c_read,
.on_write = i2c_write,
.on_stop = i2c_stop,
.user_data = s,
};
vx_i2c_attach(&cfg);
vx_log("24LC256 EEPROM ready");
}