426 lines
12 KiB
C
426 lines
12 KiB
C
#include "hal_spi_flash.h"
|
|
#include "stm32f1xx.h"
|
|
#include "stm32f1xx_hal_spi.h"
|
|
|
|
#ifdef HAL_SPI_MODULE_ENABLED
|
|
|
|
#define SPI_FLASH_WriteEnable 0x06
|
|
#define SPI_FLASH_WriteDisable 0x04
|
|
#define SPI_FLASH_ReadStatusReg 0x05
|
|
#define SPI_FLASH_WriteStatusReg 0x01
|
|
#define SPI_FLASH_ReadData 0x03
|
|
#define SPI_FLASH_FastReadData 0x0B
|
|
#define SPI_FLASH_FastReadDual 0x3B
|
|
#define SPI_FLASH_PageProgram 0x02
|
|
#define SPI_FLASH_BlockErase 0xD8
|
|
#define SPI_FLASH_SectorErase 0x20
|
|
#define SPI_FLASH_ChipErase 0xC7
|
|
#define SPI_FLASH_PowerDown 0xB9
|
|
#define SPI_FLASH_ReleasePowerDown 0xAB
|
|
#define SPI_FLASH_DeviceID 0xAB
|
|
#define SPI_FLASH_ManufactDeviceID 0x90
|
|
#define SPI_FLASH_JedecDeviceID 0x9F
|
|
#define SPI_FLASH_WIP_FLAG 0x01
|
|
#define SPI_FLASH_DUMMY_BYTE 0xFF
|
|
|
|
#define SPI_FLASH_PERIPHERAL SPI2
|
|
#define SPI_FLASH_ALTERNATE GPIO_AF2_SPI2
|
|
#define SPI_FLASH_GPIO_PORT GPIOB
|
|
#define SPI_FLASH_SCK_PIN GPIO_PIN_13
|
|
#define SPI_FLASH_MISO_PIN GPIO_PIN_14
|
|
#define SPI_FLASH_MOSI_PIN GPIO_PIN_15
|
|
#define SPI_FLASH_CS_PORT SPI_CS_GPIO_Port
|
|
#define SPI_FLASH_CS_PIN SPI_CS_Pin
|
|
|
|
#define CHOOSE_BIT_16 16
|
|
#define CHOOSE_BIT_8 8
|
|
|
|
#define SPI_FLASH_ENABLE(__HANDLE__) __HAL_SPI_ENABLE(__HANDLE__)
|
|
#define SPI_FLASH_DISABLE(__HANDLE__) __HAL_SPI_DISABLE(__HANDLE__)
|
|
#define SPI_FLASH_RCC_CLK_ENABLE() __HAL_RCC_SPI2_CLK_ENABLE()
|
|
#define SPI_FLASH_RCC_CLK_DISABLE() __HAL_RCC_SPI2_CLK_DISABLE()
|
|
|
|
#define SPI_FLASH_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
|
|
#define SPI_FLASH_CS_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
|
|
|
|
#define SPI_FLASH_CS_ENABLE() HAL_GPIO_WritePin(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN, GPIO_PIN_RESET)
|
|
#define SPI_FLASH_CS_DISABLE() HAL_GPIO_WritePin(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN, GPIO_PIN_SET)
|
|
|
|
#define CHECK_RET_RETURN(ret) \
|
|
do \
|
|
{ \
|
|
if ((ret) < 0) \
|
|
{ \
|
|
return ret; \
|
|
} \
|
|
} while (0)
|
|
|
|
SPI_HandleTypeDef g_spi_flash;
|
|
|
|
/* This function is called by inner-HAL lib */
|
|
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
|
|
{
|
|
GPIO_InitTypeDef GPIO_InitStruct;
|
|
|
|
if (hspi->Instance == SPI_FLASH_PERIPHERAL)
|
|
{
|
|
SPI_FLASH_RCC_CLK_ENABLE();
|
|
SPI_FLASH_GPIO_CLK_ENABLE();
|
|
SPI_FLASH_CS_CLK_ENABLE();
|
|
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
GPIO_InitStruct.Pin = SPI_FLASH_CS_PIN;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
|
HAL_GPIO_Init(SPI_FLASH_CS_PORT, &GPIO_InitStruct);
|
|
|
|
GPIO_InitStruct.Pin = SPI_FLASH_SCK_PIN | SPI_FLASH_MOSI_PIN | SPI_FLASH_MISO_PIN;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
|
|
HAL_GPIO_Init(SPI_FLASH_GPIO_PORT, &GPIO_InitStruct);
|
|
}
|
|
}
|
|
|
|
/* This function is called by inner-HAL lib */
|
|
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
|
|
{
|
|
if (hspi->Instance == SPI_FLASH_PERIPHERAL)
|
|
{
|
|
SPI_FLASH_RCC_CLK_DISABLE();
|
|
HAL_GPIO_DeInit(SPI_FLASH_GPIO_PORT, SPI_FLASH_SCK_PIN | SPI_FLASH_MOSI_PIN | SPI_FLASH_MISO_PIN);
|
|
HAL_GPIO_DeInit(SPI_FLASH_CS_PORT, SPI_FLASH_CS_PIN);
|
|
SPI_FLASH_DISABLE(hspi);
|
|
}
|
|
}
|
|
|
|
static int prv_spi_flash_send_byte(uint8_t send, uint8_t* recv)
|
|
{
|
|
uint8_t tmp;
|
|
uint8_t t_send = send;
|
|
|
|
if (HAL_SPI_TransmitReceive(&g_spi_flash, &t_send, &tmp, 1, HAL_MAX_DELAY) != HAL_OK)
|
|
{
|
|
return -1;
|
|
}
|
|
if (NULL != recv)
|
|
{
|
|
*recv = tmp;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int prv_spi_flash_send_cmd(uint8_t cmd, uint32_t addr)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = prv_spi_flash_send_byte(cmd, NULL);
|
|
CHECK_RET_RETURN(ret);
|
|
ret = prv_spi_flash_send_byte((addr & 0xFF0000) >> CHOOSE_BIT_16, NULL);
|
|
CHECK_RET_RETURN(ret);
|
|
ret = prv_spi_flash_send_byte((addr & 0xFF00) >> CHOOSE_BIT_8, NULL);
|
|
CHECK_RET_RETURN(ret);
|
|
ret = prv_spi_flash_send_byte(addr & 0xFF, NULL);
|
|
CHECK_RET_RETURN(ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void prv_spi_flash_write_enable(void)
|
|
{
|
|
SPI_FLASH_CS_ENABLE();
|
|
(void)prv_spi_flash_send_byte(SPI_FLASH_WriteEnable, NULL);
|
|
SPI_FLASH_CS_DISABLE();
|
|
}
|
|
|
|
static void prv_spi_flash_wait_write_end(void)
|
|
{
|
|
uint8_t status = 0;
|
|
|
|
SPI_FLASH_CS_ENABLE();
|
|
|
|
(void)prv_spi_flash_send_byte(SPI_FLASH_ReadStatusReg, NULL);
|
|
|
|
/* Loop as long as the memory is busy with a write cycle */
|
|
do
|
|
{
|
|
/* Send a dummy byte to generate the clock needed by the FLASH
|
|
and put the value of the status register in status variable */
|
|
if (prv_spi_flash_send_byte(SPI_FLASH_DUMMY_BYTE, &status) == -1)
|
|
{
|
|
break;
|
|
}
|
|
} while ((status & SPI_FLASH_WIP_FLAG) == SET); /* Write in progress */
|
|
|
|
SPI_FLASH_CS_DISABLE();
|
|
}
|
|
|
|
static int prv_spi_flash_write_page(const uint8_t* buf, uint32_t addr, int32_t len)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
|
|
if(0 == len)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
prv_spi_flash_write_enable();
|
|
SPI_FLASH_CS_ENABLE();
|
|
|
|
if ((ret = prv_spi_flash_send_cmd(SPI_FLASH_PageProgram, addr)) != -1)
|
|
{
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (prv_spi_flash_send_byte(buf[i], NULL) == -1)
|
|
{
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SPI_FLASH_CS_DISABLE();
|
|
prv_spi_flash_wait_write_end();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int prv_spi_flash_erase_sector(uint32_t addr)
|
|
{
|
|
int ret = 0;
|
|
|
|
prv_spi_flash_write_enable();
|
|
prv_spi_flash_wait_write_end();
|
|
SPI_FLASH_CS_ENABLE();
|
|
|
|
ret = prv_spi_flash_send_cmd(SPI_FLASH_SectorErase, addr);
|
|
|
|
SPI_FLASH_CS_DISABLE();
|
|
prv_spi_flash_wait_write_end();
|
|
|
|
return ret;
|
|
}
|
|
|
|
void hal_spi_flash_config(void)
|
|
{
|
|
g_spi_flash.Instance = SPI_FLASH_PERIPHERAL;
|
|
g_spi_flash.State = HAL_SPI_STATE_RESET;
|
|
g_spi_flash.Init.Mode = SPI_MODE_MASTER;
|
|
g_spi_flash.Init.Direction = SPI_DIRECTION_2LINES;
|
|
g_spi_flash.Init.DataSize = SPI_DATASIZE_8BIT;
|
|
g_spi_flash.Init.CLKPolarity = SPI_POLARITY_HIGH;
|
|
g_spi_flash.Init.CLKPhase = SPI_PHASE_2EDGE;
|
|
g_spi_flash.Init.NSS = SPI_NSS_SOFT;
|
|
g_spi_flash.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
|
|
g_spi_flash.Init.FirstBit = SPI_FIRSTBIT_MSB;
|
|
g_spi_flash.Init.TIMode = SPI_TIMODE_DISABLE;
|
|
g_spi_flash.Init.CRCPolynomial = 7;
|
|
HAL_SPI_Init(&g_spi_flash);
|
|
SPI_FLASH_ENABLE(&g_spi_flash);
|
|
SPI_FLASH_CS_DISABLE();
|
|
}
|
|
|
|
int hal_spi_flash_erase(uint32_t addr, int32_t len)
|
|
{
|
|
uint32_t begin;
|
|
uint32_t end;
|
|
int i;
|
|
|
|
if (len < 0
|
|
|| addr > SPI_FLASH_TOTAL_SIZE
|
|
|| addr + len > SPI_FLASH_TOTAL_SIZE)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
begin = addr / SPI_FLASH_SECTOR * SPI_FLASH_SECTOR;
|
|
end = (addr + len - 1) / SPI_FLASH_SECTOR * SPI_FLASH_SECTOR;
|
|
|
|
for (i = begin; i <= end; i += SPI_FLASH_SECTOR)
|
|
{
|
|
if (prv_spi_flash_erase_sector(i) == -1)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int hal_spi_flash_write(const void* buf, int32_t len, uint32_t* location)
|
|
{
|
|
const uint8_t* pbuf = (const uint8_t*)buf;
|
|
int page_cnt = 0;
|
|
int remain_cnt = 0;
|
|
int temp = 0;
|
|
uint32_t loc_addr;
|
|
uint8_t addr = 0;
|
|
uint8_t count = 0;
|
|
int i;
|
|
int ret = 0;
|
|
|
|
if (NULL == pbuf
|
|
|| NULL == location
|
|
|| len < 0
|
|
|| *location > SPI_FLASH_TOTAL_SIZE
|
|
|| len + *location > SPI_FLASH_TOTAL_SIZE)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
loc_addr = *location;
|
|
addr = loc_addr % SPI_FLASH_PAGESIZE;
|
|
count = SPI_FLASH_PAGESIZE - addr;
|
|
page_cnt = len / SPI_FLASH_PAGESIZE;
|
|
remain_cnt = len % SPI_FLASH_PAGESIZE;
|
|
|
|
if (addr == 0) /* addr is aligned to SPI_FLASH_PAGESIZE */
|
|
{
|
|
if (page_cnt == 0) /* len < SPI_FLASH_PAGESIZE */
|
|
{
|
|
ret = prv_spi_flash_write_page(pbuf, loc_addr, len);
|
|
CHECK_RET_RETURN(ret);
|
|
}
|
|
else /* len > SPI_FLASH_PAGESIZE */
|
|
{
|
|
for (i = 0; i < page_cnt; ++i)
|
|
{
|
|
ret = prv_spi_flash_write_page(pbuf + i * SPI_FLASH_PAGESIZE, loc_addr, SPI_FLASH_PAGESIZE);
|
|
CHECK_RET_RETURN(ret);
|
|
loc_addr += SPI_FLASH_PAGESIZE;
|
|
}
|
|
|
|
ret = prv_spi_flash_write_page(pbuf + page_cnt * SPI_FLASH_PAGESIZE, loc_addr, remain_cnt);
|
|
CHECK_RET_RETURN(ret);
|
|
}
|
|
}
|
|
else /* addr is not aligned to SPI_FLASH_PAGESIZE */
|
|
{
|
|
if (page_cnt == 0) /* len < SPI_FLASH_PAGESIZE */
|
|
{
|
|
if (remain_cnt > count) /* (len + loc_addr) > SPI_FLASH_PAGESIZE */
|
|
{
|
|
temp = remain_cnt - count;
|
|
|
|
ret = prv_spi_flash_write_page(pbuf, loc_addr, count);
|
|
CHECK_RET_RETURN(ret);
|
|
|
|
ret = prv_spi_flash_write_page(pbuf + count, loc_addr + count, temp);
|
|
CHECK_RET_RETURN(ret);
|
|
}
|
|
else
|
|
{
|
|
ret = prv_spi_flash_write_page(pbuf, loc_addr, len);
|
|
CHECK_RET_RETURN(ret);
|
|
}
|
|
}
|
|
else /* len > SPI_FLASH_PAGESIZE */
|
|
{
|
|
len -= count;
|
|
page_cnt = len / SPI_FLASH_PAGESIZE;
|
|
remain_cnt = len % SPI_FLASH_PAGESIZE;
|
|
|
|
ret = prv_spi_flash_write_page(pbuf, loc_addr, count);
|
|
CHECK_RET_RETURN(ret);
|
|
loc_addr += count;
|
|
|
|
for (i = 0; i < page_cnt; ++i)
|
|
{
|
|
ret = prv_spi_flash_write_page(pbuf + count + i * SPI_FLASH_PAGESIZE, loc_addr, SPI_FLASH_PAGESIZE);
|
|
CHECK_RET_RETURN(ret);
|
|
loc_addr += SPI_FLASH_PAGESIZE;
|
|
}
|
|
|
|
if (remain_cnt != 0)
|
|
{
|
|
ret = prv_spi_flash_write_page(pbuf + count + page_cnt * SPI_FLASH_PAGESIZE, loc_addr, remain_cnt);
|
|
CHECK_RET_RETURN(ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
*location += len;
|
|
return ret;
|
|
}
|
|
|
|
int hal_spi_flash_erase_write(const void* buf, int32_t len, uint32_t location)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = hal_spi_flash_erase(location, len);
|
|
CHECK_RET_RETURN(ret);
|
|
ret = hal_spi_flash_write(buf, len, &location);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int hal_spi_flash_read(void* buf, int32_t len, uint32_t location)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
uint8_t* pbuf = (uint8_t*)buf;
|
|
|
|
if (NULL == pbuf
|
|
|| len < 0
|
|
|| location > SPI_FLASH_TOTAL_SIZE
|
|
|| len + location > SPI_FLASH_TOTAL_SIZE)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
SPI_FLASH_CS_ENABLE();
|
|
|
|
if ((ret = prv_spi_flash_send_cmd(SPI_FLASH_ReadData, location)) != -1)
|
|
{
|
|
for (i = 0; i < len; ++i)
|
|
{
|
|
if (prv_spi_flash_send_byte(SPI_FLASH_DUMMY_BYTE, pbuf + i) == -1)
|
|
{
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
SPI_FLASH_CS_DISABLE();
|
|
|
|
return ret;
|
|
}
|
|
|
|
int hal_spi_flash_get_id(void)
|
|
{
|
|
uint8_t tmp1 = 0;
|
|
uint8_t tmp2 = 0;
|
|
uint8_t tmp3 = 0;
|
|
|
|
SPI_FLASH_CS_ENABLE();
|
|
|
|
if (prv_spi_flash_send_byte(SPI_FLASH_JedecDeviceID, NULL) != -1)
|
|
{
|
|
(void)prv_spi_flash_send_byte(SPI_FLASH_DUMMY_BYTE, &tmp1);
|
|
(void)prv_spi_flash_send_byte(SPI_FLASH_DUMMY_BYTE, &tmp2);
|
|
(void)prv_spi_flash_send_byte(SPI_FLASH_DUMMY_BYTE, &tmp3);
|
|
}
|
|
|
|
SPI_FLASH_CS_DISABLE();
|
|
|
|
return (tmp1 << CHOOSE_BIT_16) | (tmp2 << CHOOSE_BIT_8) | tmp3;
|
|
}
|
|
|
|
void hal_spi_flash_power_down(void)
|
|
{
|
|
SPI_FLASH_CS_ENABLE();
|
|
(void)prv_spi_flash_send_byte(SPI_FLASH_PowerDown, NULL);
|
|
SPI_FLASH_CS_DISABLE();
|
|
}
|
|
|
|
void hal_spi_flash_wake_up(void)
|
|
{
|
|
SPI_FLASH_CS_ENABLE();
|
|
(void)prv_spi_flash_send_byte(SPI_FLASH_ReleasePowerDown, NULL);
|
|
SPI_FLASH_CS_DISABLE();
|
|
}
|
|
|
|
#endif /* HAL_SPI_MODULE_ENABLED */
|