打印
[活动专区]

【AT-START-F423测评】+ 内部 flash 擦写

[复制链接]
1672|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cuyebiren|  楼主 | 2023-10-29 20:00 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
内部 flash 一般具有 1万 次擦写次数,可以规划出一块或几块区域当 EEPROM 使用,用来保存掉电后保存的数据。注意:内部 flash 没有 EEPROM 擦写次数多,且 program 之前必须先 erase(EEPROM 没此限制)。

本评测在上一篇评测程序的基础上实现,详细的配置过程请参考上两篇评测。
步骤:
1、内部 flash 分析
at32f423vct7 内部总共有 128 个扇区,每隔扇区大小是 2k bytes。
本评测使用最后 2 个扇区作为替代 EEPROM 的用户数据区域,即从地址 0x803F000 开始。
注意:在 keil 配置时最好把编译代码区的大小减去作为替代 EEPROM 的用户数据的大小。


2、编写代码
注意:本测评使用的是  byte program,相比起来,word program 更实用些。
main.c
/* add user code begin Header */
/**
  **************************************************************************
  * [url=home.php?mod=space&uid=288409]@file[/url]     main.c
  * [url=home.php?mod=space&uid=247401]@brief[/url]    main 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.
  *
  **************************************************************************
  */
/* add user code end Header */

/* Includes ------------------------------------------------------------------*/
#include "at32f423_wk_config.h"

/* private includes ----------------------------------------------------------*/
/* add user code begin private includes */
#include <string.h>
/* add user code end private includes */

/* private typedef -----------------------------------------------------------*/
/* add user code begin private typedef */

/* add user code end private typedef */

/* private define ------------------------------------------------------------*/
/* add user code begin private define */

/* add user code end private define */

/* private macro -------------------------------------------------------------*/
/* add user code begin private macro */
#define MS_TICK         (system_core_clock / 8 / 1000U)
#define TX_BUF_SIZE     1024
#define RX_BUF_SIZE     1024

#define FLASH_START_ADDR         ((uint32_t)0x08000000U)
#define FLASH_BANK_START_ADDR    FLASH_START_ADDR
#define FLASH_BANK_SECTOR_SIZE   ((uint32_t)0x00000800U)     /* 2KB */
#define FLASH_BANK_SECTOR_NUM    127
#define FLASH_BANK_SIZE \
        (FLASH_BANK_SECTOR_NUM * FLASH_BANK_SECTOR_SIZE)
#define FLASH_BANK_END_ADDR \
        (FLASH_BANK_START_ADDR + FLASH_BANK_SIZE - 1)
#define FLASH_SIZE          FLASH_BANK_SIZE
#define FLASH_END_ADDR      (FLASH_START_ADDR + FLASH_SIZE - 1)

#define USER_DATA_START_ADDR     ((uint32_t)0x0803F000U)
/* add user code end private macro */

/* private variables ---------------------------------------------------------*/
/* add user code begin private variables */
static volatile uint32_t sys_tick;
uint8_t tx_buf[TX_BUF_SIZE];    /* uart 发送缓冲区 */
volatile uint16_t tx_len;                /* uart 实际发送数据长度 */
volatile uint8_t tx_flag;                /* uart 发送繁忙标志 */
uint8_t rx_buf[RX_BUF_SIZE];    /* uart 接收缓冲区 */
volatile uint16_t rx_len;                /* uart 实际接收数据长度 */
volatile uint8_t rx_flag;                /* uart 接收完成标志 */
static const char *start_msg = "The demo is started!\n";
/* add user code end private variables */

/* private function prototypes --------------------------------------------*/
/* add user code begin function prototypes */

/* add user code end function prototypes */

/* private user code ---------------------------------------------------------*/
/* add user code begin 0 */
static void systick_init(void)
{
    SysTick_Config(MS_TICK);
    systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_DIV8);
}

static void sys_tick_increament(void)
{
    sys_tick++;
}

uint32_t sys_tick_get(void)
{
    return sys_tick;
}

void SysTick_Handler(void)
{
  sys_tick_increament();
}

