/** ****************************************************************************** * @file memspi_core.c * @brief Реализация работы с командами для внешней памяти ****************************************************************************** * @details Модуль реализует функции для работы с FLASH/EEPROM по SPI на уровне отдельных команд: - 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_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 "memspi_core.h" //------------------------------------------------------------- //----------------------COMMAND FUNCTIONS---------------------- /** * @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 Какие биты запросить. * @param Timeout Время, за которое должно быть осуществлена запись. * @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; size = 3; MEMSPI_Select(hmemspi); SPI_RES = MEMSPI_SPI_Transmit(hmemspi, command, size, Timeout); MEMSPI_Deselect(hmemspi); return SPI_RES; } /** * @brief Send command to set Write Enable Latch (WEL) in Status Register. * @param hmemspi Указатель на хендл внешней памяти. * @param Timeout Время, за которое должно быть осуществлена запись. * @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]; 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; 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; } //-------------------------------------------------------------