123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584 |
- // Flash programmer
- // Tool to flash the SPI flash chip
- #define word char
- #include "data/ASCII_BW.c"
- #include "lib/math.c"
- #include "lib/stdlib.c"
- #include "lib/gfx.c"
- #define COMMAND_IDLE 0
- #define COMMAND_FLASH_READ 114 // 'r'
- #define COMMAND_FLASH_ERASE_BLOCK 101 // 'e'
- #define COMMAND_FLASH_WRITE 119 // 'w'
- #define COMMAND_FILL_BUFFER 98 // 'b'
- #define COMMAND_DONE 100 // 'd'
- #define BLOCK_SIZE 32768
- #define SECTOR_SIZE 4096
- #define PAGE_SIZE 256
- #define COMMAND_SIZE 8
- // the current command the program is busy with
- // if idle, should listen to UART for new command
- word currentCommand;
- // UART buffer that stores a single command
- word UARTbufferIndex = 0;
- word UARTbuffer[COMMAND_SIZE];
- // Buffer of a page to write
- word pageBufferIndex = 0;
- word pageBuffer[PAGE_SIZE];
- /* Description of commands:
- READ x(24bit) Bytes from address y(24bit):
- b0: 'r'
- b1: x[23:16]
- b2: x[15:8]
- b3: x[7:0]
- b4: y[23:16]
- b5: y[15:8]
- b6: y[7:0]
- b7: '\n' (indicate end of command)
- */
- void initVram()
- {
- GFX_initVram(); // clear all VRAM
- GFX_copyPaletteTable((word)DATA_PALETTE_DEFAULT);
- GFX_copyPatternTable((word)DATA_ASCII_DEFAULT);
- GFX_cursor = 0;
- }
- // Workaround for defines in ASM
- void SpiFlash_asmDefines()
- {
- asm(
- "define W5500_SPI0_CS_ADDR = 0xC02729 ; address of SPI0_CS\n"
- "define W5500_SPI0_ADDR = 0xC02728 ; address of SPI0\n"
- );
- }
- // Sets SPI0_CS low
- void SpiBeginTransfer()
- {
- asm(
- "; backup regs\n"
- "push r1\n"
- "push r2\n"
- "load32 W5500_SPI0_CS_ADDR r2 ; r2 = W5500_SPI0_CS_ADDR\n"
- "load 0 r1 ; r1 = 0 (enable)\n"
- "write 0 r2 r1 ; write to SPI0_CS\n"
- "; restore regs\n"
- "pop r2\n"
- "pop r1\n"
- );
- }
- // Sets SPI0_CS high
- void SpiEndTransfer()
- {
- asm(
- "; backup regs\n"
- "push r1\n"
- "push r2\n"
- "load32 W5500_SPI0_CS_ADDR r2 ; r2 = W5500_SPI0_CS_ADDR\n"
- "load 1 r1 ; r1 = 1 (disable)\n"
- "write 0 r2 r1 ; write to SPI0_CS\n"
- "; restore regs\n"
- "pop r2\n"
- "pop r1\n"
- );
- }
- // write dataByte and return read value
- // write 0x00 for a read
- // Writes byte over SPI0
- word SpiTransfer(word dataByte)
- {
- word retval = 0;
- asm(
- "load32 W5500_SPI0_ADDR r2 ; r2 = W5500_SPI0_ADDR\n"
- "write 0 r2 r4 ; write r4 over SPI0\n"
- "read 0 r2 r2 ; read return value\n"
- "write -4 r14 r2 ; write to stack to return\n"
- );
- return retval;
- }
- // inits SPI by enabling SPI0 and resetting the chip
- void initSPI()
- {
- // already set CS high before enabling SPI0
- SpiEndTransfer();
- // enable SPI0
- word *p = (word *) 0xC0272A; // set address (SPI0 enable)
- *p = 1; // write value
- delay(10);
- // reset to get out of continuous read mode
- SpiBeginTransfer();
- SpiTransfer(0x66);
- SpiEndTransfer();
- delay(1);
- SpiBeginTransfer();
- SpiTransfer(0x99);
- SpiEndTransfer();
- delay(1);
- SpiBeginTransfer();
- SpiTransfer(0x66);
- SpiEndTransfer();
- delay(1);
- SpiBeginTransfer();
- SpiTransfer(0x99);
- SpiEndTransfer();
- delay(1);
- }
- // Should print 0xEF as Winbond device ID, and 0x17 for W25Q128
- void readDeviceID()
- {
- SpiBeginTransfer();
- SpiTransfer(0x90);
- SpiTransfer(0);
- SpiTransfer(0);
- SpiTransfer(0);
- word manufacturer = SpiTransfer(0);
- word deviceID = SpiTransfer(0);
- SpiEndTransfer();
- char b[10];
- itoah(manufacturer, b);
- GFX_PrintConsole("Chip manufacturer: ");
- GFX_PrintConsole(b);
- GFX_PrintConsole("\n");
- GFX_PrintConsole("Chip ID: ");
- itoah(deviceID, b);
- GFX_PrintConsole(b);
- GFX_PrintConsole("\n");
- }
- void readAndPrint(word len, word addr24, word addr16, word addr8)
- {
- word l = len;
- word a24 = addr24;
- word a16 = addr16;
- word a8 = addr8;
- SpiBeginTransfer();
- SpiTransfer(0x03);
- SpiTransfer(a24);
- SpiTransfer(a16);
- SpiTransfer(a8);
- word i;
- for (i = 0; i < l; i++)
- {
- uprintc(SpiTransfer(0x00));
- }
- SpiEndTransfer();
- }
- /* Returns status register 1 2 or 3, depending on the value of reg (1, 2 or 3)
- Status register description:
- Register 1: (default: 0x0)
- b7: Status Register Protect 0
- b6: Sector Protect Bit
- b5: Top/Bottom Protect Bit
- b4: Block Protect Bit 2
- b3: Block Protect Bit 1
- b2: Block Protect Bit 0
- b1: Write Enable Latch
- b0: BUSY: Erase/Write in Progress
- Register 2: (default: 0x2)
- b7: Suspend Status
- b6: Complement Protect
- b5: Security Register Lock bit 2
- b4: Security Register Lock bit 1
- b3: Security Register Lock bit 0
- b2: Reserved
- b1: Quad Enable
- b0: Status Register Protect 1
- Register 3: (default: 0x60)
- b7: Reserved
- b6: Output Driver Strength bit 1
- b5: Output Driver Strength bit 0
- b4: Reserved
- b3: Reserved
- b2: Write Protect Selection
- b1: Reserved
- b0: Reserved
- */
- word readStatusRegister(word reg)
- {
- SpiBeginTransfer();
- if (reg == 2)
- SpiTransfer(0x35);
- else if (reg == 3)
- SpiTransfer(0x15);
- else
- SpiTransfer(0x05);
- word status = SpiTransfer(0);
- SpiEndTransfer();
- return status;
- }
- void enableWrite()
- {
- SpiBeginTransfer();
- SpiTransfer(0x06);
- SpiEndTransfer();
- }
- // Executes chip erase operation
- // TAKES AT LEAST 20 SECONDS!
- // Returns 1 on success
- word chipErase()
- {
- enableWrite();
- word status = readStatusRegister(1);
- // Check if write is enabled
- if ((status & 0x2) == 0)
- return 0;
- // Send command
- SpiBeginTransfer();
- SpiTransfer(0xC7);
- SpiEndTransfer();
- // Wait for busy bit to be 0
- status = 1;
- while((status & 0x1) == 1)
- {
- status = readStatusRegister(1);
- }
- return 1;
- }
- // Executes 32KiB block erase operation
- // Erases the 32KiB block that contains the given byte address
- // Returns 1 on success
- word blockErase(word addr24, word addr16, word addr8)
- {
- word a24 = addr24;
- word a16 = addr16;
- word a8 = addr8;
- enableWrite();
- word status = readStatusRegister(1);
- // Check if write is enabled
- if ((status & 0x2) == 0)
- return 0;
- // Send command
- SpiBeginTransfer();
- SpiTransfer(0x52);
- SpiTransfer(a24);
- SpiTransfer(a16);
- SpiTransfer(a8);
- SpiEndTransfer();
- // Wait for busy bit to be 0
- status = 1;
- while((status & 0x1) == 1)
- {
- status = readStatusRegister(1);
- }
- return 1;
- }
- // Executes 256 byte page program operation
- // The address is the byte address of the first byte to write
- // Data wraps around at the end of a page,
- // so last address byte will usually be 0
- // Returns 1 on success
- word pageProgram(word addr24, word addr16, word addr8)
- {
- word a24 = addr24;
- word a16 = addr16;
- word a8 = addr8;
- enableWrite();
- word status = readStatusRegister(1);
- // Check if write is enabled
- if ((status & 0x2) == 0)
- return 0;
- // Send command
- SpiBeginTransfer();
- SpiTransfer(0x2);
- SpiTransfer(a24);
- SpiTransfer(a16);
- SpiTransfer(a8);
- // Send page
- word *p_pageBuffer = pageBuffer;
- word i;
- for (i = 0; i < 256; i++)
- {
- SpiTransfer(*(p_pageBuffer + i));
- }
- SpiEndTransfer();
- // Wait for busy bit to be 0
- status = 1;
- while((status & 0x1) == 1)
- {
- status = readStatusRegister(1);
- }
- return 1;
- }
- void processCommand()
- {
- if (currentCommand == COMMAND_IDLE)
- {
- // do nothing
- }
- else if (currentCommand == COMMAND_FLASH_READ)
- {
- word len = UARTbuffer[1] << 16;
- len += UARTbuffer[2] << 8;
- len += UARTbuffer[3];
- word addr24 = UARTbuffer[4];
- word addr16 = UARTbuffer[5];
- word addr8 = UARTbuffer[6];
- GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 8), 0);
- GFX_printWindowColored("Reading ", 8, GFX_WindowPosFromXY(0, 8), 0);
- char b[10];
- itoa(len, b);
- GFX_printWindowColored(b, strlen(b), GFX_WindowPosFromXY(8, 8), 0);
- GFX_printWindowColored(" bytes", 6, GFX_WindowPosFromXY(8 + strlen(b), 8), 0);
- readAndPrint(len, addr24, addr16, addr8);
- GFX_printWindowColored(" done!", 5, GFX_WindowPosFromXY(8 + strlen(b) + 6, 8), 0);
- currentCommand = COMMAND_IDLE;
- uprintc('r');
- }
- else if (currentCommand == COMMAND_FLASH_ERASE_BLOCK)
- {
- word addr24 = UARTbuffer[4];
- word addr16 = UARTbuffer[5];
- word addr8 = UARTbuffer[6];
- blockErase(addr24, addr16, addr8);
- word addrCombined = ((addr24 << 16) + (addr16 << 8) + addr8) >> 15;
- GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 8), 0);
- GFX_printWindowColored("Block ", 6, GFX_WindowPosFromXY(0, 8), 0);
- char b[10];
- itoa(addrCombined, b);
- GFX_printWindowColored(b, strlen(b), GFX_WindowPosFromXY(6, 8), 0);
- GFX_printWindowColored(" erased", 7, GFX_WindowPosFromXY(6 + strlen(b), 8), 0);
- currentCommand = COMMAND_IDLE;
- uprintc('r');
- }
- else if (currentCommand == COMMAND_FLASH_WRITE)
- {
- word addr24 = UARTbuffer[4];
- word addr16 = UARTbuffer[5];
- word addr8 = UARTbuffer[6];
- pageProgram(addr24, addr16, addr8);
- word addrCombined = (addr24 << 8) + addr16;
- GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 8), 0);
- GFX_printWindowColored("Page ", 5, GFX_WindowPosFromXY(0, 8), 0);
- char b[10];
- itoa(addrCombined, b);
- GFX_printWindowColored(b, strlen(b), GFX_WindowPosFromXY(5, 8), 0);
- GFX_printWindowColored(" written", 8, GFX_WindowPosFromXY(5 + strlen(b), 8), 0);
- currentCommand = COMMAND_IDLE;
- uprintc('r');
- }
- else if (currentCommand == COMMAND_FILL_BUFFER)
- {
- // done when full page is received
- if (pageBufferIndex == PAGE_SIZE)
- {
- pageBufferIndex = 0;
- currentCommand = COMMAND_IDLE;
- uprintc('r');
- }
- }
- else if (currentCommand == COMMAND_DONE)
- {
- // notify done
- GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 6), 0);
- GFX_printWindowColored(" ", 40, GFX_WindowPosFromXY(0, 8), 0);
- GFX_printWindowColored("Done!", 5, GFX_WindowPosFromXY(0, 6), 0);
- // allow new commands, just in case
- currentCommand = COMMAND_IDLE;
- }
- }
- int main()
- {
- initVram();
- GFX_PrintConsole("Flash Programmer\n\n");
- currentCommand = COMMAND_IDLE;
- initSPI();
- GFX_PrintConsole("SPI0 mode set\n");
- readDeviceID();
- GFX_PrintConsole("\nReady to receive commands\n\n");
- // Notify that we are ready to recieve commands
- uprintc('r');
- while (1)
- {
- processCommand();
- }
- return 48;
- }
- void int1()
- {
- /*
- word *p = (word *) 0x4C0000; // set address (timer1 state)
- *p = 1; // write value
- */
- timer1Value = 1; // notify ending of timer1
- }
- void int2()
- {
-
- }
- void int3()
- {
- // UART RX interrupt
- // Fill buffer
- if (currentCommand == COMMAND_FILL_BUFFER)
- {
- // read byte
- word *p = (word *)0xC02722; // address of UART RX
- word b = *p; // read byte from UART
- // write byte to buffer, increase index
- word *p_pageBuffer = pageBuffer;
- *(p_pageBuffer + pageBufferIndex) = b;
- pageBufferIndex++;
- //uprintc('a'); // notify write to buffer is done
- }
- // Get command
- else if (currentCommand == COMMAND_IDLE)
- {
- // read byte
- word *p = (word *)0xC02722; // address of UART RX
- word b = *p; // read byte from UART
- // write byte to buffer, increase index
- word *p_UARTbuffer = UARTbuffer;
- *(p_UARTbuffer + UARTbufferIndex) = b;
- UARTbufferIndex++;
- // execute command when 8 bytes received
- if (UARTbufferIndex == COMMAND_SIZE)
- {
- currentCommand = *(p_UARTbuffer);
- UARTbufferIndex = 0;
- // notify ready to receive when filling buffer
- if (currentCommand == COMMAND_FILL_BUFFER)
- {
- uprintc('b');
- }
- }
- }
-
- }
- void int4()
- {
- }
- void interrupt()
- {
- word i = getIntID();
- if (i == 1)
- {
- int1();
- }
- else if (i == 3)
- {
- int3();
- }
- }
|