mirror of
https://gitee.com/dlmu-cone/tronone-h7-scaffold
synced 2026-07-24 11:37:44 +08:00
ioc changed but not tested
This commit is contained in:
366
User_Code/module/periph/w25q64/w25q64.c
Normal file
366
User_Code/module/periph/w25q64/w25q64.c
Normal file
@@ -0,0 +1,366 @@
|
||||
#include "w25q64.h"
|
||||
#include <string.h>
|
||||
|
||||
static W25Q64_Handle_t w25q64 = {0};
|
||||
static bool w25q64_attached = false;
|
||||
static bool w25q64_ready = false;
|
||||
|
||||
static void w25q64_cs_low(void)
|
||||
{
|
||||
if (w25q64_attached)
|
||||
{
|
||||
HAL_GPIO_WritePin(w25q64.cs_port, w25q64.cs_pin, GPIO_PIN_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
static void w25q64_cs_high(void)
|
||||
{
|
||||
if (w25q64_attached)
|
||||
{
|
||||
HAL_GPIO_WritePin(w25q64.cs_port, w25q64.cs_pin, GPIO_PIN_SET);
|
||||
}
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_spi_tx(const uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!w25q64_attached || w25q64.hspi == NULL)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
if (HAL_SPI_Transmit(w25q64.hspi, (uint8_t *) data, len, w25q64.timeout_ms) != HAL_OK)
|
||||
{
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_spi_rx(uint8_t *data, uint16_t len)
|
||||
{
|
||||
if (!w25q64_attached || w25q64.hspi == NULL)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
if (HAL_SPI_Receive(w25q64.hspi, data, len, w25q64.timeout_ms) != HAL_OK)
|
||||
{
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_write_enable(void)
|
||||
{
|
||||
uint8_t cmd = W25Q64_CMD_WRITE_ENABLE;
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(&cmd, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_read_status(uint8_t *status)
|
||||
{
|
||||
uint8_t cmd = W25Q64_CMD_READ_STATUS_1;
|
||||
|
||||
if (status == NULL)
|
||||
{
|
||||
return W25Q64_ERR_PARAM;
|
||||
}
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(&cmd, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
if (w25q64_spi_rx(status, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_wait_ready(uint32_t timeout_ms)
|
||||
{
|
||||
uint8_t status = 0;
|
||||
uint32_t start = HAL_GetTick();
|
||||
|
||||
do
|
||||
{
|
||||
if (w25q64_read_status(&status) != W25Q64_OK)
|
||||
{
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
if ((status & 0x01U) == 0U)
|
||||
{
|
||||
return W25Q64_OK;
|
||||
}
|
||||
} while ((HAL_GetTick() - start) < timeout_ms);
|
||||
|
||||
return W25Q64_ERR_BUSY;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_command_addr(uint8_t cmd, uint32_t addr)
|
||||
{
|
||||
uint8_t header[4] = {
|
||||
cmd,
|
||||
(uint8_t) (addr >> 16),
|
||||
(uint8_t) (addr >> 8),
|
||||
(uint8_t) addr
|
||||
};
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(header, sizeof(header)) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
void W25Q64_Attach(W25Q64_Handle_t *handle)
|
||||
{
|
||||
if (handle == NULL)
|
||||
{
|
||||
W25Q64_Detach();
|
||||
return;
|
||||
}
|
||||
|
||||
w25q64 = *handle;
|
||||
w25q64_attached = (w25q64.hspi != NULL) && (w25q64.cs_port != NULL);
|
||||
w25q64.timeout_ms = (w25q64.timeout_ms == 0U) ? 100U : w25q64.timeout_ms;
|
||||
if (w25q64_attached)
|
||||
{
|
||||
HAL_GPIO_WritePin(w25q64.cs_port, w25q64.cs_pin, GPIO_PIN_SET);
|
||||
}
|
||||
w25q64_ready = false;
|
||||
}
|
||||
|
||||
void W25Q64_Detach(void)
|
||||
{
|
||||
memset(&w25q64, 0, sizeof(w25q64));
|
||||
w25q64_attached = false;
|
||||
w25q64_ready = false;
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_ReadID(uint32_t *jedec_id)
|
||||
{
|
||||
uint8_t cmd = W25Q64_CMD_READ_ID;
|
||||
uint8_t id[3] = {0};
|
||||
|
||||
if (jedec_id == NULL)
|
||||
{
|
||||
return W25Q64_ERR_PARAM;
|
||||
}
|
||||
if (!w25q64_attached)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(&cmd, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
if (w25q64_spi_rx(id, 3U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
*jedec_id = ((uint32_t) id[0] << 16) | ((uint32_t) id[1] << 8) | id[2];
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_Init(void)
|
||||
{
|
||||
uint32_t jedec_id = 0;
|
||||
|
||||
if (!w25q64_attached)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
if (W25Q64_ReadID(&jedec_id) != W25Q64_OK)
|
||||
{
|
||||
w25q64_ready = false;
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
|
||||
w25q64_ready = (jedec_id == W25Q64_JEDEC_ID);
|
||||
return w25q64_ready ? W25Q64_OK : W25Q64_ERR_ID;
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_Read(uint32_t addr, uint8_t *data, uint32_t len)
|
||||
{
|
||||
W25Q64_Status_t ret;
|
||||
uint32_t offset = 0U;
|
||||
|
||||
if (data == NULL || len == 0U)
|
||||
{
|
||||
return W25Q64_ERR_PARAM;
|
||||
}
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
ret = w25q64_command_addr(W25Q64_CMD_READ_DATA, addr);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (offset < len)
|
||||
{
|
||||
uint16_t chunk = (uint16_t) ((len - offset) > UINT16_MAX ? UINT16_MAX : (len - offset));
|
||||
ret = w25q64_spi_rx(data + offset, chunk);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return ret;
|
||||
}
|
||||
offset += chunk;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
static W25Q64_Status_t w25q64_page_program(uint32_t addr, const uint8_t *data, uint16_t len)
|
||||
{
|
||||
W25Q64_Status_t ret;
|
||||
|
||||
ret = w25q64_write_enable();
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = w25q64_command_addr(W25Q64_CMD_PAGE_PROGRAM, addr);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (w25q64_spi_tx(data, len) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
return w25q64_wait_ready(w25q64.timeout_ms);
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_Write(uint32_t addr, const uint8_t *data, uint32_t len)
|
||||
{
|
||||
uint32_t offset = 0U;
|
||||
|
||||
if (data == NULL || len == 0U)
|
||||
{
|
||||
return W25Q64_ERR_PARAM;
|
||||
}
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
while (offset < len)
|
||||
{
|
||||
uint32_t page_offset = (addr + offset) % W25Q64_PAGE_SIZE;
|
||||
uint32_t room = W25Q64_PAGE_SIZE - page_offset;
|
||||
uint16_t chunk = (uint16_t) ((len - offset) < room ? (len - offset) : room);
|
||||
W25Q64_Status_t ret = w25q64_page_program(addr + offset, data + offset, chunk);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
offset += chunk;
|
||||
}
|
||||
|
||||
return W25Q64_OK;
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_EraseSector(uint32_t addr)
|
||||
{
|
||||
W25Q64_Status_t ret;
|
||||
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
ret = w25q64_write_enable();
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = w25q64_command_addr(W25Q64_CMD_SECTOR_ERASE, addr);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
return w25q64_wait_ready(400U);
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_Erase64K(uint32_t addr)
|
||||
{
|
||||
W25Q64_Status_t ret;
|
||||
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
ret = w25q64_write_enable();
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = w25q64_command_addr(W25Q64_CMD_BLOCK_ERASE_64K, addr);
|
||||
if (ret != W25Q64_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
return w25q64_wait_ready(2000U);
|
||||
}
|
||||
|
||||
W25Q64_Status_t W25Q64_ChipErase(void)
|
||||
{
|
||||
uint8_t cmd = W25Q64_CMD_CHIP_ERASE;
|
||||
|
||||
if (!w25q64_ready)
|
||||
{
|
||||
return W25Q64_ERR_NOT_ATTACHED;
|
||||
}
|
||||
|
||||
if (w25q64_write_enable() != W25Q64_OK)
|
||||
{
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
|
||||
w25q64_cs_low();
|
||||
if (w25q64_spi_tx(&cmd, 1U) != W25Q64_OK)
|
||||
{
|
||||
w25q64_cs_high();
|
||||
return W25Q64_ERR_HAL;
|
||||
}
|
||||
w25q64_cs_high();
|
||||
|
||||
return w25q64_wait_ready(100000U);
|
||||
}
|
||||
59
User_Code/module/periph/w25q64/w25q64.h
Normal file
59
User_Code/module/periph/w25q64/w25q64.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef W25Q64_H
|
||||
#define W25Q64_H
|
||||
|
||||
#include "main.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define W25Q64_PAGE_SIZE 256U
|
||||
#define W25Q64_SECTOR_SIZE 4096U
|
||||
#define W25Q64_FLASH_SIZE 0x800000U
|
||||
#define W25Q64_JEDEC_ID 0xEF4017U
|
||||
|
||||
#define W25Q64_CMD_WRITE_ENABLE 0x06U
|
||||
#define W25Q64_CMD_READ_STATUS_1 0x05U
|
||||
#define W25Q64_CMD_READ_ID 0x9FU
|
||||
#define W25Q64_CMD_READ_DATA 0x03U
|
||||
#define W25Q64_CMD_PAGE_PROGRAM 0x02U
|
||||
#define W25Q64_CMD_SECTOR_ERASE 0x20U
|
||||
#define W25Q64_CMD_BLOCK_ERASE_64K 0xD8U
|
||||
#define W25Q64_CMD_CHIP_ERASE 0xC7U
|
||||
|
||||
typedef enum
|
||||
{
|
||||
W25Q64_OK = 0,
|
||||
W25Q64_ERR_PARAM = -1,
|
||||
W25Q64_ERR_NOT_ATTACHED = -2,
|
||||
W25Q64_ERR_HAL = -3,
|
||||
W25Q64_ERR_ID = -4,
|
||||
W25Q64_ERR_BUSY = -5
|
||||
} W25Q64_Status_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SPI_HandleTypeDef *hspi;
|
||||
GPIO_TypeDef *cs_port;
|
||||
uint16_t cs_pin;
|
||||
uint32_t timeout_ms;
|
||||
} W25Q64_Handle_t;
|
||||
|
||||
void W25Q64_Attach(W25Q64_Handle_t *handle);
|
||||
void W25Q64_Detach(void);
|
||||
|
||||
W25Q64_Status_t W25Q64_Init(void);
|
||||
W25Q64_Status_t W25Q64_ReadID(uint32_t *jedec_id);
|
||||
W25Q64_Status_t W25Q64_Read(uint32_t addr, uint8_t *data, uint32_t len);
|
||||
W25Q64_Status_t W25Q64_Write(uint32_t addr, const uint8_t *data, uint32_t len);
|
||||
W25Q64_Status_t W25Q64_EraseSector(uint32_t addr);
|
||||
W25Q64_Status_t W25Q64_Erase64K(uint32_t addr);
|
||||
W25Q64_Status_t W25Q64_ChipErase(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user