Prusa-Firmware/Firmware/w25x20cl.c
bubnikv eef6c68c9f Added support for a secondary boot loader, based on the OptiBoot project,
modified to update the external flash memory on Einsy boards.
Due to a bug in the USB to serial converter firmware on the Prusa Einsy
boards, the STK500 protocol has been modified to never send semicolon
characters towards the main processor.

This firmware updater is compatible with a modified avrdude using
the "arduino" protocol, see the following commit.
https://github.com/prusa3d/Slic3r/tree/fwupdater_languages
2018-06-14 15:13:21 +02:00

185 lines
4.7 KiB
C

//w25x20cl.c
#include "w25x20cl.h"
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "io_atmega2560.h"
#include "spi.h"
#define _MFRID 0xEF
#define _DEVID 0x11
#define _CMD_ENABLE_WR 0x06
#define _CMD_ENABLE_WR_VSR 0x50
#define _CMD_DISABLE_WR 0x04
#define _CMD_RD_STATUS_REG 0x05
#define _CMD_WR_STATUS_REG 0x01
#define _CMD_RD_DATA 0x03
#define _CMD_RD_FAST 0x0b
#define _CMD_RD_FAST_D_O 0x3b
#define _CMD_RD_FAST_D_IO 0xbb
#define _CMD_PAGE_PROGRAM 0x02
#define _CMD_SECTOR_ERASE 0x20
#define _CMD_BLOCK32_ERASE 0x52
#define _CMD_BLOCK64_ERASE 0xd8
#define _CMD_CHIP_ERASE 0xc7
#define _CMD_CHIP_ERASE2 0x60
#define _CMD_PWR_DOWN 0xb9
#define _CMD_PWR_DOWN_REL 0xab
#define _CMD_MFRID_DEVID 0x90
#define _CMD_MFRID_DEVID_D 0x92
#define _CMD_JEDEC_ID 0x9f
#define _CMD_RD_UID 0x4b
#define _CS_LOW() PORT(W25X20CL_PIN_CS) &= ~__MSK(W25X20CL_PIN_CS)
#define _CS_HIGH() PORT(W25X20CL_PIN_CS) |= __MSK(W25X20CL_PIN_CS)
//#define _SPI_TX swspi_tx
//#define _SPI_RX swspi_rx
#define _SPI_TX(b) spi_txrx(b)
#define _SPI_RX() spi_txrx(0xff)
int w25x20cl_mfrid_devid(void);
int8_t w25x20cl_init(void)
{
PIN_OUT(W25X20CL_PIN_CS);
_CS_HIGH();
W25X20CL_SPI_ENTER();
if (!w25x20cl_mfrid_devid()) return 0;
return 1;
}
void w25x20cl_enable_wr(void)
{
_CS_LOW();
_SPI_TX(_CMD_ENABLE_WR); // send command 0x06
_CS_HIGH();
}
void w25x20cl_disable_wr(void)
{
_CS_LOW();
_SPI_TX(_CMD_DISABLE_WR); // send command 0x04
_CS_HIGH();
}
uint8_t w25x20cl_rd_status_reg(void)
{
_CS_LOW();
_SPI_TX(_CMD_RD_STATUS_REG); // send command 0x90
uint8_t val = _SPI_RX(); // receive value
_CS_HIGH();
return val;
}
void w25x20cl_wr_status_reg(uint8_t val)
{
_CS_LOW();
_SPI_TX(_CMD_WR_STATUS_REG); // send command 0x90
_SPI_TX(val); // send value
_CS_HIGH();
}
void w25x20cl_rd_data(uint32_t addr, uint8_t* data, uint16_t cnt)
{
_CS_LOW();
_SPI_TX(_CMD_RD_DATA); // send command 0x03
_SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23
_SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15
_SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7
while (cnt--) // receive data
*(data++) = _SPI_RX();
_CS_HIGH();
}
void w25x20cl_page_program(uint32_t addr, uint8_t* data, uint16_t cnt)
{
_CS_LOW();
_SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02
_SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23
_SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15
_SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7
while (cnt--) // send data
_SPI_TX(*(data++));
_CS_HIGH();
}
void w25x20cl_page_program_P(uint32_t addr, uint8_t* data, uint16_t cnt)
{
_CS_LOW();
_SPI_TX(_CMD_PAGE_PROGRAM); // send command 0x02
_SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23
_SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15
_SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7
while (cnt--) // send data
_SPI_TX(pgm_read_byte(data++));
_CS_HIGH();
}
void w25x20cl_erase(uint8_t cmd, uint32_t addr)
{
_CS_LOW();
_SPI_TX(cmd); // send command 0x20
_SPI_TX(((uint8_t*)&addr)[2]); // send addr bits 16..23
_SPI_TX(((uint8_t*)&addr)[1]); // send addr bits 8..15
_SPI_TX(((uint8_t*)&addr)[0]); // send addr bits 0..7
_CS_HIGH();
}
void w25x20cl_sector_erase(uint32_t addr)
{
return w25x20cl_erase(_CMD_SECTOR_ERASE, addr);
}
void w25x20cl_block32_erase(uint32_t addr)
{
return w25x20cl_erase(_CMD_BLOCK32_ERASE, addr);
}
void w25x20cl_block64_erase(uint32_t addr)
{
return w25x20cl_erase(_CMD_BLOCK64_ERASE, addr);
}
void w25x20cl_chip_erase(void)
{
_CS_LOW();
_SPI_TX(_CMD_CHIP_ERASE); // send command 0xc7
_CS_HIGH();
}
void w25x20cl_rd_uid(uint8_t* uid)
{
_CS_LOW();
_SPI_TX(_CMD_RD_UID); // send command 0x4b
uint8_t cnt = 4; // 4 dummy bytes
while (cnt--) // receive dummy bytes
_SPI_RX();
cnt = 8; // 8 bytes UID
while (cnt--) // receive UID
uid[7 - cnt] = _SPI_RX();
_CS_HIGH();
}
int w25x20cl_mfrid_devid(void)
{
_CS_LOW();
_SPI_TX(_CMD_MFRID_DEVID); // send command 0x90
uint8_t cnt = 3; // 3 address bytes
while (cnt--) // send address bytes
_SPI_TX(0x00);
uint8_t w25x20cl_mfrid = _SPI_RX(); // receive mfrid
uint8_t w25x20cl_devid = _SPI_RX(); // receive devid
_CS_HIGH();
return ((w25x20cl_mfrid == _MFRID) && (w25x20cl_devid == _DEVID));
}
void w25x20cl_wait_busy(void)
{
while (w25x20cl_rd_status_reg() & W25X20CL_STATUS_BUSY) ;
}