#include "at45db041.h" #include "periph.h" #include #include /*Make the buffer visible for the external flash*/ extern uint8_t SPI_REC_BUF[512]; /*Information structure*/ at45db_t AT45DB; /** * @brief Initialize the external flash, with basic parameters and checks its availability. * @retval None. */ void at45db_init() { memset(&AT45DB, 0, sizeof(AT45DB)); uint16_t res = -1; uint8_t status_register[2] = {0}; /*Check if the external flash memory is accessible*/ res = at45db_read_man_id(); printf("device.man.id: 0x%02X\r\n", res); if (!res) { /*External flash memory is not accessible*/ printf("Unable to communicate with external flash. Initiate wake up process!\r\n"); /*Wake up process*/ res = at45db_wake_up_from_deep_sleep(AT45DB); if (!res) { /*Device could be in ultra deep sleep*/ res = at45db_wake_up_from_ultra_deep_sleep(AT45DB); if (!res) { printf("Cannot wake up the external flash from ultra deep sleep\r\n"); } else if (res) { printf("External flash memory woke up from ultra deep sleep\r\n"); } } else if (res) { printf("External flash memory wake up from power down mode\r\n"); } } else if (res) { printf("Correct device ID, external flash memory is accessible\r\n"); } HAL_Delay(100); /*Initializa information structure*/ #ifdef BINARY_PAGE_SIZE AT45DB.block_size = 2048; AT45DB.blocks = 256; AT45DB.flash_mbit = 4; AT45DB.page_size = 256; #endif #ifdef DATAFLASH_PAGE_SIZE AT45DB.block_size = 2112; AT45DB.blocks = 256; AT45DB.flash_mbit = 4; AT45DB.page_size = 264; #endif } void at45db_disable_protection(void) { uint8_t cmd[4]; // Магическая последовательность для отключения защиты cmd[0] = 0x3D; cmd[1] = 0x2A; cmd[2] = 0x7F; cmd[3] = 0x9A; at45db_wait_ready(); FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, cmd, 4, HAL_MAX_DELAY); FLASH_CS_DISABLE(); at45db_wait_ready(); printf("Sector protection disabled command sent.\r\n"); } /** * @brief Считывает один байт статус-регистра AT45DB041E. * @retval 1 байт статуса. * * Бит 7 (0x80) — RDY/BUSY: 1 = готов, 0 = занят * Бит 0 (0x01) — Page Size: 1 = binary (256 байт), 0 = standard (264 байта) */ uint8_t at45db_get_status(void) { uint8_t cmd = STATUS_REGISTER; uint8_t status = 0; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, &cmd, 1, HAL_MAX_DELAY); HAL_SPI_Receive(&hspi2, &status, 1, HAL_MAX_DELAY); FLASH_CS_DISABLE(); return status; } /** * @brief Читает Manufacturer + Device ID. * @retval DEV_ID_OK или DEV_ID_ERROR. */ dev_id_t at45db_read_man_id(void) { uint8_t opcode = MAN_ID_OPCD; uint8_t rec_buf[4] = {0}; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, &opcode, 1, HAL_MAX_DELAY); HAL_SPI_Receive(&hspi2, rec_buf, 4, HAL_MAX_DELAY); FLASH_CS_DISABLE(); if (rec_buf[0] != 0x1F || rec_buf[1] != 0x24) return DEV_ID_ERROR; return DEV_ID_OK; } /** * @brief Проверяет текущий режим размера страницы. * @retval 256 если включён binary mode, 264 — если стандартный. */ uint16_t at45db_get_page_size(void) { return (at45db_get_status() & 0x01) ? 256 : 264; } /** * @brief Проверяет, готов ли чип к новой операции. * @retval 1 — готов, 0 — занят. */ int at45db_is_ready(void) { return (at45db_get_status() & 0x80) ? 1 : 0; } /** * @brief Wakes up external flash from deep sleep mode. * @param info : Structure information about the external flash operation. * @retval 1 for success, 0 on failure. */ uint16_t at45db_wake_up_from_deep_sleep(at45db_t info) { uint16_t res = -1; uint8_t cmd = WAKE_UP_DEEP_SLEEP; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, &cmd, 1, HAL_MAX_DELAY); FLASH_CS_DISABLE(); // TODO: fix /*Return the MISO pin to its initial state*/ // SET_BIT(GPIO_SPIx->MODER, (1U<<(SPIx_GPIO_MISO_PIN*2+1))); // CLEAR_BIT(GPIO_SPIx->MODER, (1U<MODER, (1U<<(SPIx_GPIO_MISO_PIN*2+1))); // CLEAR_BIT(GPIO_SPIx->MODER, (1U<> 16) & 0xFF; cmd[2] = (addr >> 8) & 0xFF; cmd[3] = addr & 0xFF; cmd[4] = 0x00; // dummy FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, cmd, 5, HAL_MAX_DELAY); HAL_SPI_Receive(&hspi2, data, size, HAL_MAX_DELAY); FLASH_CS_DISABLE(); } /** * @brief Enter flash into ultra deep sleep. * @param info : Structure information about the external flash operation. * @retval None. */ void at45db_ultra_deep_sleep(at45db_t info) { uint8_t opcode = ULTRA_DEEP_SLEEP; /*Select the slave device*/ FLASH_CS_ENABLE(); /*Transmit the proper opcode*/ HAL_SPI_Transmit(&hspi2, &opcode, 1, HAL_MAX_DELAY); /*Give some time to the system*/ HAL_Delay(100); /*Release the device*/ FLASH_CS_DISABLE(); // TODO: fix /*Make the MISO pin analog, for power saving*/ // SET_BIT(GPIO_SPIx->MODER, (1U<<(SPIx_GPIO_MISO_PIN*2+1))); // SET_BIT(GPIO_SPIx->MODER, (1U<<(SPIx_GPIO_MISO_PIN*2))); info.state = _U_DEEP_SLEEP; } void at45db_write_page(uint16_t page, uint8_t *data) { uint8_t cmd[4]; uint32_t addr = (uint32_t)page << 8; cmd[0] = 0x84; // Buffer 1 Write cmd[1] = 0x00; cmd[2] = 0x00; cmd[3] = 0x00; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, cmd, 4, HAL_MAX_DELAY); HAL_SPI_Transmit(&hspi2, data, 256, HAL_MAX_DELAY); FLASH_CS_DISABLE(); cmd[0] = 0x83; cmd[1] = (addr >> 16) & 0xFF; cmd[2] = (addr >> 8) & 0xFF; cmd[3] = addr & 0xFF; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, cmd, 4, HAL_MAX_DELAY); FLASH_CS_DISABLE(); } void at45db_read_continuous(uint32_t addr, uint8_t *buffer, uint32_t size) { uint8_t cmd[8]; /*Preparing the command*/ cmd[0] = 0xE8; //Opcode cmd[1] = (addr >> 16) & 0xFF; // Address byte 1 cmd[2] = (addr >> 8) & 0xFF; // Address byte 2 cmd[3] = addr & 0xFF; // Address byte 3 cmd[4] = 0x00; // Dummy byte 1 cmd[5] = 0x00; // Dummy byte 2 cmd[6] = 0x00; // Dummy byte 3 cmd[7] = 0x00; // Dummy byte 4 /*Select the external flash memory*/ FLASH_CS_ENABLE(); /*Send the proper commands to load data to the internal buffer 1*/ HAL_SPI_Transmit(&hspi2, cmd, sizeof(cmd), HAL_MAX_DELAY); /*Receive the data*/ HAL_SPI_Receive(&hspi2, buffer, size, HAL_MAX_DELAY); /*Deselect the external flash memory*/ FLASH_CS_DISABLE(); } /** * @brief Configure page size. Careful you only have 10000 times to do that. * @param mode : Set 1 for DataFlash (264 bytes), 2 for Binary (256 bytes). * @retval None. */ void at45db_page_size_conf(uint16_t mode) { uint8_t cmd[4] = {0}; cmd[0] = 0x3D; cmd[1] = 0x2A; cmd[2] = 0x80; /*Check user input*/ if (mode == 1) { /*Data flash page size*/ cmd[3] = 0xA7; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, cmd, sizeof(cmd), HAL_MAX_DELAY); FLASH_CS_DISABLE(); } else if (mode == 2) { /*Binary page size*/ cmd[3] = 0xA6; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, cmd, sizeof(cmd), HAL_MAX_DELAY); FLASH_CS_DISABLE(); } } /** * @brief Perform chip erase. This command erase the entire main memory. * @retval None. */ void at45db_chip_erase(void) { uint8_t cmd[4] = {0}; int res = -1; cmd[0] = CHIP_ERASE_1; cmd[1] = CHIP_ERASE_2; cmd[2] = CHIP_ERASE_3; cmd[3] = CHIP_ERASE_4; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, cmd, 4, HAL_MAX_DELAY); FLASH_CS_DISABLE(); /*Check for fault operation*/ res = at45db_fault_check(); if (res == 1) { printf("There was a fault in erase operation...\n\r"); } else if (res == 0) { printf("Successful, erase operation...\n\r"); } } /** * @brief Checks if a fault erased after an erase or program operation. * @retval 1 if an error is detected, 0 otherwise. */ uint16_t at45db_fault_check(void) { uint8_t status_register[2]; uint8_t opcode = STATUS_REGISTER; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, &opcode, 1, HAL_MAX_DELAY); HAL_SPI_Receive(&hspi2, status_register, 2, HAL_MAX_DELAY); FLASH_CS_DISABLE(); /*Check the 5th bit of the second byte EPE bit*/ if ((status_register[1] & EPE_BIT)) { /*Error detected*/ return 1; } /*Success, in erasing external flash memory*/ return 0; } /** * @brief This function erases a sector inside the external memory. * @param sector_num : This is the number of the sector you need to erase. * @retval None. */ void at45db_sector_erase(uint8_t sector_num) { uint8_t opcode = SECTOR_ERASE; uint8_t address_byte[3]; address_byte[0] = ((sector_num) << 3) & 0xF8; address_byte[1] = 0x00; address_byte[2] = 0x00; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, &opcode, 1, HAL_MAX_DELAY); HAL_SPI_Transmit(&hspi2, address_byte, 3, HAL_MAX_DELAY); FLASH_CS_DISABLE(); } /** * @brief Erases a specific page inside the main memory. * @reval None. */ void at45db_page_erase(uint16_t page) { uint8_t cmd[4]; uint8_t opcode = 0x81; // PAGE_ERASE_CMD // Для Binary Mode (256 байт) сдвиг должен быть 8 // Для Standard Mode (264 байта) сдвиг должен быть 9 // Используем ваш макрос PAGE_SHIFT uint32_t addr = (uint32_t)page << PAGE_SHIFT; FLASH_CS_ENABLE(); HAL_SPI_Transmit(&hspi2, &opcode, 1, HAL_MAX_DELAY); cmd[0] = (addr >> 16) & 0xFF; cmd[1] = (addr >> 8) & 0xFF; cmd[2] = addr & 0xFF; HAL_SPI_Transmit(&hspi2, cmd, 3, HAL_MAX_DELAY); FLASH_CS_DISABLE(); } /** * @brief Enter flash into deep sleep mode. * @param info : Structure information about the external flash operation. * @retval None. */ void at45db_deep_sleep(at45db_t *info) { uint8_t opcode = DEEP_SLEEP; /*Select the device*/ FLASH_CS_ENABLE(); /*Transmit the command the external FLASH memory*/ HAL_SPI_Transmit(&hspi2, &opcode, 1, HAL_MAX_DELAY); /*Give some time to process*/ HAL_Delay(100); /*Release the slave device*/ FLASH_CS_DISABLE(); /*Give some time to the system*/ HAL_Delay(2); //TODO: fix /*Make the MISO pin analog, for power saving*/ // SET_BIT(GPIO_SPIx->MODER, (1U<<(SPIx_GPIO_MISO_PIN*2+1))); // SET_BIT(GPIO_SPIx->MODER, (1U<<(SPIx_GPIO_MISO_PIN*2))); } void at45db_wait_ready(void) { while (!(at45db_get_status() & 0x80)) { HAL_Delay(1); } }