Структуризировано: добавлены комменты и переименованы переменные
This commit is contained in:
@@ -1,336 +1,48 @@
|
||||
/********************************W25 FLASH**********************************
|
||||
Данный файл содержит базовые функции для общения с памятью FLASH по SPI.
|
||||
//-------------------Функции-------------------//
|
||||
@func users
|
||||
- W25_FLASH_Read Считывание FLASH
|
||||
- W25_FLASH_Write_Area Запись данных в заданный участок FLASH (с потерей данных в выбраном сектора за пределами этого участка)
|
||||
- W25_FLASH_Erase_Sector Очистка сектора FLASH
|
||||
- W25_FLASH_Program_Area Программирование FLASH
|
||||
|
||||
@func initialization
|
||||
- W25_Base_Init Инициализация SPI и GPIO для FLASH
|
||||
|
||||
@func process interaction with flash
|
||||
- W25_FLASH_Program_Page Программирование страницы. *есть более общая функция W25_FLASH_Program_Area, которая программирует участки больше страницы
|
||||
- W25_WriteEnablingUntilTimeout Разрешение записи, пока не будет ответа или не истек таймаут
|
||||
- W25_WaitOnFlagUntilTimeout Ожидание флага пока не истек таймаута
|
||||
|
||||
@func cmd functions
|
||||
- W25_CMD_Read_Status_Register Отправка комманд Read Status Register 1 / Read Status Register 1 (0x05h / 0x35h)
|
||||
- W25_CMD_Write_Status_Register Отправка комманды Write Status Register (0x01h)
|
||||
- W25_CMD_Write_Enable Отправка комманды Write Enable (0x06h)
|
||||
- W25_CMD_Write_Disable Отправка комманды Write Disable (0x04h)
|
||||
- W25_CMD_Read_Data Отправка комманды Read Data (0x03h)
|
||||
- W25_CMD_Fast_Read Отправка комманды Fast Read (0x0Bh)
|
||||
- W25_CMD_Page_Program Отправка комманды Page Program (0x02h)
|
||||
- W25_CMD_Erase_Sector Отправка комманды Erase Sector (0x20h)
|
||||
- W25_CMD_Read_JEDEC_ID Отправка комманды Read JEDEC ID (0x4Bh)
|
||||
- W25_CMD_Read_Device_ID Отправка комманды Read Manufacture / Device Id (0x90)
|
||||
|
||||
@func SPI functions
|
||||
- W25_SPI_Transmit Функция отправки по SPI (содержит только HAL_SPI_Transmit)
|
||||
- W25_SPI_Receive Функция приема по SPI (содержит только HAL_SPI_Receive)
|
||||
***************************************************************************/
|
||||
#include "spi_flash.h"
|
||||
uint8_t rx_buf[1025];
|
||||
uint8_t tx_buf[10];
|
||||
uint8_t sector_buff[W25_SECTOR_SIZE];
|
||||
|
||||
/* USER CODE BEGIN PV */
|
||||
char str1[30];
|
||||
|
||||
//----------------------FUNCTION FUNCTIONS---------------------
|
||||
//-------------------------------------------------------------
|
||||
HAL_StatusTypeDef W25_FLASH_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
|
||||
// wait for unbusy
|
||||
if(W25_WaitOnFlagUntilTimeout(hw25, W25_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if its unbusy for timeout
|
||||
return HAL_TIMEOUT; // return timeout error
|
||||
|
||||
W25_CMD_Read_Data(hw25, FLASH_Address, pBuff, Size);
|
||||
return HAL_OK;
|
||||
}
|
||||
HAL_StatusTypeDef W25_FLASH_Write_Area(W25_HandleTypeDef *hw25, W25_reProgramInitTypeDef *WriteInit, uint32_t Timeout)
|
||||
{
|
||||
uint8_t sector_buff[256];
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
uint32_t timeoutcnt = Timeout;
|
||||
HAL_StatusTypeDef W25_Status;
|
||||
|
||||
// WAIT FOR UNBUSY
|
||||
if(W25_WaitOnFlagUntilTimeout(hw25, W25_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if its unbusy for timeout
|
||||
return HAL_TIMEOUT; // return timeout error
|
||||
|
||||
// SAVE USER "SECTOR" FROM FLASH
|
||||
timeoutcnt = HAL_GetTick() - tickstart; // update timeout
|
||||
Timeout -= timeoutcnt;
|
||||
tickstart += timeoutcnt;
|
||||
// store data from flash
|
||||
W25_Status = W25_FLASH_Read(hw25, WriteInit->Sector_Address, sector_buff, WriteInit->Sector_Size, Timeout);
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
// ERASE SECTOR
|
||||
timeoutcnt = HAL_GetTick() - tickstart; // update timeout
|
||||
Timeout -= timeoutcnt;
|
||||
tickstart += timeoutcnt;
|
||||
// erase flash
|
||||
W25_Status = W25_FLASH_Erase_Sector(hw25, WriteInit->Sector_Address, Timeout);
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
// CHANGE DATA IN USER "SECTOR"
|
||||
uint32_t addr_shift = WriteInit->Data_Address - WriteInit->Sector_Address;
|
||||
for(int i = 0; i < WriteInit->Data_Size; i++)
|
||||
{
|
||||
sector_buff[addr_shift+i] = WriteInit->pDataPtr[addr_shift+i];
|
||||
}
|
||||
|
||||
// RESTORE UPDATED DATA TO FLASH
|
||||
timeoutcnt = HAL_GetTick() - tickstart; // update timeout
|
||||
Timeout -= timeoutcnt;
|
||||
tickstart += timeoutcnt;
|
||||
// restore data to flash
|
||||
W25_Status = W25_FLASH_Program_Area(hw25, WriteInit->Sector_Address, sector_buff, WriteInit->Sector_Size, Timeout);
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef W25_FLASH_Program_Area(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
HAL_StatusTypeDef W25_Status;
|
||||
|
||||
// CALC AREA TO PROGRAM
|
||||
uint16_t bytecnt = 0;
|
||||
uint16_t firstpage_size = 0;
|
||||
uint16_t lastpage_size = Size;
|
||||
uint16_t firstpage = (FLASH_Address/256);
|
||||
uint16_t lastpage = ((FLASH_Address+Size-1)/256);
|
||||
if(firstpage != lastpage) // if area is on several pages
|
||||
{
|
||||
firstpage_size = (firstpage+1)*256 - FLASH_Address; // set size of data at first page
|
||||
lastpage_size = (FLASH_Address+Size) - lastpage*256; // set size of data at last page
|
||||
}
|
||||
|
||||
// PROGRAM PAGES: FROM FIRST NO THE PREVIOUS TO THE LAST
|
||||
for(int i = 0; i < lastpage - firstpage; i++)
|
||||
{
|
||||
W25_Status = W25_FLASH_Program_Page(hw25, FLASH_Address, &pData[bytecnt], firstpage_size, Timeout, tickstart); // programm page
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
// note for multiple page program: first we program rest of the first page,
|
||||
// then we shift byte count to data, that shoud be on the next page
|
||||
bytecnt += firstpage_size;
|
||||
FLASH_Address += firstpage_size;
|
||||
// and set start size as page size. because next pages will be fully programmed
|
||||
firstpage_size = W25_PAGE_SIZE;
|
||||
}
|
||||
|
||||
// PROGRAM LAST PAGE
|
||||
W25_Status = W25_FLASH_Program_Page(hw25, FLASH_Address, &pData[bytecnt], lastpage_size, Timeout, tickstart); // programm page
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef W25_FLASH_Program_Page(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint32_t tickstart)
|
||||
{
|
||||
// enable writting and waiting for unbusy
|
||||
if(W25_WriteEnablingUntilTimeout(hw25, Timeout, tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
|
||||
// programm page (instruction)
|
||||
W25_CMD_Page_Program(hw25, FLASH_Address, pData, Size);
|
||||
|
||||
// waiting for ending of writting
|
||||
if(W25_WaitOnFlagUntilTimeout(hw25, W25_SR_WEL|W25_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if writting isnt done (W25 busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef W25_FLASH_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint32_t Timeout)
|
||||
{
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
|
||||
// enable writting and waiting for unbusy
|
||||
if(W25_WriteEnablingUntilTimeout(hw25, Timeout, tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
|
||||
// programm page (instruction)
|
||||
W25_CMD_Erase_Sector(hw25, FLASH_Address);
|
||||
|
||||
// waiting for ending of erasing
|
||||
if(W25_WaitOnFlagUntilTimeout(hw25, W25_SR_WEL|W25_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if erase isnt done (W25 busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT; // return timeout because erasing instruction accepted, but arent done
|
||||
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef W25_WriteEnablingUntilTimeout(W25_HandleTypeDef *hw25, uint32_t Timeout, uint32_t tickstart)
|
||||
{
|
||||
// enable writting
|
||||
W25_CMD_Read_Status_Register(hw25, W25_SR_WEL|W25_SR_BUSY);
|
||||
while((hw25->SR&W25_SR_WEL) != W25_SR_WEL)
|
||||
{
|
||||
// if flash isnt busy - set WEL flag
|
||||
if((hw25->SR&W25_SR_BUSY) == 0)
|
||||
W25_CMD_Write_Enable(hw25);
|
||||
|
||||
W25_CMD_Read_Status_Register(hw25, W25_SR_WEL);
|
||||
if((HAL_GetTick() - tickstart) >= Timeout) // if time is out
|
||||
return HAL_TIMEOUT; // set timeout
|
||||
}
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
HAL_StatusTypeDef W25_WaitOnFlagUntilTimeout(W25_HandleTypeDef *hw25, uint16_t FlagMask, uint16_t FlagStatus, uint32_t Timeout, uint32_t tickstart)
|
||||
{
|
||||
// enable writting
|
||||
W25_CMD_Read_Status_Register(hw25, FlagMask);
|
||||
while((hw25->SR&FlagMask) != FlagStatus)
|
||||
{
|
||||
W25_CMD_Read_Status_Register(hw25, FlagMask);
|
||||
if((HAL_GetTick() - tickstart) >= Timeout) // if time is out
|
||||
return HAL_TIMEOUT; // set timeout
|
||||
}
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
|
||||
//-----------------ELEMENTARY COMMAND FUNCTIONS----------------
|
||||
//-------------------------------------------------------------
|
||||
void W25_CMD_Read_Data(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size)
|
||||
{
|
||||
uint8_t command[4];
|
||||
uint8_t response[2] = {0};
|
||||
|
||||
command[0] = W25_READ_DATA;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 4);
|
||||
W25_SPI_Receive(hw25, pBuff, Size);
|
||||
W25_CS_Reset(hw25);
|
||||
}
|
||||
void W25_CMD_Fast_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size)
|
||||
{
|
||||
uint8_t command[5] = {0};
|
||||
uint8_t response[2] = {0};
|
||||
|
||||
command[0] = W25_READ_DATA;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
command[4] = 0xFF;
|
||||
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 5);
|
||||
W25_SPI_Receive(hw25, pBuff, Size);
|
||||
W25_CS_Reset(hw25);
|
||||
}
|
||||
void W25_CMD_Page_Program(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size)
|
||||
{
|
||||
// 1 command byte + 3 address bytes + 256 data bytes
|
||||
uint8_t command[1+3+256];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = W25_PAGE_PROGRAM;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
|
||||
if((FLASH_Address/256) != ((FLASH_Address+Size-1)/256))
|
||||
return;
|
||||
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 4); // send insctruction to write
|
||||
W25_SPI_Transmit(hw25, pData, Size); // send data to write
|
||||
W25_CS_Reset(hw25);
|
||||
}
|
||||
|
||||
void W25_CMD_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH_Address)
|
||||
{
|
||||
uint8_t command[4];
|
||||
uint8_t response[8];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = W25_ERASE_SECTOR;
|
||||
command[1] = FLASH_Address >> 16;
|
||||
command[2] = FLASH_Address >> 8;
|
||||
command[3] = FLASH_Address;
|
||||
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 4);
|
||||
W25_CS_Reset(hw25);
|
||||
}
|
||||
|
||||
void W25_CMD_Write_Enable(W25_HandleTypeDef *hw25)
|
||||
{
|
||||
uint8_t command[1];
|
||||
command[0] = W25_WRITE_ENABLE;
|
||||
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 1);
|
||||
W25_CS_Reset(hw25);
|
||||
}
|
||||
|
||||
void W25_CMD_Write_Status_Register(W25_HandleTypeDef *hw25, uint16_t WrittenBits)
|
||||
{
|
||||
uint8_t command[2];
|
||||
|
||||
command[0] = W25_WRITE_STATUS_REG;
|
||||
command[1] = WrittenBits >> 2;
|
||||
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 1);
|
||||
W25_CS_Reset(hw25);
|
||||
}
|
||||
|
||||
void W25_CMD_Read_Status_Register(W25_HandleTypeDef *hw25, uint16_t RequestedBits)
|
||||
{
|
||||
uint8_t command[2];
|
||||
uint8_t *pSRPtr = 0;
|
||||
uint8_t size = 1;
|
||||
|
||||
if(RequestedBits >> 8) // if its high byte of status register
|
||||
{
|
||||
command[0] = W25_READ_STATUS_REG_2;
|
||||
pSRPtr = (uint8_t *)(&hw25->SR) + 1; // set pointer to HI byte of SR register
|
||||
size = 1;
|
||||
if(RequestedBits & 0xFF) // if low byte also requester
|
||||
{
|
||||
size = 2; // set size to 2 bytes
|
||||
command[1] = W25_READ_STATUS_REG_1;
|
||||
}
|
||||
}
|
||||
else // of its low byte of status register
|
||||
{
|
||||
command[0] = W25_READ_STATUS_REG_1;
|
||||
pSRPtr = (uint8_t *)(&hw25->SR); // set pointer to LO byte of SR register
|
||||
size = 1;
|
||||
}
|
||||
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 1); // send insctruction to read SR
|
||||
W25_SPI_Receive(hw25, pSRPtr, 1); // receive response
|
||||
W25_CS_Reset(hw25);
|
||||
if(size > 1) // if 2 bytes are requested
|
||||
{
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, command+1, 1); // send insctruction to read SR
|
||||
W25_SPI_Receive(hw25, pSRPtr-1, 1); // receive response
|
||||
W25_CS_Reset(hw25);
|
||||
}
|
||||
}
|
||||
uint32_t W25_CMD_Read_JEDEC_ID(W25_HandleTypeDef *hw25)
|
||||
{
|
||||
uint8_t dt[4] = {0};
|
||||
uint32_t return_val;
|
||||
|
||||
tx_buf[0] = W25_READ_JEDEC_ID;
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, tx_buf, 1);
|
||||
W25_SPI_Receive(hw25, &dt[1], 3);
|
||||
W25_CS_Reset(hw25);
|
||||
|
||||
return_val = (*(uint64_t *)dt);
|
||||
return __REV(return_val) & 0xFFFFFF;
|
||||
}
|
||||
|
||||
uint64_t W25_CMD_Read_Device_ID(W25_HandleTypeDef *hw25)
|
||||
{
|
||||
uint8_t dt[8];
|
||||
uint64_t return_val_LO;
|
||||
uint64_t return_val_HI;
|
||||
tx_buf[0] = W25_READ_UNIQUE_ID;
|
||||
W25_CS_Set(hw25);
|
||||
W25_SPI_Transmit(hw25, tx_buf, 1);
|
||||
W25_SPI_Receive(hw25, dt, 8);
|
||||
W25_CS_Reset(hw25);
|
||||
|
||||
return_val_LO = (*(uint64_t *)dt) >> 32;
|
||||
return_val_HI = (*(uint64_t *)dt) & 0xFFFFFFFF;
|
||||
return ((uint64_t)__REV(return_val_HI) << 32) | __REV(return_val_LO);
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
|
||||
//--------------------------FOR USER---------------------------
|
||||
/**
|
||||
* @brief Initialize SPI and GPIO for W25 FLASH.
|
||||
* @param hw25 - указатель на структуру с настройками SPI и GPIO портов.
|
||||
*/
|
||||
void W25_Base_Init(W25_HandleTypeDef *hw25)
|
||||
{
|
||||
|
||||
@@ -395,17 +107,492 @@ void W25_Base_Init(W25_HandleTypeDef *hw25)
|
||||
HAL_GPIO_Init(hw25->GPIOs.MOSI_GPIOx, &GPIO_InitStruct);
|
||||
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Read data from external FLASH.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс откуда начинать считывание.
|
||||
* @param pBuff - куда записывать данные из FLASH.
|
||||
* @param Size - сколько байтов считывать.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @return HAL status.
|
||||
* @note Включает в себя проверку на доступность памяти (флаг BUSY)
|
||||
*/
|
||||
HAL_StatusTypeDef W25_FLASH_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
|
||||
// wait for unbusy
|
||||
if(W25_WaitOnFlagUntilTimeout(hw25, W25_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if its unbusy for timeout
|
||||
return HAL_TIMEOUT; // return timeout error
|
||||
|
||||
W25_CMD_Read_Data(hw25, FLASH_Address, pBuff, Size);
|
||||
return HAL_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Write data to area in external FLASH.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param WriteInit - указатель на структуру, определяющую участок памяти для записи.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц.
|
||||
* Данные в сектора участка, но за пределами участка не сохраняются.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_FLASH_Write_Area(W25_HandleTypeDef *hw25, W25_WriteInitTypeDef *WriteInit, uint32_t Timeout)
|
||||
{
|
||||
uint8_t sector_buff[256];
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
uint32_t timeoutcnt = Timeout;
|
||||
HAL_StatusTypeDef W25_Status;
|
||||
|
||||
// WAIT FOR UNBUSY
|
||||
if(W25_WaitOnFlagUntilTimeout(hw25, W25_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if its unbusy for timeout
|
||||
return HAL_TIMEOUT; // return timeout error
|
||||
|
||||
// SAVE USER "SECTOR" FROM FLASH
|
||||
timeoutcnt = HAL_GetTick() - tickstart; // update timeout
|
||||
Timeout -= timeoutcnt;
|
||||
tickstart += timeoutcnt;
|
||||
// store data from flash
|
||||
W25_Status = W25_FLASH_Read(hw25, WriteInit->Sector_Address, sector_buff, WriteInit->Sector_Size, Timeout);
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
// ERASE SECTOR
|
||||
timeoutcnt = HAL_GetTick() - tickstart; // update timeout
|
||||
Timeout -= timeoutcnt;
|
||||
tickstart += timeoutcnt;
|
||||
// erase flash
|
||||
W25_Status = W25_FLASH_Erase_Sector(hw25, WriteInit->Sector_Address, Timeout);
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
// CHANGE DATA IN USER "SECTOR"
|
||||
uint32_t addr_shift = WriteInit->Data_Address - WriteInit->Sector_Address;
|
||||
for(int i = 0; i < WriteInit->Data_Size; i++)
|
||||
{
|
||||
sector_buff[addr_shift+i] = WriteInit->pDataPtr[addr_shift+i];
|
||||
}
|
||||
|
||||
// RESTORE UPDATED DATA TO FLASH
|
||||
timeoutcnt = HAL_GetTick() - tickstart; // update timeout
|
||||
Timeout -= timeoutcnt;
|
||||
tickstart += timeoutcnt;
|
||||
// restore data to flash
|
||||
W25_Status = W25_FLASH_Program_Area(hw25, WriteInit->Sector_Address, sector_buff, WriteInit->Sector_Size, Timeout);
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program area in external FLASH.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц.
|
||||
* Данные в сектора участка, но за пределами участка не сохраняются.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_FLASH_Program_Area(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout)
|
||||
{
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
HAL_StatusTypeDef W25_Status;
|
||||
|
||||
// CALC AREA TO PROGRAM
|
||||
uint16_t bytecnt = 0;
|
||||
uint16_t firstpage_size = 0;
|
||||
uint16_t lastpage_size = Size;
|
||||
uint16_t firstpage = (FLASH_Address/256);
|
||||
uint16_t lastpage = ((FLASH_Address+Size-1)/256);
|
||||
if(firstpage != lastpage) // if area is on several pages
|
||||
{
|
||||
firstpage_size = (firstpage+1)*256 - FLASH_Address; // set size of data at first page
|
||||
lastpage_size = (FLASH_Address+Size) - lastpage*256; // set size of data at last page
|
||||
}
|
||||
|
||||
// PROGRAM PAGES: FROM FIRST NO THE PREVIOUS TO THE LAST
|
||||
for(int i = 0; i < lastpage - firstpage; i++)
|
||||
{
|
||||
W25_Status = W25_FLASH_Program_Page(hw25, FLASH_Address, &pData[bytecnt], firstpage_size, Timeout, tickstart); // programm page
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
// note for multiple page program: first we program rest of the first page,
|
||||
// then we shift byte count to data, that shoud be on the next page
|
||||
bytecnt += firstpage_size;
|
||||
FLASH_Address += firstpage_size;
|
||||
// and set start size as page size. because next pages will be fully programmed
|
||||
firstpage_size = W25_PAGE_SIZE;
|
||||
}
|
||||
|
||||
// PROGRAM LAST PAGE
|
||||
W25_Status = W25_FLASH_Program_Page(hw25, FLASH_Address, &pData[bytecnt], lastpage_size, Timeout, tickstart); // programm page
|
||||
if(W25_Status != HAL_OK)
|
||||
return W25_Status;
|
||||
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Erase external FLASH Sector.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс где надо данные стереть.
|
||||
* @param Timeout - время, за которое должно быть осуществлена очистка.
|
||||
* @return HAL status.
|
||||
* @note При Timeout = 0, функция не будет ожидать окончания очистки (выставления в 0 флагов BUSY и WEL)
|
||||
* @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_FLASH_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint32_t Timeout)
|
||||
{
|
||||
uint32_t tickstart = HAL_GetTick();
|
||||
|
||||
// enable writting and waiting for unbusy
|
||||
if(W25_WriteEnablingUntilTimeout(hw25, Timeout, tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
|
||||
// programm page (instruction)
|
||||
W25_CMD_Erase_Sector(hw25, FLASH_Address);
|
||||
|
||||
// waiting for ending of erasing
|
||||
if(Timeout) // if timeout isn zero - wait it.
|
||||
if(W25_WaitOnFlagUntilTimeout(hw25, W25_SR_WEL|W25_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if erase isnt done (W25 busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT; // return timeout because erasing instruction accepted, but arent done
|
||||
// note: if timeout == 0, erasing wouldnt be checking for ending (check busy flag)
|
||||
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Program page in external FLASH.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart - время, относительно которого надо отсчитывать таймаут.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать только байты в прелелах одной страницы.
|
||||
Для более гибкого программирования есть функция W25_FLASH_Program_Area, которая программирует участки любой длины (в теории).
|
||||
*/
|
||||
HAL_StatusTypeDef W25_FLASH_Program_Page(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint32_t tickstart)
|
||||
{
|
||||
// enable writting and waiting for unbusy
|
||||
if(W25_WriteEnablingUntilTimeout(hw25, Timeout, tickstart) != HAL_OK) // if writting isnt enable
|
||||
return HAL_TIMEOUT; // return timeout
|
||||
|
||||
// programm page (instruction)
|
||||
W25_CMD_Page_Program(hw25, FLASH_Address, pData, Size);
|
||||
|
||||
// waiting for ending of writting
|
||||
if(W25_WaitOnFlagUntilTimeout(hw25, W25_SR_WEL|W25_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if writting isnt done (W25 busy and WEL bit isnt in reset state)
|
||||
return HAL_TIMEOUT;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Setting WEL bit until it setted or until timeout.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart - время, относительно которого надо отсчитывать таймаут.
|
||||
* @return HAL status.
|
||||
* @note Подает команду на разрешение записи до тех пор, пока она запись не разрешиться или до тех пор, пока таймаут не истечет.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_WriteEnablingUntilTimeout(W25_HandleTypeDef *hw25, uint32_t Timeout, uint32_t tickstart)
|
||||
{
|
||||
// enable writting
|
||||
W25_CMD_Read_Status_Register(hw25, W25_SR_WEL|W25_SR_BUSY);
|
||||
while((hw25->SR&W25_SR_WEL) != W25_SR_WEL)
|
||||
{
|
||||
// if flash isnt busy - set WEL flag
|
||||
if((hw25->SR&W25_SR_BUSY) == 0)
|
||||
W25_CMD_Write_Enable(hw25);
|
||||
|
||||
W25_CMD_Read_Status_Register(hw25, W25_SR_WEL);
|
||||
if((HAL_GetTick() - tickstart) >= Timeout) // if time is out
|
||||
return HAL_TIMEOUT; // set timeout
|
||||
}
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Wait for flag until timeout.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FlagMask - маска для флагов, какие флаги считывать.
|
||||
* @param FlagStatus - какое состояние должно быть у выбранных флагов.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart - время, относительно которого надо отсчитывать таймаут.
|
||||
* @return HAL status.
|
||||
* @note Считывает флаги до тех пор, пока они не будут в состоянии FlagStatus или до тех пор, пока таймаут не истечет.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_WaitOnFlagUntilTimeout(W25_HandleTypeDef *hw25, uint16_t FlagMask, uint16_t FlagStatus, uint32_t Timeout, uint32_t tickstart)
|
||||
{
|
||||
// enable writting
|
||||
W25_CMD_Read_Status_Register(hw25, FlagMask);
|
||||
while((hw25->SR&FlagMask) != FlagStatus)
|
||||
{
|
||||
W25_CMD_Read_Status_Register(hw25, FlagMask);
|
||||
if((HAL_GetTick() - tickstart) >= Timeout) // if time is out
|
||||
return HAL_TIMEOUT; // set timeout
|
||||
}
|
||||
return HAL_OK; // if all ok return HAL_OK
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------
|
||||
//----------------------COMMAND FUNCTIONS----------------------
|
||||
/**
|
||||
* @brief Send command to read Status Register.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param RequestedBits - какие биты запросить.
|
||||
* @return Заполняет Status Register в hw25.
|
||||
* @note Всего есть две комманды: на запрос верхнего или нижниго байта.
|
||||
* Функция в соответствии с RequestedBits определяет какой байт запросить, или два байта сразу.
|
||||
*/
|
||||
void W25_CMD_Read_Status_Register(W25_HandleTypeDef *hw25, uint16_t RequestedBits)
|
||||
{
|
||||
uint8_t command[2];
|
||||
uint8_t *pSRPtr = 0;
|
||||
uint8_t size = 1;
|
||||
|
||||
if(RequestedBits >> 8) // if its high byte of status register
|
||||
{
|
||||
command[0] = W25_READ_STATUS_REG_2;
|
||||
pSRPtr = (uint8_t *)(&hw25->SR) + 1; // set pointer to HI byte of SR register
|
||||
size = 1;
|
||||
if(RequestedBits & 0xFF) // if low byte also requester
|
||||
{
|
||||
size = 2; // set size to 2 bytes
|
||||
command[1] = W25_READ_STATUS_REG_1;
|
||||
}
|
||||
}
|
||||
else // of its low byte of status register
|
||||
{
|
||||
command[0] = W25_READ_STATUS_REG_1;
|
||||
pSRPtr = (uint8_t *)(&hw25->SR); // set pointer to LO byte of SR register
|
||||
size = 1;
|
||||
}
|
||||
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 1); // send insctruction to read SR
|
||||
W25_SPI_Receive(hw25, pSRPtr, 1); // receive response
|
||||
W25_Deselect(hw25);
|
||||
if(size > 1) // if 2 bytes are requested
|
||||
{
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command+1, 1); // send insctruction to read SR
|
||||
W25_SPI_Receive(hw25, pSRPtr-1, 1); // receive response
|
||||
W25_Deselect(hw25);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command to write bits in Status Register.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param WrittenBits - какие биты запросить.
|
||||
* @note Данная команда посылает биты, как сдвинутые на 2 вправо. Т.е. 0-й бит в комманде - 2-й бит BP0.
|
||||
Но биты указываются в также как они расположены и регистре. Функция сама выполняет сдвиг.
|
||||
*/
|
||||
void W25_CMD_Write_Status_Register(W25_HandleTypeDef *hw25, uint16_t WrittenBits)
|
||||
{
|
||||
uint8_t command[2];
|
||||
|
||||
command[0] = W25_WRITE_STATUS_REG;
|
||||
command[1] = WrittenBits >> 2;
|
||||
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 1);
|
||||
W25_Deselect(hw25);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command to set Write Enable Latch (WEL) in Status Register.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @note Разрешает запись в FLASH, путем высталения WEL в Status Register
|
||||
*/
|
||||
void W25_CMD_Write_Enable(W25_HandleTypeDef *hw25)
|
||||
{
|
||||
uint8_t command[1];
|
||||
command[0] = W25_WRITE_ENABLE;
|
||||
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 1);
|
||||
W25_Deselect(hw25);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send command to read data from FLASH.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс откуда начинать считывание.
|
||||
* @param pBuff - куда записывать данные из FLASH.
|
||||
* @param Size - сколько байтов считывать.
|
||||
* @return pBuff.
|
||||
*/
|
||||
|
||||
void W25_CMD_Read_Data(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size)
|
||||
{
|
||||
uint8_t command[4];
|
||||
uint8_t response[2] = {0};
|
||||
|
||||
command[0] = W25_READ_DATA;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 4);
|
||||
W25_SPI_Receive(hw25, pBuff, Size);
|
||||
W25_Deselect(hw25);
|
||||
}
|
||||
/**
|
||||
* @brief Send command to fast page program.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @note Программирование FLASH только в пределах одной страницы.
|
||||
* Т.е. если запись с 0x0, то не больше 256 байт. Если с 0ч40, то не больше 192 байт.
|
||||
*/
|
||||
void W25_CMD_Fast_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size)
|
||||
{
|
||||
uint8_t command[5] = {0};
|
||||
uint8_t response[2] = {0};
|
||||
|
||||
command[0] = W25_READ_DATA;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
command[4] = 0xFF;
|
||||
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 5);
|
||||
W25_SPI_Receive(hw25, pBuff, Size);
|
||||
W25_Deselect(hw25);
|
||||
}
|
||||
/**
|
||||
* @brief Send command to fast page program.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @note Программирование FLASH только в пределах одной страницы.
|
||||
* Т.е. если запись с 0x0, то не больше 256 байт. Если с 0ч40, то не больше 192 байт.
|
||||
*/
|
||||
void W25_CMD_Page_Program(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size)
|
||||
{
|
||||
// 1 command byte + 3 address bytes + 256 data bytes
|
||||
uint8_t command[1+3+256];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = W25_PAGE_PROGRAM;
|
||||
command[1] = FLASH_Address >> 16 & 0xFF;
|
||||
command[2] = FLASH_Address >> 8 & 0xFF;
|
||||
command[3] = FLASH_Address & 0xFF;
|
||||
|
||||
if((FLASH_Address/256) != ((FLASH_Address+Size-1)/256))
|
||||
return;
|
||||
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 4); // send insctruction to write
|
||||
W25_SPI_Transmit(hw25, pData, Size); // send data to write
|
||||
W25_Deselect(hw25);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command to erase sector.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс где надо данные стереть.
|
||||
* @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом.
|
||||
*/
|
||||
void W25_CMD_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH_Address)
|
||||
{
|
||||
uint8_t command[4];
|
||||
uint8_t response[8];
|
||||
FLASH_Address = FLASH_Address & 0xFFFFFF;
|
||||
|
||||
command[0] = W25_ERASE_SECTOR;
|
||||
command[1] = FLASH_Address >> 16;
|
||||
command[2] = FLASH_Address >> 8;
|
||||
command[3] = FLASH_Address;
|
||||
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 4);
|
||||
W25_Deselect(hw25);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send command to read JEDEC ID.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @return JEDEC ID микросхемы.
|
||||
*/
|
||||
uint32_t W25_CMD_Read_JEDEC_ID(W25_HandleTypeDef *hw25)
|
||||
{
|
||||
uint8_t command[1] = {0};
|
||||
uint8_t receive[4] = {0};
|
||||
uint32_t return_val;
|
||||
|
||||
command[0] = W25_READ_JEDEC_ID;
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 1);
|
||||
W25_SPI_Receive(hw25, &receive[1], 3);
|
||||
W25_Deselect(hw25);
|
||||
|
||||
return_val = (*(uint64_t *)receive);
|
||||
return __REV(return_val) & 0xFFFFFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send command to read JEDEC ID.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @return Device ID микросхемы.
|
||||
*/
|
||||
uint64_t W25_CMD_Read_Device_ID(W25_HandleTypeDef *hw25)
|
||||
{
|
||||
uint8_t command[1] = {0};
|
||||
uint8_t receive[8] = {0};
|
||||
uint64_t return_val_LO;
|
||||
uint64_t return_val_HI;
|
||||
command[0] = W25_READ_UNIQUE_ID;
|
||||
W25_Select(hw25);
|
||||
W25_SPI_Transmit(hw25, command, 1);
|
||||
W25_SPI_Receive(hw25, receive, 8);
|
||||
W25_Deselect(hw25);
|
||||
|
||||
return_val_LO = (*(uint64_t *)receive) >> 32;
|
||||
return_val_HI = (*(uint64_t *)receive) & 0xFFFFFFFF;
|
||||
return ((uint64_t)__REV(return_val_HI) << 32) | __REV(return_val_LO);
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------
|
||||
//---------------------PERIPTH FUNCTIONS-----------------------
|
||||
/**
|
||||
* @brief SPI Transmit.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param data - указатель на данные для отправки.
|
||||
* @param size - размер данных для отправки.
|
||||
* @return Device ID микросхемы.
|
||||
* @note Здесь вызывается только функция HAL, и ничего больше.
|
||||
*/
|
||||
void W25_SPI_Transmit (W25_HandleTypeDef *hw25, uint8_t *data, uint16_t size)
|
||||
{
|
||||
HAL_SPI_Transmit (&hw25->hspi, data, size, 500);
|
||||
|
||||
}
|
||||
//-------------------------------------------------------------
|
||||
/**
|
||||
* @brief SPI Receive.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param data - указатель на буффер для прниема данных.
|
||||
* @param size - размер данных для приема.
|
||||
* @return Device ID микросхемы.
|
||||
* @note Здесь вызывается только функция HAL, и ничего больше.
|
||||
*/
|
||||
void W25_SPI_Receive (W25_HandleTypeDef *hw25, uint8_t *data, uint16_t size)
|
||||
{
|
||||
HAL_SPI_Receive (&hw25->hspi, data, size, 500);
|
||||
|
||||
@@ -1,36 +1,9 @@
|
||||
/********************************W25 FLASH***********************************
|
||||
Данный файл содержит базовые функции для общения с SPI Flash.
|
||||
//-------------------Функции-------------------//
|
||||
@func users
|
||||
- W25_FLASH_Read Считывание FLASH
|
||||
- W25_FLASH_Write_Area Запись данных в заданный участок FLASH (с потерей данных в выбраном сектора за пределами этого участка)
|
||||
- W25_FLASH_Erase_Sector Очистка сектора FLASH
|
||||
- W25_FLASH_Program_Area Программирование FLASH
|
||||
|
||||
@func initialization
|
||||
- W25_Base_Init Инициализация SPI и GPIO для FLASH
|
||||
|
||||
@func process interaction with flash
|
||||
- W25_FLASH_Program_Page Программирование страницы. *есть более общая функция W25_FLASH_Program_Area, которая программирует участки больше страницы
|
||||
- W25_WriteEnablingUntilTimeout Разрешение записи, пока не будет ответа или не истек таймаут
|
||||
- W25_WaitOnFlagUntilTimeout Ожидание флага пока не истек таймаута
|
||||
|
||||
@func cmd functions
|
||||
- W25_CMD_Read_Status_Register Отправка комманд Read Status Register 1 / Read Status Register 1 (0x05h / 0x35h)
|
||||
- W25_CMD_Write_Status_Register Отправка комманды Write Status Register (0x01h)
|
||||
- W25_CMD_Write_Enable Отправка комманды Write Enable (0x06h)
|
||||
- W25_CMD_Write_Disable Отправка комманды Write Disable (0x04h)
|
||||
- W25_CMD_Read_Data Отправка комманды Read Data (0x03h)
|
||||
- W25_CMD_Fast_Read Отправка комманды Fast Read (0x0Bh)
|
||||
- W25_CMD_Page_Program Отправка комманды Page Program (0x02h)
|
||||
- W25_CMD_Erase_Sector Отправка комманды Erase Sector (0x20h)
|
||||
- W25_CMD_Read_JEDEC_ID Отправка комманды Read JEDEC ID (0x4Bh)
|
||||
- W25_CMD_Read_Device_ID Отправка комманды Read Manufacture / Device Id (0x90)
|
||||
|
||||
@func SPI functions
|
||||
- W25_SPI_Transmit Функция отправки по SPI (содержит только HAL_SPI_Transmit)
|
||||
- W25_SPI_Receive Функция приема по SPI (содержит только HAL_SPI_Receive)
|
||||
/********************************W25 FLASH**********************************
|
||||
Данный файл содержит инклюды и дефайны для общения с памятью FLASH по SPI.
|
||||
***************************************************************************/
|
||||
#ifndef __SPI_FLASH_H_
|
||||
#define __SPI_FLASH_H_
|
||||
|
||||
#include "stm32f4xx_hal.h"
|
||||
#include "gpio_general.h"
|
||||
|
||||
@@ -45,10 +18,12 @@
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////---DEFINES---////////////////////////////
|
||||
/**
|
||||
* @brief Defines for CMD.
|
||||
* @brief Defines for W25 chip.
|
||||
*/
|
||||
#define W25_CS_Set(_hw25_) (_hw25_->GPIOs.CS_GPIOx->BSRR = _hw25_->GPIOs.CS_PIN << 16)
|
||||
#define W25_CS_Reset(_hw25_) (_hw25_->GPIOs.CS_GPIOx->BSRR = _hw25_->GPIOs.CS_PIN)
|
||||
#define W25_Select(_hw25_) (_hw25_->GPIOs.CS_GPIOx->BSRR = _hw25_->GPIOs.CS_PIN << 16)
|
||||
#define W25_Deselect(_hw25_) (_hw25_->GPIOs.CS_GPIOx->BSRR = _hw25_->GPIOs.CS_PIN)
|
||||
#define W25_SECTOR_SIZE (0x1000)
|
||||
#define W25_PAGE_SIZE (0x100)
|
||||
/**
|
||||
* @brief Defines for CMD.
|
||||
*/
|
||||
@@ -79,17 +54,13 @@
|
||||
#define W25_SR_BP0 (1<<2)
|
||||
#define W25_SR_WEL (1<<1)
|
||||
#define W25_SR_BUSY (1<<0)
|
||||
/**
|
||||
* @brief Defines for W25 chip.
|
||||
*/
|
||||
#define W25_SECTOR_SIZE (0x1000)
|
||||
#define W25_PAGE_SIZE (0x100)
|
||||
|
||||
/**
|
||||
* @brief Calc dividing including remainder (divide and ceil)
|
||||
* @param _val_ - делимое.
|
||||
* @param _div_ - делитель.
|
||||
* @note Если результат деления без остатка: он возвращается как есть
|
||||
Если с остатком - округляется вверх
|
||||
* Если с остатком - округляется вверх
|
||||
*/
|
||||
//#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */
|
||||
#define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */
|
||||
@@ -107,7 +78,7 @@ typedef struct
|
||||
|
||||
uint32_t Sector_Address;
|
||||
uint32_t Sector_Size;
|
||||
}W25_reProgramInitTypeDef;
|
||||
}W25_WriteInitTypeDef;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -134,7 +105,11 @@ extern W25_HandleTypeDef hw25;
|
||||
///////////////////////---STRUCTURES & ENUMS---//////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
///////////////////////---FUNCTIONS FOR USER---//////////////////////
|
||||
/**
|
||||
* @brief Initialize SPI and GPIO for W25 FLASH.
|
||||
* @param hw25 - указатель на структуру с настройками SPI и GPIO портов.
|
||||
*/
|
||||
void W25_Base_Init(W25_HandleTypeDef *hw25);
|
||||
|
||||
/**
|
||||
@@ -152,18 +127,20 @@ HAL_StatusTypeDef W25_FLASH_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address
|
||||
/**
|
||||
* @brief Write data to area in FLASH.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param reProgramInit - указатель на структуру, определяющую участок памяти для записи.
|
||||
* @param WriteInit - указатель на структуру, определяющую участок памяти для записи.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц.
|
||||
* Данные в сектора участка, но за пределами участка не сохраняются.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_FLASH_Write_Area(W25_HandleTypeDef *hw25, W25_reProgramInitTypeDef *reProgramInit, uint32_t Timeout);
|
||||
HAL_StatusTypeDef W25_FLASH_Write_Area(W25_HandleTypeDef *hw25, W25_WriteInitTypeDef *WriteInit, uint32_t Timeout);
|
||||
|
||||
/**
|
||||
* @brief Program area in FLASH.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param reProgramInit - указатель на структуру, определяющую участок памяти для записи.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц.
|
||||
@@ -174,19 +151,52 @@ HAL_StatusTypeDef W25_FLASH_Program_Area(W25_HandleTypeDef *hw25, uint32_t FLASH
|
||||
/**
|
||||
* @brief Erase FLASH Sector.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param reProgramInit - указатель на структуру, определяющую участок памяти для записи.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param FLASH_Address - адресс где надо данные стереть.
|
||||
* @param Timeout - время, за которое должно быть осуществлена очистка.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц.
|
||||
* Данные в сектора участка, но за пределами участка не сохраняются.
|
||||
* @note При Timeout = 0, функция не будет ожидать окончания очистки (выставления в 0 флагов BUSY и WEL)
|
||||
* @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_FLASH_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint32_t Timeout);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Program page in FLASH.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart - время, относительно которого надо отсчитывать таймаут.
|
||||
* @return HAL status.
|
||||
* @note Позволяет перепрограммировать только байты в прелелах одной страницы.
|
||||
Для более гибкого программирования есть функция W25_FLASH_Program_Area, которая программирует участки любой длины (в теории).
|
||||
*/
|
||||
HAL_StatusTypeDef W25_FLASH_Program_Page(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint32_t tickstart);
|
||||
/**
|
||||
* @brief Setting WEL bit until it setted or until timeout.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart - время, относительно которого надо отсчитывать таймаут.
|
||||
* @return HAL status.
|
||||
* @note Подает команду на разрешение записи до тех пор, пока она запись не разрешиться или до тех пор, пока таймаут не истечет.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_WriteEnablingUntilTimeout(W25_HandleTypeDef *hw25, uint32_t Timeout, uint32_t tickstart);
|
||||
HAL_StatusTypeDef W25_WaitOnFlagUntilTimeout(W25_HandleTypeDef *hw25, uint16_t FlagMask, uint16_t FlagStatus, uint32_t Timeout, uint32_t tickstart);
|
||||
|
||||
/**
|
||||
* @brief Wait for flag until timeout.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FlagMask - маска для флагов, какие флаги считывать.
|
||||
* @param FlagStatus - какое состояние должно быть у выбранных флагов.
|
||||
* @param Timeout - время, за которое должно быть осуществлено чтение.
|
||||
* @param tickstart - время, относительно которого надо отсчитывать таймаут.
|
||||
* @return HAL status.
|
||||
* @note Считывает флаги до тех пор, пока они не будут в состоянии FlagStatus или до тех пор, пока таймаут не истечет.
|
||||
*/
|
||||
HAL_StatusTypeDef W25_WaitOnFlagUntilTimeout(W25_HandleTypeDef *hw25, uint16_t FlagMask, uint16_t FlagStatus, uint32_t Timeout, uint32_t tickstart);
|
||||
///////////////////////---FUNCTIONS FOR USER---//////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//////////////////////---FUNCTION FOR COMMAND---/////////////////////
|
||||
/**
|
||||
* @brief Send command to read Status Register.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
@@ -236,9 +246,9 @@ void W25_CMD_Fast_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t
|
||||
/**
|
||||
* @brief Send command to fast page program.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
* @param FLASH_Address - адресс откуда начинать считывание.
|
||||
* @param FLASH_Address - адресс куда начинать записывать.
|
||||
* @param pData - откуда брать данные для записи в FLASH.
|
||||
* @param Size - сколько байтов считывать.
|
||||
* @param Size - сколько байтов записать.
|
||||
* @note Программирование FLASH только в пределах одной страницы.
|
||||
* Т.е. если запись с 0x0, то не больше 256 байт. Если с 0ч40, то не больше 192 байт.
|
||||
*/
|
||||
@@ -265,7 +275,10 @@ uint32_t W25_CMD_Read_JEDEC_ID(W25_HandleTypeDef *hw25);
|
||||
* @return Device ID микросхемы.
|
||||
*/
|
||||
uint64_t W25_CMD_Read_Device_ID(W25_HandleTypeDef *hw25);
|
||||
//////////////////////---FUNCTION FOR COMMAND---/////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
//////////////////////---FUNCTION FOR PERIPTH---/////////////////////
|
||||
/**
|
||||
* @brief SPI Transmit.
|
||||
* @param hw25 - указатель на хендл flash.
|
||||
@@ -286,5 +299,6 @@ void W25_SPI_Transmit (W25_HandleTypeDef *hw25, uint8_t *data, uint16_t size);
|
||||
*/
|
||||
void W25_SPI_Receive (W25_HandleTypeDef *hw25, uint8_t *data, uint16_t size);
|
||||
|
||||
///////////////////////////---FUNCTIONS---///////////////////////////
|
||||
//////////////////////---FUNCTION FOR PERIPTH---/////////////////////
|
||||
|
||||
#endif // __SPI_FLASH_H_
|
||||
Reference in New Issue
Block a user