GD32F405VG 串口IAP调试记录(一)

        一直在忙别的事情,忘了更新。

        今天再更新一下进展,上次只对GD32F405VG的Flash进行了划分:

BOOT_ADDRESS:0x08000000 - 0x08003FFF     16k(扇区0)

APP_ADDRESS:0x08004000 - 0x0807FFFF        512k-16k=496k(扇区1-7)

Buffer_ADDRESS:0x08080000 - 0x080FEFFF     512k-4k=508k(扇区8-11)

Flags_ADDRESS:0x80FF000 -0x80FFFFF          4k(扇区11的最后4k)

       自己简单的绘制了一份流程图,上电初始1个串口,初始化成DMA的收发方式,用于打印信息和接收数据,初始化1个定时器,用于倒计时。上电先读Flags_ADDRESS的数据,Flags_ADDRESS的数据来源于APP中写入到Flash中的数据。

完成Bootloader,最关键的有3点:

1、串口的正常收发;

2、片上Flash的正确读写;

3、跳转函数;

Flash的读写主要是参考兆易创新官方提供的代码例程

/*************************************
 * 函 数 名:uint32_t fmc_sector_get(uint32_t address)
 * 描    述:根据地址确定扇区号
 * 输    入:address:flash地址
 * 输    出:无
 * 引脚使用:无
 ************************************/
uint32_t fmc_sector_get(uint32_t address)
{
    uint32_t sector = 0;
    if((address < ADDR_FMC_SECTOR_1) && (address >= ADDR_FMC_SECTOR_0)){
        sector = CTL_SECTOR_NUMBER_0;
    }else if((address < ADDR_FMC_SECTOR_2) && (address >= ADDR_FMC_SECTOR_1)){
        sector = CTL_SECTOR_NUMBER_1;
    }else if((address < ADDR_FMC_SECTOR_3) && (address >= ADDR_FMC_SECTOR_2)){
        sector = CTL_SECTOR_NUMBER_2;
    }else if((address < ADDR_FMC_SECTOR_4) && (address >= ADDR_FMC_SECTOR_3)){
        sector = CTL_SECTOR_NUMBER_3;  
    }else if((address < ADDR_FMC_SECTOR_5) && (address >= ADDR_FMC_SECTOR_4)){
        sector = CTL_SECTOR_NUMBER_4;
    }else if((address < ADDR_FMC_SECTOR_6) && (address >= ADDR_FMC_SECTOR_5)){
        sector = CTL_SECTOR_NUMBER_5;
    }else if((address < ADDR_FMC_SECTOR_7) && (address >= ADDR_FMC_SECTOR_6)){
        sector = CTL_SECTOR_NUMBER_6;
    }else if((address < ADDR_FMC_SECTOR_8) && (address >= ADDR_FMC_SECTOR_7)){
        sector = CTL_SECTOR_NUMBER_7;  
    }else if((address < ADDR_FMC_SECTOR_9) && (address >= ADDR_FMC_SECTOR_8)){
        sector = CTL_SECTOR_NUMBER_8;
    }else if((address < ADDR_FMC_SECTOR_10) && (address >= ADDR_FMC_SECTOR_9)){
        sector = CTL_SECTOR_NUMBER_9;
    }else if((address < ADDR_FMC_SECTOR_11) && (address >= ADDR_FMC_SECTOR_10)){
        sector = CTL_SECTOR_NUMBER_10;
    }else{
        sector = CTL_SECTOR_NUMBER_11;
    }
    return sector;
}

/*************************************
 * 函 数 名:void fmc_erase_sector(uint32_t fmc_sector)
 * 描    述:擦除指定扇区
 * 输    入:fmc_sector:flash扇区号
 * 输    出:无
 * 引脚使用:无
 ************************************/
