当前位置:   article > 正文

【正点原子STM32连载】 第五十二章 串口IAP实验 摘自【正点原子】APM32E103最小系统板使用指南

【正点原子STM32连载】 第五十二章 串口IAP实验 摘自【正点原子】APM32E103最小系统板使用指南

1)实验平台:正点原子APM32E103最小系统板
2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420
3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban

第五十二章 串口IAP实验

本章将介绍在APM32E103上使用串口进行IAP,以实现简单的IAP功能。通过本章的学习,读者将学习到IAP的使用。
本章分为如下几个小节:
52.1 硬件设计
52.2 程序设计
52.3 下载验证

52.1 硬件设计
52.1.1 例程功能

  1. 程序运行后进入等待接收APP的bin数据的状态
  2. 接收到APP的bin数据后,先后按下KEY0按键和KEY_UP按键,可分别进行将APP的bin数据加载到Flash和跳转到APP的位置执行APP的操作
  3. LED0闪烁,指示程序正在运行
    52.1.2 硬件资源
  4. LED
    LED0 - PB5
  5. 按键
    KEY0 - PE4
    KEY_UP - PA0
  6. USART1(PA9、PA10连接至板载USB转串口芯片上)
  7. 正点原子 2.8/3.5/4.3/7/10寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
    52.1.3 原理图
    本章实验使用的IAP为软件算法,因此没有对应的连接原理图。
    52.2 程序设计
    52.2.1 IAP的实现
    本章实验提供了用于IAP的驱动代码,如下图所示:
    在这里插入图片描述

图52.2.1.1 IAP驱动代码
IAP的实现最主要分为两个步骤,分别为加载APP固件至Flash和跳转到APP中运行,为此本实验实现了以上两个函数,如下所示:
void iap_write_appbin(uint32_t appxaddr,uint8_t *appbuf,uint32_t applen);
void iap_load_app(uint32_t appxaddr);
以上两个函数就分别实现了加载APP固件至Flash和跳转到APP运行的功能,这两个函数的使用示例,如下所示:

#include " apm32e10x.h"
#include "./IAP/iap.h"

#define FLASH_APP_ADDR (0x08010000)
#define APP_MAX_SIZE (120*1024)

static uint8_t appbin[APP_MAX_SIZE];

