打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

4 内嵌闪存控制器(EFC)
4.1 EFC简介

内嵌的闪存存储器可以用于在线编程(ICP)或在程序中编程(IAP)烧写。
在线编程 (In-Circuit Programming - ICP) 方式用于更新闪存存储器的全部内容, 它通过 JTAG、 SWD协议或系统加载程序(Bootloader)下载用户应用程序到微控制器中。ICP 是一种快速有效的编程方法,消除了封装和管座的困扰。

与 ICP 方式对应,在程序中编程(In-Application Programming - IAP)可以使用微控制器支持的任一种通信接口(如 I/O 端口、USB、CAN、UART、I2C、SPI 等)下载程序或数据到存储器中。IAP 允许用户在程序运行时重新烧写闪存存储器中的内容。然而,IAP 要求至少有一部分程序已经使用 ICP烧到闪存存储器中。
闪存接口是在 AHB 协议上实现了对指令和数据的访问,它通过对存储器的预取缓存,加快了存储器的访问;闪存接口还实现了在所有工作电压下对闪存编程和擦除所需的逻辑电路,这里还包括访问和写入保护以及选择字节的控制。

4.2 主要特点

  • 256K字节闪存
  • 带预取缓冲器的读接口
  • 选择字节加载
  • 闪存编程/擦除操作
  • 读出/写入保护
  • HEX加密保护
  • 系统存储器区域作为主存扩展使用
  • 密码保护指定范围程序区(安全库区),安全库区包含主存存储区或系统存储器区域
  • 32位CRC校验
  • 低功耗模式
/********************************************************************************
* @file    bsp_flash.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-09-30
* @brief   flash读写操作
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

#include "RTE_Components.h"
#include CMSIS_device_header

#include "bsp_flash.h"
#include "sys_api.h"

/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"

/* Private Define ------------------------------------------------------------*/
#define BSP_FLASH_PAGE_SIZE  BS_FLASH_PAGE_SIZE
/* Private Variables ---------------------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
/**
  * @brief  Flash erase page
  * @param  page_addr: flash addr example
  * @param  page_num: Number of pages to erase
  * @retval status
  */
uint8_t bsp_flash_erase_page(uint32_t page_addr, uint32_t page_num)
{
    uint32_t i;

    // 一页 512 字节
    if (page_addr % BSP_FLASH_PAGE_SIZE != 0)
    {
        page_addr -= (page_addr % BSP_FLASH_PAGE_SIZE);
    }
    if (page_addr < 1)
    {
        page_addr = 1;
    }
    FLASH_Unlock();
    for (i = 0; i < page_num; i++)
    {
        FLASH_ErasePage(page_addr + i * BSP_FLASH_PAGE_SIZE);
    }
    FLASH_Lock();
    return 0;
}

/**
 * @brief  flash 读字节
 * @param  addr: flash地址
 * @retval 字节内容
 */
uint8_t bsp_flash_read_byte(uint32_t addr)
{
    return (uint8_t)*(uint32_t *)(addr);
}

/**
 * @brief  flash 读多字节
 * @param  addr: flash地址
 * @param  *data: 缓存buff地址
 * @param  len: 读取长度
 * @retval 0--失败 1--成功
 */
bool bsp_flash_read_nbyte(uint32_t addr, uint8_t *data, uint32_t len)
{
    uint32_t i;

    if (len == 0)
    {
        return false;
    }

    for (i = 0; i < len; i++)
    {
        *(data + i) = bsp_flash_read_byte(addr + i);
    }

    return true;
}

/**
 * @brief  flash 读半字
 * @param  addr: flash地址
 * @retval 半字内容
 */
uint16_t bsp_flash_read_halfword(uint32_t addr)
{
    return (uint16_t)*(uint32_t *)(addr);
}

/**
 * @brief  flash 读字
 * @param  addr: flash地址
 * @retval 字内容
 */
uint32_t bsp_flash_read_word(uint32_t addr)
{
    return (uint32_t)*(uint32_t *)(addr);
}

/**
 * @brief  flash 写字节
 * @param  addr: flash地址
 * @param  data: 字节
 * @retval 0--失败 1--成功
 */
bool bsp_flash_write_byte(uint32_t addr, uint8_t data)
{
    FLASH_Unlock();
    if (FLASH_ProgramByte(addr, data))
    {
        FLASH_Lock();
        return false;
    }
    FLASH_Lock();
    return true;
}

/**
 * @brief  flash 写字
 * @param  addr: flash地址
 * @param  data: 字
 * @retval 0--失败 1--成功
 */
bool bsp_flash_write_word(uint32_t addr, uint32_t data)
{
    FLASH_Unlock();
    if (FLASH_ProgramWord(addr, data))
    {
        FLASH_Lock();
        return false;
    }
    FLASH_Lock();
    return true;
}

/**
 * @brief  flash 写多字节
 * @param  addr: flash地址
 * @param  *data: 数据缓冲区
 * @param  len: 数据长度
 * @retval 0--失败 1--成功
 */