void fmc_erase_sector(uint32_t fmc_sector)
{
    fmc_unlock();                                                                                     /* unlock the flash program erase controller */
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);/* clear pending flags */
    if(FMC_READY != fmc_sector_erase(fmc_sector))
        {
        while(1);                                                                                     /* wait the erase operation complete*/
    }
    fmc_lock();                                                                                            /* lock the flash program erase controller */
}

/*************************************
 * 函 数 名:void my_fmc_erase_sector(void)
 * 描    述:指定地址的扇区
 * 输    入:StartAddr:起始地址,EndAddr:终止地址
 * 输    出:无
 * 引脚使用:无
 ************************************/
void my_fmc_erase_sector(uint32_t StartAddr, uint32_t EndAddr)
{
        uint16_t StartSector, EndSector,i;
        fmc_unlock();
        fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
        StartSector = fmc_sector_get(StartAddr);                        /* 获取起始扇区号 */
        EndSector = fmc_sector_get(EndAddr);                                /* 获取终止扇区号 */
        for(i = StartSector; i <= EndSector; i += 8)                                                        
        {
                if(FMC_READY != fmc_sector_erase(i))
                {
                     while(1);
                }
        }
        fmc_lock();
}

/*************************************
 * 函 数 名:void fmc_write_32bit_data(uint32_t address, uint16_t length, int32_t* data_32)
 * 描    述:写入32位数据
 * 输    入:    uint32_t address      数据写入的flash地址
                            uint16_t length            数据个数
                            int32_t* data_32        数据存储地址
 * 输    出:无
 * 引脚使用:无
 ************************************/
void fmc_write_32bit_data(uint32_t address, uint16_t length, int32_t* data_32)
{
    uint16_t StartSector, EndSector,i;
    fmc_unlock();                                                                                                                                                                                            
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
    StartSector = fmc_sector_get(address);
    EndSector = fmc_sector_get(address + 4*length);                    /*  */
    for(i = StartSector; i <= EndSector; i += 8)
        {
        if(FMC_READY != fmc_sector_erase(i))
                {
            while(1);
        }
    }
    for(i=0; i<length; i++)
        {
        if(FMC_READY == fmc_word_program(address, data_32[i]))
                {
            address = address + 4;
        }
                else
                { 
            while(1);
        }
    }
    fmc_lock();
}

void my_fmc_write_32bit_data(uint32_t address, uint16_t length, int32_t* data_32)
{
//    uint16_t StartSector, EndSector,i;
    fmc_unlock();
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);

    for(uint16_t i=0; i<length; i++)
        {
        if(FMC_READY == fmc_word_program(address, data_32[i]))
                {
            address = address + 4;
        }
                else
                { 
            while(1);
        }
    }
    fmc_lock();
}

void    my_fmc_write_8bit_data(uint32_t address, uint16_t length, uint8_t* data_8)
{
        fmc_unlock();
    fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_OPERR | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR);
        for(uint16_t i = 0; i<length; i++)
        {
                if(FMC_READY == fmc_byte_program(address, data_8[i]))
                {
                        address += 1;
                }
                else
                {
                        while(1);
                }
        }
        fmc_lock();
}    

void fmc_read_32bit_data(uint32_t address, uint16_t length, int32_t* data_32)
{
    uint8_t i;
    for(i=0; i<length; i++)
        {
        data_32[i] = *(__IO int32_t*)address;
        address = address + 4;
    }
}

跳转函数主要参考博主”嵌入式小黑屋“,经过实测,跳转函数可以正常跳转。

