/********************************MEMSPI FLASH********************************** Данный файл содержит базовые функции для общения с памятью FLASH по SPI. //-------------------Функции-------------------// @func users - MEMSPI_Read_Memory Считывание внешней FLASH/EEPROM - MEMSPI_EEPROM_Write Запись данных в внешнюю EEPROM - MEMSPI_FLASH_Write Запись данных в внешнюю FLASH (функция сама очищает нужные сектора, и если надо сохраняет выбранные данные) - MEMSPI_FLASH_Program Программирование внешней FLASH (выбранный участок FLASH должен быть очищен) - MEMSPI_FLASH_Erase Очистка внешней FLASH @func initialization - MEMSPI_Base_Init Инициализация SPI и GPIO для внешней памяти @func service - MEMSPI_EEPROM_Write_Page Запись страницы в EEPROM *есть более общая функция MEMSPI_EEPROM_Write, которая записывает участки больше страницы - MEMSPI_FLASH_Erase_Sector Очистка сектора FLASH. *есть более общая функция MEMSPI_FLASH_Erase, которая может ощичать несколько секторов - MEMSPI_FLASH_Program_Page Программирование страницы. *есть более общая функция MEMSPI_FLASH_Program, которая программирует участки больше страницы - MEMSPI_WriteEnablingUntilTimeout Разрешение записи, пока не будет ответа или не истек таймаут - MEMSPI_WaitOnFlagsUntilTimeout Ожидание флага пока не истек таймаута @func cmd functions - MEMSPI_CMD_Read_Status_Register Отправка комманд Read Status Register / Read Status Register 2 (0x05h / 0x35h) - MEMSPI_CMD_Write_Status_Register Отправка комманды Write Status Register (0x01h) - MEMSPI_CMD_Write_Enable Отправка комманды Write Enable (0x06h) - MEMSPI_CMD_Write_Disable Отправка комманды Write Disable (0x04h) - MEMSPI_CMD_Read_Data Отправка комманды Read Data (0x03h) - MEMSPI_CMD_EEPROM_Write Отправка комманды Write (eeprom) (0x02h) - MEMSPI_CMD_FLASH_Page_Program Отправка комманды Page Program (flash) (0x02h) - MEMSPI_CMD_FLASH_Erase_Sector Отправка комманды Erase Sector (flash) (0x20h) - MEMSPI_CMD_Read_JEDEC_ID Отправка комманды Read JEDEC ID (0x4Bh) - MEMSPI_CMD_Read_Device_ID Отправка комманды Read Manufacture / Device Id (0x90) ***************************************************************************/ #include "memory_spi.h" uint8_t sector_buff[MEMSPI_SECTOR_SIZE]; //------------------------------------------------------------------- //-----------------------------FOR USER------------------------------ /** * @brief Initialize SPI and GPIO for MEMSPI FLASH. * @param hmemspi - указатель на структуру с настройками SPI и GPIO портов. */ void MEMSPI_Base_Init(MEMSPI_HandleTypeDef *hmemspi) { SPI_SettingsTypeDef sspi; // SPI PERIPH INIT if(hmemspi->sspi.hspi.Instance == NULL) hmemspi->sspi.hspi.Instance = SPI1; hmemspi->sspi.hspi.Init.Mode = SPI_MODE_MASTER; hmemspi->sspi.hspi.Init.Direction = SPI_DIRECTION_2LINES; hmemspi->sspi.hspi.Init.DataSize = SPI_DATASIZE_8BIT; hmemspi->sspi.hspi.Init.CLKPolarity = SPI_POLARITY_LOW; hmemspi->sspi.hspi.Init.CLKPhase = SPI_PHASE_1EDGE; hmemspi->sspi.hspi.Init.NSS = SPI_NSS_SOFT; hmemspi->sspi.hspi.Init.FirstBit = SPI_FIRSTBIT_MSB; hmemspi->sspi.hspi.Init.TIMode = SPI_TIMODE_DISABLE; hmemspi->sspi.hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // SPI INIT SPI_Base_Init(&hmemspi->sspi); // GPIO INIT GPIO_Clock_Enable(hmemspi->CS_GPIOx); // CHIP SELECT PIN INIT GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = hmemspi->CS_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLDOWN; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(hmemspi->CS_GPIOx, &GPIO_InitStruct); } //-----------------------INTERRUPT MODE FUNCTIONS-------------------- /** * @brief Read external FLASH/EEPROM with interrupt. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс откуда начинать считывание. * @param pBuff - куда записывать данные из FLASH. * @param Size - сколько байтов считывать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return HAL status. */ HAL_StatusTypeDef MEMSPI_Read_Memory_IT(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size) { HAL_StatusTypeDef MEMSPI_Status; uint32_t tickstart = HAL_GetTick(); MEMSPI_Status = MEMSPI_CMD_Read_Data_IT(hmemspi, FLASH_Address, pBuff, Size); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; return HAL_OK; } //-----------------------BLOCKING MODE FUNCTIONS--------------------- /** * @brief Read external FLASH/EEPROM. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс откуда начинать считывание. * @param pBuff - куда записывать данные из FLASH. * @param Size - сколько байтов считывать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return HAL status. * @note Включает в себя проверку на доступность памяти (флаг BUSY) */ HAL_StatusTypeDef MEMSPI_Read_Memory(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size, uint32_t Timeout) { HAL_StatusTypeDef MEMSPI_Status; uint32_t tickstart = HAL_GetTick(); // wait for unbusy if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_BUSY, 0, &Timeout, &tickstart) != HAL_OK) // if its unbusy for timeout return HAL_TIMEOUT; // return timeout error MEMSPI_Status = MEMSPI_CMD_Read_Data(hmemspi, FLASH_Address, pBuff, Size, Timeout); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; return HAL_OK; } /** * @brief Write external EEPROM. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в EEPROM. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должна быть осуществлена запись. * @param WaitForEnd - ожидание, пока память не выполненит операцию. * @return HAL status. * @note Позволяет записать участок памяти. Можно записывать несколько страниц. */ HAL_StatusTypeDef MEMSPI_EEPROM_Write(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd) { uint32_t tickstart = HAL_GetTick(); HAL_StatusTypeDef MEMSPI_Status; // CALC AREA TO WRITE uint16_t bytecnt = 0; uint16_t currentpage_size = 0; uint16_t lastpage_size = Size; uint16_t firstpage = (FLASH_Address/MEMSPI_PAGE_SIZE); uint16_t lastpage = ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE); if(firstpage != lastpage) // if area is on several pages { currentpage_size = (firstpage+1)*MEMSPI_PAGE_SIZE - FLASH_Address; // set size of data on first page lastpage_size = (FLASH_Address+Size) - lastpage*MEMSPI_PAGE_SIZE; // set size of data on last page } // PROGRAM PAGES: FROM FIRST NO THE PREVIOUS TO THE LAST hmemspi->hNextAddr = FLASH_Address; // address would automatically increase in this variable for(int i = 0; i < lastpage - firstpage; i++) { MEMSPI_Status = MEMSPI_EEPROM_Write_Page(hmemspi, hmemspi->hNextAddr, &pData[bytecnt], currentpage_size, &Timeout, &tickstart, 0); // programm page if(MEMSPI_Status != HAL_OK) // note: no need waiting for end: the next call will wait for unbusy return MEMSPI_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 += currentpage_size; // and set current size as page size. because next pages will be fully programmed currentpage_size = MEMSPI_PAGE_SIZE; } // PROGRAM LAST PAGE MEMSPI_Status = MEMSPI_FLASH_Program_Page(hmemspi, hmemspi->hNextAddr, &pData[bytecnt], lastpage_size, &Timeout, &tickstart, WaitForEnd); // programm page if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; return HAL_OK; } /** * @brief Write external FLASH. * @param hmemspi - указатель на хендл внешней памяти. * @param WriteInit - указатель на структуру, определяющую участок памяти для записи. * @param Timeout - время, за которое должно быть осуществлено чтение. * @param WaitForEnd - ожидание, пока память не выполненит операцию. * @return HAL status. * @note Позволяет перепрограммировать участок памяти. Можно записывать несколько страниц. * Данные в сектора участка, но за пределами участка не сохраняются. */ HAL_StatusTypeDef MEMSPI_FLASH_Write(MEMSPI_HandleTypeDef *hmemspi, MEMSPI_WriteInitTypeDef *WriteInit, uint32_t Timeout, uint8_t WaitForEnd) { uint32_t tickstart = HAL_GetTick(); uint32_t timeoutcnt = Timeout; uint8_t *writebuff = WriteInit->pDataPtr; HAL_StatusTypeDef MEMSPI_Status; // CHECK FOR UNDEFINED STRUCTURE if (WriteInit->Sector_Size == 0) // if sector undefined { // fill it with data init WriteInit->Sector_Address = WriteInit->Data_Address; WriteInit->Sector_Size = WriteInit->Data_Size; } else if (WriteInit->Data_Size == 0) // if data undefined { // fill it with sector init WriteInit->Data_Address = WriteInit->Sector_Address; WriteInit->Data_Size = WriteInit->Sector_Size; } // if both undefined - return HAL ERR else if ((WriteInit->Sector_Size == 0) && (WriteInit->Data_Size == 0)) { return HAL_ERROR; } // CHECK FOR CORRECT STRUCTURE // if data is beyound sector if((WriteInit->Data_Address < WriteInit->Sector_Address) || ((WriteInit->Data_Address + WriteInit->Data_Size) > (WriteInit->Sector_Address + WriteInit->Sector_Size))) return HAL_ERROR; // WRITE FLASH WITH SAVING PREVIOUS DATA if(WriteInit->fSavePrevoisData) { // store data from flash MEMSPI_Status = MEMSPI_Read_Memory(hmemspi, WriteInit->Sector_Address, sector_buff, WriteInit->Sector_Size, Timeout); if(MEMSPI_Status != HAL_OK) return MEMSPI_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]; } // CALC AREA TO REPROGRAM uint16_t lastsector_size = WriteInit->Sector_Size; uint16_t firstsector = (WriteInit->Sector_Address/MEMSPI_SECTOR_SIZE); uint16_t lastsector = ((WriteInit->Sector_Address+WriteInit->Sector_Size-1)/MEMSPI_SECTOR_SIZE); if(firstsector != lastsector) // if area is on several pages { lastsector_size = (WriteInit->Sector_Address+WriteInit->Sector_Size) - lastsector*MEMSPI_SECTOR_SIZE; // set size of data on last page } // REPROGRAM SECTORS: FROM FIRST SECTOR NO THE PREVIOUS TO THE LAST hmemspi->hNextAddr = WriteInit->Sector_Address; // address would automatically increase in this variable hmemspi->hNextSector = firstsector+1; uint16_t bytescnt = 0; uint16_t bytes_to_next_sector = 0; for(int i = 0; i < (lastsector - firstsector); i++) { // ERASE FLASH MEMSPI_Status = MEMSPI_FLASH_Erase(hmemspi, hmemspi->hNextAddr, 1, Timeout, 0); if(MEMSPI_Status != HAL_OK) // note: no need waiting for end: the next call will wait for unbusy return MEMSPI_Status; // PROGRAM FLASH WITH NEW DATA // calc bytes to next sector bytes_to_next_sector = hmemspi->hNextSector*MEMSPI_SECTOR_SIZE - hmemspi->hNextAddr; // program data to flash MEMSPI_Status = MEMSPI_FLASH_Program(hmemspi, hmemspi->hNextAddr, §or_buff[bytescnt], bytes_to_next_sector, Timeout, 0); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; // shift bytes count to data, that shoud be on the next page bytescnt += bytes_to_next_sector; } // ERASE FLASH MEMSPI_Status = MEMSPI_FLASH_Erase(hmemspi, hmemspi->hNextAddr, 1, Timeout, 0); if(MEMSPI_Status != HAL_OK) // note: no need waiting for end: the next call will wait for unbusy return MEMSPI_Status; // PROGRAM LAST SECTOR MEMSPI_Status = MEMSPI_FLASH_Program(hmemspi, hmemspi->hNextAddr, §or_buff[bytescnt], lastsector_size, Timeout, WaitForEnd); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; } // WRITE FLASH WITHOUT SAVING PREVIOUS DATA else { // ERASE FLASH MEMSPI_Status = MEMSPI_FLASH_Erase(hmemspi, WriteInit->Sector_Address, WriteInit->Sector_Size, Timeout, 0); if(MEMSPI_Status != HAL_OK) // note: no need waiting for end: the next call will wait for unbusy return MEMSPI_Status; // PROGRAM FLASH WITH NEW DATA // program data to flash MEMSPI_Status = MEMSPI_FLASH_Program(hmemspi, WriteInit->Sector_Address, WriteInit->pDataPtr, WriteInit->Sector_Size, Timeout, WaitForEnd); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; } return HAL_OK; } /** * @brief Program external FLASH. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @param WaitForEnd - ожидание, пока память не выполненит операцию. * @return HAL status. * @note Программирование участка памяти, без ограничений на кол-во байт */ HAL_StatusTypeDef MEMSPI_FLASH_Program(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd) { uint32_t tickstart = HAL_GetTick(); HAL_StatusTypeDef MEMSPI_Status; // CALC AREA TO PROGRAM uint16_t lastpage_size = Size; uint16_t firstpage = (FLASH_Address/MEMSPI_PAGE_SIZE); uint16_t lastpage = ((FLASH_Address+Size-1)/MEMSPI_PAGE_SIZE); if(firstpage != lastpage) // if area is on several pages { lastpage_size = (FLASH_Address+Size) - lastpage*MEMSPI_PAGE_SIZE; // set size of data on last page } // PROGRAM PAGES: FROM FIRST NO THE PREVIOUS TO THE LAST hmemspi->hNextAddr = FLASH_Address; // address would automatically increase in this variable hmemspi->hNextPage = firstpage+1; // address would automatically increase in this variable uint16_t bytecnt = 0; uint16_t bytes_to_next_page = 0; for(int i = 0; i < lastpage - firstpage; i++) { // calc bytes to next sector bytes_to_next_page = hmemspi->hNextPage*MEMSPI_PAGE_SIZE - hmemspi->hNextAddr; MEMSPI_Status = MEMSPI_FLASH_Program_Page(hmemspi, hmemspi->hNextAddr, &pData[bytecnt], bytes_to_next_page, &Timeout, &tickstart, 0); // programm page if(MEMSPI_Status != HAL_OK) // note: no need waiting for end: the next call will wait for unbusy return MEMSPI_Status; // then we shift byte count to data, that shoud be on the next page bytecnt += bytes_to_next_page; } // PROGRAM LAST PAGE MEMSPI_Status = MEMSPI_FLASH_Program_Page(hmemspi, hmemspi->hNextAddr, &pData[bytecnt], lastpage_size, &Timeout, &tickstart, WaitForEnd); // programm page if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; return HAL_OK; // if all ok return HAL_OK } /** * @brief Erase external FLASH. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс где надо данные стереть. * @param Size - сколько байтов стереть. * @param Timeout - время, за которое должно быть осуществлена очистка. * @param WaitForEnd - ожидание, пока память не выполненит операцию. * @return HAL status. * @note Т.к. очитска происходит по секторам, Size нужен, чтобы определить сколько секторов очистить * И если начальны адресс будет на Sector 0, а последний байт на Sector 1, то произойдет очистка Sector 0 и Sector 1 */ HAL_StatusTypeDef MEMSPI_FLASH_Erase(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint16_t Size, uint32_t Timeout, uint8_t WaitForEnd) { uint32_t tickstart = HAL_GetTick(); HAL_StatusTypeDef MEMSPI_Status; // CALC AREA TO ERASE uint16_t bytecnt = 0; uint16_t firstsector = (FLASH_Address/MEMSPI_SECTOR_SIZE); uint16_t lastsector = ((FLASH_Address+Size-1)/MEMSPI_SECTOR_SIZE); for(int i = 0; i <= (lastsector - firstsector); i++) { MEMSPI_Status = MEMSPI_FLASH_Erase_Sector(hmemspi, FLASH_Address, &Timeout, &tickstart, WaitForEnd); // programm page if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; FLASH_Address += MEMSPI_SECTOR_SIZE; } return HAL_OK; } //------------------------------------------------------------------- //-------------------------SERVICE FUNCTIONS------------------------- //----------------------INTERRUPT MODE FUNCTIONS--------------------- /** * @brief Handler for SPI FLASH/EEPROM. * @param hmemspi - указатель на хендл внешней памяти. * @return HAL status. * @note Включает в себя проверку на доступность памяти (флаг BUSY) */ void MEMSPI_Handler(MEMSPI_HandleTypeDef *hmemspi) { HAL_SPI_StateTypeDef active_line = hmemspi->sspi.hspi.State; HAL_SPI_IRQHandler(&hmemspi->sspi.hspi); /* RX Callback */ if (( hmemspi->sspi.hspi.RxXferCount == 0U) && (hmemspi->MEM_State == MEM_RECEIVE_DATA) && // if all bytes are received and receive is active hmemspi->sspi.hspi.State != HAL_SPI_STATE_BUSY_RX) // also check that receive "REALLY" isnt busy MEM_SPI_OperationCplt_Handler(hmemspi); /* TX Callback */ if (( hmemspi->sspi.hspi.TxXferCount == 0U) && (hmemspi->MEM_State == MEM_SEND_COMMAND) && // if all bytes are transmited and transmit is active hmemspi->sspi.hspi.State != HAL_SPI_STATE_BUSY_TX) // also check that transmit "REALLY" isnt busy MEM_SPI_TransmitCommandCplt_Handler(hmemspi); } /** * @brief Handler for transmit SPI command to EEPROM/FLASH. * @param hmemspi - указатель на хендл внешней памяти. * @return HAL status. * @note После отправки комманды - инициализирует прием ответа если надо или завершает команду. */ void MEM_SPI_TransmitCommandCplt_Handler(MEMSPI_HandleTypeDef *hmemspi) { __HAL_UNLOCK(&hmemspi->sspi.hspi); uint8_t endcmd = 0; hmemspi->MEM_State = MEM_RECEIVE_DATA; switch(hmemspi->Active_CMD) { case WRITE_ENABLE: endcmd = 1; break; case WRITE_DISABLE: endcmd = 1; break; case WRITE_STATUS_REG: endcmd = 1; break; case ERASE_SECTOR: endcmd = 1; break; case PAGE_PROGRAM: endcmd = 1; break; case READ_STATUS_REG: MEMSPI_SPI_Receive_IT(hmemspi, (uint8_t *)&hmemspi->SR, 1); break; case READ_DATA: MEMSPI_SPI_Receive_IT(hmemspi, hmemspi->pRxBuffPtr, hmemspi->RxXferSize); break; case READ_JEDEC_ID: MEMSPI_SPI_Receive_IT(hmemspi, &hmemspi->pRxBuffPtr[1], 3); break; case READ_UNIQUE_ID: MEMSPI_SPI_Receive_IT(hmemspi, hmemspi->pRxBuffPtr, 8); break; default: break; } } /** * @brief Handler for receive SPI response from EEPROM/FLASH. * @param hmemspi - указатель на хендл внешней памяти. * @return HAL status. * @note Завершает общение с памятью. */ void MEM_SPI_OperationCplt_Handler(MEMSPI_HandleTypeDef *hmemspi) { __HAL_UNLOCK(&hmemspi->sspi.hspi); uint64_t return_val_LO; uint64_t return_val_HI; switch(hmemspi->Active_CMD) { case READ_JEDEC_ID: *(uint32_t *)hmemspi->pRxBuffPtr = __REV((*(uint64_t *)hmemspi->pRxBuffPtr)) & 0xFFFFFF; break; case READ_UNIQUE_ID: return_val_LO = (*(uint64_t *)hmemspi->pRxBuffPtr) >> 32; return_val_HI = (*(uint64_t *)hmemspi->pRxBuffPtr) & 0xFFFFFFFF; *(uint64_t *)hmemspi->pRxBuffPtr = ((uint64_t)__REV(return_val_HI) << 32) | __REV(return_val_LO); break; default: break; } hmemspi->Active_CMD = WAIT_FOR_CMD; MEMSPI_Deselect(hmemspi); } //-----------------------BLOCKING MODE FUNCTIONS-------------------- /** * @brief Write page in external EEPROM. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в EEPROM. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @param WaitForEnd - ожидание, пока память не выполненит операцию. * @return HAL status. * @note Позволяет записывать только байты в пределах одной страницы. Для более гибкой записи есть функция MEMSPI_EEPROM_Write, которая программирует участки любой длины (в теории). */ HAL_StatusTypeDef MEMSPI_EEPROM_Write_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd) { HAL_StatusTypeDef MEMSPI_Status; // enable writting and waiting for unbusy if(MEMSPI_WriteEnablingUntilTimeout(hmemspi, Timeout, tickstart) != HAL_OK) // if writting isnt enable return HAL_TIMEOUT; // return timeout MEMSPI_Status = MEMSPI_CMD_EEPROM_Write(hmemspi, FLASH_Address, pData, Size, *Timeout); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; // waiting for ending of writting if need if(WaitForEnd) if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if writting isnt done (MEMSPI busy and WEL bit isnt in reset state) return HAL_TIMEOUT; // update handle variables hmemspi->hNextAddr = (FLASH_Address+Size); hmemspi->hNextPage = (FLASH_Address+Size)/MEMSPI_PAGE_SIZE; hmemspi->hNextSector = (FLASH_Address+Size)/MEMSPI_SECTOR_SIZE; return HAL_OK; } /** * @brief Erase external FLASH Sector. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс где надо данные стереть. * @param Timeout - время, за которое должно быть осуществлена очистка. * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @param WaitForEnd - ожидание, пока память не выполненит операцию. * @return HAL status. * @note При Timeout = 0, функция не будет ожидать окончания очистки (выставления в 0 флагов BUSY и WEL) * @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом. */ HAL_StatusTypeDef MEMSPI_FLASH_Erase_Sector(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd) { HAL_StatusTypeDef MEMSPI_Status; // enable writting and waiting for unbusy if(MEMSPI_WriteEnablingUntilTimeout(hmemspi, Timeout, tickstart) != HAL_OK) // if writting isnt enable return HAL_TIMEOUT; // return timeout // erase sector (instruction) MEMSPI_Status = MEMSPI_CMD_FLASH_Erase_Sector(hmemspi, FLASH_Address, *Timeout); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; // waiting for ending of erasing if need if(WaitForEnd) if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if erase isnt done (MEMSPI 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 hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @param WaitForEnd - ожидание, пока память не выполненит операцию. * @return HAL status. * @note Позволяет перепрограммировать только байты в прелелах одной страницы. Для более гибкого программирования есть функция MEMSPI_FLASH_Program, которая программирует участки любой длины (в теории). */ HAL_StatusTypeDef MEMSPI_FLASH_Program_Page(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size, uint32_t *Timeout, uint32_t *tickstart, uint8_t WaitForEnd) { HAL_StatusTypeDef MEMSPI_Status; // enable writting and waiting for unbusy if(MEMSPI_WriteEnablingUntilTimeout(hmemspi, 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/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 // programm page (instruction) MEMSPI_Status = MEMSPI_CMD_FLASH_Page_Program(hmemspi, FLASH_Address, pData, Size, *Timeout); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; // waiting for ending of writting if need if(WaitForEnd) if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if writting isnt done (MEMSPI busy and WEL bit isnt in reset state) return HAL_TIMEOUT; // update handle variables hmemspi->hNextAddr = (FLASH_Address+Size); hmemspi->hNextPage = (hmemspi->hNextAddr+Size)/MEMSPI_PAGE_SIZE; hmemspi->hNextSector = (hmemspi->hNextAddr+Size)/MEMSPI_SECTOR_SIZE; return HAL_OK; } /** * @brief Setting WEL bit until it setted or until timeout. * @param hmemspi - указатель на хендл внешней памяти. * @param Timeout - время, за которое должно быть осуществлено чтение. * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @return HAL status. * @note Подает команду на разрешение записи до тех пор, пока она запись не разрешиться или до тех пор, пока таймаут не истечет. */ HAL_StatusTypeDef MEMSPI_WriteEnablingUntilTimeout(MEMSPI_HandleTypeDef *hmemspi, uint32_t *Timeout, uint32_t *tickstart) { HAL_StatusTypeDef MEMSPI_Status; // wait for unbusy if(MEMSPI_WaitOnFlagsUntilTimeout(hmemspi, MEMSPI_SR_BUSY, 0, Timeout, tickstart) != HAL_OK) // if its unbusy for timeout return HAL_TIMEOUT; // enable writing while((hmemspi->SR&MEMSPI_SR_WEL) != MEMSPI_SR_WEL) { // if flash isnt busy - set WEL flag if((hmemspi->SR&MEMSPI_SR_BUSY) == 0) MEMSPI_CMD_Write_Enable(hmemspi, *Timeout); // check is writting enabled MEMSPI_Status = MEMSPI_CMD_Read_Status_Register(hmemspi, MEMSPI_SR_WEL|MEMSPI_SR_BUSY, 1, *Timeout); if(MEMSPI_Status != HAL_OK) { MEMSPI_Deselect(hmemspi); return MEMSPI_Status; } if((HAL_GetTick() - *tickstart) >= *Timeout) // if time is out { MEMSPI_Deselect(hmemspi); return HAL_TIMEOUT; // set timeout } } MEMSPI_Deselect(hmemspi); MEMSPI_Update_Timeout_Variables(Timeout, tickstart); return HAL_OK; // if all ok return HAL_OK } /** * @brief Wait for flag until timeout. * @param hmemspi - указатель на хендл внешней памяти. * @param FlagMask - маска для флагов, какие флаги считывать. * @param FlagStatus - какое состояние должно быть у выбранных флагов. * @param Timeout - время, за которое должно быть осуществлено чтение. * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @return HAL status. * @note Считывает флаги до тех пор, пока они не будут в состоянии FlagStatus или до тех пор, пока таймаут не истечет. */ HAL_StatusTypeDef MEMSPI_WaitOnFlagsUntilTimeout(MEMSPI_HandleTypeDef *hmemspi, uint16_t FlagMask, uint16_t FlagStatus, uint32_t *Timeout, uint32_t *tickstart) { HAL_StatusTypeDef MEMSPI_Status; uint32_t tickstart_reserve; uint32_t max_delay = HAL_MAX_DELAY; if(tickstart == NULL) tickstart = &tickstart_reserve; if(Timeout == NULL) Timeout = &max_delay; // check flags do{ if(hmemspi->sspi.hspi.State == HAL_SPI_STATE_READY) MEMSPI_Status = MEMSPI_CMD_Read_Status_Register(hmemspi, FlagMask, 0, *Timeout); }while(((HAL_GetTick() - *tickstart) < *Timeout) && (MEMSPI_Status != HAL_OK)); while((hmemspi->SR&FlagMask) != FlagStatus) { // check flags // MEMSPI_Status = MEMSPI_CMD_Read_Status_Register(hmemspi, FlagMask, *Timeout); MEMSPI_Status = MEMSPI_SPI_Receive(hmemspi, (uint8_t *)&hmemspi->SR, 1, *Timeout); // receive response if(MEMSPI_Status != HAL_OK) { MEMSPI_Deselect(hmemspi); return MEMSPI_Status; } if((HAL_GetTick() - *tickstart) >= *Timeout) // if time is out { MEMSPI_Deselect(hmemspi); return HAL_TIMEOUT; // set timeout } } MEMSPI_Deselect(hmemspi); MEMSPI_Update_Timeout_Variables(Timeout, tickstart); return HAL_OK; // if all ok return HAL_OK } /** * @brief Wait for flag until timeout in interrupt mode. * @param hmemspi - указатель на хендл внешней памяти. * @param FlagMask - маска для флагов, какие флаги считывать. * @param FlagStatus - какое состояние должно быть у выбранных флагов. * @param Timeout - время, за которое должно быть осуществлено чтение. * @param tickstart - время, относительно которого надо отсчитывать таймаут. * @return HAL status. * @note Считывает флаги до тех пор, пока они не будут в состоянии FlagStatus или до тех пор, пока таймаут не истечет. */ HAL_StatusTypeDef MEMSPI_WaitOnFlagsUntilTimeout_IT(MEMSPI_HandleTypeDef *hmemspi, uint16_t FlagMask, uint16_t FlagStatus, uint32_t *Timeout, uint32_t *tickstart) { HAL_StatusTypeDef MEMSPI_Status; // check flags MEMSPI_Status = MEMSPI_CMD_Read_Status_Register(hmemspi, FlagMask, 0, *Timeout); if(MEMSPI_Status != HAL_OK) return MEMSPI_Status; while((hmemspi->SR&FlagMask) != FlagStatus) { // check flags // MEMSPI_Status = MEMSPI_CMD_Read_Status_Register(hmemspi, FlagMask, *Timeout); MEMSPI_Status = MEMSPI_SPI_Receive(hmemspi, (uint8_t *)&hmemspi->SR, 1, *Timeout); // receive response if(MEMSPI_Status != HAL_OK) { MEMSPI_Deselect(hmemspi); return MEMSPI_Status; } if((HAL_GetTick() - *tickstart) >= *Timeout) // if time is out { MEMSPI_Deselect(hmemspi); return HAL_TIMEOUT; // set timeout } } MEMSPI_Deselect(hmemspi); MEMSPI_Update_Timeout_Variables(Timeout, tickstart); return HAL_OK; // if all ok return HAL_OK } /** * @brief Update Timeout variables. * @param Timeout - указатель на переменную содержащию значение таймаута * @param tickstart - указатель на переменную содержащию начальное кол-во тиков. */ void MEMSPI_Update_Timeout_Variables(uint32_t *Timeout, uint32_t *tickstart) { uint32_t timeoutcnt = HAL_GetTick() - *tickstart; // update timeout *Timeout -= timeoutcnt; *tickstart += timeoutcnt; } //------------------------------------------------------------------- //-------------------------COMMAND FUNCTIONS------------------------- //------------------------------BLOCKING----------------------------- /** * @brief Send command to read Status Register. * @param hmemspi - указатель на хендл внешней памяти. * @param RequestedBits - какие биты запросить. * @param EndCMD - завершать комманду или нет. (очистка Chip Selected пина) * @param Timeout - время, за которое должно быть осуществлено чтение. * @return Заполняет Status Register в hmemspi. * @note Всего есть две комманды: на запрос верхнего или нижниго байта. * Функция в соответствии с RequestedBits определяет какой байт запросить, или два байта сразу. */ 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 { #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; 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; } /** * @brief Send command to write bits in Status Register. * @param hmemspi - указатель на хендл внешней памяти. * @param WrittenBits - какие биты запросить. * @note Данная команда посылает биты, как сдвинутые на 2 вправо. Т.е. 0-й бит в комманде - 2-й бит BP0. Но биты указываются в также как они расположены и регистре. Функция сама выполняет сдвиг. */ 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; command[0] = MEMSPI_WRITE_STATUS_REG; command[1] = WrittenBits; command[2] = WrittenBits >> 8; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 3, Timeout); MEMSPI_Deselect(hmemspi); return SPI_RES; } /** * @brief Send command to set Write Enable Latch (WEL) in Status Register. * @param hmemspi - указатель на хендл внешней памяти. * @note Разрешает запись в FLASH, путем высталения WEL в Status Register */ HAL_StatusTypeDef MEMSPI_CMD_Write_Enable(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout) { HAL_StatusTypeDef SPI_RES; uint8_t command[1]; command[0] = MEMSPI_WRITE_ENABLE; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 1, Timeout); MEMSPI_Deselect(hmemspi); return SPI_RES; } /** * @brief Send command to read data from FLASH/EEPROM. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс откуда начинать считывание. * @param pBuff - куда записывать данные из FLASH. * @param Size - сколько байтов считывать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return pBuff. */ 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]; command[0] = MEMSPI_READ_DATA; 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); SPI_RES = MEMSPI_SPI_Receive(hmemspi, pBuff, Size, Timeout); MEMSPI_Deselect(hmemspi); return SPI_RES; } /** * @brief Send command to write eeprom. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должна быть осуществлена запись. * @note Рзамер данных для записи в EEPROM без ограничений. */ 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; command[0] = MEMSPI_WRITE_EEPROM; 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; } /** * @brief Send command to page program in FLASH. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должна быть осуществлена запись. * @note Программирование FLASH только в пределах одной страницы. * Т.е. если запись с 0x0, то не больше 256 байт. Если с 0ч40, то не больше 192 байт. */ 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; 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 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; } /** * @brief Send command to erase sector. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс где надо данные стереть. * @param Timeout - время, за которое должна быть осуществлена очистка. * @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом. */ 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]; uint8_t response[8]; FLASH_Address = FLASH_Address & 0xFFFFFF; command[0] = MEMSPI_ERASE_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; } /** * @brief Send command to read JEDEC ID. * @param hmemspi - указатель на хендл внешней памяти. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return JEDEC ID микросхемы. */ uint32_t MEMSPI_CMD_Read_JEDEC_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout) { HAL_StatusTypeDef SPI_RES; uint8_t command[1] = {0}; uint8_t receive[4] = {0}; uint32_t return_val; command[0] = MEMSPI_READ_JEDEC_ID; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 1, Timeout); SPI_RES = MEMSPI_SPI_Receive(hmemspi, &receive[1], 3, Timeout); MEMSPI_Deselect(hmemspi); return_val = (*(uint64_t *)receive); return __REV(return_val) & 0xFFFFFF; } /** * @brief Send command to read JEDEC ID. * @param hmemspi - указатель на хендл внешней памяти. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return Device ID микросхемы. */ uint64_t MEMSPI_CMD_Read_Device_ID(MEMSPI_HandleTypeDef *hmemspi, uint32_t Timeout) { HAL_StatusTypeDef SPI_RES; uint8_t command[1] = {0}; uint8_t receive[8] = {0}; 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 ((uint64_t)__REV(return_val_HI) << 32) | __REV(return_val_LO); } /** * @brief Send command to fast read data from FLASH. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс откуда начинать считывание. * @param pBuff - куда записывать данные из FLASH. * @param Size - сколько байтов считывать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @note Данная функция предполагает отправку одного dummy байта после адресса, но у меня поч не работает пока :( */ 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}; command[0] = MEMSPI_READ_DATA; command[1] = FLASH_Address >> 16 & 0xFF; command[2] = FLASH_Address >> 8 & 0xFF; command[3] = FLASH_Address & 0xFF; command[4] = 0xFF; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, 5, Timeout); SPI_RES = MEMSPI_SPI_Receive(hmemspi, pBuff, Size, Timeout); MEMSPI_Deselect(hmemspi); return SPI_RES; } //------------------------------------------------------------------- //-------------------------COMMAND FUNCTIONS------------------------- //-----------------------------INTERRUPT----------------------------- /** * @brief Send command to read Status Register. * @param hmemspi - указатель на хендл внешней памяти. * @param RequestedBits - какие биты запросить. * @param EndCMD - завершать комманду или нет. (очистка Chip Selected пина) * @param Timeout - время, за которое должно быть осуществлено чтение. * @return Заполняет Status Register в hmemspi. * @note Всего есть две комманды: на запрос верхнего или нижниго байта. * Функция в соответствии с RequestedBits определяет какой байт запросить, или два байта сразу. */ HAL_StatusTypeDef MEMSPI_CMD_Read_Status_Register_IT(MEMSPI_HandleTypeDef *hmemspi, uint16_t RequestedBits, uint8_t EndCMD) { HAL_StatusTypeDef SPI_RES; uint8_t command[2]; uint8_t *pSRPtr = 0; uint8_t size = 1; command[0] = MEMSPI_READ_STATUS_REG; hmemspi->Active_OP = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, 1); // send insctruction to read SR return SPI_RES; } /** * @brief Send command to write bits in Status Register. * @param hmemspi - указатель на хендл внешней памяти. * @param WrittenBits - какие биты запросить. * @note Данная команда посылает биты, как сдвинутые на 2 вправо. Т.е. 0-й бит в комманде - 2-й бит BP0. Но биты указываются в также как они расположены и регистре. Функция сама выполняет сдвиг. */ HAL_StatusTypeDef MEMSPI_CMD_Write_Status_Register_IT(MEMSPI_HandleTypeDef *hmemspi, uint16_t WrittenBits) { HAL_StatusTypeDef SPI_RES; uint8_t command[3]; uint8_t size; command[0] = MEMSPI_WRITE_STATUS_REG; command[1] = WrittenBits; command[2] = WrittenBits >> 8; hmemspi->Active_CMD = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, 3); return SPI_RES; } /** * @brief Send command to set Write Enable Latch (WEL) in Status Register. * @param hmemspi - указатель на хендл внешней памяти. * @note Разрешает запись в FLASH, путем высталения WEL в Status Register */ HAL_StatusTypeDef MEMSPI_CMD_Write_Enable_IT(MEMSPI_HandleTypeDef *hmemspi) { HAL_StatusTypeDef SPI_RES; uint8_t command[1]; command[0] = MEMSPI_WRITE_ENABLE; hmemspi->Active_CMD = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, 1); return SPI_RES; } /** * @brief Send command to read data from FLASH/EEPROM. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс откуда начинать считывание. * @param pBuff - куда записывать данные из FLASH. * @param Size - сколько байтов считывать. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return pBuff. */ HAL_StatusTypeDef MEMSPI_CMD_Read_Data_IT(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pBuff, uint16_t Size) { HAL_StatusTypeDef SPI_RES; uint8_t command[4]; command[0] = MEMSPI_READ_DATA; command[1] = FLASH_Address >> 16 & 0xFF; command[2] = FLASH_Address >> 8 & 0xFF; command[3] = FLASH_Address & 0xFF; hmemspi->Active_CMD = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; hmemspi->pRxBuffPtr = pBuff; hmemspi->RxXferSize = Size; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, 4); return SPI_RES; } /** * @brief Send command to write eeprom. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должна быть осуществлена запись. * @note Рзамер данных для записи в EEPROM без ограничений. */ HAL_StatusTypeDef MEMSPI_CMD_EEPROM_Write_IT(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size) { 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; // check if data 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 for(int i = 0; i < Size; i++) command[4+i] = pData[i]; hmemspi->Active_CMD = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, Size+4); // send insctruction+data to write return SPI_RES; } /** * @brief Send command to page program in FLASH. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс куда начинать записывать. * @param pData - откуда брать данные для записи в FLASH. * @param Size - сколько байтов записать. * @param Timeout - время, за которое должна быть осуществлена запись. * @note Программирование FLASH только в пределах одной страницы. * Т.е. если запись с 0x0, то не больше 256 байт. Если с 0ч40, то не больше 192 байт. */ HAL_StatusTypeDef MEMSPI_CMD_FLASH_Page_Program_IT(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address, uint8_t *pData, uint16_t Size) { 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 data 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 for(int i = 0; i < Size; i++) command[4+i] = pData[i]; hmemspi->Active_CMD = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, Size+4); // send insctruction+data to write return SPI_RES; } /** * @brief Send command to erase sector. * @param hmemspi - указатель на хендл внешней памяти. * @param FLASH_Address - адресс где надо данные стереть. * @param Timeout - время, за которое должна быть осуществлена очистка. * @note Микросхема вроде сама высчитывает какой сектор ерейзнуть, в соответствии с заданным адресом. */ HAL_StatusTypeDef MEMSPI_CMD_FLASH_Erase_Sector_IT(MEMSPI_HandleTypeDef *hmemspi, uint32_t FLASH_Address) { HAL_StatusTypeDef SPI_RES; uint8_t command[4]; uint8_t response[8]; FLASH_Address = FLASH_Address & 0xFFFFFF; command[0] = MEMSPI_ERASE_SECTOR; command[1] = FLASH_Address >> 16; command[2] = FLASH_Address >> 8; command[3] = FLASH_Address; hmemspi->Active_CMD = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, 4); return SPI_RES; } /** * @brief Send command to read JEDEC ID. * @param hmemspi - указатель на хендл внешней памяти. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return JEDEC ID микросхемы. */ HAL_StatusTypeDef MEMSPI_CMD_Read_JEDEC_ID_IT(MEMSPI_HandleTypeDef *hmemspi, uint32_t *JEDEC_ID_var) { HAL_StatusTypeDef SPI_RES; uint8_t command[1] = {0}; command[0] = MEMSPI_READ_JEDEC_ID; hmemspi->Active_CMD = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; hmemspi->pRxBuffPtr = (uint8_t *)&JEDEC_ID_var[0]; hmemspi->RxXferSize = 4; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, 1); return SPI_RES; } /** * @brief Send command to read JEDEC ID. * @param hmemspi - указатель на хендл внешней памяти. * @param Timeout - время, за которое должно быть осуществлено чтение. * @return Device ID микросхемы. */ HAL_StatusTypeDef MEMSPI_CMD_Read_Device_ID_IT(MEMSPI_HandleTypeDef *hmemspi, uint64_t *Device_ID_var) { HAL_StatusTypeDef SPI_RES; uint8_t command[1] = {0}; uint8_t receive[8] = {0}; command[0] = MEMSPI_READ_UNIQUE_ID; hmemspi->Active_CMD = command[0]; hmemspi->MEM_State = MEM_SEND_COMMAND; hmemspi->pRxBuffPtr = (uint8_t *)&Device_ID_var[0]; hmemspi->RxXferSize = 8; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit_IT(hmemspi, command, 1); return SPI_RES; }