diff --git a/CMakeLists.txt b/CMakeLists.txt index c61d771..840bc29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,11 +13,12 @@ add_executable(picoprom eeprom.c picoprom.c xmodem.c + i2c.c ) pico_add_extra_outputs(picoprom) -target_link_libraries(picoprom pico_stdlib) +target_link_libraries(picoprom pico_stdlib hardware_i2c) pico_enable_stdio_usb(picoprom 1) pico_enable_stdio_uart(picoprom 0) diff --git a/README.md b/README.md index 88126b2..90821f6 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,14 @@ the same arrangement that they appear on the EEPROM, to make it easy and tidy to | GP15 | 13 | D2 | | GP17 | 16 | D4 | | GND | 14 | GND | | GP16 | 15 | D3 | - +**I2C pinout** +| Pico pin | EEPROM pin | Function | +| -------- |:----------:| -------- | +| 3V3(OUT) | 8 | VCC | +| GP3 | 7 | RW | +| GP4 | 5 | SDA | +| GP5 | 6 | SCL | +| GND | 4 | GND | ### Other options Depending upon preference, you could swap the CE and WE connections, or connect diff --git a/configs.c b/configs.c index cc4bfbb..c9bcf17 100644 --- a/configs.c +++ b/configs.c @@ -15,50 +15,56 @@ static picoprom_config_t gConfigs[] = { "AT28C256", 32768, - 64, 10, 1, 0, - true, false + 64, 10, 1, 0, 0, + false, true, false }, { "AT28C256F", 32768, 64, 3, 1, 0, - true, false + false, true, false }, { "AT28C64", 8192, - 0, 10, 1, 1000, - false, false + 0, 10, 1, 1000, 0, + false, false, false }, { "AT28C64B", 8192, - 64, 10, 1, 0, - true, false + 64, 10, 1, 0, 0, + false, true, false }, { "AT28C64E", 8192, - 0, 10, 1, 200, - false, false + 0, 10, 1, 200, 0, + false, false, false }, { "AT28C16", 2048, - 0, 10, 1, 1000, - false, false + 0, 10, 1, 1000, 0, + false, false, false }, { "AT28C16E", 2048, - 0, 10, 1, 200, - false, false + 0, 10, 1, 200, 0, + false, false, false }, { "M28C16", 2048, - 64, 3, 1, 0, - true, false + 64, 5, 1, 100, 0, + false, true, false + }, + { + "AT24C04", + 1024, + 16, 3, 1, 0, 0x50, + true, true, false }, { NULL @@ -133,7 +139,13 @@ static command_t gCommands[] = { 'p', "return to programming mode", NULL }, { 0 } }; - +uint8_t getKey(void) { // hardware-independent wrapper + uint8_t ch_read; + do { + ch_read = getchar_timeout_us(0); // 4 tries per 87 uSec char window at 115200 bps + } while ((ch_read == '\0') || (ch_read == 0xff)); + return ch_read; +} void change_settings() { @@ -157,7 +169,7 @@ void change_settings() printf("\n"); printf("?"); - int c = getchar(); + int c = getKey(); for (int i = 0; gCommands[i].key; ++i) { if (c == gCommands[i].key) diff --git a/configs.h b/configs.h index 4163356..2a55c50 100644 --- a/configs.h +++ b/configs.h @@ -4,7 +4,7 @@ #pragma once #include - +#include typedef struct { @@ -14,6 +14,8 @@ typedef struct int pageDelayMs; int pulseDelayUs; int byteDelayUs; + int i2cAddress; + bool i2c; bool writeProtect; bool writeProtectDisable; } picoprom_config_t; @@ -26,6 +28,7 @@ void init_settings(); void show_settings(); void change_settings(); +uint8_t getKey(void); #endif diff --git a/i2c.c b/i2c.c new file mode 100644 index 0000000..a3a751f --- /dev/null +++ b/i2c.c @@ -0,0 +1,96 @@ +#include "eeprom.h" +#include "configs.h" + +#include +#include + +#include "hardware/gpio.h" +#include "hardware/i2c.h" +#include "pico/binary_info.h" +#include "pico/stdlib.h" + +#define RW 3 + + +static int i2c_writeByte(uint8_t word_address, uint8_t *data){ + int address = gConfig.i2cAddress; + int ret; + if (gConfig.writeProtect){ + gpio_put(RW,1); + gpio_put(RW,0); + } + ret = i2c_write_blocking(i2c_default, address, data, 2, false); + return ret; + +} + +static int i2c_readByte(uint8_t word_address, uint8_t *data){ + int address = gConfig.i2cAddress; + int ret; + gpio_put(RW,1); + ret = i2c_write_blocking(i2c_default, address, &word_address, 1, true); + gpio_put(RW, 0); + ret = i2c_read_blocking(i2c_default, address, data, 1, false); + + return ret; +} + + +void i2c_eeprom_writeImage(const uint8_t* buffer, size_t size){ + if (gConfig.writeProtect){ + gpio_put(RW,1); + gpio_put(RW,0); + } + + int pageSize = gConfig.pageSize; + int address = gConfig.i2cAddress; + + for(int i = 0; i < size/16; i++){ + uint8_t* page = (uint8_t*)malloc(pageSize + 1); + + for(int j = 0; j <= pageSize;j++){ + if(j == 0){ + page[0] = i*pageSize; + }else{ + page[j] = buffer[i+(j-1)]; + } + + } + if(i != 0 && page[0] == 0x00){ + address = address + 0x01; + } + i2c_write_blocking(i2c_default, address ,page, 16+1, false); + free(page); + sleep_ms(gConfig.pageDelayMs); + + } +} + +int i2c_eeprom_readImage(uint8_t* buffer, size_t size){ + int ret; + ret = i2c_read_blocking(i2c_default, gConfig.i2cAddress, buffer, size, false); + return ret; +} + +bool i2c_eeprom_init(){ + int ret; + uint8_t rxdata; + bool EEPROMPresent = false; + + i2c_init(i2c_default, 200 * 1000); + gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C); + gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C); + bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C)); + gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN); + gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN); + gpio_init(RW); + gpio_set_dir(RW, GPIO_OUT); + gpio_put(RW, 0); + + ret = i2c_read_blocking(i2c_default, gConfig.i2cAddress, &rxdata, 1, false); //Dummy read to check if the EEPROM is responding + if(ret >0){ + EEPROMPresent = true; + } + return EEPROMPresent; + +} \ No newline at end of file diff --git a/i2c.h b/i2c.h new file mode 100644 index 0000000..fb79b73 --- /dev/null +++ b/i2c.h @@ -0,0 +1,18 @@ +#ifndef INCLUDED_I2C_H +#define INCLUDED_I2C_H + +#pragma once + +#include +#include +#include + +bool i2c_eeprom_init(); + +void i2c_eeprom_writeImage(const uint8_t* buffer, size_t size); +int i2c_eeprom_readImage(uint8_t* buffer, size_t size); + +static int i2c_readByte(uint8_t word_address, uint8_t *data); +static int i2c_writeByte(uint8_t word_address, uint8_t *data); + +#endif diff --git a/picoprom.c b/picoprom.c index 71b910e..60c26eb 100644 --- a/picoprom.c +++ b/picoprom.c @@ -9,13 +9,13 @@ #include "configs.h" #include "xmodem.h" #include "eeprom.h" - +#include "i2c.h" static bool setup() { bi_decl(bi_program_description("PicoPROM - EEPROM programming tool")); - bool eepromOk = eeprom_init(); + stdio_init_all(); @@ -23,11 +23,7 @@ static bool setup() printf("\nUSB Serial connected\n"); - if (!eepromOk) - { - printf("ERROR: no pin was mapped to Write Enable (ID 15)\n"); - return false; - } + init_settings(); @@ -79,6 +75,27 @@ void loop() char buffer[65536]; int sizeReceived = xmodem_receive(buffer, sizeof buffer, NULL, input_handler); + + bool eepromOk = false; + if(gConfig.i2c){ + eepromOk = i2c_eeprom_init(); + if (!eepromOk) + { + printf("Device not connected.\n"); + printf("Press any key and try again"); + getKey(); + } + }else{ + eepromOk = eeprom_init(); + if (!eepromOk) + { + printf("ERROR: no pin was mapped to Write Enable (ID 15)\n"); + printf("Press any key and try again"); + getKey(); + } + + } + if (sizeReceived < 0) { xmodem_dumplog(); @@ -102,7 +119,13 @@ void loop() } printf("Writing to EEPROM...\n"); - eeprom_writeImage(buffer, sizeReceived); + + if(gConfig.i2c){ + i2c_eeprom_writeImage(buffer, sizeReceived); + }else{ + eeprom_writeImage(buffer, sizeReceived); + } + printf("\n"); printf("Done\n"); @@ -111,6 +134,8 @@ void loop() int main() { + + if (!setup()) return -1;