void vJumpToApplication(void)
{
        uint32_t    JumpAddress = *(__IO uint32_t*)(APP_ADDRESS + 4);
        pFunction    Jump_To_Application;
        if(((*(__IO uint32_t*)APP_ADDRESS) & 0x2FFE0000) == 0x20000000)        /* APP_ADDRESS是新程序的起始地址,检查栈顶地址是否合法,即栈顶地址是否为0x2000xxxx(内置SRAM) */
        {
                usart_disable(USART0);                                                                                /* 关闭串口0 */
                timer_disable(TIMER4);                                                                                /* 关闭定时器4 */
                rcu_deinit();                                                                                                    /* 复位系统RCU时钟 */
                __set_MSP(*(__IO uint32_t*) APP_ADDRESS);                                            /* 初始化APP堆栈指针(用户代码区的第一个字用存放栈顶地址 */
                SCB->VTOR = APP_ADDRESS;                                                                            /* 重定向中断向量表 */

                JumpAddress = *(__IO uint32_t*) (APP_ADDRESS + 4);                        /* 用户代码区第二个字存储为新程序起始地址(新程序复位向量指针) */
                Jump_To_Application = (pFunction) JumpAddress;                                /* 设置PC指针为新程序复位中断函数的地址 */
                Jump_To_Application();                                            
        }
        else
        {
                Bootloader_dma_printf("!!!ERROR:APP_ADDRESS SP ERROR!!!\r\n");    /* 打印错误信息 */
        }        
}

  • 20
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: gd32f405是一款具有DMA功能的微控制器,可以通过串口与外部设备进行数据通信。串口通信是一种常用的数据传输方式,它通过数据线来传输数据,并且具有较好的适应性和广泛的应用场景。 gd32f405支持使用DMA(直接内存访问)来处理串口数据传输。DMA是一种硬件模块,可以在不需要CPU干预的情况下,直接从内存读取数据并将其传输到外部设备,或将外部设备的数据传输到内存。这样可以减轻CPU的负担,提高数据传输效率。 使用DMA进行串口数据传输有以下几个步骤: 1. 配置DMA通道:首先需要配置DMA通道用于串口数据传输的接口。在gd32f405中,可以使用多个DMA通道进行不同功能的数据传输。 2. 配置串口:需要配置串口相关参数,包括波特率、数据位数、校验位等。gd32f405的串口模块具有多个发送和接收缓冲区,可以通过调用相应的函数对串口进行配置。 3. 配置DMA传输方向和长度:根据具体需求,需要设置DMA的传输方向,即是从内存到外设还是从外设到内存。同时需要设置数据传输的长度。 4. 启动DMA传输:配置完成后,通过调用相应的函数启动DMA传输。DMA将自动从内存读取数据并进行串口传输,或从串口接收数据并写入内存,无需CPU干预。 通过使用DMA进行串口数据传输,可大大提高数据传输效率,减少CPU的负担。gd32f405的DMA功能使得串口通信更加可靠和高效。 ### 回答2: gd32f405是一款单片机芯片,而串口和DMA是其提供的两种功能。 串口是一种用于数据传输的接口,通过串行通信的方式可以实现将数据从一个设备传输到另一个设备。gd32f405内置了多个串口通道,可以通过配置相关寄存器和使用相应的引脚来实现与其他设备的串口通信。 而DMA(Direct Memory Access)是一种直接内存访问的技术,可以在不经过CPU的情况下,直接将数据从外设读取到内存或从内存写入到外设。在gd32f405中,通过配置DMA通道的相关寄存器,可以实现串口数据的DMA传输。 具体实现串口-DMA的步骤如下: 1. 配置串口:包括波特率、数据位、停止位、校验位等参数。 2. 配置DMA通道:包括传输方向、数据宽度、传输大小等参数。 3. 配置内存地址和外设地址:分别指定DMA传输的起始地址和目标地址。 4. 使能串口的DMA模式和DMA通道。 5. 当需要进行数据传输时,触发DMA传输请求。 6. 当DMA传输完成后,通过相应的中断或标志位进行处理。 通过串口-DMA的方式,可以实现高效的数据传输,减轻CPU负担。此外,gd32f405还支持多个DMA通道,可以同时进行多路数据传输,提高系统的数据处理效率。 总结来说,gd32f405芯片提供了串口和DMA功能,可以通过配置相关寄存器和引脚,实现串口数据的高效传输,并且支持多通道的DMA操作,提高系统的性能和效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值