|  | 
|  | 1 | +#include <stdio.h> | 
|  | 2 | +#include "pico/stdlib.h" | 
|  | 3 | +#include "hardware/i2c.h" | 
|  | 4 | + | 
|  | 5 | +// This is the max number of bytes which can be written at once during a page write | 
|  | 6 | +#define MAX_PAGE_WRITE 32 | 
|  | 7 | + | 
|  | 8 | +// This is the 24LC32's capacity in bytes | 
|  | 9 | +#define EEPROM_SIZE 4096 | 
|  | 10 | + | 
|  | 11 | +// Acknowledge polling can be used to see when a write cycle is complete | 
|  | 12 | +// Wait for the i2c slave to acknowledge our empty write | 
|  | 13 | +bool ack_poll(uint8_t i2c_addr, i2c_inst_t *i2c_instance) { | 
|  | 14 | +    int timeout = 100; | 
|  | 15 | +    for (int i = 0; i < timeout; i++) { | 
|  | 16 | +        if (i2c_write_blocking(i2c_instance, i2c_addr, NULL, 1, false) == 1) { | 
|  | 17 | +            return true; | 
|  | 18 | +        } | 
|  | 19 | +        sleep_ms(1); | 
|  | 20 | +    } | 
|  | 21 | +    printf("ack timeout\n"); | 
|  | 22 | +    return false; | 
|  | 23 | +} | 
|  | 24 | + | 
|  | 25 | +// Read num bytes of memory starting at given address into result | 
|  | 26 | +bool read_eeprom(uint16_t address, uint8_t *result, uint16_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance) { | 
|  | 27 | +    if ((address + num - 1) > EEPROM_SIZE) { | 
|  | 28 | +        printf("ERROR: Tried to read memory outside EEPROM's range.\n"); | 
|  | 29 | +        return false; | 
|  | 30 | +    } | 
|  | 31 | + | 
|  | 32 | +    for (int i = 0; i < num; i++) { | 
|  | 33 | +        uint8_t byte1 = (uint8_t)(address >> 8); | 
|  | 34 | +        uint8_t byte2 = (uint8_t)(address); | 
|  | 35 | + | 
|  | 36 | +        uint8_t buf[2] = {byte1, byte2}; | 
|  | 37 | + | 
|  | 38 | +        i2c_write_blocking(i2c_instance, i2c_addr, buf, 2, true); | 
|  | 39 | +        i2c_read_blocking(i2c_instance, i2c_addr, (result + i), 1, false); | 
|  | 40 | + | 
|  | 41 | +        address++; | 
|  | 42 | +    } | 
|  | 43 | +     | 
|  | 44 | +    return true; | 
|  | 45 | +} | 
|  | 46 | + | 
|  | 47 | +// Write a single byte of data at a specified address in memory | 
|  | 48 | +bool byte_write_eeprom(uint16_t address, uint8_t data, uint8_t i2c_addr, i2c_inst_t *i2c_instance) { | 
|  | 49 | +    if (address >= EEPROM_SIZE) { | 
|  | 50 | +        printf("ERROR: Tried to write to memory outside EEPROM's range.\n"); | 
|  | 51 | +        return false; | 
|  | 52 | +    }  | 
|  | 53 | + | 
|  | 54 | +    uint8_t byte1 = (uint8_t)(address >> 8); | 
|  | 55 | +    uint8_t byte2 = (uint8_t)(address); | 
|  | 56 | + | 
|  | 57 | +    uint8_t buf[3] = {byte1, byte2, data}; | 
|  | 58 | + | 
|  | 59 | +    i2c_write_blocking(i2c_instance, i2c_addr, buf, 3, false); | 
|  | 60 | + | 
|  | 61 | +    // ack_poll to wait for write to be complete | 
|  | 62 | +    return ack_poll(i2c_addr, i2c_instance); | 
|  | 63 | +} | 
|  | 64 | + | 
|  | 65 | +// Write a block of data to eeprom  | 
|  | 66 | +bool page_write_eeprom(uint16_t address, uint8_t *data, uint8_t num, uint8_t i2c_addr, i2c_inst_t *i2c_instance) { | 
|  | 67 | +    if (num > MAX_PAGE_WRITE) { | 
|  | 68 | +        printf("ERROR: Tried to write more than %i bytes.\n", MAX_PAGE_WRITE); | 
|  | 69 | +        return false; | 
|  | 70 | +    } else if ((address + num - 1) > EEPROM_SIZE) { | 
|  | 71 | +        printf("ERROR: Tried to write to memory outside EEPROM's range.\n"); | 
|  | 72 | +        return false; | 
|  | 73 | +    } | 
|  | 74 | + | 
|  | 75 | +    uint8_t byte1 = (uint8_t)(address >> 8); | 
|  | 76 | +    uint8_t byte2 = (uint8_t)(address); | 
|  | 77 | +    uint8_t buf[2 + num]; | 
|  | 78 | +    buf[0] = byte1; | 
|  | 79 | +    buf[1] = byte2; | 
|  | 80 | + | 
|  | 81 | +    // transfer data into buffer | 
|  | 82 | +    for (int i = 0; i < num; i++) { | 
|  | 83 | +        buf[i + 2] = data[i]; | 
|  | 84 | +    } | 
|  | 85 | + | 
|  | 86 | +    i2c_write_blocking(i2c_instance, i2c_addr, buf, 2 + num, false); | 
|  | 87 | + | 
|  | 88 | +    // ack_poll to wait for write to be complete | 
|  | 89 | +    return ack_poll(i2c_addr, i2c_instance); | 
|  | 90 | +} | 
|  | 91 | + | 
|  | 92 | +// Initialise i2c for given gpio at given frequency | 
|  | 93 | +void eeprom_init(int sda_pin, int scl_pin, int freq, i2c_inst_t *i2c_instance) { | 
|  | 94 | +    i2c_init(i2c_instance, freq); | 
|  | 95 | +     | 
|  | 96 | +    gpio_set_function(sda_pin, GPIO_FUNC_I2C); | 
|  | 97 | +    gpio_set_function(scl_pin, GPIO_FUNC_I2C); | 
|  | 98 | +    gpio_pull_up(sda_pin); | 
|  | 99 | +    gpio_pull_up(scl_pin); | 
|  | 100 | +} | 
|  | 101 | + | 
0 commit comments