Files
TencentOS-tiny/board/TencentOS_tiny_EVB_AIoT/BSP/Hardware/W25QXX-SPI/w25q64.c
2021-12-30 12:53:52 +08:00

257 lines
5.5 KiB
C

#include "w25q64.h"
#if defined(USE_ST_HAL)
static void spi_init(void)
{
// it will be called in main.
// MX_SPIx_Init();
}
static void spi_cs_select(void)
{
HAL_GPIO_WritePin(SPI_CS_PORT, SPI_CS_PIN, GPIO_PIN_RESET);
/* tCHSH: /CS Active Hold Time relative to CLK, min is 5 ns. */
for (int i = 0; i < 50; i++) {
__NOP();
}
}
static void spi_cs_deselect(void)
{
HAL_GPIO_WritePin(SPI_CS_PORT, SPI_CS_PIN, GPIO_PIN_SET);
/* tSHSL: /CS Deselect Time (for Array Read -> Array Read ->
-> Erase or Program -> Read Status Registers), min is 10 ns. */
for (int i = 0; i < 100; i++) {
__NOP();
}
}
static int spi_transmit(uint8_t *buf, uint16_t size)
{
HAL_StatusTypeDef status;
status = HAL_SPI_Transmit(&SPI_Handle, buf, size, 100);
return status == HAL_OK ? 0 : -1;
}
static int spi_receive(uint8_t *buf, uint16_t size)
{
HAL_StatusTypeDef status;
status = HAL_SPI_Receive(&SPI_Handle, buf, size, 100);
return status == HAL_OK ? 0 : -1;
}
#elif defined(USE_NXP_FSL)
static void spi_init(void)
{
lpspi_master_config_t masterConfig;
uint32_t srcClock_Hz;
/* Set clock source for LPSPI */
CLOCK_SetMux(kCLOCK_LpspiMux, LPSPI_CLOCK_SOURCE_SELECT);
CLOCK_SetDiv(kCLOCK_LpspiDiv, LPSPI_CLOCK_SOURCE_DIVIDER);
/* Master config */
LPSPI_MasterGetDefaultConfig(&masterConfig);
masterConfig.baudRate = TRANSFER_BAUDRATE;
srcClock_Hz = LPSPI_MASTER_CLK_FREQ;
LPSPI_MasterInit(SPI_Handle, &masterConfig, srcClock_Hz);
}
static void spi_cs_select(void)
{
GPIO_PinWrite(SPI_CS_PORT, SPI_CS_PIN, 0);
/* tCHSH: /CS Active Hold Time relative to CLK, min is 5 ns. */
for (int i = 0; i < 500; i++) {
__NOP();
}
}
static void spi_cs_deselect(void)
{
GPIO_PinWrite(SPI_CS_PORT, SPI_CS_PIN, 1);
/* tSHSL: /CS Deselect Time (for Array Read -> Array Read ->
-> Erase or Program -> Read Status Registers), min is 10 ns. */
for (int i = 0; i < 1000; i++) {
__NOP();
}
}
static int spi_transmit(uint8_t *buf, uint16_t size)
{
status_t status;
lpspi_transfer_t masterXfer;
/* Start master transfer, transfer data to slave. */
masterXfer.txData = buf;
masterXfer.rxData = NULL;
masterXfer.dataSize = size;
masterXfer.configFlags = kLPSPI_MasterByteSwap;
status = LPSPI_MasterTransferBlocking(SPI_Handle, &masterXfer);
return status == kStatus_Success ? 0 : -1;
}
static int spi_receive(uint8_t *buf, uint16_t size)
{
status_t status;
lpspi_transfer_t masterXfer;
/* Start master transfer, receive data from slave */
masterXfer.txData = NULL;
masterXfer.rxData = buf;
masterXfer.dataSize = size;
masterXfer.configFlags = kLPSPI_MasterByteSwap;
status = LPSPI_MasterTransferBlocking(SPI_Handle, &masterXfer);
return status == kStatus_Success ? 0 : -1;
}
#endif /* USE_ST_HAL or USE_NXP_FSL */
int w25qxx_init(void)
{
spi_init();
return 0;
}
uint16_t w25qxx_read_deviceid(void)
{
uint8_t recv_buf[2] = {0};
uint16_t device_id = 0;
uint8_t send_data[4] = {ManufactDeviceID_CMD, 0x00, 0x00, 0x00};
spi_cs_select();
if (spi_transmit(send_data, 4) == 0) {
if (spi_receive(recv_buf, 2) == 0) {
device_id = (recv_buf[0] << 8) | recv_buf[1];
}
}
spi_cs_deselect();
return device_id;
}
static void w25qxx_wait_busy(void)
{
uint8_t cmd;
uint8_t result;
cmd = READ_STATU_REGISTER_1;
spi_cs_select();
spi_transmit(&cmd, 1);
while (1) {
spi_receive(&result, 1);
if ((result & 0x01) != 0x01) {
break;
}
}
spi_cs_deselect();
return;
}
int w25qxx_read(uint8_t* buffer, uint32_t start_addr, uint16_t nbytes)
{
uint8_t cmd[4];
cmd[0] = READ_DATA_CMD;
cmd[1] = (uint8_t)(start_addr >> 16);
cmd[2] = (uint8_t)(start_addr >> 8);
cmd[3] = (uint8_t)(start_addr);
spi_cs_select();
if (spi_transmit(cmd, 4) == 0) {
if (spi_receive(buffer, nbytes) == 0) {
spi_cs_deselect();
return 0;
}
}
spi_cs_deselect();
return -1;
}
void w25qxx_write_enable(void)
{
uint8_t cmd = WRITE_ENABLE_CMD;
spi_cs_select();
spi_transmit(&cmd, 1);
spi_cs_deselect();
}
void w25qxx_write_disable(void)
{
uint8_t cmd = WRITE_DISABLE_CMD;
spi_cs_select();
spi_transmit(&cmd, 1);
spi_cs_deselect();
}
int w25qxx_erase_sector(uint32_t sector_addr)
{
uint8_t cmd[4];
cmd[0] = SECTOR_ERASE_CMD;
cmd[1] = (uint8_t)(sector_addr>>16);
cmd[2] = (uint8_t)(sector_addr>>8);
cmd[3] = (uint8_t)(sector_addr);
w25qxx_wait_busy();
w25qxx_write_enable();
spi_cs_select();
if (spi_transmit(cmd, 4) != 0) {
spi_cs_deselect();
return -1;
}
spi_cs_deselect();
w25qxx_wait_busy();
return 0;
}
int w25qxx_page_program(uint8_t* dat, uint32_t write_addr, uint16_t nbytes)
{
uint8_t cmd[4];
cmd[0] = PAGE_PROGRAM_CMD;
cmd[1] = (uint8_t)(write_addr >> 16);
cmd[2] = (uint8_t)(write_addr >> 8);
cmd[3] = (uint8_t)(write_addr);
w25qxx_wait_busy();
w25qxx_write_enable();
spi_cs_select();
if (spi_transmit(cmd, 4) != 0) {
spi_cs_deselect();
return -1;
}
if (spi_transmit(dat, nbytes) != 0) {
spi_cs_deselect();
return -1;
}
spi_cs_deselect();
w25qxx_wait_busy();
return 0;
}