uint8_t flash_erase(uint32_t addr, uint32_t size)
{
    uint32_t end_addr;
    uint32_t start_sector_addr, end_sector_addr;

    if (addr < FLASH_START_ADDR || size == 0)
        return 0;
   
    end_addr = addr + size - 1;
    if (end_addr > FLASH_END_ADDR)
        return 0;

    /* 解锁 flash 编程/擦除操作 */
    flash_unlock();
    /* 清除标志位 */
    flash_flag_clear(FLASH_PRGMERR_FLAG | FLASH_EPPERR_FLAG);

    /* 计算擦除的起始 sector 地址和结束 sector 地址
    *      地址需要对齐到物理 sector 地址,
    *      即必须是 FLASH_START_ADDR + n * FLASH_BANK_SECTOR_SIZE
    */
    start_sector_addr = FLASH_BANK_START_ADDR +
                        (addr - FLASH_BANK_START_ADDR) /
                        FLASH_BANK_SECTOR_SIZE * FLASH_BANK_SECTOR_SIZE;

    end_sector_addr = FLASH_BANK_START_ADDR +
                    (end_addr - FLASH_BANK_START_ADDR) /
                    FLASH_BANK_SECTOR_SIZE * FLASH_BANK_SECTOR_SIZE;

    /* 擦除 flash */
    while (start_sector_addr <= end_sector_addr) {
        if (flash_sector_erase(start_sector_addr) != FLASH_OPERATE_DONE) {
            flash_lock();
            return 0;
        }

        start_sector_addr += FLASH_BANK_SECTOR_SIZE;
    }

    /* 锁定 flash 编程/擦除操作 */
    flash_lock();

    return 1;
}

uint8_t flash_program_byte(uint32_t addr, uint8_t *data, uint32_t size)
{
    uint32_t end_addr;

    if (addr < FLASH_START_ADDR || addr % 4 != 0)
        return 0;
   
    end_addr = addr + size - 1;
    if (end_addr > FLASH_END_ADDR)
        return 0;

    /* 解锁 flash 编程/擦除操作 */
    flash_unlock();
    /* 清除标志位 */
    flash_flag_clear(FLASH_PRGMERR_FLAG | FLASH_EPPERR_FLAG);

    /* 编程 flash */
    while (addr <= end_addr) {
        if (flash_byte_program(addr, *data++) != FLASH_OPERATE_DONE) {
            flash_lock();
            return 0;
        }

        addr++;
    }

    /* 锁定 flash 编程/擦除操作 */
    flash_lock();
   
    return 1;
}

uint8_t flash_erase_check(uint32_t addr, uint32_t size)
{
    uint32_t end_addr;

    if (addr < FLASH_START_ADDR)
        return 0;
   
    end_addr = addr + size - 1;
    if (end_addr > FLASH_END_ADDR)
        return 0;

    while (addr <= end_addr) {
        if (*(uint8_t *)addr != 0xFF)
            return 0;

        addr++;
    }

    return 1;
}

uint8_t flash_program_byte_check(uint32_t addr, uint8_t *data, uint32_t size)
{
    uint32_t end_addr;

    if (addr < FLASH_START_ADDR)
        return 0;
   
    end_addr = addr + size - 1;
    if (end_addr > FLASH_END_ADDR)
        return 0;

    while (addr <= end_addr) {
        if (*(uint8_t *)addr != *data++)
            return 0;

        addr++;
    }

    return 1;
}

static void uart_send(uint8_t *data, uint16_t size)
{
    wk_dma_channel_config(DMA1_CHANNEL2, (uint32_t)&USART1->dt, (uint32_t)data, size);
    dma_interrupt_enable(DMA1_CHANNEL2, DMA_FDT_INT, TRUE); /* 打开 dma 发送完成中断 */
    dma_channel_enable(DMA1_CHANNEL2, TRUE);                /* 启动 dma 通道传输 */
}
/* add user code end 0 */


/**
  * @brief  take some delay for waiting power stable, delay is about 60ms with frequency 8MHz.
  * @param  none
  * @retval none
  */
static void wk_wait_for_power_stable(void)
{
  volatile uint32_t delay = 0;
  for(delay = 0; delay < 50000; delay++);
}

/**
  * @brief main function.
  * @param  none
  * @retval none
  */
