├── LICENSE ├── README.md ├── documentation ├── EEPROM_pic1.jpg ├── EEPROM_pic2.png ├── EEPROM_pic3.png ├── EEPROM_pic4.png ├── EEPROM_pic5.jpg ├── EEPROM_pic6.jpg ├── EEPROM_pic7.jpg └── EEPROM_pic8.jpg ├── hardware ├── EEPROM_programmer_BOM_v1.0.tsv ├── EEPROM_programmer_gerber_v1.0.zip └── EEPROM_programmer_schematic_v1.0.pdf └── software ├── atmega328p ├── EEPROM_Programmer_m328p.ino ├── eeprom_programmer_m328p.hex └── makefile ├── atmega8 ├── EEPROM_Programmer_m8.ino ├── eeprom_programmer_m8.hex └── makefile └── python ├── bin2eeprom.py ├── eeprom.py ├── eeprom2bin.py ├── eepromcmd.py ├── eepromgui.py ├── finddevice.py └── readme.txt /LICENSE: -------------------------------------------------------------------------------- 1 | This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. 2 | To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send 3 | a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Parallel EEPROM Programmer based on ATmega8 2 | Parallel EEPROM Programmer for 28C64B and 28C256 featuring: 3 | - GUI-based front-end written in Python 4 | - Possibility to access the programmer via a serial monitor 5 | - Hardware SPI with 8 Mbps to control address bus via shift registers 6 | - Hardware UART with 1 Mbps for data transfer to/from PC via USB 2.0 7 | - Utilizing the fast page write mode of the EEPROM 8 | - Binary data transmission 9 | 10 | ![EEPROM_pic1.jpg](https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/master/documentation/EEPROM_pic1.jpg) 11 | 12 | - Project Video (YouTube): https://youtu.be/FkSXgdC_ToQ 13 | - Design Files (EasyEDA): https://easyeda.com/wagiminator/y-atmega-eeprom-programmer 14 | 15 | # Hardware 16 | The heart of the EEPROM programmer is an ATmega8 microcontroller. The address bus of the EEPROM (up to 15 bit) is controlled via two daisy-chained 74HC595 shift registers using hardware SPI @ 8 Mbps. The data bus is controlled directly via the pins of the ATmega. Address and data bus are simultaneously driven to achieve the maximum data transfer rate. The data connection to the PC runs via the hardware UART interface of the ATmega transfering the data in binary format with up to 1 Mbps. A CH330N (or CH340N) converts the serial data for USB 2.0. 17 | 18 | # 28C64B and 28C256 EEPROMs 19 | This EEPROM is a high-performance electrically erasable and programmable read-only memory. The device offers access times to 150 ns with power dissipation of just 440 mW. When the device is deselected, the CMOS standby current is less than 200 μA. 20 | The EEPROM is accessed like a Static RAM for the read or write cycle without the need for external components. The device contains a 64-byte page register to allow writing of up to 64 bytes simultaneously. The end of a write cycle can be detected by data polling. Once the end of a write cycle has been detected a new access for a read or write can begin. 21 | An optional software data protection mechanism is available to guard against inadvertent writes. The EEPROM is ideally suited to replace (E)EPROMs in old 8-bit computers. 22 | 23 | ![EEPROM_pic4.png](https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/master/documentation/EEPROM_pic4.png) 24 | 25 | ## Read Access 26 | The EEPROM is accessed like a Static RAM. When !CE and !OE are low and !WE is high, the data stored at the memory location determined by the address pins is asserted on the outputs. The outputs are put in the high impedance state when either !CE or !OE is high. 27 | 28 | ## Write Access 29 | A low pulse on the !WE or !CE input with !CE or !WE low (respectively) and !OE high initiates a write cycle. The address is latched on the falling edge of !CE or !WE, whichever occurs last. The data is latched by the first rising edge of !CE or !WE. Once a byte write has been started it will automatically time itself to completion. 30 | The page write operation allows 1 to 64 bytes of data to be written into the device during a single internal programming period. A page write operation is initiated in the same manner as a byte write; the first byte written can then be followed by 1 to 63 additional 31 | bytes. Each successive byte must be written within 150 μs of the previous byte. All bytes during a page write operation must reside on the same page as defined by the state of the A6 - A14 inputs. For each WE high to low transition during the page write operation, A6 - A14 must be the same. 32 | The A0 to A5 inputs are used to specify which bytes within the page are to be written. The bytes may be loaded in any order and may be altered within the same load period. Only bytes which are specified for writing will be written; unnecessary cycling of other bytes within the page does not occur. 33 | 34 | ## Data Polling 35 | The EEPROM features DATA Polling to indicate the end of a write cycle. During a byte or page write cycle an attempted read of the last byte written will result in the complement of the written data to be presented on I/O7. Once the write cycle has been completed, true data is valid on all outputs, and the next write cycle may begin. DATA Polling may begin at anytime during the write cycle. 36 | In addition to DATA Polling the EEPROM provides another method for determining the end of a write cycle. During the write operation, successive attempts to read data from the device will result in I/O6 toggling between one and zero. Once the write has completed, I/O6 will stop toggling and valid data will be read. Reading the toggle bit may begin at any time during the write cycle. 37 | 38 | # Software 39 | ## Implementation 40 | On the microcontroller side, data is received via UART and written to the EEPROM according to the data sheet or vice versa. The programmer is controlled with simple commands, which are also sent via the serial interface: 41 | 42 | |Command|Function| 43 | |:-|:-| 44 | |i |Print "EEPROM Programmer" (for identification)| 45 | |v |Print firmware version| 46 | |a 0100 |Set address bus to 0100 (hex) (for test purposes)| 47 | |d 0000 7fff |Print hex dump of memory addresses 0000-7fff (hex)| 48 | |f 1000 1fff ff |Fill memory (1000-1fff) with value ff (hex)| 49 | |r 0000 3fff |Read memory addresses 0000-3fff (hex) and send as binary data| 50 | |p 0100 013f |Page write binary data to memory page 0100-013f (bytes must follow)| 51 | |l |Lock EEPROM (enable write protection)| 52 | |u |Unlock EEPROM (disable write protection)| 53 | 54 | Any serial monitor (set BAUD rate to 1000000) can be used for control from the PC. However, in order to use the full capabilities, it is recommended to use the attached Python scripts. The script "eepromgui.py" offers a simple graphical user interface and functions for reading and writing binary files as well as for displaying the EEPROM content. The scripts have only been tested on Linux, but should work on all operating systems. 55 | 56 | ![EEPROM_pic2.png](https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/master/documentation/EEPROM_pic2.png) 57 | ![EEPROM_pic3.png](https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/master/documentation/EEPROM_pic3.png) 58 | 59 | ## Compiling and Uploading 60 | ### If using the Arduino IDE 61 | - Make sure you have installed [MiniCore](https://github.com/MCUdude/MiniCore). 62 | - Go to **Tools -> Board -> MiniCore** and select **ATmega8**. 63 | - Go to **Tools** and choose the following board options: 64 | - **Clock:** External 16 MHz 65 | - **BOD:** BOD 4.0V 66 | - **Compiler LTO:** LTO enabled 67 | - **Bootloader:** No bootloader 68 | - Leave the rest at the default settings 69 | - Connect your programmer to your PC and to the ICSP header of the device. 70 | - Go to **Tools -> Programmer** and select your ISP programmer (e.g. [USBasp](https://aliexpress.com/wholesale?SearchText=usbasp)). 71 | - Go to **Tools -> Burn Bootloader** to burn the fuses. 72 | - Open EEPROM_Programmer sketch and click **Upload**. 73 | 74 | ### If using the precompiled hex-file 75 | - Make sure you have installed [avrdude](https://learn.adafruit.com/usbtinyisp/avrdude). 76 | - Connect your programmer to your PC and to the ICSP header of the device. 77 | - Open a terminal. 78 | - Navigate to the folder with the hex-file. 79 | - Execute the following command (if necessary replace "usbasp" with the programmer you use): 80 | ``` 81 | avrdude -c usbasp -p m8 -U lfuse:w:0x3f:m -U hfuse:w:0xd1:m -U flash:w:eeprom_programmer_m8.hex 82 | ``` 83 | 84 | ### If using the makefile (Linux/Mac) 85 | - Make sure you have installed [avr-gcc toolchain and avrdude](http://maxembedded.com/2015/06/setting-up-avr-gcc-toolchain-on-linux-and-mac-os-x/). 86 | - Connect your programmer to your PC and to the ICSP header of the device. 87 | - Open a terminal. 88 | - Navigate to the folder with the makefile and the Arduino sketch. 89 | - Run `PROGRMR=usbasp make install` to compile, burn the fuses and upload the firmware (change PROGRMR accordingly). 90 | 91 | ## Installing Python and Drivers 92 | Python needs to be installed on your PC in order to use the software. Most Linux distributions already include this. Windows users can follow these [instructions](https://www.pythontutorial.net/getting-started/install-python/). In addition PySerial and Tkinter (8.6 or newer) must be installed. However, these are already included in most Python installations. 93 | 94 | Windows users may also need to install a [driver](http://www.wch.cn/download/CH341SER_ZIP.html) for the CH330N/CH340N USB to serial adapter. This is not necessary for Linux or Mac users. 95 | 96 | # Operating Instructions 97 | 1. Connect the EEPROM Programmer via USB to your PC. 98 | 2. Insert your EEPROM into the ZIF socket with pin1 facing to the handle of the socket. 99 | 3. Run the eepromgui.py application. 100 | 101 | # References, Links and Notes 102 | 1. [AT28C64B Datasheet](https://ww1.microchip.com/downloads/en/DeviceDoc/doc0270.pdf) 103 | 2. [AT28C256 Datasheet](http://ww1.microchip.com/downloads/en/DeviceDoc/doc0006.pdf) 104 | 3. [ATmega8A Datasheet](https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega8A-Data-Sheet-DS40001974B.pdf) 105 | 4. [74HC595 Datasheet](https://www.diodes.com/assets/Datasheets/74HC595.pdf) 106 | 5. [CH330N Datasheet](https://datasheet.lcsc.com/szlcsc/2008191734_WCH-Jiangsu-Qin-Heng-CH330N_C108996.pdf) 107 | 108 | ![EEPROM_pic8.jpg](https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/master/documentation/EEPROM_pic8.jpg) 109 | 110 | # License 111 | ![license.png](https://i.creativecommons.org/l/by-sa/3.0/88x31.png) 112 | 113 | This work is licensed under Creative Commons Attribution-ShareAlike 3.0 Unported License. 114 | (http://creativecommons.org/licenses/by-sa/3.0/) 115 | -------------------------------------------------------------------------------- /documentation/EEPROM_pic1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/documentation/EEPROM_pic1.jpg -------------------------------------------------------------------------------- /documentation/EEPROM_pic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/documentation/EEPROM_pic2.png -------------------------------------------------------------------------------- /documentation/EEPROM_pic3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/documentation/EEPROM_pic3.png -------------------------------------------------------------------------------- /documentation/EEPROM_pic4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/documentation/EEPROM_pic4.png -------------------------------------------------------------------------------- /documentation/EEPROM_pic5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/documentation/EEPROM_pic5.jpg -------------------------------------------------------------------------------- /documentation/EEPROM_pic6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/documentation/EEPROM_pic6.jpg -------------------------------------------------------------------------------- /documentation/EEPROM_pic7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/documentation/EEPROM_pic7.jpg -------------------------------------------------------------------------------- /documentation/EEPROM_pic8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/documentation/EEPROM_pic8.jpg -------------------------------------------------------------------------------- /hardware/EEPROM_programmer_BOM_v1.0.tsv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/hardware/EEPROM_programmer_BOM_v1.0.tsv -------------------------------------------------------------------------------- /hardware/EEPROM_programmer_gerber_v1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/hardware/EEPROM_programmer_gerber_v1.0.zip -------------------------------------------------------------------------------- /hardware/EEPROM_programmer_schematic_v1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wagiminator/ATmega-EEPROM-Programmer/ee36a85d630b2070e72148dd0cfe965636504dff/hardware/EEPROM_programmer_schematic_v1.0.pdf -------------------------------------------------------------------------------- /software/atmega328p/EEPROM_Programmer_m328p.ino: -------------------------------------------------------------------------------- 1 | // Parallel EEPROM Programmer for 28C256 and 28C64B - for ATmega328P 2 | // 3 | // This version of the software implements: 4 | // - Hardware SPI with 8 Mbps to control address bus via shift registers 5 | // - Hardware UART with 1 Mbps for data transfer to/from PC via USB 2.0 6 | // - Fast page write mode 7 | // - Access via serial monitor 8 | // - Binary data transmission 9 | // 10 | // Usage examples via serial monitor (set baud rate to 1000000): 11 | // - i - print "EEPROM Programmer" (for identification) 12 | // - v - print firmware version 13 | // - a 0100 - set address bus to 0100 (hex) (for test purposes) 14 | // - d 0000 7fff - print hex dump of memory addresses 0000-7fff (hex) 15 | // - f 1000 1fff ff - fill memory (1000-1fff) with value ff (hex) 16 | // 17 | // Usage examples for binary data transmissions: 18 | // (do not use these commands via serial monitor !!!) 19 | // - r 0000 3fff - read memory addresses 0000-3fff (hex) and send as binary data 20 | // - p 0100 013f - page write binary data to memory page 0100-013f (hex) 21 | // - l - lock EEPROM (enable write protection) 22 | // - u - unlock EEPROM (disable write protection) 23 | // 24 | // Core: MiniCore (https://github.com/MCUdude/MiniCore) 25 | // Board: ATmega328 26 | // Clock: External 16 MHz 27 | // BOD: BOD 4.3V 28 | // Compiler LTO: LTO enabled 29 | // Variant: 328P / 328PA 30 | // Bootloader: No bootloader 31 | // Leave the rest on default settings. Don't forget to "Burn bootloader"! 32 | // No Arduino core functions or libraries are used. Use the makefile if 33 | // you want to compile without Arduino IDE. 34 | // 35 | // 2019 by Stefan Wagner 36 | // Project Files (EasyEDA): https://easyeda.com/wagiminator 37 | // Project Files (Github): https://github.com/wagiminator 38 | // License: http://creativecommons.org/licenses/by-sa/3.0/ 39 | 40 | 41 | // Libraries 42 | #include 43 | #include 44 | 45 | // Identifiers 46 | #define VERSION "1.0" 47 | #define IDENT "EEPROM Programmer" 48 | 49 | // Pin and port definitions 50 | #define CONTROL_REG DDRB 51 | #define CONTROL_PORT PORTB 52 | #define DATAL_REG DDRC 53 | #define DATAL_PORT PORTC 54 | #define DATAL_INPUT PINC 55 | #define DATAH_REG DDRD 56 | #define DATAH_PORT PORTD 57 | #define DATAH_INPUT PIND 58 | #define LED_REG DDRC 59 | #define LED_PORT PORTC 60 | #define CE_REG DDRC 61 | #define CE_PORT PORTC 62 | 63 | #define DATA (1<> 4); 159 | printNibble (value & 0x0f); 160 | } 161 | 162 | // Convert word into hex characters and print it via UART 163 | void printWord(uint16_t value) { 164 | printByte(value >> 8); 165 | printByte(value); 166 | } 167 | 168 | // Convert character representing a hex nibble into 4-bit value 169 | uint8_t hexDigit(char c) { 170 | if (c >= '0' && c <= '9') return c - '0'; 171 | else if (c >= 'a' && c <= 'f') return c - 'a' + 10; 172 | else if (c >= 'A' && c <= 'F') return c - 'A' + 10; 173 | else return 0; 174 | } 175 | 176 | // Convert string containing a hex byte into 8-bit value 177 | uint8_t hexByte(char* a) { 178 | return ((hexDigit(a[0]) << 4) + hexDigit(a[1])); 179 | } 180 | 181 | // Convert string containing a hex word into 16-bit value 182 | uint16_t hexWord(char* data) { 183 | return ((hexDigit(data[0]) << 12) + 184 | (hexDigit(data[1]) << 8) + 185 | (hexDigit(data[2]) << 4) + 186 | (hexDigit(data[3]))); 187 | } 188 | 189 | // ----------------------------------------------------------------------------- 190 | // Low Level Communication with EEPROM 191 | // ----------------------------------------------------------------------------- 192 | 193 | // Setup SPI for controlling shift registers for the address bus 194 | void SPI_init(void) { 195 | CONTROL_REG |= (DATA | LATCH | CLOCK); // set control pins as outputs 196 | CONTROL_PORT &= ~(DATA | LATCH | CLOCK); // set control pins low 197 | SPCR = (1<> 8; // high byte of address 204 | while (!(SPSR & (1<> 8; 214 | DATAL_PORT = (DATAL_PORT & 0b11111100) | (value & 0b00000011); 215 | while (!(SPSR & (1<100ns 225 | disableWrite; // set high to initiate write cycle 226 | } 227 | 228 | // Wait for write cycle to finish using data polling 229 | void waitWriteCycle (uint8_t writtenByte) { 230 | enableOutput; // EEPROM output enable 231 | delay125ns; // wait for output valid 232 | while (writtenByte != (readDataBus)); // wait until valid reading 233 | disableOutput; // EEPROM output disable 234 | } 235 | 236 | // Read a byte from the EEPROM at the given address 237 | uint8_t readDataByte(uint16_t addr) { 238 | enableOutput; // EEPROM output enable 239 | setAddress (addr); // set address bus 240 | delay125ns; // wait for output valid 241 | uint8_t value = readDataBus; // read data byte from data bus 242 | disableOutput; // EEPROM output disable 243 | return value; // return byte 244 | } 245 | 246 | // Write a byte to the EEPROM at the given address 247 | void writeDataByte (uint16_t addr, uint8_t value) { 248 | setDataBusWrite; // set data bus pins as output 249 | setByte (addr, value); // write byte to EEPROM 250 | setDataBusRead; // release data bus (set as input) 251 | waitWriteCycle (value); // wait for write cycle to finish 252 | } 253 | 254 | // Write up to 64 bytes; bytes have to be page aligned (28C256 and 26C64B only) 255 | void writePage (uint16_t addr, uint8_t count) { 256 | if (!count) return; // return if no bytes to write 257 | WriteLEDon; // turn on write LED 258 | setDataBusWrite; // set data bus pins as output 259 | 260 | for (uint8_t i=0; i numbers of bytes 261 | setByte (addr++, pageBuffer[i]); // to EEPROM 262 | } 263 | 264 | setDataBusRead; // release data bus (set as input) 265 | waitWriteCycle (pageBuffer[count-1]); // wait for write cycle to finish 266 | WriteLEDoff; // turn off write LED 267 | } 268 | 269 | // ----------------------------------------------------------------------------- 270 | // High Level EEPROM Functions 271 | // ----------------------------------------------------------------------------- 272 | 273 | // Write the special six-byte code to turn off software data protection 274 | void disableWriteProtection() { 275 | setDataBusWrite; // set data bus pins as output 276 | setByte (0x5555, 0xaa); // write code sequence 277 | setByte (0x2aaa, 0x55); 278 | setByte (0x5555, 0x80); 279 | setByte (0x5555, 0xaa); 280 | setByte (0x2aaa, 0x55); 281 | setByte (0x5555, 0x20); 282 | setDataBusRead; // release data bus (set as input) 283 | _delay_ms(10); // wait write cycle time 284 | } 285 | 286 | // Write the special three-byte code to turn on software data protection 287 | void enableWriteProtection() { 288 | setDataBusWrite; // set data bus pins as output 289 | setByte (0x5555, 0xaa); // write code sequence 290 | setByte (0x2aaa, 0x55); 291 | setByte (0x5555, 0xa0); 292 | setDataBusRead; // release data bus (set as input) 293 | _delay_ms(10); // wait write cycle time 294 | } 295 | 296 | // Fill specified part of EEPROM memory with the given value 297 | void fillMemory(uint16_t addr, uint16_t dataLength, uint8_t value) { 298 | uint16_t addr2; uint8_t count; // initialize variables 299 | for (uint8_t i=0; i<64; i++) pageBuffer[i] = value; // fill page buffer with value 300 | disableWriteProtection(); // disable write protection 301 | while (dataLength) { // repeat until all bytes written 302 | addr2 = addr | 0x3f; // addr2 = end of current page 303 | count = addr2 - addr + 1; // number of bytes to fill rest of page 304 | if (count > dataLength) count = dataLength; // make sure not to write too many bytes 305 | writePage (addr, count); // fill page with data 306 | addr += count; // next page address 307 | dataLength -= count; // decrease number of bytes to write 308 | } 309 | enableWriteProtection(); // enable write protection 310 | } 311 | 312 | // Read content of EEPROM and print hex dump via UART 313 | void printContents(uint16_t addr, uint16_t count) { 314 | static char ascii[17]; // buffer string 315 | ascii[16] = 0; // string terminator 316 | ReadLEDon; // turn on read LED 317 | for (uint16_t base = 0; base < count; base += 16) { 318 | printWord(base); UART_print(": "); 319 | for (uint8_t offset = 0; offset <= 15; offset += 1) { 320 | uint8_t databyte = readDataByte(addr + base + offset); 321 | if (databyte > 31 && databyte < 127) ascii[offset] = databyte; 322 | else ascii[offset] = '.'; 323 | printByte(databyte); 324 | UART_print(" "); 325 | } 326 | UART_print(" "); UART_println(ascii); 327 | } 328 | ReadLEDoff; // turn off read LED 329 | } 330 | 331 | // Read content of EEPROM and send it as binary data via UART 332 | void readBinary(uint16_t addr, uint16_t count) { 333 | ReadLEDon; 334 | while (count) { 335 | UART_write(readDataByte(addr++)); 336 | count--; 337 | } 338 | ReadLEDoff; 339 | } 340 | 341 | // Write binary data from UART to a memory page 342 | void writePageBinary(uint16_t startAddr, uint8_t count) { 343 | for (uint8_t i=0; i $(TARGET).asm 89 | 90 | size: 91 | @echo "------------------" 92 | @echo "FLASH: $(shell $(AVRSIZE) -d $(TARGET).elf | awk '/[0-9]/ {print $$1 + $$2}') bytes" 93 | @echo "SRAM: $(shell $(AVRSIZE) -d $(TARGET).elf | awk '/[0-9]/ {print $$2 + $$3}') bytes" 94 | @echo "------------------" 95 | 96 | removetemp: 97 | @echo "Removing temporary files ..." 98 | @$(CLEAN) 99 | 100 | removeelf: 101 | @echo "Removing $(TARGET).elf ..." 102 | @rm -f $(TARGET).elf 103 | -------------------------------------------------------------------------------- /software/atmega8/EEPROM_Programmer_m8.ino: -------------------------------------------------------------------------------- 1 | // Parallel EEPROM Programmer for 28C256 and 28C64B - for ATmega8(A) 2 | // 3 | // This version of the software implements: 4 | // - Hardware SPI with 8 Mbps to control address bus via shift registers 5 | // - Hardware UART with 1 Mbps for data transfer to/from PC via USB 2.0 6 | // - Fast page write mode 7 | // - Access via serial monitor 8 | // - Binary data transmission 9 | // 10 | // Usage examples via serial monitor (set baud rate to 1000000): 11 | // - i - print "EEPROM Programmer" (for identification) 12 | // - v - print firmware version 13 | // - a 0100 - set address bus to 0100 (hex) (for test purposes) 14 | // - d 0000 7fff - print hex dump of memory addresses 0000-7fff (hex) 15 | // - f 1000 1fff ff - fill memory (1000-1fff) with value ff (hex) 16 | // 17 | // Usage examples for binary data transmissions: 18 | // (do not use these commands via serial monitor !!!) 19 | // - r 0000 3fff - read memory addresses 0000-3fff (hex) and send as binary data 20 | // - p 0100 013f - page write binary data to memory page 0100-013f (hex) 21 | // - l - lock EEPROM (enable write protection) 22 | // - u - unlock EEPROM (disable write protection) 23 | // 24 | // Core: MiniCore (https://github.com/MCUdude/MiniCore) 25 | // Board: ATmega8 26 | // Clock: External 16 MHz 27 | // BOD: BOD 4.0V 28 | // Compiler LTO: LTO enabled 29 | // Bootloader: No bootloader 30 | // Leave the rest on default settings. Don't forget to "Burn bootloader"! 31 | // No Arduino core functions or libraries are used. Use the makefile if 32 | // you want to compile without Arduino IDE. 33 | // 34 | // 2019 by Stefan Wagner 35 | // Project Files (EasyEDA): https://easyeda.com/wagiminator 36 | // Project Files (Github): https://github.com/wagiminator 37 | // License: http://creativecommons.org/licenses/by-sa/3.0/ 38 | 39 | 40 | // Libraries 41 | #include 42 | #include 43 | 44 | // Identifiers 45 | #define VERSION "1.0" 46 | #define IDENT "EEPROM Programmer" 47 | 48 | // Pin and port definitions 49 | #define CONTROL_REG DDRB 50 | #define CONTROL_PORT PORTB 51 | #define DATAL_REG DDRC 52 | #define DATAL_PORT PORTC 53 | #define DATAL_INPUT PINC 54 | #define DATAH_REG DDRD 55 | #define DATAH_PORT PORTD 56 | #define DATAH_INPUT PIND 57 | #define LED_REG DDRC 58 | #define LED_PORT PORTC 59 | #define CE_REG DDRC 60 | #define CE_PORT PORTC 61 | 62 | #define DATA (1<> 4); 158 | printNibble (value & 0x0f); 159 | } 160 | 161 | // Convert word into hex characters and print it via UART 162 | void printWord(uint16_t value) { 163 | printByte(value >> 8); 164 | printByte(value); 165 | } 166 | 167 | // Convert character representing a hex nibble into 4-bit value 168 | uint8_t hexDigit(char c) { 169 | if (c >= '0' && c <= '9') return c - '0'; 170 | else if (c >= 'a' && c <= 'f') return c - 'a' + 10; 171 | else if (c >= 'A' && c <= 'F') return c - 'A' + 10; 172 | else return 0; 173 | } 174 | 175 | // Convert string containing a hex byte into 8-bit value 176 | uint8_t hexByte(char* a) { 177 | return ((hexDigit(a[0]) << 4) + hexDigit(a[1])); 178 | } 179 | 180 | // Convert string containing a hex word into 16-bit value 181 | uint16_t hexWord(char* data) { 182 | return ((hexDigit(data[0]) << 12) + 183 | (hexDigit(data[1]) << 8) + 184 | (hexDigit(data[2]) << 4) + 185 | (hexDigit(data[3]))); 186 | } 187 | 188 | // ----------------------------------------------------------------------------- 189 | // Low Level Communication with EEPROM 190 | // ----------------------------------------------------------------------------- 191 | 192 | // Setup SPI for controlling shift registers for the address bus 193 | void SPI_init(void) { 194 | CONTROL_REG |= (DATA | LATCH | CLOCK); // set control pins as outputs 195 | CONTROL_PORT &= ~(DATA | LATCH | CLOCK); // set control pins low 196 | SPCR = (1<> 8; // high byte of address 203 | while (!(SPSR & (1<> 8; 213 | DATAL_PORT = (DATAL_PORT & 0b11111100) | (value & 0b00000011); 214 | while (!(SPSR & (1<100ns 224 | disableWrite; // set high to initiate write cycle 225 | } 226 | 227 | // Wait for write cycle to finish using data polling 228 | void waitWriteCycle (uint8_t writtenByte) { 229 | enableOutput; // EEPROM output enable 230 | delay125ns; // wait for output valid 231 | while (writtenByte != (readDataBus)); // wait until valid reading 232 | disableOutput; // EEPROM output disable 233 | } 234 | 235 | // Read a byte from the EEPROM at the given address 236 | uint8_t readDataByte(uint16_t addr) { 237 | enableOutput; // EEPROM output enable 238 | setAddress (addr); // set address bus 239 | delay125ns; // wait for output valid 240 | uint8_t value = readDataBus; // read data byte from data bus 241 | disableOutput; // EEPROM output disable 242 | return value; // return byte 243 | } 244 | 245 | // Write a byte to the EEPROM at the given address 246 | void writeDataByte (uint16_t addr, uint8_t value) { 247 | setDataBusWrite; // set data bus pins as output 248 | setByte (addr, value); // write byte to EEPROM 249 | setDataBusRead; // release data bus (set as input) 250 | waitWriteCycle (value); // wait for write cycle to finish 251 | } 252 | 253 | // Write up to 64 bytes; bytes have to be page aligned (28C256 and 26C64B only) 254 | void writePage (uint16_t addr, uint8_t count) { 255 | if (!count) return; // return if no bytes to write 256 | WriteLEDon; // turn on write LED 257 | setDataBusWrite; // set data bus pins as output 258 | 259 | for (uint8_t i=0; i numbers of bytes 260 | setByte (addr++, pageBuffer[i]); // to EEPROM 261 | } 262 | 263 | setDataBusRead; // release data bus (set as input) 264 | waitWriteCycle (pageBuffer[count-1]); // wait for write cycle to finish 265 | WriteLEDoff; // turn off write LED 266 | } 267 | 268 | // ----------------------------------------------------------------------------- 269 | // High Level EEPROM Functions 270 | // ----------------------------------------------------------------------------- 271 | 272 | // Write the special six-byte code to turn off software data protection 273 | void disableWriteProtection() { 274 | setDataBusWrite; // set data bus pins as output 275 | setByte (0x5555, 0xaa); // write code sequence 276 | setByte (0x2aaa, 0x55); 277 | setByte (0x5555, 0x80); 278 | setByte (0x5555, 0xaa); 279 | setByte (0x2aaa, 0x55); 280 | setByte (0x5555, 0x20); 281 | setDataBusRead; // release data bus (set as input) 282 | _delay_ms(10); // wait write cycle time 283 | } 284 | 285 | // Write the special three-byte code to turn on software data protection 286 | void enableWriteProtection() { 287 | setDataBusWrite; // set data bus pins as output 288 | setByte (0x5555, 0xaa); // write code sequence 289 | setByte (0x2aaa, 0x55); 290 | setByte (0x5555, 0xa0); 291 | setDataBusRead; // release data bus (set as input) 292 | _delay_ms(10); // wait write cycle time 293 | } 294 | 295 | // Fill specified part of EEPROM memory with the given value 296 | void fillMemory(uint16_t addr, uint16_t dataLength, uint8_t value) { 297 | uint16_t addr2; uint8_t count; // initialize variables 298 | for (uint8_t i=0; i<64; i++) pageBuffer[i] = value; // fill page buffer with value 299 | disableWriteProtection(); // disable write protection 300 | while (dataLength) { // repeat until all bytes written 301 | addr2 = addr | 0x3f; // addr2 = end of current page 302 | count = addr2 - addr + 1; // number of bytes to fill rest of page 303 | if (count > dataLength) count = dataLength; // make sure not to write too many bytes 304 | writePage (addr, count); // fill page with data 305 | addr += count; // next page address 306 | dataLength -= count; // decrease number of bytes to write 307 | } 308 | enableWriteProtection(); // enable write protection 309 | } 310 | 311 | // Read content of EEPROM and print hex dump via UART 312 | void printContents(uint16_t addr, uint16_t count) { 313 | static char ascii[17]; // buffer string 314 | ascii[16] = 0; // string terminator 315 | ReadLEDon; // turn on read LED 316 | for (uint16_t base = 0; base < count; base += 16) { 317 | printWord(base); UART_print(": "); 318 | for (uint8_t offset = 0; offset <= 15; offset += 1) { 319 | uint8_t databyte = readDataByte(addr + base + offset); 320 | if (databyte > 31 && databyte < 127) ascii[offset] = databyte; 321 | else ascii[offset] = '.'; 322 | printByte(databyte); 323 | UART_print(" "); 324 | } 325 | UART_print(" "); UART_println(ascii); 326 | } 327 | ReadLEDoff; // turn off read LED 328 | } 329 | 330 | // Read content of EEPROM and send it as binary data via UART 331 | void readBinary(uint16_t addr, uint16_t count) { 332 | ReadLEDon; 333 | while (count) { 334 | UART_write(readDataByte(addr++)); 335 | count--; 336 | } 337 | ReadLEDoff; 338 | } 339 | 340 | // Write binary data from UART to a memory page 341 | void writePageBinary(uint16_t startAddr, uint8_t count) { 342 | for (uint8_t i=0; i $(TARGET).asm 88 | 89 | size: 90 | @echo "------------------" 91 | @echo "FLASH: $(shell $(AVRSIZE) -d $(TARGET).elf | awk '/[0-9]/ {print $$1 + $$2}') bytes" 92 | @echo "SRAM: $(shell $(AVRSIZE) -d $(TARGET).elf | awk '/[0-9]/ {print $$2 + $$3}') bytes" 93 | @echo "------------------" 94 | 95 | removetemp: 96 | @echo "Removing temporary files ..." 97 | @$(CLEAN) 98 | 99 | removeelf: 100 | @echo "Removing $(TARGET).elf ..." 101 | @rm -f $(TARGET).elf 102 | -------------------------------------------------------------------------------- /software/python/bin2eeprom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # EEPROM Programmer - bin2eeprom 4 | # 5 | # Reads binary file and writes the data to the EEPROM. 6 | # python3 bin2eeprom.py 7 | # Address must be hex value without prefix 8 | # 9 | # Usage example: 10 | # python3 bin2eeprom.py 0000 content.bin 11 | # 12 | # pySerial needs to be installed 13 | # 14 | # 2019 by Stefan Wagner 15 | 16 | import sys 17 | import os 18 | from eeprom import Programmer 19 | 20 | 21 | # functions 22 | def progress(percent=0, width=50): 23 | left = width * percent // 100 24 | right = width - left 25 | sys.stdout.write('\r[' + '#' * left + ' ' * right + '] ' + str(percent) + '%') 26 | sys.stdout.flush() 27 | 28 | 29 | # get and check command line arguments 30 | try: 31 | startAddr = int(sys.argv[1], 16) 32 | fileName = sys.argv[2] 33 | except: 34 | sys.stderr.write ('ERROR: Something wrong with the arguments\n') 35 | sys.exit(1) 36 | 37 | try: 38 | fileSize = os.stat(fileName).st_size 39 | except: 40 | sys.stderr.write ('ERROR: File not found\n') 41 | sys.exit(1) 42 | 43 | if (startAddr < 0) or (startAddr > 0x7fff): 44 | sys.stderr.write ('ERROR: Address out of range\n') 45 | sys.exit(1) 46 | 47 | if (startAddr + fileSize) > 0x8000: 48 | sys.stderr.write ('ERROR: Binary file doesn\'t fit into eeprom\n') 49 | sys.exit(1) 50 | 51 | 52 | # establish serial connection 53 | print ('Connecting to EEPROM Programmer ...') 54 | eeprom = Programmer() 55 | if not eeprom.is_open: 56 | sys.stderr.write ('ERROR: EEPROM Programmer not found\n') 57 | sys.exit(1) 58 | 59 | 60 | # open binary file 61 | print ('Opening binary file ...') 62 | try: 63 | f = open(fileName, 'rb') 64 | except: 65 | sys.stderr.write ('ERROR: Could not open file\n') 66 | ser.close() 67 | sys.exit(1) 68 | 69 | 70 | # writing binary data 71 | print ('Writing data from binary file to EEPROM ...') 72 | eeprom.unlock() 73 | 74 | datalength = fileSize 75 | byteswritten = 0 76 | addr1 = startAddr 77 | 78 | while (datalength): 79 | count = (addr1 | 0x3f) - addr1 + 1 80 | if count > datalength: 81 | count = datalength 82 | addr2 = addr1 + count - 1 83 | eeprom.sendcommand('p', addr1, addr2) 84 | eeprom.write(f.read(count)) 85 | byteswritten += count 86 | progress(byteswritten * 100 // fileSize) 87 | eeprom.readline() 88 | addr1 += count 89 | datalength -= count 90 | 91 | eeprom.lock() 92 | print ('') 93 | print (str(byteswritten) + ' bytes written') 94 | 95 | 96 | # verify written data 97 | print ('Verifying written data ...') 98 | f.seek(0) 99 | endAddr = startAddr + byteswritten - 1 100 | count = byteswritten 101 | eeprom.sendcommand ('r', startAddr, endAddr) 102 | 103 | while (count): 104 | data = eeprom.read(1) 105 | if data: 106 | if data != f.read(1): 107 | sys.stderr.write ('ERROR: Data mismatch\n') 108 | f.close() 109 | eeprom.close() 110 | sys.exit(1) 111 | count -= 1 112 | eeprom.readline() 113 | print ('Mission accomplished') 114 | 115 | 116 | # close binary file and serial connection, then exit 117 | f.close() 118 | eeprom.close() 119 | sys.exit(0) 120 | -------------------------------------------------------------------------------- /software/python/eeprom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # EEPROM Programmer - Module eeprom 4 | # 5 | # Module that contains the class Programmer which is used by the other scripts. 6 | # Programmer is inheritated from the class Serial of the pySerial module. It 7 | # provides the basic functions for communicating with the EEPROM programmer. 8 | # 9 | # pySerial needs to be installed 10 | # 11 | # 2020 by Stefan Wagner 12 | 13 | from serial import Serial 14 | from serial.tools.list_ports import comports 15 | 16 | class Programmer(Serial): 17 | def __init__(self): 18 | super().__init__(baudrate = 1000000, timeout = 1, write_timeout = 1) 19 | self.identify() 20 | 21 | def identify(self): 22 | pid = '1a86' 23 | hid = '7523' 24 | did = 'EEPROM Programmer' 25 | for p in comports(): 26 | if pid and hid in p.hwid: 27 | self.port = p.device 28 | 29 | try: 30 | self.open() 31 | except: 32 | continue 33 | 34 | try: 35 | self.sendcommand ('i') 36 | data = self.getline() 37 | except: 38 | self.close() 39 | continue 40 | 41 | if data == did: 42 | self.readline() 43 | break 44 | else: 45 | self.close() 46 | 47 | 48 | def sendcommand(self, cmd, startAddr=-1, endAddr=-1, ctrlByte=-1): 49 | if startAddr >= 0: 50 | cmd += ' %04x' % startAddr 51 | if endAddr >= 0: 52 | cmd += ' %04x' % endAddr 53 | if ctrlByte >= 0: 54 | cmd += ' %02x' % ctrlByte 55 | self.write((cmd + '\n').encode()) 56 | 57 | 58 | def getline(self): 59 | return self.readline().decode().rstrip('\r\n') 60 | 61 | 62 | def confirmation(self): 63 | return (self.getline() == 'Ready') 64 | 65 | 66 | def getversion(self): 67 | self.sendcommand ('v') 68 | version = self.getline() 69 | self.readline() 70 | return version 71 | 72 | 73 | def unlock(self): 74 | self.sendcommand('u') 75 | return self.confirmation() 76 | 77 | 78 | def lock(self): 79 | self.sendcommand('l') 80 | return self.confirmation() 81 | 82 | 83 | if __name__ == '__main__': 84 | eeprom = Programmer() 85 | if not eeprom.is_open: 86 | print('ERROR: EEPROM Programmer not found') 87 | exit(1) 88 | 89 | print('EEPROM Programmer found on ' + eeprom.port) 90 | print('Firmware version: ' + eeprom.getversion()) 91 | -------------------------------------------------------------------------------- /software/python/eeprom2bin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # EEPROM Programmer - eeprom2bin 4 | # 5 | # Reads EEPROM memory and writes the data to a .bin file. 6 | # python3 eeprom2bin.py 7 | # Addresses must be hex values without prefix 8 | # 9 | # Usage example: 10 | # python3 eeprom2bin.py 0000 03ff output.bin 11 | # 12 | # pySerial needs to be installed 13 | # 14 | # 2020 by Stefan Wagner 15 | 16 | import sys 17 | from eeprom import Programmer 18 | 19 | 20 | # get and check command line arguments 21 | try: 22 | startAddr = int(sys.argv[1], 16) 23 | endAddr = int(sys.argv[2], 16) 24 | fileName = sys.argv[3] 25 | except: 26 | sys.stderr.write('ERROR: Something wrong with the arguments\n') 27 | sys.exit(1) 28 | 29 | if not (0 <= startAddr <= endAddr <= 0x7fff): 30 | sys.stderr.write('ERROR: Something wrong with the addresses\n') 31 | sys.exit(1) 32 | 33 | count = endAddr - startAddr + 1 34 | 35 | 36 | # establish serial connection 37 | print('Connecting to EEPROM Programmer ...') 38 | eeprom = Programmer() 39 | if not eeprom.is_open: 40 | sys.stderr.write ('ERROR: EEPROM Programmer not found\n') 41 | sys.exit(1) 42 | 43 | 44 | # open output file 45 | print('Opening file for writing ...') 46 | try: 47 | f = open(fileName, 'wb') 48 | except: 49 | sys.stderr.write('ERROR: Could not open file\n') 50 | ser.close() 51 | sys.exit(1) 52 | 53 | 54 | # send command 55 | print('Sending command to EEPROM programmer ...') 56 | eeprom.sendcommand ('r', startAddr, endAddr) 57 | 58 | 59 | # receive data 60 | print('Transfering data from EEPROM to binary file ...') 61 | while (count): 62 | data = eeprom.read(1) 63 | if data: 64 | f.write(data) 65 | count -= 1 66 | 67 | if eeprom.confirmation(): 68 | print(str(endAddr - startAddr +1) + ' bytes successfully transfered to ' 69 | + fileName) 70 | else: 71 | sys.stderr.write('ERROR: Data transfer failed\n') 72 | f.close() 73 | eeprom.close() 74 | sys.exit(1) 75 | 76 | 77 | # close output file and serial connection, then exit 78 | f.close() 79 | eeprom.close() 80 | sys.exit(0) 81 | -------------------------------------------------------------------------------- /software/python/eepromcmd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # EEPROM Programmer - eepromcmd 4 | # 5 | # Sends a command to the programmer and prints the received data. 6 | # python3 eepromcmd.py [ [ []]] 7 | # 8 | # Usage examples: 9 | # python3 eepromcmd.py d 0000 7fff - print hex dump of memory addresses 0000-7fff 10 | # python3 eepromcmd.py f 1000 1fff ff - fill memory (1000-1fff) with value ff 11 | # 12 | # pySerial needs to be installed 13 | # 14 | # 2020 by Stefan Wagner 15 | 16 | import sys 17 | from eeprom import Programmer 18 | 19 | 20 | # get and check command line arguments 21 | startAddr = endAddr = ctrlByte = 0 22 | try: 23 | l = len(sys.argv) 24 | cmd = sys.argv[1] 25 | if l > 2: 26 | startAddr = abs(int(sys.argv[2], 16)) 27 | if l > 3: 28 | endAddr = abs(int(sys.argv[3], 16)) 29 | if l > 4: 30 | ctrlByte = abs(int(sys.argv[4], 16)) 31 | except: 32 | sys.stderr.write ('ERROR: Something wrong with the arguments\n') 33 | sys.exit(1) 34 | 35 | if cmd[0] not in ['i', 'v', 'a', 'd', 'f']: 36 | sys.stderr.write ('ERROR: Invalid command\n') 37 | sys.exit(1) 38 | 39 | if (startAddr > 0x7fff) or (endAddr > 0x7fff) or ctrlByte > (0xff): 40 | sys.stderr.write ('ERROR: Invalid parameters\n') 41 | sys.exit(1) 42 | 43 | 44 | # establish serial connection 45 | print('Connecting to EEPROM Programmer ...') 46 | eeprom = Programmer() 47 | if not eeprom.is_open: 48 | sys.stderr.write ('ERROR: EEPROM Programmer not found\n') 49 | sys.exit(1) 50 | 51 | 52 | # send command 53 | print ('Sending command to EEPROM programmer ...') 54 | eeprom.sendcommand (cmd, startAddr, endAddr, ctrlByte) 55 | 56 | 57 | # receive data 58 | while (1): 59 | data = eeprom.getline() 60 | if data: 61 | if data == 'Ready': 62 | break 63 | print (data) 64 | print ('Mission accomplished') 65 | 66 | 67 | # close serial connection and exit 68 | eeprom.close() 69 | sys.exit(0) 70 | -------------------------------------------------------------------------------- /software/python/eepromgui.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # EEPROM Programmer - eepromgui 4 | # 5 | # A simple GUI based on tkinter to interface with the EERPOM programmer. 6 | # 7 | # pySerial and tkinter (8.6 or newer) need to be installed 8 | # 9 | # 2020 by Stefan Wagner 10 | 11 | import os 12 | from eeprom import Programmer 13 | from tkinter import * 14 | from tkinter import messagebox, filedialog 15 | from tkinter.ttk import * 16 | 17 | 18 | class Progressbox(Toplevel): 19 | def __init__(self, root = None, title = 'Please wait !', 20 | activity = 'Doing stuff ...', value = 0): 21 | Toplevel.__init__(self, root) 22 | self.__step = IntVar() 23 | self.__step.set(value) 24 | self.__act = StringVar() 25 | self.__act.set(activity) 26 | self.title(title) 27 | self.resizable(width=False, height=False) 28 | self.transient(root) 29 | self.grab_set() 30 | Label(self, textvariable = self.__act).pack(padx = 20, pady = 10) 31 | Progressbar(self, orient = HORIZONTAL, length = 200, 32 | variable = self.__step, mode = 'determinate').pack( 33 | padx = 10, pady = 10) 34 | self.update_idletasks() 35 | 36 | def setactivity(self, activity): 37 | self.__act.set(activity) 38 | self.update_idletasks() 39 | 40 | def setvalue(self, value): 41 | self.__step.set(value) 42 | self.update_idletasks() 43 | 44 | 45 | def showContent(): 46 | eeprom = Programmer() 47 | if not eeprom.is_open: 48 | messagebox.showerror('Error', 'EEPROM Programmer not found !') 49 | return 50 | 51 | contentWindow = Toplevel(mainWindow) 52 | contentWindow.title('EEPROM memory content') 53 | contentWindow.minsize(200, 100) 54 | contentWindow.resizable(width=False, height=True) 55 | contentWindow.transient(mainWindow) 56 | contentWindow.grab_set() 57 | 58 | l = Listbox(contentWindow, font = 'TkFixedFont', height = 36, width = 72) 59 | l.pack(side='left', fill=BOTH) 60 | s = Scrollbar(contentWindow, orient = VERTICAL, command = l.yview) 61 | l['yscrollcommand'] = s.set 62 | s.pack(side='right', fill='y') 63 | 64 | startAddr = 0 65 | endAddr = eepromType.get() 66 | eeprom.sendcommand ('r', startAddr, endAddr) 67 | while (startAddr < endAddr): 68 | bytesline = '%04x: ' % startAddr 69 | asciiline = ' ' 70 | i = 16 71 | while(i): 72 | data = eeprom.read(1) 73 | if data: 74 | bytesline += '%02x ' % data[0] 75 | if (data[0] > 31) and data[0] < 127: asciiline += chr(data[0]) 76 | else: asciiline += '.' 77 | i -= 1 78 | l.insert('end', bytesline + asciiline) 79 | startAddr += 16 80 | eeprom.readline() 81 | eeprom.close() 82 | 83 | contentWindow.mainloop() 84 | contentWindow.quit() 85 | 86 | 87 | 88 | def uploadBin(): 89 | eeprom = Programmer() 90 | if not eeprom.is_open: 91 | messagebox.showerror('Error', 'EEPROM Programmer not found !') 92 | return 93 | 94 | maxAddr = eepromType.get() 95 | startAddr = 0 96 | 97 | fileName = filedialog.askopenfilename(title = "Select binary file for upload", 98 | filetypes = (("binary files","*.bin"),("all files","*.*"))) 99 | if not fileName: 100 | return 101 | 102 | try: 103 | f = open(fileName, 'rb') 104 | except: 105 | messagebox.showerror('Error', 'Could not open file !') 106 | eeprom.close() 107 | return 108 | 109 | fileSize = os.stat(fileName).st_size 110 | if (startAddr + fileSize) > (maxAddr + 1): 111 | messagebox.showerror('Error', 'Binary file doesn\'t fit into EEPROM !') 112 | f.close() 113 | eeprom.close() 114 | return 115 | 116 | progress = Progressbox(mainWindow, 'Please wait !', 'Writing data to EEPROM ...') 117 | 118 | eeprom.unlock() 119 | 120 | datalength = fileSize 121 | byteswritten = 0 122 | addr1 = startAddr 123 | while (datalength): 124 | count = (addr1 | 0x3f) - addr1 + 1 125 | if count > datalength: 126 | count = datalength 127 | addr2 = addr1 + count - 1 128 | eeprom.sendcommand('p', addr1, addr2) 129 | eeprom.write(f.read(count)) 130 | byteswritten += count 131 | progress.setvalue(byteswritten * 100 // fileSize) 132 | eeprom.readline() 133 | addr1 += count 134 | datalength -= count 135 | 136 | eeprom.lock() 137 | 138 | progress.setactivity('Verifying written data ...') 139 | f.seek(0) 140 | endAddr = startAddr + byteswritten - 1 141 | count = byteswritten 142 | eeprom.sendcommand ('r', startAddr, endAddr) 143 | 144 | while (count): 145 | data = eeprom.read(1) 146 | if data: 147 | if data != f.read(1): 148 | progress.close() 149 | messagebox.showerror('Error', 'Verification failed !') 150 | f.close() 151 | eeprom.close() 152 | return 153 | count -= 1 154 | eeprom.readline() 155 | 156 | f.close() 157 | eeprom.close() 158 | progress.destroy() 159 | messagebox.showinfo('Mission accomplished', 160 | str(byteswritten) + ' bytes successfully written !') 161 | 162 | 163 | def downloadBin(): 164 | eeprom = Programmer() 165 | if not eeprom.is_open: 166 | messagebox.showerror('Error', 'EEPROM Programmer not found !') 167 | return 168 | 169 | startAddr = 0 170 | endAddr = eepromType.get() 171 | count = endAddr - startAddr + 1 172 | 173 | fileName = filedialog.asksaveasfilename(title = "Select output file", 174 | filetypes = (("binary files","*.bin"),("all files","*.*"))) 175 | if not fileName: 176 | return 177 | 178 | try: 179 | f = open(fileName, 'wb') 180 | except: 181 | messagebox.showerror('Error', 'Could not open file !') 182 | eeprom.close() 183 | return 184 | 185 | eeprom.sendcommand ('r', startAddr, endAddr) 186 | while (count): 187 | data = eeprom.read(1) 188 | if data: 189 | f.write(data) 190 | count -= 1 191 | eeprom.readline() 192 | f.close() 193 | eeprom.close() 194 | messagebox.showinfo('Mission accomplished', 'Download completed !') 195 | 196 | 197 | 198 | 199 | mainWindow = Tk() 200 | mainWindow.title('EEPROM Programmer') 201 | mainWindow.resizable(width=False, height=False) 202 | 203 | eepromType = IntVar() 204 | eepromType.set(0x1fff) 205 | 206 | typeFrame = Frame(mainWindow, borderwidth = 2, relief = 'groove') 207 | Label(typeFrame, text = '1. Choose EEPROM type:').pack(pady = 5) 208 | Radiobutton(typeFrame, text = '28C64B ( 8k)', variable=eepromType, 209 | value = 0x1fff).pack() 210 | Radiobutton(typeFrame, text = '28C256 (32k)', variable=eepromType, 211 | value = 0x7fff).pack() 212 | typeFrame.pack(padx = 10, pady = 10, ipadx = 5, ipady = 5, fill = 'x') 213 | 214 | actionFrame = Frame(mainWindow, borderwidth = 2, relief = 'groove') 215 | Label(actionFrame, text = '2. Take your action:').pack(pady = 5) 216 | Button(actionFrame, text = 'Show EEPROM Content', command = showContent 217 | ).pack(padx = 10, fill = 'x') 218 | Button(actionFrame, text = 'Binary file to EEPROM', command = uploadBin, 219 | ).pack(padx = 10, fill = 'x') 220 | Button(actionFrame, text = 'EEPROM to binary file', command = downloadBin, 221 | ).pack(padx = 10, fill = 'x') 222 | actionFrame.pack(padx =10, ipadx = 5, ipady = 5, fill = 'x') 223 | 224 | Button(mainWindow, text = 'Exit', command = mainWindow.quit).pack(pady = 10) 225 | 226 | mainWindow.mainloop() 227 | -------------------------------------------------------------------------------- /software/python/finddevice.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # EEPROM Programmer - finddevice 4 | # 5 | # Finds the EEPROM programmer and returns the com port. The function 6 | # getPort() is used by the other scripts to detect the correct com port. 7 | # python3 finddevice.py 8 | # 9 | # pySerial needs to be installed 10 | # 11 | # 2020 by Stefan Wagner 12 | 13 | import serial 14 | import serial.tools.list_ports 15 | 16 | def getPort(): 17 | pid = '1a86' 18 | hid = '7523' 19 | did = 'EEPROM Programmer' 20 | port = None 21 | 22 | print('Searching for ' + did + ' ...') 23 | ports = list(serial.tools.list_ports.comports()) 24 | for p in ports: 25 | if pid and hid in p.hwid: 26 | try: 27 | ser = serial.Serial(p.device, 1000000, timeout = 1, write_timeout = 1) 28 | except: 29 | continue 30 | 31 | try: 32 | ser.write (b'i\n') 33 | data = ser.readline().decode().rstrip('\r\n') 34 | except: 35 | ser.close() 36 | continue 37 | 38 | if data == did: 39 | port = p.device 40 | print (did + ' found on port ' + port) 41 | ser.readline() 42 | ser.write (b'v\n') 43 | print ('Firmware version: ' + ser.readline().decode().rstrip('\r\n')) 44 | ser.readline() 45 | ser.close() 46 | break 47 | else: 48 | ser.close() 49 | 50 | if not port: 51 | print('ERROR: ' + did + ' not found') 52 | 53 | return port 54 | 55 | 56 | if __name__ == '__main__': 57 | getPort() 58 | -------------------------------------------------------------------------------- /software/python/readme.txt: -------------------------------------------------------------------------------- 1 | Python scripts for the EEPROM Programmer 2 | ======================================== 3 | These scripts can be used to interface with the EEPROM programmer. 4 | The Scripts have been tested on Linux, but they should work with other OS 5 | as well. You need to install Python 3.6+ and pySerial. For eepromgui.py 6 | you need to have tkinter 8.6+ installed. 7 | You may need to make the scripts executable. Windows users have to install 8 | CH330/340 drivers. 9 | 10 | 11 | eepromgui.py 12 | ------------ 13 | Simple GUI-based application for up- and downloading binary files. 14 | 15 | 16 | eepromcmd.py 17 | ------------ 18 | Command line skript which sends a command to the programmer and prints the 19 | received data. This can be used instead of a serial monitor. 20 | (Commands must comply with those shown in the EEPROM sketch. Addresses are 21 | always hex values without prefix.) 22 | 23 | Usage: 24 | python3 eepromcmd.py [ [ []]] 25 | 26 | Examples: 27 | python3 eepromcmd.py d 0000 7fff - print hex dump of memory addresses 0000-7fff 28 | python3 eepromcmd.py f 1000 1fff ff - fill memory (1000-1fff) with value ff 29 | 30 | 31 | eeprom2bin.py 32 | ------------- 33 | Command line skript which reads EEPROM memory and writes the binary data 34 | to a .bin file. 35 | 36 | Usage: 37 | python3 eeprom2bin.py 38 | (Addresses must be hex values without prefix) 39 | 40 | Example: 41 | python3 eeprom2bin.py 0000 03ff output.bin 42 | 43 | 44 | bin2eeprom.py 45 | ------------- 46 | Command line skript which reads binary file and writes the data to the EEPROM. 47 | 48 | Usage: 49 | python3 bin2eeprom.py 50 | (Address must be hex value without prefix) 51 | 52 | Example: 53 | python3 bin2eeprom.py 0000 content.bin 54 | 55 | 56 | eeprom.py 57 | --------- 58 | Module that contains the class Programmer which is used by the other scripts. 59 | Programmer is inheritated from the class Serial of the pySerial module. It 60 | provides the basic functions for communicating with the EEPROM programmer. 61 | 62 | 63 | finddevice.py 64 | ------------- 65 | Module that contains the function getPort() which detects the com port of the 66 | EEPROM programmer. This module is no longer used since the port detection is 67 | now handled by the Programmer class. 68 | 69 | Example: 70 | python finddevice.py 71 | --------------------------------------------------------------------------------