/* * Flash-based Non-Volatile Memory (NVM) * * This file supports storing and loading persistent configuration based on * the STM32 builtin flash memory. * * The STM32F405xx has 12 flash sectors of heterogeneous size. We use the last * two sectors for configuration data. These pages have a size of 128kB each. * Setting any bit in these sectors to 0 is always possible, but setting them * to 1 requires erasing the whole sector. * * We consider each sector as an array of 64-bit fields except the first N bytes, which we * instead use as an allocation block. The allocation block is a compact bit-field (2 bit per entry) * that keeps track of the state of each field (erased, invalid, valid). * * One sector is always considered the valid (read) sector and the other one is the * target for the next write access: they can be considered to be ping-pong or double buffred. * * When writing a block of data, instead of always erasing the whole writable sector the * new data is appended in the erased area. This presumably increases flash life span. * The writable sector is only erased if there is not enough space for the new data. * * On startup, if there is exactly one sector * whose last non-erased value has the state "valid" that sector is considered * the valid sector. In any other case the selection is undefined. * * * To write a new block of data atomically we first mark all associated fields * as "invalid" (in the allocation table) then write the data and then mark the * fields as "valid" (in the direction of increasing address). */ #include #include //#include #include "flash.h" #include "stm32f405xx.h" #include "stm32f4xx_board.h" #include "can.h" //#include "main.h" //#include "tim.h" //#include "gpio.h" #define K(v) (v<<10) static uint32_t sectors_size[12] = {K(16), K(16), K(16), K(16), K(64), K(128), K(128), K(128), K(128), K(128), K(128), K(128)}; static const uint32_t FLASH_ERR_FLAGS = #if defined(FLASH_FLAG_EOP) FLASH_FLAG_EOP | #endif #if defined(FLASH_FLAG_OPERR) FLASH_FLAG_OPERR | #endif #if defined(FLASH_FLAG_WRPERR) FLASH_FLAG_WRPERR | #endif #if defined(FLASH_FLAG_PGAERR) FLASH_FLAG_PGAERR | #endif #if defined(FLASH_FLAG_PGSERR) FLASH_FLAG_PGSERR | #endif #if defined(FLASH_FLAG_PGPERR) FLASH_FLAG_PGPERR | #endif 0; void HAL_FLASH_ClearError() { __HAL_FLASH_CLEAR_FLAG(FLASH_ERR_FLAGS); } static uint32_t _sector_frame_address(uint32_t Address) { uint32_t sector = 0; if((Address < ADDR_FLASH_SECTOR_1) && (Address >= ADDR_FLASH_SECTOR_0)) { sector = FLASH_SECTOR_0; } else if((Address < ADDR_FLASH_SECTOR_2) && (Address >= ADDR_FLASH_SECTOR_1)) { sector = FLASH_SECTOR_1; } else if((Address < ADDR_FLASH_SECTOR_3) && (Address >= ADDR_FLASH_SECTOR_2)) { sector = FLASH_SECTOR_2; } else if((Address < ADDR_FLASH_SECTOR_4) && (Address >= ADDR_FLASH_SECTOR_3)) { sector = FLASH_SECTOR_3; } else if((Address < ADDR_FLASH_SECTOR_5) && (Address >= ADDR_FLASH_SECTOR_4)) { sector = FLASH_SECTOR_4; } else if((Address < ADDR_FLASH_SECTOR_6) && (Address >= ADDR_FLASH_SECTOR_5)) { sector = FLASH_SECTOR_5; } else if((Address < ADDR_FLASH_SECTOR_7) && (Address >= ADDR_FLASH_SECTOR_6)) { sector = FLASH_SECTOR_6; } else if((Address < ADDR_FLASH_SECTOR_8) && (Address >= ADDR_FLASH_SECTOR_7)) { sector = FLASH_SECTOR_7; } else if((Address < ADDR_FLASH_SECTOR_9) && (Address >= ADDR_FLASH_SECTOR_8)) { sector = FLASH_SECTOR_8; } else if((Address < ADDR_FLASH_SECTOR_10) && (Address >= ADDR_FLASH_SECTOR_9)) { sector = FLASH_SECTOR_9; } else if((Address < ADDR_FLASH_SECTOR_11) && (Address >= ADDR_FLASH_SECTOR_10)) { sector = FLASH_SECTOR_10; }else { sector = FLASH_SECTOR_11; } return sector; } void flash_unlock(void) { /* Authorize the FLASH Registers access */ WRITE_REG(FLASH->KEYR, FLASH_KEY1); WRITE_REG(FLASH->KEYR, FLASH_KEY2); } /** * @brief Locks the FLASH control register access * @retval HAL Status */ void flash_lock(void) { /* Set the LOCK Bit to lock the FLASH Registers access */ FLASH->CR |= FLASH_CR_LOCK; } void flash_wait_ready(uint32_t Timeout) { uint32_t tickstart = 0U; tickstart = HAL_GetTick(); while(__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY) != RESET) { // wdog_reload(); if(Timeout != HAL_MAX_DELAY) { if((Timeout == 0U)||((HAL_GetTick() - tickstart ) > Timeout)) { return; } } } /* Check FLASH End of Operation flag */ if (__HAL_FLASH_GET_FLAG(FLASH_FLAG_EOP) != RESET) { /* Clear FLASH End of Operation pending bit */ __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP); } } void flash_erase_sector(uint32_t Sector) { uint32_t tmp_psize = 0U; uint8_t VoltageRange = FLASH_VOLTAGE_RANGE_3; if (VoltageRange == FLASH_VOLTAGE_RANGE_1) { tmp_psize = FLASH_PSIZE_BYTE; } else if (VoltageRange == FLASH_VOLTAGE_RANGE_2) { tmp_psize = FLASH_PSIZE_HALF_WORD; } else if (VoltageRange == FLASH_VOLTAGE_RANGE_3) { tmp_psize = FLASH_PSIZE_WORD; } else { tmp_psize = FLASH_PSIZE_DOUBLE_WORD; } /* Need to add offset of 4 when sector higher than FLASH_SECTOR_11 */ if (Sector > FLASH_SECTOR_11) { Sector += 4U; } /* If the previous operation is completed, proceed to erase the sector */ CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE); FLASH->CR |= tmp_psize; CLEAR_BIT(FLASH->CR, FLASH_CR_SNB); FLASH->CR |= FLASH_CR_SER | (Sector << FLASH_CR_SNB_Pos); FLASH->CR |= FLASH_CR_STRT; flash_wait_ready(2000); CLEAR_BIT(FLASH->CR, (FLASH_CR_SER | FLASH_CR_SNB)); } static void flash_write_word(uint32_t Address, uint32_t Data) { /* If the previous operation is completed, proceed to program the new data */ CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE); FLASH->CR |= FLASH_PSIZE_WORD; FLASH->CR |= FLASH_CR_PG; *(__IO uint32_t*)Address = Data; flash_wait_ready(10); FLASH->CR &= (~FLASH_CR_PG); } //不能用 static void flash_write_byte(uint32_t Address, uint8_t Data) { /* If the previous operation is completed, proceed to program the new data */ CLEAR_BIT(FLASH->CR, FLASH_CR_PSIZE); FLASH->CR |= FLASH_PSIZE_BYTE; FLASH->CR |= FLASH_CR_PG; *(__IO uint8_t*)Address = Data; flash_wait_ready(10); FLASH->CR &= (~FLASH_CR_PG); } // @brief Erases a flash sector. This sets all bits in the sector to 1. // The sector's current index is reset to the minimum value (n_reserved). // @returns 0 on success or a non-zero error code otherwise int flash_erase_page(uint32_t address) { // wdog_reload(); flash_unlock(); HAL_FLASH_ClearError(); flash_erase_sector(_sector_frame_address(address)); flash_lock(); // wdog_reload(); return 0; } int flash_erase_pages(uint32_t address, uint32_t size) { for (; size > 0; ) { flash_erase_page(address); uint8_t sector = _sector_frame_address(address); address += sectors_size[sector]; size -= sectors_size[sector];; } return 0; } int flash_erase_app(uint8_t app_num) { if(app_num == 1) { app_status_set(1,false); //total = 16+64+128+128=336k flash_erase_page(ADDR_FLASH_SECTOR_3);//16k flash_erase_page(ADDR_FLASH_SECTOR_4);//64k flash_erase_page(ADDR_FLASH_SECTOR_5);//128k flash_erase_page(ADDR_FLASH_SECTOR_6);//128k } else if(app_num == 2) { app_status_set(2,false); //total = 128+128+128=384k flash_erase_page(ADDR_FLASH_SECTOR_7);//128k flash_erase_page(ADDR_FLASH_SECTOR_8);//128k flash_erase_page(ADDR_FLASH_SECTOR_9);//128k } return 0; } void app_status_set(uint8_t app_num,bool status) { uint8_t app_ok_flag[2]; if(app_num == 1) { app_ok_flag[0] = status; app_ok_flag[1] = *(volatile uint8_t*)(CONFIG_IAP_INFO_ADDR+1); flash_erase_page(CONFIG_IAP_INFO_ADDR); flash_write_page(CONFIG_IAP_INFO_ADDR, app_ok_flag, 2, false); } else if(app_num == 2) { app_ok_flag[0] = *(volatile uint8_t*)(CONFIG_IAP_INFO_ADDR); app_ok_flag[1] = status; flash_erase_page(CONFIG_IAP_INFO_ADDR); flash_write_page(CONFIG_IAP_INFO_ADDR, app_ok_flag, 2, false); } } int flash_write_page(uint32_t target_addr, uint8_t *data, uint32_t length, bool erase) { uint32_t offset = target_addr & 0x3; target_addr -= offset; if (erase && flash_erase_page(target_addr) != 0) { return -1; } // wdog_reload(); flash_unlock(); HAL_FLASH_ClearError(); // handle unaligned start for (; (offset & 0x3) && length; ++data, ++offset, --length) { flash_write_byte(target_addr + offset, *data); } // write 32-bit values (64-bit doesn't work) for (; length >= 4; data += 4, offset += 4, length -=4) { flash_write_word(target_addr + offset, *(uint32_t *)data); } // handle unaligned end for (; length; ++data, ++offset, --length) { flash_write_byte(target_addr + offset, *data); } flash_lock(); return 0; } int flash_test(void) { int reg = 0; uint8_t buffer[1024]; reg = flash_erase_pages(ADDR_FLASH_SECTOR_2, ADDR_FLASH_SECTOR_10-ADDR_FLASH_SECTOR_2); memset(buffer, 0x55, sizeof(buffer)); reg = flash_erase_page(ADDR_FLASH_SECTOR_10); reg = flash_write_page(ADDR_FLASH_SECTOR_10, buffer, sizeof(buffer), false); memset(buffer, 0xAA, sizeof(buffer)); reg = flash_write_page(ADDR_FLASH_SECTOR_10, buffer, sizeof(buffer), true); memset(buffer, 0x55, sizeof(buffer)); reg = flash_erase_page(ADDR_FLASH_SECTOR_11); reg = flash_write_page(ADDR_FLASH_SECTOR_11, buffer, sizeof(buffer), false); memset(buffer, 0xAA, sizeof(buffer)); reg = flash_write_page(ADDR_FLASH_SECTOR_11, buffer, sizeof(buffer), true); return reg; } #if 1 //APP1_ADRESS 内容复制到 APP2_ADRESS void app1_copy_to_app2(void) { uint8_t data[1]; //1、擦除APP2的flash和完整性标志位 flash_erase_app(2); //2、从APP1_ADDRESS读出APP2_ADDRESS - APP1_ADDRESS个数据,复制写入到APP2_ADDRESS for (uint32_t i = 0; i < APP2_ADDRESS - APP1_ADDRESS; i++) { data[0] = *(volatile uint8_t*)(APP1_ADDRESS + i); flash_write_page(APP2_ADDRESS + i, data, 1, false); } } void app2_copy_to_app1(void) { uint8_t data[1]; //1、擦除APP1的flash和完整性标志位 flash_erase_app(1); //2、从APP2_ADDRESS读出APP2_ADDRESS - APP1_ADDRESS个数据,复制写入到APP1_ADDRESS for (uint32_t i = 0; i < APP2_ADDRESS - APP1_ADDRESS; i++) { data[0] = *(volatile uint8_t*)(APP2_ADDRESS + i); flash_write_page(APP1_ADDRESS + i, data, 1, false); } } #else //使用字(32位)为单位批量复制,提效不大 void app1_copy_to_app2(void) { uint32_t app_size = APP2_ADDRESS - APP1_ADDRESS; // 1. 擦除APP2区域 flash_erase_app(2); // 2. 一次性读取较多数据,批量写入 uint32_t buffer[256]; // 1KB缓冲区 uint32_t offset = 0; while (offset < app_size) { // 计算本次复制的数据量(不超过缓冲区大小) uint32_t copy_size = app_size - offset; if (copy_size > sizeof(buffer)) { copy_size = sizeof(buffer); } // 按字(32位)读取 uint32_t word_count = (copy_size + 3) / 4; // 向上取整到4字节 for (uint32_t i = 0; i < word_count; i++) { buffer[i] = *(volatile uint32_t*)(APP1_ADDRESS + offset + i * 4); } // 批量写入 flash_write_page(APP2_ADDRESS + offset, (uint8_t*)buffer, copy_size, false); offset += copy_size; } } #endif void jump_to_app(uint32_t app_addr) { __disable_irq(); // 3. 清除所有中断挂起位(非常重要!) for (int i = 0; i < 8; i++) { NVIC->ICPR[i] = 0xFFFFFFFF; // 清除挂起 NVIC->ICER[i] = 0xFFFFFFFF; // 禁用中断 } SysTick->CTRL = 0; HAL_CAN_DeInit(&hcan1); HAL_DeInit(); __set_MSP(REG32(app_addr)); // SCB->VTOR = app_addr; ((void (*)(void))(REG32(app_addr + 4)))(); } #if 0 void flash_write_magic(uint32_t magic) { uint32_t buffer[16]; if (magic == REG32(CONFIG_IAP_INFO_ADDR + 8)) { return; } memcpy(buffer, (void *)CONFIG_IAP_INFO_ADDR, sizeof(buffer)); buffer[2] = magic; flash_write_page(CONFIG_IAP_INFO_ADDR, (u8 *)buffer, sizeof(buffer), true); } uint32_t flash_read_magic(void) { return REG32(CONFIG_IAP_INFO_ADDR + 8); } #endif