From b6e8e69ab3aa40bd3b828985ef61dce7e7e19c4e Mon Sep 17 00:00:00 2001 From: alexey Date: Tue, 13 Aug 2024 10:35:16 +0300 Subject: [PATCH] =?UTF-8?q?=D0=90=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82?= =?UTF-8?q?=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D1=8B=20=D1=84?= =?UTF-8?q?=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Доделаны(?) 4 базовые самостоятельные функции для общения с флеш: Read, Write, Program, Erase. --- spi_flash/spi_flash.c | 187 +++++++++++++++++++++++++++--------------- spi_flash/spi_flash.h | 39 ++++++--- 2 files changed, 150 insertions(+), 76 deletions(-) diff --git a/spi_flash/spi_flash.c b/spi_flash/spi_flash.c index 02b0809..b65711f 100644 --- a/spi_flash/spi_flash.c +++ b/spi_flash/spi_flash.c @@ -2,16 +2,17 @@ Данный файл содержит базовые функции для общения с памятью FLASH по SPI. //-------------------Функции-------------------// @func users - - W25_FLASH_Read Считывание FLASH - - W25_FLASH_Write_Area Запись данных в заданный участок FLASH (с потерей данных в выбраном сектора за пределами этого участка) - - W25_FLASH_Erase_Sector Очистка сектора FLASH - - W25_FLASH_Program_Area Программирование FLASH + - W25_FLASH_Read Считывание внешней FLASH + - W25_FLASH_Write Запись данных в внешнюю FLASH (функция сама очищает нужные сектора, и если надо сохраняет выбранные данные) + - W25_FLASH_Program Программирование внешней FLASH (выбранный участок FLASH должен быть очищен) + - W25_FLASH_Erase Очистка внешней FLASH @func initialization - W25_Base_Init Инициализация SPI и GPIO для FLASH @func process interaction with flash - - W25_FLASH_Program_Page Программирование страницы. *есть более общая функция W25_FLASH_Program_Area, которая программирует участки больше страницы + - W25_FLASH_Erase_Sector Очистка сектора FLASH. *есть более общая функция W25_FLASH_Erase, которая может ощичать несколько секторов + - W25_FLASH_Program_Page Программирование страницы. *есть более общая функция W25_FLASH_Program, которая программирует участки больше страницы - W25_WriteEnablingUntilTimeout Разрешение записи, пока не будет ответа или не истек таймаут - W25_WaitOnFlagUntilTimeout Ожидание флага пока не истек таймаута @@ -109,7 +110,7 @@ void W25_Base_Init(W25_HandleTypeDef *hw25) } /** - * @brief Read data from external FLASH. + * @brief Read external FLASH. * @param hw25 - указатель на хендл flash. * @param FLASH_Address - адресс откуда начинать считывание. * @param pBuff - куда записывать данные из FLASH. @@ -130,7 +131,7 @@ HAL_StatusTypeDef W25_FLASH_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address return HAL_OK; } /** - * @brief Write data to area in external FLASH. + * @brief Write external FLASH. * @param hw25 - указатель на хендл flash. * @param WriteInit - указатель на структуру, определяющую участок памяти для записи. * @param Timeout - время, за которое должно быть осуществлено чтение. @@ -138,123 +139,168 @@ HAL_StatusTypeDef W25_FLASH_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address * @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц. * Данные в сектора участка, но за пределами участка не сохраняются. */ -HAL_StatusTypeDef W25_FLASH_Write_Area(W25_HandleTypeDef *hw25, W25_WriteInitTypeDef *WriteInit, uint32_t Timeout) +HAL_StatusTypeDef W25_FLASH_Write(W25_HandleTypeDef *hw25, W25_WriteInitTypeDef *WriteInit, uint32_t Timeout) { - uint8_t sector_buff[256]; uint32_t tickstart = HAL_GetTick(); uint32_t timeoutcnt = Timeout; + uint8_t *writebuff = WriteInit->pDataPtr; 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 + + // ERASE 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); + W25_Status = W25_FLASH_Erase(hw25, WriteInit->Sector_Address, WriteInit->Sector_Size, 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++) + // WRITE FLASH WITH SAVING PREVIOUS DATA + if(WriteInit->fSavePrevoisData) { - sector_buff[addr_shift+i] = WriteInit->pDataPtr[addr_shift+i]; + uint8_t sector_buff[WriteInit->Sector_Size]; + 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; + + // 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]; + } + + writebuff = sector_buff; // set pointer to buffer that need to be restored + + // PROGRAM FLASH WITH NEW DATA + timeoutcnt = HAL_GetTick() - tickstart; // update timeout + Timeout -= timeoutcnt; + tickstart += timeoutcnt; + // program data to flash + W25_Status = W25_FLASH_Program(hw25, WriteInit->Sector_Address, writebuff, WriteInit->Sector_Size, Timeout); + if(W25_Status != HAL_OK) + return W25_Status; + } + // WRITE FLASH WITHOUT SAVING PREVIOUS DATA + else + { + // PROGRAM FLASH WITH NEW DATA + timeoutcnt = HAL_GetTick() - tickstart; // update timeout + Timeout -= timeoutcnt; + tickstart += timeoutcnt; + // program data to flash + W25_Status = W25_FLASH_Program(hw25, WriteInit->Sector_Address, writebuff, WriteInit->Sector_Size, Timeout); + if(W25_Status != HAL_OK) + return W25_Status; } - - // 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. + * @brief Program external FLASH. * @param hw25 - указатель на хендл flash. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return HAL status. - * @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц. - * Данные в сектора участка, но за пределами участка не сохраняются. + * @note Программирование участка памяти, без ограничений на кол-во байт */ -HAL_StatusTypeDef W25_FLASH_Program_Area(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout) +HAL_StatusTypeDef W25_FLASH_Program(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 currentpage_size = 0; uint16_t lastpage_size = Size; - uint16_t firstpage = (FLASH_Address/256); - uint16_t lastpage = ((FLASH_Address+Size-1)/256); + uint16_t firstpage = (FLASH_Address/W25_PAGE_SIZE); + uint16_t lastpage = ((FLASH_Address+Size-1)/W25_PAGE_SIZE); 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 + currentpage_size = (firstpage+1)*W25_PAGE_SIZE - FLASH_Address; // set size of data on first page + lastpage_size = (FLASH_Address+Size) - lastpage*W25_PAGE_SIZE; // set size of data on last page } // PROGRAM PAGES: FROM FIRST NO THE PREVIOUS TO THE LAST + hw25->hNextAddr = FLASH_Address; // address would increase automatically in this variable 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 + W25_Status = W25_FLASH_Program_Page(hw25, hw25->hNextAddr, &pData[bytecnt], currentpage_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; + bytecnt += currentpage_size; + // and set current size as page size. because next pages will be fully programmed + currentpage_size = W25_PAGE_SIZE; } // PROGRAM LAST PAGE - W25_Status = W25_FLASH_Program_Page(hw25, FLASH_Address, &pData[bytecnt], lastpage_size, Timeout, tickstart); // programm page + W25_Status = W25_FLASH_Program_Page(hw25, hw25->hNextAddr, &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. + * @param hw25 - указатель на хендл flash. + * @param FLASH_Address - адресс где надо данные стереть. + * @param Size - сколько байтов стереть. + * @param Timeout - время, за которое должно быть осуществлена очистка. + * @return HAL status. + * @note Т.к. очитска происходит по секторам, Size нужен, чтобы определить сколько секторов очистить + * И если начальны адресс будет на Sector 0, а последний байт на Sector 1, то произойдет очистка Sector 0 и Sector 1 + */ +HAL_StatusTypeDef W25_FLASH_Erase(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint16_t Size, uint32_t Timeout) +{ + uint32_t tickstart = HAL_GetTick(); + HAL_StatusTypeDef W25_Status; + + // CALC AREA TO ERASE + uint16_t bytecnt = 0; + uint16_t firstsector = (FLASH_Address/W25_SECTOR_SIZE); + uint16_t lastsector = ((FLASH_Address+Size-1)/W25_SECTOR_SIZE); + + for(int i = 0; i <= (lastsector - firstsector); i++) + { + W25_Status = W25_FLASH_Erase_Sector(hw25, FLASH_Address, Timeout, tickstart); // programm page + if(W25_Status != HAL_OK) + return W25_Status; + FLASH_Address += W25_SECTOR_SIZE; + } + return HAL_OK; +} + /** * @brief Erase external FLASH Sector. * @param hw25 - указатель на хендл flash. * @param FLASH_Address - адресс где надо данные стереть. * @param Timeout - время, за которое должно быть осуществлена очистка. + * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @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(); - +HAL_StatusTypeDef W25_FLASH_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, 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) + // erase sector (instruction) W25_CMD_Erase_Sector(hw25, FLASH_Address); // waiting for ending of erasing @@ -262,7 +308,7 @@ HAL_StatusTypeDef W25_FLASH_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH 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 } @@ -276,21 +322,30 @@ HAL_StatusTypeDef W25_FLASH_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @return HAL status. * @note Позволяет перепрограммировать только байты в прелелах одной страницы. - Для более гибкого программирования есть функция W25_FLASH_Program_Area, которая программирует участки любой длины (в теории). + Для более гибкого программирования есть функция W25_FLASH_Program, которая программирует участки любой длины (в теории). */ 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 - + + // check if flash range is placed at one page + if((FLASH_Address/W25_PAGE_SIZE) != ((FLASH_Address+Size-1)/W25_PAGE_SIZE)) // if page of first byte isnt equal page of last byte + return HAL_ERROR; // return error + // 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; + // update handle variables + hw25->hNextAddr = (FLASH_Address+Size); + hw25->hNextPage = (FLASH_Address+Size)/W25_PAGE_SIZE; + hw25->hNextSector = (FLASH_Address+Size)/W25_SECTOR_SIZE; + return HAL_OK; } /** @@ -304,6 +359,7 @@ HAL_StatusTypeDef W25_FLASH_Program_Page(W25_HandleTypeDef *hw25, uint32_t FLASH HAL_StatusTypeDef W25_WriteEnablingUntilTimeout(W25_HandleTypeDef *hw25, uint32_t Timeout, uint32_t tickstart) { // enable writting + W25_CMD_Write_Enable(hw25); W25_CMD_Read_Status_Register(hw25, W25_SR_WEL|W25_SR_BUSY); while((hw25->SR&W25_SR_WEL) != W25_SR_WEL) { @@ -486,7 +542,7 @@ void W25_CMD_Fast_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t 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]; + uint8_t command[1+3+W25_PAGE_SIZE]; FLASH_Address = FLASH_Address & 0xFFFFFF; command[0] = W25_PAGE_PROGRAM; @@ -494,8 +550,9 @@ void W25_CMD_Page_Program(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8 command[2] = FLASH_Address >> 8 & 0xFF; command[3] = FLASH_Address & 0xFF; - if((FLASH_Address/256) != ((FLASH_Address+Size-1)/256)) - return; + // check if flash range is placed at one page + if((FLASH_Address/W25_PAGE_SIZE) != ((FLASH_Address+Size-1)/W25_PAGE_SIZE)) // if page of first byte isnt equal page of last byte + return; // return error W25_Select(hw25); W25_SPI_Transmit(hw25, command, 4); // send insctruction to write @@ -582,7 +639,7 @@ uint64_t W25_CMD_Read_Device_ID(W25_HandleTypeDef *hw25) */ void W25_SPI_Transmit (W25_HandleTypeDef *hw25, uint8_t *data, uint16_t size) { - HAL_SPI_Transmit (&hw25->hspi, data, size, 500); + HAL_SPI_Transmit (&hw25->hspi, data, size, HAL_MAX_DELAY); } /** @@ -595,6 +652,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) { - HAL_SPI_Receive (&hw25->hspi, data, size, 500); + HAL_SPI_Receive (&hw25->hspi, data, size, HAL_MAX_DELAY); } //------------------------------------------------------------- diff --git a/spi_flash/spi_flash.h b/spi_flash/spi_flash.h index 067dbd7..cb8b077 100644 --- a/spi_flash/spi_flash.h +++ b/spi_flash/spi_flash.h @@ -78,6 +78,7 @@ typedef struct uint32_t Sector_Address; uint32_t Sector_Size; + unsigned fSavePrevoisData:1; }W25_WriteInitTypeDef; typedef struct @@ -99,6 +100,9 @@ typedef struct uint16_t SR; SPI_HandleTypeDef hspi; W25_GPIOTypeDef GPIOs; + uint32_t hNextAddr; + uint16_t hNextPage; + uint16_t hNextSector; }W25_HandleTypeDef; extern W25_HandleTypeDef hw25; @@ -113,7 +117,7 @@ extern W25_HandleTypeDef hw25; void W25_Base_Init(W25_HandleTypeDef *hw25); /** - * @brief Read data from external FLASH. + * @brief Read external FLASH. * @param hw25 - указатель на хендл flash. * @param FLASH_Address - адресс откуда начинать считывание. * @param pBuff - куда записывать данные из FLASH. @@ -125,7 +129,7 @@ void W25_Base_Init(W25_HandleTypeDef *hw25); HAL_StatusTypeDef W25_FLASH_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout); /** - * @brief Write data to area in FLASH. + * @brief Write external FLASH. * @param hw25 - указатель на хендл flash. * @param WriteInit - указатель на структуру, определяющую участок памяти для записи. * @param Timeout - время, за которое должно быть осуществлено чтение. @@ -133,34 +137,46 @@ HAL_StatusTypeDef W25_FLASH_Read(W25_HandleTypeDef *hw25, uint32_t FLASH_Address * @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц. * Данные в сектора участка, но за пределами участка не сохраняются. */ -HAL_StatusTypeDef W25_FLASH_Write_Area(W25_HandleTypeDef *hw25, W25_WriteInitTypeDef *WriteInit, uint32_t Timeout); +HAL_StatusTypeDef W25_FLASH_Write(W25_HandleTypeDef *hw25, W25_WriteInitTypeDef *WriteInit, uint32_t Timeout); /** - * @brief Program area in FLASH. + * @brief Program external FLASH. * @param hw25 - указатель на хендл flash. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return HAL status. - * @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц. - * Данные в сектора участка, но за пределами участка не сохраняются. + * @note Программирование участка памяти, без ограничений на кол-во байт */ -HAL_StatusTypeDef W25_FLASH_Program_Area(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout); +HAL_StatusTypeDef W25_FLASH_Program(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout); /** - * @brief Erase FLASH Sector. + * @brief Erase external FLASH. + * @param hw25 - указатель на хендл flash. + * @param FLASH_Address - адресс где надо данные стереть. + * @param Size - сколько байтов стереть. + * @param Timeout - время, за которое должно быть осуществлена очистка. + * @return HAL status. + * @note Т.к. очитска происходит по секторам, Size нужен, чтобы определить сколько секторов очистить + * И если начальны адресс будет на Sector 0, а последний байт на Sector 1, то произойдет очистка Sector 0 и Sector 1 + */ +HAL_StatusTypeDef W25_FLASH_Erase(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint16_t Size, uint32_t Timeout); + +/** + * @brief Erase external FLASH Sector. * @param hw25 - указатель на хендл flash. * @param FLASH_Address - адресс где надо данные стереть. * @param Timeout - время, за которое должно быть осуществлена очистка. + * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @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); +HAL_StatusTypeDef W25_FLASH_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH_Address, uint32_t Timeout, uint32_t tickstart); /** - * @brief Program page in FLASH. + * @brief Program page in external FLASH. * @param hw25 - указатель на хендл flash. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. @@ -169,9 +185,10 @@ HAL_StatusTypeDef W25_FLASH_Erase_Sector(W25_HandleTypeDef *hw25, uint32_t FLASH * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @return HAL status. * @note Позволяет перепрограммировать только байты в прелелах одной страницы. - Для более гибкого программирования есть функция W25_FLASH_Program_Area, которая программирует участки любой длины (в теории). + Для более гибкого программирования есть функция W25_FLASH_Program, которая программирует участки любой длины (в теории). */ 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.