Большой апгрейд:

- исправлены баги библиотеки memspi
- добавлены модули для сохранения настреок в eeprom и flash (с равномерным износом)
- надо тестить, проверять и рефакторить
This commit is contained in:
2026-02-17 18:34:50 +03:00
parent e9d2214953
commit 643391038e
8 changed files with 2534 additions and 193 deletions

View File

@@ -32,44 +32,44 @@
*/
HAL_StatusTypeDef MEMSPI_CMD_Read_Status_Register(MEMSPI_HandleTypeDef *hmemspi, uint16_t RequestedBits, uint8_t EndCMD, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
uint8_t command[2];
uint8_t *pSRPtr = 0;
uint8_t size = 1;
if(RequestedBits >> 8) // if its high byte of status register
{
HAL_StatusTypeDef SPI_RES;
uint8_t command[2];
uint8_t *pSRPtr = 0;
uint8_t size = 1;
if(RequestedBits >> 8) // if its high byte of status register
{
#ifdef MEMSPI_READ_STATUS_REG_2
command[0] = MEMSPI_READ_STATUS_REG_2;
pSRPtr = (uint8_t *)(&hmemspi->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] = MEMSPI_READ_STATUS_REG;
}
#endif // MEMSPI_READ_STATUS_REG_2
}
else // of its low byte of status register
command[0] = MEMSPI_READ_STATUS_REG_2;
pSRPtr = (uint8_t *)(&hmemspi->SR) + 1; // set pointer to HI byte of SR register
size = 1;
if(RequestedBits & 0xFF) // if low byte also requester
{
command[0] = MEMSPI_READ_STATUS_REG;
pSRPtr = (uint8_t *)(&hmemspi->SR); // set pointer to LO byte of SR register
size = 1;
}
MEMSPI_Select(hmemspi);
size = 2; // set size to 2 bytes
command[1] = MEMSPI_READ_STATUS_REG;
}
#endif // MEMSPI_READ_STATUS_REG_2
}
else // of its low byte of status register
{
command[0] = MEMSPI_READ_STATUS_REG;
pSRPtr = (uint8_t *)(&hmemspi->SR); // set pointer to LO byte of SR register
size = 1;
}
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 1, Timeout); // send insctruction to read SR
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pSRPtr, 1, Timeout); // receive response
if(size > 1) // if 2 bytes are requested
{
MEMSPI_Deselect(hmemspi);
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command+1, 1, Timeout); // send insctruction to read SR
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pSRPtr-1, 1, Timeout); // receive response
MEMSPI_Deselect(hmemspi);
}
if(EndCMD)
MEMSPI_Deselect(hmemspi);
return SPI_RES;
if(size > 1) // if 2 bytes are requested
{
MEMSPI_Deselect(hmemspi);
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command+1, 1, Timeout); // send insctruction to read SR
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pSRPtr-1, 1, Timeout); // receive response
MEMSPI_Deselect(hmemspi);
}
if(EndCMD)
MEMSPI_Deselect(hmemspi);
return SPI_RES;
}
/**
@@ -82,21 +82,21 @@ HAL_StatusTypeDef MEMSPI_CMD_Read_Status_Register(MEMSPI_HandleTypeDef *hmemspi,
*/
HAL_StatusTypeDef MEMSPI_CMD_Write_Status_Register(MEMSPI_HandleTypeDef *hmemspi, uint16_t WrittenBits, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
uint8_t command[3];
uint8_t size;
HAL_StatusTypeDef SPI_RES;
uint8_t command[3];
uint8_t size;
command[0] = MEMSPI_WRITE_STATUS_REG;
command[1] = WrittenBits;
command[2] = WrittenBits >> 8;
size = 3;
command[1] = WrittenBits;
command[2] = WrittenBits >> 8;
size = 3;
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, size, Timeout);
MEMSPI_Deselect(hmemspi);
return SPI_RES;
return SPI_RES;
}
/**
@@ -107,7 +107,7 @@ HAL_StatusTypeDef MEMSPI_CMD_Write_Status_Register(MEMSPI_HandleTypeDef *hmemspi
*/
HAL_StatusTypeDef MEMSPI_CMD_Write_Enable(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
HAL_StatusTypeDef SPI_RES;
uint8_t command[1];
command[0] = MEMSPI_WRITE_ENABLE;
@@ -115,7 +115,7 @@ HAL_StatusTypeDef MEMSPI_CMD_Write_Enable(MEMSPI_HandleTypeDef *hmemspi, uint32_
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 1, Timeout);
MEMSPI_Deselect(hmemspi);
return SPI_RES;
return SPI_RES;
}
@@ -130,9 +130,9 @@ HAL_StatusTypeDef MEMSPI_CMD_Write_Enable(MEMSPI_HandleTypeDef *hmemspi, uint32_
*/
HAL_StatusTypeDef MEMSPI_CMD_Read_Data(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
uint8_t command[4];
uint8_t response[2] = {0};
HAL_StatusTypeDef SPI_RES;
uint8_t command[4];
uint8_t response[2] = {0};
command[0] = MEMSPI_READ_DATA;
command[1] = FLASH_Address >> 16 & 0xFF;
@@ -144,7 +144,7 @@ HAL_StatusTypeDef MEMSPI_CMD_Read_Data(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pBuff, Size, Timeout);
MEMSPI_Deselect(hmemspi);
return SPI_RES;
return SPI_RES;
}
/**
@@ -158,22 +158,22 @@ HAL_StatusTypeDef MEMSPI_CMD_Read_Data(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
*/
HAL_StatusTypeDef MEMSPI_CMD_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
// 1 command byte + 3 address bytes + 256 data bytes
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
FLASH_Address = FLASH_Address & 0xFFFFFF;
HAL_StatusTypeDef SPI_RES;
// 1 command byte + 3 address bytes + 256 data bytes
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
FLASH_Address = FLASH_Address & 0xFFFFFF;
command[0] = MEMSPI_WRITE_EEPROM;
command[1] = FLASH_Address >> 16 & 0xFF;
command[2] = FLASH_Address >> 8 & 0xFF;
command[3] = FLASH_Address & 0xFF;
command[1] = FLASH_Address >> 16 & 0xFF;
command[2] = FLASH_Address >> 8 & 0xFF;
command[3] = FLASH_Address & 0xFF;
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout); // send insctruction to write
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, pData, Size, Timeout); // send data to write
MEMSPI_Deselect(hmemspi);
return SPI_RES;
return SPI_RES;
}
/**
* @brief Send command to page program in FLASH.
@@ -187,26 +187,57 @@ HAL_StatusTypeDef MEMSPI_CMD_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_
*/
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Page_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
// 1 command byte + 3 address bytes + 256 data bytes
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
FLASH_Address = FLASH_Address & 0xFFFFFF;
HAL_StatusTypeDef SPI_RES;
// 1 command byte + 3 address bytes + 256 data bytes
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
FLASH_Address = FLASH_Address & 0xFFFFFF;
command[0] = MEMSPI_PAGE_PROGRAM;
command[1] = FLASH_Address >> 16 & 0xFF;
command[2] = FLASH_Address >> 8 & 0xFF;
command[3] = FLASH_Address & 0xFF;
// check if flash range is placed at one page
if((FLASH_Address/MEMSPI_PAGE_SIZE) != ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE)) // if page of first byte isnt equal page of last byte
return HAL_ERROR; // return error
command[1] = FLASH_Address >> 16 & 0xFF;
command[2] = FLASH_Address >> 8 & 0xFF;
command[3] = FLASH_Address & 0xFF;
// check if flash range is placed at one page
if((FLASH_Address/MEMSPI_PAGE_SIZE) != ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE)) // if page of first byte isnt equal page of last byte
return HAL_ERROR; // return error
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout); // send insctruction to write
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, pData, Size, Timeout); // send data to write
MEMSPI_Deselect(hmemspi);
return SPI_RES;
return SPI_RES;
}
/**
* @brief Send command to byte program in FLASH.
* @param hmemspi - указатель на хендл внешней памяти.
* @param FLASH_Address - адресс куда начинать записывать.
* @param Byte - байт для записи в FLASH.
* @param Timeout - время, за которое должна быть осуществлена запись.
*/
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Byte_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t Byte, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
// 1 command byte + 3 address bytes + 256 data bytes
uint8_t command[1+3+MEMSPI_PAGE_SIZE];
FLASH_Address = FLASH_Address & 0xFFFFFF;
command[0] = MEMSPI_BYTE_PROGRAM;
command[1] = FLASH_Address >> 16 & 0xFF;
command[2] = FLASH_Address >> 8 & 0xFF;
command[3] = FLASH_Address & 0xFF;
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout); // send insctruction to write
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, &Byte, 1, Timeout); // send byte to write
MEMSPI_Deselect(hmemspi);
if(SPI_RES != HAL_OK)
{
printf_memspi_err("Error Program Byte: 0x%08lX", (unsigned long)FLASH_Address);
}
return SPI_RES;
}
/**
@@ -218,23 +249,118 @@ HAL_StatusTypeDef MEMSPI_CMD_FLASH_Page_Program(MEMSPI_HandleTypeDef *hmemspi, u
*/
HAL_StatusTypeDef MEMSPI_CMD_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
uint8_t command[4];
HAL_StatusTypeDef SPI_RES;
uint8_t command[4];
uint8_t response[8];
FLASH_Address = FLASH_Address & 0xFFFFFF;
FLASH_Address = FLASH_Address & 0xFFFFFF;
command[0] = MEMSPI_ERASE_SECTOR;
command[1] = FLASH_Address >> 16;
command[2] = FLASH_Address >> 8;
command[3] = FLASH_Address;
command[1] = FLASH_Address >> 16;
command[2] = FLASH_Address >> 8;
command[3] = FLASH_Address;
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout);
MEMSPI_Deselect(hmemspi);
return SPI_RES;
return SPI_RES;
}
/**
* @brief Send command to unprotect sector.
* @param hmemspi - указатель на хендл внешней памяти.
* @param FLASH_Address - адресс сектора, с которого надо снять защиту.
* @param Timeout - время, за которое должна быть осуществлена операция.
* @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом.
*/
HAL_StatusTypeDef MEMSPI_CMD_Unprotect_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout)
{
#ifdef MEMSPI_PROTECT_SECTOR
HAL_StatusTypeDef SPI_RES;
uint8_t command[4];
FLASH_Address = FLASH_Address & 0xFFFFFF;
command[0] = MEMSPI_UNPROTECT_SECTOR;
command[1] = FLASH_Address >> 16;
command[2] = FLASH_Address >> 8;
command[3] = FLASH_Address;
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout);
MEMSPI_Deselect(hmemspi);
return SPI_RES;
#else
return HAL_ERROR;
#endif
}
/**
* @brief Send command to protect sector.
* @param hmemspi - указатель на хендл внешней памяти.
* @param FLASH_Address - адресс сектора, на который надо поставить защиту.
* @param Timeout - время, за которое должна быть осуществлена операция.
* @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом.
*/
HAL_StatusTypeDef MEMSPI_CMD_Protect_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t Timeout)
{
#ifdef MEMSPI_PROTECT_SECTOR
HAL_StatusTypeDef SPI_RES;
uint8_t command[4];
FLASH_Address = FLASH_Address & 0xFFFFFF;
command[0] = MEMSPI_PROTECT_SECTOR;
command[1] = FLASH_Address >> 16;
command[2] = FLASH_Address >> 8;
command[3] = FLASH_Address;
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout);
MEMSPI_Deselect(hmemspi);
return SPI_RES;
#else
return HAL_ERROR;
#endif
}
/**
* @brief Send command to read Sector Protection Register.
* @param hmemspi Указатель на хендл внешней памяти.
* @param FLASH_Address Адрес в пределах интересующего сектора (A16-A0).
* @param pStatus Указатель для сохранения статуса защиты (0x00 - не защищен, 0xFF - защищен).
* @param Timeout Время, за которое должно быть осуществлено чтение.
* @return HAL_StatusTypeDef.
* @note Команда 0x3C. После адреса микросхема начинает выдавать байты FFh или 00h.
* Рекомендуется читать минимум 2 байта для корректного определения статуса на высокой частоте.
*/
HAL_StatusTypeDef MEMSPI_CMD_Read_Sector_Protection(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pStatus, uint32_t Timeout)
{
#ifdef MEMSPI_PROTECT_SECTOR
HAL_StatusTypeDef SPI_RES;
uint8_t command[4];
uint8_t receive[2] = {0}; // читаем 2 байта для надежности
FLASH_Address = FLASH_Address & 0xFFFFFF;
command[0] = MEMSPI_READ_PROTECT_REG;
command[1] = FLASH_Address >> 16;
command[2] = FLASH_Address >> 8;
command[3] = FLASH_Address;
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 4, Timeout);
SPI_RES = MEMSPI_SPI_Receive(hmemspi, receive, 2, Timeout); // Читаем данные защиты (рекомендуется минимум 2 байта для корректного определения на высокой частоте SCK)
MEMSPI_Deselect(hmemspi);
if(SPI_RES == HAL_OK) {
*pStatus = receive[1]; // Второй байт более надежен на высокой частоте
// Согласно документации: 0x00 - сектор не защищен, 0xFF - сектор защищен
}
return SPI_RES;
#else
return HAL_ERROR;
#endif
}
/**
* @brief Send command to read JEDEC ID.
@@ -244,10 +370,10 @@ HAL_StatusTypeDef MEMSPI_CMD_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, u
*/
uint32_t MEMSPI_CMD_Read_JEDEC_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
HAL_StatusTypeDef SPI_RES;
uint8_t command[1] = {0};
uint8_t receive[4] = {0};
uint32_t return_val;
uint32_t return_val;
command[0] = MEMSPI_READ_JEDEC_ID;
MEMSPI_Select(hmemspi);
@@ -267,19 +393,19 @@ uint32_t MEMSPI_CMD_Read_JEDEC_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeou
*/
uint64_t MEMSPI_CMD_Read_Device_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
HAL_StatusTypeDef SPI_RES;
uint8_t command[1] = {0};
uint8_t receive[8] = {0};
uint64_t return_val_LO;
uint64_t return_val_HI;
uint64_t return_val_LO;
uint64_t return_val_HI;
command[0] = MEMSPI_READ_UNIQUE_ID;
MEMSPI_Select(hmemspi);
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 1, Timeout);
SPI_RES = MEMSPI_SPI_Receive(hmemspi, receive, 8, Timeout);
MEMSPI_Deselect(hmemspi);
return_val_LO = (*(uint64_t *)receive) >> 32;
return_val_HI = (*(uint64_t *)receive) & 0xFFFFFFFF;
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);
}
/**
@@ -293,9 +419,9 @@ uint64_t MEMSPI_CMD_Read_Device_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeo
*/
HAL_StatusTypeDef MEMSPI_CMD_Fast_Read(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout)
{
HAL_StatusTypeDef SPI_RES;
uint8_t command[5] = {0};
uint8_t response[2] = {0};
HAL_StatusTypeDef SPI_RES;
uint8_t command[5] = {0};
uint8_t response[2] = {0};
command[0] = MEMSPI_READ_DATA;
command[1] = FLASH_Address >> 16 & 0xFF;
@@ -307,8 +433,8 @@ HAL_StatusTypeDef MEMSPI_CMD_Fast_Read(MEMSPI_HandleTypeDef *hmemspi, uint32_t F
SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 5, Timeout);
SPI_RES = MEMSPI_SPI_Receive(hmemspi, pBuff, Size, Timeout);
MEMSPI_Deselect(hmemspi);
return SPI_RES;
return SPI_RES;
}
//-------------------------------------------------------------