diff --git a/CubeKeil Example/Core/Src/main.c b/CubeKeil Example/Core/Src/main.c index baca127..c4cea99 100644 --- a/CubeKeil Example/Core/Src/main.c +++ b/CubeKeil Example/Core/Src/main.c @@ -58,7 +58,7 @@ void SystemClock_Config(void); /* USER CODE BEGIN 0 */ W25_HandleTypeDef hw25; HAL_StatusTypeDef W25_RES; -W25_reProgramInitTypeDef writeInit; +W25_WriteInitTypeDef writeInit; uint8_t read_buff[20] = {0}; uint8_t write_buff[20] = {0x14,0x13,0x12,0x11,0x10, @@ -115,16 +115,16 @@ int main(void) /* Infinite loop */ /* USER CODE BEGIN WHILE */ - // Example for using manufactire info CMD + // Example for FLASH: using manufactire info CMD uint32_t w25_ID = W25_CMD_Read_JEDEC_ID(&hw25); uint64_t w25_unique_ID = W25_CMD_Read_Device_ID(&hw25); - // Example for erase/program/read functions + // Example for FLASH: erase/program/read functions W25_RES = W25_FLASH_Erase_Sector(&hw25, 0, 1000); W25_RES = W25_FLASH_Program_Area(&hw25, 0xf9, write_buff, 15, 100); W25_CMD_Read_Data(&hw25, 0xf9, read_buff, 15); - // Example for write area functions + // Example for FLASH: write area functions init writeInit.pDataPtr = write_buff; writeInit.Data_Address = 0xfb; writeInit.Data_Size = 1; @@ -132,6 +132,7 @@ int main(void) writeInit.Sector_Size = 15; while (1) { + // Example for FLASH: write area functions W25_FLASH_Write_Area(&hw25, &writeInit, 1000); HAL_Delay(10); W25_CMD_Read_Data(&hw25, 0xf9, read_buff, 15); diff --git a/CubeKeil Example/MDK-ARM/flash eeprom Example.uvoptx b/CubeKeil Example/MDK-ARM/flash eeprom Example.uvoptx index b6013b6..de0ccbe 100644 --- a/CubeKeil Example/MDK-ARM/flash eeprom Example.uvoptx +++ b/CubeKeil Example/MDK-ARM/flash eeprom Example.uvoptx @@ -154,7 +154,7 @@ 0 135 1 -
134230134
+
134230152
0 0 0 @@ -165,6 +165,22 @@ \\flash_eeprom_Example\../Core/Src/main.c\135 + + 1 + 0 + 136 + 1 +
0
+ 0 + 0 + 0 + 0 + 0 + 0 + ../Core/Src/main.c + + +
@@ -312,18 +328,6 @@ 2 2 - 5 - 0 - 0 - 0 - ..\Core\Inc\stm32f4xx_hal_conf.h - stm32f4xx_hal_conf.h - 0 - 0 - - - 2 - 3 1 0 0 @@ -335,7 +339,7 @@ 2 - 4 + 3 1 0 0 @@ -347,7 +351,7 @@ 2 - 5 + 4 1 0 0 @@ -359,7 +363,7 @@ 2 - 6 + 5 1 0 0 @@ -371,7 +375,7 @@ 2 - 7 + 6 1 0 0 @@ -383,7 +387,7 @@ 2 - 8 + 7 1 0 0 @@ -393,6 +397,18 @@ 0 0 + + 2 + 8 + 5 + 0 + 0 + 0 + ..\Core\Inc\stm32f4xx_hal_conf.h + stm32f4xx_hal_conf.h + 0 + 0 + @@ -649,7 +665,7 @@ 5 28 1 - 1 + 0 0 0 ..\..\spi_flash\spi_flash.c @@ -684,7 +700,7 @@ 0 0 0 - ..\..\..\.GENERAL\gpio_general.c + ..\..\GENERAL\gpio_general.c gpio_general.c 0 0 @@ -696,7 +712,7 @@ 0 0 0 - ..\..\..\.GENERAL\gpio_general.h + ..\..\GENERAL\gpio_general.h gpio_general.h 0 0 @@ -708,7 +724,7 @@ 0 0 0 - ..\..\..\.GENERAL\periph_general.h + ..\..\GENERAL\periph_general.h periph_general.h 0 0 diff --git a/CubeKeil Example/MDK-ARM/flash eeprom Example.uvprojx b/CubeKeil Example/MDK-ARM/flash eeprom Example.uvprojx index 64b6699..445a7e9 100644 --- a/CubeKeil Example/MDK-ARM/flash eeprom Example.uvprojx +++ b/CubeKeil Example/MDK-ARM/flash eeprom Example.uvprojx @@ -395,11 +395,6 @@ Application/User/Core - - stm32f4xx_hal_conf.h - 5 - ..\Core\Inc\stm32f4xx_hal_conf.h - main.c 1 @@ -430,6 +425,11 @@ 1 ../Core/Src/stm32f4xx_hal_msp.c + + stm32f4xx_hal_conf.h + 5 + ..\Core\Inc\stm32f4xx_hal_conf.h + @@ -609,17 +609,17 @@ gpio_general.c 1 - ..\..\..\.GENERAL\gpio_general.c + ..\..\GENERAL\gpio_general.c gpio_general.h 5 - ..\..\..\.GENERAL\gpio_general.h + ..\..\GENERAL\gpio_general.h periph_general.h 5 - ..\..\..\.GENERAL\periph_general.h + ..\..\GENERAL\periph_general.h diff --git a/GENERAL/flash_general.c b/GENERAL/flash_general.c deleted file mode 100644 index f904b65..0000000 --- a/GENERAL/flash_general.c +++ /dev/null @@ -1,190 +0,0 @@ -#include "flash_general.h" -FLASH_EraseInitTypeDef EraseInitStruct; -extern HAL_StatusTypeDef res_hal; -unsigned CRC_Update; -//uint32_t PAGE_OFFSET = ((uint32_t)((4-1) * 0x0400)); -uint32_t PAGE_NUMB = 127; - -//---------------------------------------------------------- -/*-----------------BOOTLOADER FUNCTIONS-------------------*/ - -/* Записать в память данные, произвольного размера */ -HAL_StatusTypeDef FLASH_Write_Data(uint32_t* Address, uint8_t* Data, int Data_size) -{ - int data_cnt = 0; - uint32_t adr;а - uint32_t word_data; - - - res_hal = HAL_FLASH_Unlock(); - - if (res_hal != HAL_OK) return res_hal; - - for (adr = *Address; adr < *Address + Data_size; adr = adr + 4) - { - - - word_data = ( - Data[data_cnt] | - Data[data_cnt + 1] << 8 | - Data[data_cnt + 2] << 16 | - Data[data_cnt + 3] << 24); - - if (adr == (0x40+USART2_IRQn*4)+MAIN_APP_START_ADDRESS) - { - // check if uart handler is correct - if (word_data == FLASH_Read_Word(MAIN_APP_START_ADDRESS+4) + 0x1A) // if there is no specific address for uart handler - { - word_data = FLASH_Read_Word(UART_HANDLER_ADD); // write address of bootloader uart handler - CRC_Update = 1; - - } - } - - res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr, word_data); - - if (res_hal != HAL_OK) return res_hal; - - data_cnt += 4; - } - - *Address += Data_size; - res_hal = HAL_FLASH_Lock(); - - return res_hal; -} - -/* Очистить приложение */ -HAL_StatusTypeDef FLASH_Erase_App(void) // -{ - uint32_t PageError = 0x00; - - res_hal = HAL_FLASH_Unlock(); - - if (res_hal != HAL_OK) - { - __ASM(""); - return res_hal; - } - - EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;// erase pages - EraseInitStruct.Banks = FLASH_BANK_1; - EraseInitStruct.Sector = KEY_FLASH_SECTOR_X+1; //first sector for erase - EraseInitStruct.NbSectors = 8;// num of sector that need to be erased - - res_hal = HAL_FLASHEx_Erase(&EraseInitStruct, &PageError); - - if (res_hal != HAL_OK) - { - __ASM(""); - return res_hal; - } - - res_hal = HAL_FLASH_Lock(); - - return res_hal; -} - -/* Записать ключ в память */ -void SetKey(void) -{ - HAL_FLASH_Unlock(); - - HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, BOOTLOADER_KEY_SECTOR_ADR, BL_KEY_APP_WRITTEN); - - HAL_FLASH_Lock(); -} -/* Считать ключ из памяти */ -uint32_t ReadKey(void) -{ - return (*(__IO uint32_t*)BOOTLOADER_KEY_SECTOR_ADR); -} -/* Очистить настройки бутлоадера для запуска приложения (CRC) */ -void ResetAppSettings(void) -{ - HAL_FLASH_Unlock(); - uint32_t PageError = 0x00; - - EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;// erase pages - EraseInitStruct.Banks = APP_SET_FLASH_BANK_X; - EraseInitStruct.Sector = APP_SET_FLASH_SECTOR_X; //address - EraseInitStruct.NbSectors = 1;// num of erased pages - - HAL_FLASHEx_Erase(&EraseInitStruct, &PageError); - HAL_FLASH_Lock(); - -} -/* Очистить сектор с ключом (ключ, количество перезагрузок из-за WDGT) */ -void ResetKeySector(void) -{ - HAL_FLASH_Unlock(); - uint32_t PageError = 0x00; - - EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;// erase pages - EraseInitStruct.Banks = KEY_FLASH_BANK_X; - EraseInitStruct.Sector = KEY_FLASH_SECTOR_X; //address - EraseInitStruct.NbSectors = 1;// num of erased pages - - HAL_FLASHEx_Erase(&EraseInitStruct, &PageError); - HAL_FLASH_Lock(); - -} -/*-----------------BOOTLOADER FUNCTIONS-------------------*/ -//---------------------------------------------------------- - - - -//-----------------ELEMENTARY FUNCTIONS--------------------- -/* functions for reading bytes/halswords/words */ -uint8_t FLASH_Read_Byte(uint32_t add) -{ - return (*(__IO uint8_t*)(add)); -} -uint16_t FLASH_Read_HalfWord(uint32_t add) -{ - return (*(__IO uint16_t*)(add)); -} -uint32_t FLASH_Read_Word(uint32_t add) -{ - return (*(__IO uint32_t*)(add)); -} -/* functions for writing bytes/halswords/words */ -HAL_StatusTypeDef FLASH_Write_Byte(uint32_t Address, uint8_t Data) -{ - res_hal = HAL_FLASH_Unlock(); - - if (res_hal != HAL_OK) return res_hal; - - res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, Address, (uint8_t)(Data)); - - if (res_hal != HAL_OK) return res_hal; - - res_hal = HAL_FLASH_Lock(); - return res_hal; -} -HAL_StatusTypeDef FLASH_Write_HalfWord(uint32_t Address, uint16_t Data) -{ - res_hal = HAL_FLASH_Unlock(); - - if (res_hal != HAL_OK) return res_hal; - - res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, (uint16_t)(Data)); - - if (res_hal != HAL_OK) return res_hal; - - res_hal = HAL_FLASH_Lock(); - return res_hal; -} -HAL_StatusTypeDef FLASH_Write_Word(uint32_t Address, uint32_t Data) -{ - res_hal = HAL_FLASH_Unlock(); - if (res_hal != HAL_OK) return res_hal; - - res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, (uint32_t)(Data)); - if (res_hal != HAL_OK) return res_hal; - - res_hal = HAL_FLASH_Lock(); - return res_hal; -} -//---------------------------------------------------------- - diff --git a/GENERAL/flash_general.h b/GENERAL/flash_general.h deleted file mode 100644 index 4d23041..0000000 --- a/GENERAL/flash_general.h +++ /dev/null @@ -1,77 +0,0 @@ -/*********************************UART************************************** -Данный файл содержит объявления базовых функции и дефайны для инициализации -UART. -***************************************************************************/ -#ifndef __UART_GENERAL_H_ -#define __UART_GENERAL_H_ - -////////////////////////////////////////////////////////////////////// -/////////////////////////---USER SETTINGS---///////////////////////// -#define HAL_UART_MODULE_ENABLED // need to uncomment these defines in stm32f4xx_hal_conf.h -#define HAL_USART_MODULE_ENABLED // also need to add hal_uart.c (source code) - -//#define USE_USART1 -//#define USE_USART2 -//#define USE_USART3 -//#define USE_UART4 -//#define USE_UART5 -//#define USE_USART6 -/* note: used uart defines in modbus.h */ - -/////////////////////////---USER SETTINGS---///////////////////////// -#include "periph_general.h" - - - -///////////////////////////////////////////////////////////////////// -////////////////////////////---DEFINES---//////////////////////////// -/** - * @brief Analog for HAL define. Remade with pointer to structure. - * @note @ref __HAL_LINKDMA. - */ -#define __USER_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__) \ -do{ \ -(__HANDLE__)->__PPP_DMA_FIELD__ = (__DMA_HANDLE__); \ -(__DMA_HANDLE__)->Parent = (__HANDLE__);} while(0U) - - -////////////////////////////---DEFINES---//////////////////////////// - - -///////////////////////////////////////////////////////////////////// -///////////////////////---STRUCTURES & ENUMS---////////////////////// -typedef struct // struct with settings for custom function -{ - UART_HandleTypeDef huart; - - GPIO_TypeDef *GPIOx; - uint16_t GPIO_PIN_RX; - uint16_t GPIO_PIN_TX; - - DMA_Stream_TypeDef *DMAChannel; // DMAChannel = 0 if doesnt need - uint32_t DMA_CHANNEL_X; // DMAChannel = 0 if doesnt need - - -}UART_SettingsTypeDef; -///////////////////////---STRUCTURES & ENUMS---////////////////////// - - -///////////////////////////////////////////////////////////////////// -///////////////////////////---FUNCTIONS---/////////////////////////// -/** - * @brief Initialize UART with UART_SettingsTypeDef structure. - * @param suart - указатель на структуру с настройками UART. - * @return HAL status. - * @note Данная структура содержит хендл ЮАРТ и настройки перефирии (GPIO) - */ -/* functions for reading bytes/halswords/words */ -uint8_t FLASH_Read_Byte(uint32_t add); -uint16_t FLASH_Read_HalfWord(uint32_t add); -uint32_t FLASH_Read_Word(uint32_t add); -/* functions for writing bytes/halswords/words */ -HAL_StatusTypeDef FLASH_Write_Byte(uint32_t Address, uint8_t Data); -HAL_StatusTypeDef FLASH_Write_HalfWord(uint32_t Address, uint16_t Data); -HAL_StatusTypeDef FLASH_Write_Word(uint32_t Address, uint32_t Data); -///////////////////////////---FUNCTIONS---/////////////////////////// - -#endif // __UART_GENERAL_H_ \ No newline at end of file diff --git a/GENERAL/gpio_general.c b/GENERAL/gpio_general.c index 49e6fb5..5e866d0 100644 --- a/GENERAL/gpio_general.c +++ b/GENERAL/gpio_general.c @@ -1,4 +1,4 @@ -/**********************************TIM************************************** +/*********************************GPIO************************************** Данный файл содержит базовые функции для инициализации портов. //-------------------Функции-------------------// @func users diff --git a/GENERAL/gpio_general.h b/GENERAL/gpio_general.h index d7a9dea..18b2eb3 100644 --- a/GENERAL/gpio_general.h +++ b/GENERAL/gpio_general.h @@ -1,4 +1,4 @@ -/**********************************TIM************************************** +/*********************************GPIO************************************** Данный файл содержит объявления базовых функции и дефайны для инициализации портов. ***************************************************************************/ @@ -7,13 +7,13 @@ #include "periph_general.h" - +/* undone #define SPI_Alternate_Mapping(INSTANCE) ((((INSTANCE) == TIM1) || ((INSTANCE) == TIM2))? GPIO_AF1_TIM1: \ (((INSTANCE) == TIM3) || ((INSTANCE) == TIM4) || ((INSTANCE) == TIM5))? GPIO_AF2_TIM3: \ (((INSTANCE) == TIM8) || ((INSTANCE) == TIM9) || ((INSTANCE) == TIM10) || ((INSTANCE) == TIM11))? GPIO_AF3_TIM8: \ (((INSTANCE) == TIM12) || ((INSTANCE) == TIM13) || ((INSTANCE) == TIM14))? GPIO_AF9_TIM12: \ (0)) - +*/ #define TIM_Alternate_Mapping(INSTANCE) ((((INSTANCE) == TIM1) || ((INSTANCE) == TIM2))? GPIO_AF1_TIM1: \ (((INSTANCE) == TIM3) || ((INSTANCE) == TIM4) || ((INSTANCE) == TIM5))? GPIO_AF2_TIM3: \ diff --git a/GENERAL/periph_general.h b/GENERAL/periph_general.h index 1e7db4f..79a5118 100644 --- a/GENERAL/periph_general.h +++ b/GENERAL/periph_general.h @@ -1,4 +1,4 @@ -/**********************************TIM************************************** +/********************************PERIPH************************************* Данный файл содержит инклюды и дефайны для всех библиотек базовой перефирии. ***************************************************************************/ #ifndef __PERIPH_GENERAL_H_ diff --git a/spi_flash/spi_flash.c b/spi_flash/spi_flash.c index fde2470..02b0809 100644 --- a/spi_flash/spi_flash.c +++ b/spi_flash/spi_flash.c @@ -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); diff --git a/spi_flash/spi_flash.h b/spi_flash/spi_flash.h index 5317267..067dbd7 100644 --- a/spi_flash/spi_flash.h +++ b/spi_flash/spi_flash.h @@ -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_ \ No newline at end of file