Files
TencentOS-tiny/board/STM32F103_SIM800A/Hardware/hal_spi_flash.c
supowang edb2879617 first commit for opensource
first commit for opensource
2019-09-16 13:19:50 +08:00

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 */