/** ************************************************************************** * @file flash.c * @brief flash program ************************************************************************** * Copyright notice & Disclaimer * * The software Board Support Package (BSP) that is made available to * download from Artery official website is the copyrighted work of Artery. * Artery authorizes customers to use, copy, and distribute the BSP * software and its related documentation for the purpose of design and * development in conjunction with Artery microcontrollers. Use of the * software is governed by this copyright notice and the following disclaimer. * * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES, * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS, * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS, * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * ************************************************************************** */ #include "bsp_flash.h" #include "string.h" /** @addtogroup AT32A423_periph_examples * @{ */ #if defined (AT32A423xC) #define SECTOR_SIZE 2048 /* this parameter depends on the specific model of the chip */ #else #define SECTOR_SIZE 1024 /* this parameter depends on the specific model of the chip */ #endif #define FLASH_HEAD 0XA55AA55A #define FLASH_TAIL 0X5AA55AA5 uint16_t flash_buf[SECTOR_SIZE / 2]; /** * @brief read data using halfword mode * @param read_addr: the address of reading * @param p_buffer: the buffer of reading data * @param num_read: the number of reading data * @retval 0 = success, 1 = fail */ uint8_t flash_read(uint32_t read_addr, void *p_buffer, uint32_t num_read) { uint16_t *buf = (uint16_t *)p_buffer; uint32_t i; for(i = 0; i < num_read; i++) { buf[i] = *(uint16_t*)(read_addr); read_addr += 2; } return 0; } /** * @brief write data using halfword mode without checking * @param write_addr: the address of writing * @param p_buffer: the buffer of writing data * @param num_write: the number of writing data * @retval 0 = success, 1 = fail */ uint8_t flash_write_nocheck(uint32_t write_addr, const void *p_buffer, uint32_t num_write) { uint16_t *buf = (uint16_t *)p_buffer; uint32_t i; flash_status_type status = FLASH_OPERATE_DONE; for(i = 0; i < num_write; i++) { status = flash_halfword_program(write_addr, buf[i]); if(status != FLASH_OPERATE_DONE) return 1; write_addr += 2; } return 0; } /** * @brief write data using halfword mode with checking * @param write_addr: the address of writing * @param p_buffer: the buffer of writing data * @param num_write: the number of writing data * @retval 0 = success, 1 = fail */ uint8_t flash_write(uint32_t write_addr, const void *p_buffer, uint32_t num_write) { uint16_t *buf = (uint16_t *)p_buffer; uint32_t offset_addr; uint32_t sector_position; uint32_t sector_offset; uint32_t sector_remain; uint32_t i; flash_status_type status = FLASH_OPERATE_DONE; flash_unlock(); offset_addr = write_addr - FLASH_BASE; sector_position = offset_addr / SECTOR_SIZE; sector_offset = (offset_addr % SECTOR_SIZE) / 2; sector_remain = (SECTOR_SIZE / 2) - sector_offset; if(num_write <= sector_remain) sector_remain = num_write; while(1) { flash_read(sector_position * SECTOR_SIZE + FLASH_BASE, flash_buf, SECTOR_SIZE / 2); for(i = 0; i < sector_remain; i++) { if(flash_buf[sector_offset + i] != 0xFFFF) break; } if(i < sector_remain) { status = flash_operation_wait_for(ERASE_TIMEOUT); if((status == FLASH_PROGRAM_ERROR) || (status == FLASH_EPP_ERROR)) flash_flag_clear(FLASH_PRGMERR_FLAG | FLASH_EPPERR_FLAG); else if(status == FLASH_OPERATE_TIMEOUT) { flash_lock(); return 1; } status = flash_sector_erase(sector_position * SECTOR_SIZE + FLASH_BASE); if(status != FLASH_OPERATE_DONE) { flash_lock(); return 1; } for(i = 0; i < sector_remain; i++) { flash_buf[i + sector_offset] = buf[i]; } if(flash_write_nocheck(sector_position * SECTOR_SIZE + FLASH_BASE, flash_buf, SECTOR_SIZE / 2) != 0) { flash_lock(); return 1; } } else { if(flash_write_nocheck(write_addr, buf, sector_remain) != 0) { flash_lock(); return 1; } } if(num_write == sector_remain) break; else { sector_position++; sector_offset = 0; buf += sector_remain; write_addr += (sector_remain * 2); num_write -= sector_remain; if(num_write > (SECTOR_SIZE / 2)) sector_remain = SECTOR_SIZE / 2; else sector_remain = num_write; } } flash_lock(); return 0; } int load_config_params(flash_para_struct *params) { uint32_t *head = (uint32_t*)FMC_WRITE_START_ADDR; uint32_t *tail = (uint32_t*)(FMC_WRITE_START_ADDR + sizeof(flash_para_struct) - 4); if(*head == FLASH_HEAD && *tail == FLASH_TAIL) { memcpy((uint32_t *)params, head, sizeof(flash_para_struct)); return 1; } else { return -1; } } int save_config_params(flash_para_struct *params) { params->flash_head = FLASH_HEAD; params->flash_tail = FLASH_TAIL; flash_write(FMC_WRITE_START_ADDR, params, sizeof(flash_para_struct)/sizeof(uint16_t)); return 0; } /** * @brief 擦除指定扇区 * @param sector_addr 扇区起始地址 * @param len 擦除长度(未使用,保持接口兼容) * @return 0 = success, 1 = fail */ uint8_t flash_erase(uint32_t sector_addr, uint32_t len) { flash_status_type status; flash_unlock(); status = flash_operation_wait_for(ERASE_TIMEOUT); if(status == FLASH_OPERATE_TIMEOUT) { flash_lock(); return 1; } if((status == FLASH_PROGRAM_ERROR) || (status == FLASH_EPP_ERROR)) { flash_flag_clear(FLASH_PRGMERR_FLAG | FLASH_EPPERR_FLAG); } status = flash_sector_erase(sector_addr); flash_lock(); return (status == FLASH_OPERATE_DONE) ? 0 : 1; } /** * @} */ /** * @} */ uint8_t bsp_flash_is_erased(uint32_t addr, uint32_t size) { const uint8_t *flash_ptr = (const uint8_t *)addr; uint32_t i; for (i = 0U; i < size; i++) { if (flash_ptr[i] != 0xFF) { return 0; } } return 1; }