一、FLASH读写接口的实现

//读1个字节
uint8_t FLASH_ReadByte(uint32_t Addr)
{
    return *(vu8 *)Addr;
}
//读2个字节
uint16_t FLASH_ReadHalfWord(uint32_t Addr)
{
    return *(vu16 *)Addr;
}
//读N个字节
void FLASH_ReadNByte(uint32_t Addr,uint8_t *pBuff,uint32_t Len)
{
    uint32_t i;

    for(i = 0;i < Len;i++)
    {
        pBuff[i] = FLASH_ReadByte(Addr);
        Addr += 1;
    }
}
#define STM32_SECTOR_SIZE   2048    //页大小
#define STM32_SECTOR_NUM    255     //页数

//STM32 FLASH的起始地址
#define STM32_FLASH_BASE 0x08000000

void FLASH_ReadPage(uint8_t Page_Num,uint8_t *pBuff)
{
    uint16_t i;
    uint32_t Buff;
    uint32_t Addr;

    //是否超出范围
    if(Page_Num > STM32_SECTOR_NUM)
        return;
    //先计算页首地址
    Addr = Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE;

    for(i = 0;i < STM32_SECTOR_SIZE;i += 4)
    {
        Buff = FLASH_ReadWord(Addr);

        pBuff[i]   = Buff;
        pBuff[i+1] = Buff >> 8;
        pBuff[i+2] = Buff >> 16;
        pBuff[i+3] = Buff >> 24;

        Addr += 4;
    }
}
void FLASH_WritePage(uint8_t Page_Num,uint8_t *pBuff)
{
    uint16_t i;
    uint16_t Buff;
    uint32_t Addr;

    //是否超出范围
    if(Page_Num > STM32_SECTOR_NUM)
        return;
    //解锁
    FLASH_Unlock();
    //先计算页首地址
    Addr = Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE;

    for(i = 0;i < STM32_SECTOR_SIZE ;i += 2)
    {
        Buff = ((uint16_t)pBuff[i+1] << 8) | pBuff[i];
        FLASH_ProgramHalfWord(Addr,Buff);
        Addr += 2;
    }
    //上锁
    FLASH_Lock();
}
void FLASH_WriteNData(uint32_t Addr,uint8_t *pBuff,uint32_t Len)
{
    uint32_t Offset;
    uint8_t  Page_Num;
    uint16_t Page_Offset;
    uint16_t Free_Space;
    uint16_t i;

    if((Addr < STM32_FLASH_BASE) || (Addr > STM32_FLASH_END))
        return;

    Offset = Addr - STM32_FLASH_BASE;//偏移地址
    Page_Num = Offset / STM32_SECTOR_SIZE;//得到地址所在页
    Page_Offset = Offset % STM32_SECTOR_SIZE;//在页内的偏移地址
    Free_Space = STM32_SECTOR_SIZE -  Page_Offset;//页区剩余空间
    //要写入的数据是否大于剩余空间
    if(Len <= Free_Space)
        Free_Space = Len;

    FLASH_Unlock();//解锁

    while(1)
    {
        FLASH_ReadPage(Page_Num,STM32_FLASH_BUFF);//先把数据读到缓存中
        FLASH_ErasePage(Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE);//页擦除
        //修改缓存数据
        for(i = 0;i < Free_Space;i++)
        {
            STM32_FLASH_BUFF[i+Page_Offset] = pBuff[i];
        }
        FLASH_WritePage(Page_Num,STM32_FLASH_BUFF);//把缓存数据写入
        //判断是否超出当前页,超出进入下一页
        if(Len == Free_Space)
            break;
        else
        {
            Page_Num++;//下一页
            Page_Offset = 0;
            pBuff += Free_Space;

            Len -= Free_Space;
            if(Len > STM32_SECTOR_SIZE)
                Free_Space = STM32_SECTOR_SIZE;
            else
                Free_Space = Len;
        }
    }
    FLASH_Lock();
}
void FLASH_WriteNByte(uint32_t Addr,uint8_t *pBuff,uint32_t Len)
{
    uint16_t i;
    uint16_t temp = 0;

    if((Addr < STM32_FLASH_BASE) || (Addr > STM32_FLASH_END))
        return;

    FLASH_Unlock();//解锁

    for(i = 0;i < Len;i += 2)
    {
        temp = pBuff[i];
        temp |= (uint16_t)pBuff[i+1] << 8;

        FLASH_ProgramHalfWord(Addr,temp);
        Addr += 2;
        if(Addr > STM32_FLASH_END)
        {
            FLASH_Lock();
            return;
        }
    }
    FLASH_Lock();
}
void Flash_EraseSector(uint8_t Start_Page,uint8_t End_Page)
{
    uint8_t i;
    uint8_t num = 0;

    if(Start_Page > End_Page)
        return;

    FLASH_Unlock();//解锁

    num = End_Page - Start_Page;//擦除页数

    for(i = 0;i <= num;i++)
    {
        FLASH_ErasePage((Start_Page + i) * STM32_SECTOR_SIZE + STM32_FLASH_BASE);//页擦除
    }

    FLASH_Lock();
}
void Test_Flash_WR(uint8_t Page_Num)
{
    uint16_t i = 0;
    uint8_t j = 0;

    //是否超出范围
    if(Page_Num > STM32_SECTOR_NUM)
        return;

    for(i = 0;i < STM32_SECTOR_SIZE;i++)
    {
        buff[i] = j++;
    }
    //页擦除
//  Flash_EraseSector(Page_Num,Page_Num);
    //写入
//  FLASH_WritePage(Page_Num,buff);
    //写入
//  FLASH_WriteNByte(Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE,buff,STM32_SECTOR_SIZE);
    //写入
    FLASH_WriteNData(Page_Num * STM32_SECTOR_SIZE + STM32_FLASH_BASE + 4,buff,10);
    //清零
    memset(buff,0,STM32_SECTOR_SIZE);
    //读出
    FLASH_ReadPage(Page_Num,buff);

    for(i = 0;i < STM32_SECTOR_SIZE;i++)
    {
        printf("%02X ",buff[i]);
    }
    printf("\r\n");
}

