//w25x20cl.c #include "w25x20cl.h" #include #include #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) ; }