void example_fun(void)
{
    uint32_t appsize;
    
    /* 通过串口等方式获取APP的二进制数据 */
    appsize = get_app_bin(appbin);
    
    /* 将APP的二进制数据写入Flash的指定地址中 */
    iap_write_appbin(FLASH_APP_ADDR, appbin, appsize);
    
    /* 跳转到APP在Flash中的起始地址运行 */
    iap_load_app(FLASH_APP_ADDR);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

52.2.2 APP工程修改
APP程序要能够在指定的Flash起始地址运行,需要编译器在编译APP的时候知道APP将被保存在Flash的那个位置,对于MDK软件,可以在Options for Target窗口中设置,如下图所示:
在这里插入图片描述

图52.2.2.1 配置MDK中的Flash空间
上图中将APP程序保存在Flash中的空间配置为0x8010000~(0x8010000+0xF0000),通过这样的配置便可以使APP被保存在指定Flash位置中执行。读者可以自行配置“Start”和“Size”参数,但要注意不能超过Flash的范围,并且也不要覆盖IAP程序(Bootloader)。
上一小节中将APP保存到Flash中的操作操作的是二进制数据,因此APP也应当被编译为二进制文件,然后MDK软件中并没有直接编译出二进制文件的选项,因此需要配置MDK在编译完成后执行指定的命令,如下图所示:
在这里插入图片描述

图52.2.2.2 配置MDK生成二进制文件
完成以上配置后,便可在APP程序编译完成后在工程的Output目录下得到正确的二进制文件。
52.2.3 实验应用代码
本章实验的应用代码,如下所示:

int main(void)
{
    uint32_t lastcount = 0;
    uint32_t applenth = 0;
    uint8_t clearflag = 0;
    uint8_t t = 0;
    uint8_t key;
    
    NVIC_ConfigPriorityGroup(NVIC_PRIORITY_GROUP_4);  /* 设置中断优先级分组为组4 */
    sys_apm32_clock_init(15);                         /* 配置系统时钟 */
    delay_init(120);                                  /* 初始化延时功能 */
    usart_init(115200);                               /* 初始化串口 */
    led_init();                                       /* 初始化LED */
    key_init();                                       /* 初始化按键 */
    lcd_init();                                       /* 初始化LCD */
    
    lcd_show_string(30,  50, 200, 16, 16, "APM32", RED);
    lcd_show_string(30,  70, 200, 16, 16, "IAP TEST", RED);
    lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "KEY0: Copy APP2FLASH!", RED);
    lcd_show_string(30, 130, 200, 16, 16, "KEY_UP: Run FLASH APP", RED);
    
    while (1)
    {
        if (g_usart_rx_cnt != 0)
        {

/* 新一次循环若没有接收到新的数据,则认为数据接收完毕 */
            if (lastcount == g_usart_rx_cnt)
            {
                applenth = g_usart_rx_cnt;
                lastcount = 0;
                g_usart_rx_cnt = 0;
                printf("用户程序接收完成!\r\n");
                printf("代码长度:%dBytes\r\n", applenth);
            }
            else
            {
                lastcount = g_usart_rx_cnt;
            }
        }
        
        t++;
        key = key_scan(0);
        switch (key)
        {
/* 将接收到的APP的bin数据写入Flash */
            case KEY0_PRES:
            {
                if (applenth != 0)
                {
                    printf("开始更新固件...\r\n");
                    lcd_show_string(30, 190, 200, 16, 16, 
                                    "Copying APP2FLASH...", BLUE);
                    if (((*(volatile uint32_t *)
(0X20001000 + 4)) & 0xFF000000) == 0x08000000)
                    {
                        iap_write_appbin(FLASH_APP1_ADDR, 
g_usart_rx_buf, 
applenth);
                        lcd_show_string(30, 190, 200, 16, 16, 
"Copy APP Successed!!", BLUE);
                        printf("固件更新完成!\r\n");
                    }
                    else
                    {
                        lcd_show_string(30, 190, 200, 16, 16, 
"Illegal FLASH APP!  ", BLUE);
                        printf("非FLASH应用程序!\r\n");
                    }
                }
                else
                {
                    printf("没有可以更新的固件!\r\n");
                    lcd_show_string(30, 190, 200, 16, 16, "No APP!", BLUE);
                }
                clearflag = 7;
                break;
            }
            case WKUP_PRES:                          /* 运行Flash中的APP */
            {
                printf("flash addr :%x \r\n",
		 	 	 	   (*(volatile uint32_t *)
					   (FLASH_APP1_ADDR + 4)) & 0xFF000000);
                if (((*(volatile uint32_t *)
(FLASH_APP1_ADDR + 4)) & 0xFF000000) == 0x08000000)
                {
                    printf("开始执行FLASH用户代码!!\r\n\r\n");
                    delay_ms(10);
                    iap_load_app(FLASH_APP1_ADDR);
                }

                else
                {
                    printf("没有可以运行的固件!\r\n");
                    lcd_show_string(30, 190, 200, 16, 16, "No APP!", BLUE);
                }
                clearflag = 7;
                break;
            }
            default:
            {
                break;
            }
        }
        
        if (t == 2)
        {
            LED0_TOGGLE();
            if (clearflag != 0)
            {
                clearflag--;
                if (clearflag == 0)
                {
                    lcd_fill(30, 190, 240, 210 + 26, WHITE);
                }
            }
            t = 0;
        }
        
        delay_ms(100);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123

从上面的代码中可以看出,程序是通过串口接收APP的二进制数据的,因此串口驱动中的串口接收缓存因该设置的足够大,以能够容纳APP的二进制数据,本实验中串口接收缓存的配置如下所示:
/* 定义最大接收120KB数据 */
#define USART_REC_LEN (120 * 1024)
在判断APP二进制数据接收完毕后,便可通过KEY0按键调用函数iap_write_appbin()将APP的二进制数据写入Flash中的FLASH_APP1_ADDR位置中,FLASH_APP1_ADDR是一个宏,该宏的定义如下所示:
#define FLASH_APP1_ADDR 0x08010000
需要注意的是,APP写入的位置应当与上一小节中配置MDK软件的指定Flash位置相同。
将APP的二进制数据写入到Flash中后,此时运行的依旧是IAP(Bootloader)程序,此时可以按下KEY_UP按键来跳转到Flash中APP的位置执行APP程序。
52.3 下载验证
在完成编译和烧录操作后,可以看到LCD上显示了本实验的相关实验信息,此时程序正在等待串口接收APP的二进制数据,此时便可通过串口调试助手将实现编译生成的APP二进制文件发送给MCU,待发送完毕后按下KEY0按键,将APP的二进制数据写入到Flash中,若写入成功,LCD上将会有相应的提示,此时便可按下KEY_UP按键将程序跳转到APP的保存位置中运行,若指定的Flash位置保存了正确的APP固件,那么便可看到MCU正在运行APP程序,而非IAP(Bootloader)程序。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/172519
推荐阅读
相关标签
  

闽ICP备14008679号