二、分区规划

Bootloader12K0 - 5引导程序
APP100K6 - 55存储App
Download100K56 - 105下载缓存
Flag2K255升级标志

三、Bootloader程序实现

#define FLASH_APP_ADDR                STM32_SECTOR6_ADDR
#define FLASH_DOWNLOAD_ADDR     STM32_SECTOR56_ADDR
#define FLASH_APP_FLAG                 STM32_SECTOR255_ADDR
#define FLASH_UPDATA_FLAG           FLASH_APP_FLAG + 2

int main(void)
{
    SystemInit();
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

    Delay_Init();

    LED_Init();
    KEY_Init();
    USART1_Init(115200);

    //判断是否需要升级固件
    if(FLASH_ReadHalfWord(FLASH_UPDATA_FLAG) == 0xAA55)
    {
        printf("Updata App...\r\n");

        IAP_Copy_App();//拷贝到app分区

        printf("Updata App Succeed...\r\n");
    }
    //判断是否有APP程序
    //中断向量表判断
    if(((*(vu32*)(FLASH_APP_ADDR + 4))&0xFF000000) == 0x08000000)
    {
        printf("Run App...\r\n\r\n");

        Delay_ms(10);
        IAP_Load_App(FLASH_APP_ADDR);//转到app
    }

    printf("No App\r\n");

    TIM3_Init(1000,72);//定时0.001s

    while(1)
    {
        Task_Process();

        if(USART1_RX_CNT > 0)
        {
            IAP_WriteBin(FLASH_DOWNLOAD_ADDR,USART1_RxBuff,USART1_RX_CNT);
            USART1_RX_CNT = 0;
        }
    }
}
typedef void (*IAP_Fun)(void);
IAP_Fun JumpApp;

uint8_t STM32_FLASH_BUFF[STM32_SECTOR_SIZE] = {0};

void IAP_Copy_App(void)
{
    uint8_t i;
    uint8_t buf[2] = {0x00,0x00};
    //擦除App扇区
    Flash_EraseSector(6,55);

    for(i = 0;i < 50;i++)
    {
        FLASH_ReadPage(56 + i,STM32_FLASH_BUFF);
        FLASH_WritePage(6 + i,STM32_FLASH_BUFF);
        LED3 = !LED3;
    }

    FLASH_WriteNData(FLASH_UPDATA_FLAG,buf,2);
}

void IAP_Load_App(uint32_t Addr)
{
    //检查栈顶地址是否合法
    if(((*(vu32*)Addr) & 0x2FFE0000) == 0x20000000)
    {
        __disable_irq();
        JumpApp = (IAP_Fun)*(vu32 *)(Addr + 4);
        MSR_MSP(*(vu32 *)Addr);
        JumpApp();
    }
}
void IAP_WriteBin(uint32_t Addr,uint8_t *pBuff,uint32_t Len)
{
    uint8_t buf[2] = {0xAA,0x55};
    //擦除App扇区
    Flash_EraseSector(6,55);
    //写入程序
    FLASH_WriteNByte(Addr,pBuff,Len);
    //更新标记
    FLASH_WriteNData(FLASH_UPDATA_FLAG,buf,2);
    //复位单片机
    NVIC_SystemReset();
}
02-11 02:18