bool bsp_flash_write_nbyte(uint32_t addr, uint8_t *data, uint32_t len)
{
    uint32_t i;

    if (len == 0)
    {
        return false;
    }
    FLASH_Unlock();
    for (i = 0; i < len; i++)
    {
        FLASH_ProgramByte((addr + i), *(data + i));
    }
    FLASH_Lock();
    return true;
}

/**
 * @brief  得到flash每页字节大小
 * @note   
 * @retval 
 */
uint16_t bsp_flash_get_page_size(void)
{
    return BSP_FLASH_PAGE_SIZE;
}

/**
 * @brief  flash 写多字节(带关闭中断函数)
 * @param  addr: flash地址
 * @param  *data: 数据缓冲区
 * @param  len: 数据长度
 * @retval 0--失败 1--成功
 */
bool bsp_flash_write_nbyte_s(uint32_t addr, uint8_t *data, uint32_t len)
{
    bool ret;
    sys_disable_irq();
    ret = bsp_flash_write_nbyte(addr, data, len);
    sys_enable_irq();
    return ret;
}

bool bsp_flash_is_busy(void)
{
    if (FLASH->STS == 1)
    {
        return true;
    }
    else
    {
        return false;
    }
}

/**
 * @brief  flash搬运 (addr2 搬运到 addr1 ,并擦除addr1)
 * @param  t_addr: 目标地址(addr1)
 * @param  s_addr: 欲搬地址(addr2)
 * @param  size: 字节大小
 * @retval 0--失败 1--成功
 */
bool bsp_flash_carry(uint32_t t_addr, uint32_t s_addr, uint32_t size)
{
    bool ret = true;
    uint32_t word_len;
    uint32_t page_len;
    uint32_t i;

    word_len = (size / sizeof(uint32_t));
    page_len = (size % BSP_FLASH_PAGE_SIZE) == 0 ?
                (size / BSP_FLASH_PAGE_SIZE) : (size / BSP_FLASH_PAGE_SIZE) + 1;
    
    for (i = 0; i < page_len; i++)
    {
        bsp_flash_erase_page(t_addr + i * BSP_FLASH_PAGE_SIZE, 1);
    }
    while(bsp_flash_is_busy());
    for (i = 0; i < word_len; i++)
    {
        ret = bsp_flash_write_word(t_addr + i * sizeof(uint32_t),
                                   bsp_flash_read_word(s_addr + i * sizeof(uint32_t)));
        if (ret == false)
        {
            break;
        }
    }

    if (ret == true)
    {
        for (i = 0; i < page_len; i++)
        {
            bsp_flash_erase_page(s_addr + i * BSP_FLASH_PAGE_SIZE, 1);
        }
    }

    return ret;
}

/********************************************************************************
* @file    bsp_flash.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-03
* @brief   flash操作
********************************************************************************/

#ifndef __BSP_FLASH_H
#define __BSP_FLASH_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

/* Public struct ------------------------------------------------------------*/
typedef struct
{
    uint32_t usercfg0;
    uint32_t usercfg1;
    uint32_t usercfg2;
    uint32_t boot_state;       // 0--run app  1--in dfu  2--move ota in app
    uint32_t boot_run_tick;    // 掉电次数
    uint32_t boot_carry_size;  // 需要复制的字节数量
    uint32_t app_crc;          // app 运行前先crc校验,防止app损坏
    uint32_t chip_lock;        // 任意值--锁住swo XXXX--特殊码解锁swo
} option_bytes_t;

typedef struct
{
    uint8_t boot_state;       // 0--run app  1--in dfu  2--move ota in app
    uint16_t boot_run_tick;   // 掉电次数
    uint32_t boot_carry_size; // 需要复制的字节数量
    uint16_t app_crc;         // app 运行前先crc校验,防止app损坏
    uint16_t chip_lock;       // 任意值--锁住swo XXXX--特殊码解锁swo
} boot_info_t;

/* Public Function Prototypes ------------------------------------------------*/

uint8_t bsp_flash_erase_page(uint32_t page_addr, uint32_t page_num);

uint8_t bsp_flash_read_byte(uint32_t addr);
bool bsp_flash_read_nbyte(uint32_t addr, uint8_t *data, uint32_t len);

uint16_t bsp_flash_read_halfword(uint32_t addr);
uint32_t bsp_flash_read_word(uint32_t addr);

bool bsp_flash_write_byte(uint32_t addr, uint8_t data);
bool bsp_flash_write_nbyte(uint32_t addr, uint8_t *data, uint32_t len);
bool bsp_flash_write_nbyte_s(uint32_t addr, uint8_t *data, uint32_t len);
bool bsp_flash_write_word(uint32_t addr, uint32_t data);

bool bsp_flash_is_busy(void);
bool bsp_flash_carry(uint32_t t_addr, uint32_t s_addr, uint32_t size);

#endif

posted on 2022-08-13 11:00  xuejianqiang  阅读(196)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033