185 lines
4.7 KiB
C
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) ;
|
||
|
}
|