int main(void)
{
  /* add user code begin 1 */
    uint32_t start_tick;
  /* add user code end 1 */

  /* add a necessary delay to ensure that Vdd is higher than the operating
     voltage of battery powered domain (2.57V) when the battery powered
     domain is powered on for the first time and being operated. */
  wk_wait_for_power_stable();
  
  /* system clock config. */
  wk_system_clock_config();

  /* config periph clock. */
  wk_periph_clock_config();

  /* nvic config. */
  wk_nvic_config();

  /* init dma1 channel1 */
  wk_dma1_channel1_init();
  /* config dma channel transfer parameter */
  /* user need to modify parameters memory_base_addr and buffer_size */
  wk_dma_channel_config(DMA1_CHANNEL1, (uint32_t)&USART1->dt, (uint32_t)rx_buf, RX_BUF_SIZE);
  dma_channel_enable(DMA1_CHANNEL1, TRUE);

  /* init dma1 channel2 */
  wk_dma1_channel2_init();
  /* config dma channel transfer parameter */
  /* user need to modify parameters memory_base_addr and buffer_size */
  wk_dma_channel_config(DMA1_CHANNEL2, (uint32_t)&USART1->dt, (uint32_t)start_msg, strlen(start_msg));
  dma_channel_enable(DMA1_CHANNEL2, TRUE);

  /* init usart1 function. */
  wk_usart1_init();

  /* init gpio function. */
  wk_gpio_config();

  /* add user code begin 2 */
    systick_init();
   
    dma_interrupt_enable(DMA1_CHANNEL2, DMA_FDT_INT, TRUE); /* 打开 dma 发送完成中断 */

    rx_len = RX_BUF_SIZE;                                   /* 设置接收的最大长度 */
    dma_flag_clear(DMA1_FDT1_FLAG);                         /* 清除 uart dma 传输完成标志 */
    usart_flag_clear(USART1, USART_IDLEF_FLAG);             /* 清除空闲中断标志 */
    dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE); /* 打开 uart dma 接收完成中断 */
    usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE);   /* 打开 uart 空闲中断 */
   
    start_tick = sys_tick_get();
  /* add user code end 2 */

  while(1)
  {
    /* add user code begin 3 */
    if (rx_flag) {
        rx_flag = 0;
        
        while (tx_flag == 0);                           /* 等待发送就绪 */
        
        if (rx_len) {
            memcpy(tx_buf, rx_buf, rx_len);             /* 拷贝接收数据 */
            /* 编程到 flash */
            if (!flash_erase(USER_DATA_START_ADDR, rx_len)) {
                uart_send((uint8_t *)"flash erase failed!\n", strlen("flash erase failed!\n"));
            } else if (!flash_erase_check(USER_DATA_START_ADDR, rx_len)) {
                uart_send((uint8_t *)"flash erase check failed!", strlen("flash erase check failed!"));
            } else if (!flash_program_byte(USER_DATA_START_ADDR, tx_buf, rx_len)) {
                uart_send((uint8_t *)"flash program failed!", strlen("flash program failed!"));
            } else if (!flash_program_byte_check(USER_DATA_START_ADDR, tx_buf, rx_len)) {
                uart_send((uint8_t *)"flash program check failed!", strlen("flash program check failed!"));
            } else {
                uart_send((uint8_t *)"flash program succeed!\n", strlen("flash program succeed!\n"));
                tx_flag = 0;
                while (tx_flag == 0);
                uart_send((uint8_t *)"program data is:\n", strlen("program data is:\n"));
                tx_flag = 0;
                while (tx_flag == 0);
                uart_send(tx_buf, rx_len);
                tx_flag = 0;
                while (tx_flag == 0);
                uart_send((uint8_t *)"\n", strlen("\n"));
            }
            
            tx_flag = 0;                                /* 设置发送繁忙标志 */
        }
//        else {
//            while (1);
//        }

        /* 重新启动 uart dma 接收 */
        dma_flag_clear(DMA1_FDT1_FLAG);                         /* 清除 uart dma 传输完成标志 */
        usart_flag_clear(USART1, USART_IDLEF_FLAG);             /* 清除空闲中断标志 */
        dma_interrupt_enable(DMA1_CHANNEL1, DMA_FDT_INT, TRUE); /* 打开 uart dma 接收完成中断 */
        usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE);   /* 打开 uart 空闲中断 */
        rx_len = RX_BUF_SIZE;                                   /* 设置接收的最大长度 */
        /* 重新配置 dma 接收参数 */
        wk_dma_channel_config(DMA1_CHANNEL1, (uint32_t)&USART1->dt, (uint32_t)rx_buf, RX_BUF_SIZE);
        dma_channel_enable(DMA1_CHANNEL1, TRUE);                /* 打开 dma 通道传输 */
    }
   
    if (sys_tick_get() - start_tick >= 500) {                   /* 每隔 500 ms 翻转一次 LED */
        start_tick = sys_tick_get();
        gpio_bits_toggle(LED2_GPIO_PORT, LED2_PIN);
        gpio_bits_toggle(LED3_GPIO_PORT, LED3_PIN);
        gpio_bits_toggle(LED4_GPIO_PORT, LED4_PIN);
    }
    /* add user code end 3 */
  }
}
3、测试
可以看到,uart 打印信息显示,flash 擦除、编程成功。使用 ArteryICPProgrammer 工具读出来的 flash 对应位置的数据和 program 的一致。

flash.rar

6.2 MB

使用特权

评论回复
沙发
单片小菜| | 2023-11-1 10:13 | 只看该作者
这个可以应用于BootLoader

使用特权

评论回复
板凳
lajfda003| | 2023-11-1 11:16 | 只看该作者
这个确实不错的,很棒的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

39

帖子

0

粉丝