打印
[研电赛技术支持]

Boot综合实验

[复制链接]
2157|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2021-11-3 16:54 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
知识点

设计并实现一个boot,需要用到如下知识点,


1. 体会boot的作用


2. 新增闪存控制器学习


3. 串口知识复习


4. FLASH&SPI知识复习


5. 状态机知识点复习


6. 初识上位机软件


7. xmodem通信协议学习


8. 交互界面设计



设计细节UI界面设计启动引导界面

**************************
  Press Ctrl+c into bootmenu.
. . . . . <-- 此处每秒打印一个点,打印完5个点后,进入APP,打印期间按下Ctrl+c进入boot主界面



主界面

按相应的数字,进入相应的功能界面


**************************

  welcome to boot

**************************

0. help

1. reboot

2. get app by uart

3. update

4. update and reboot

5. dump app in flash

6. dump app in rom




帮助界面

**************************
0. help
1. reboot
2. get app by uart
3. update
4. update and reboot
5. dump app in flash
6. dump app in rom


重启界面
**************************
booting...



获取APP文件界面

**************************
please wait a moment to get the app.
**************************
getting app,press q stop.

<---选择Transfer/Send Xmodem../选择文件/确定

Starting xmodem transfer.  Press Ctrl+C to cancel.
Transferring test.bin...
  100%       6 KB       6 KB/sec    00:00:01      50 Errors  

**************************
get app file sucess.
press 0 get help.



升级界面
**************************
updating...
**************************
update ok, press 0 get help.



升级并重启界面

**************************
updating...
**************************
update ok, press 0 get help.
**************************
booting...



从Flash中dump文件界面
**************************
app dumpping from flash...

<---选择本地文件,Transfer/Recive Xmodem../选择文件/确定

Starting xmodem transfer.  Press Ctrl+C to cancel.
Transferring D:\aaa.bin...
         62 KB        6 KB/sec    00:00:10   0 Errors  

**************************
app dumpping ok, press 0 get help.



从Rom中dump文件界面

**************************
app dumpping from rom...

<---选择本地文件,Transfer/Recive Xmodem../选择文件/确定

Starting xmodem transfer.  Press Ctrl+C to cancel.
Transferring D:\aaa.bin...
         62 KB        6 KB/sec    00:00:10   0 Errors  

**************************
app dumpping ok, press 0 get help.



使用特权

评论回复
沙发
tpgf|  楼主 | 2021-11-3 16:55 | 只看该作者
状态机设计

如下图,通过用户输入指令,分别进入不同功能,显示不同引导界面,并在该状态下完成相应子功能。


使用特权

评论回复
板凳
tpgf|  楼主 | 2021-11-3 16:57 | 只看该作者
各子功能设计引导进入APP功能设计(涉及CPU程序运行原理)

所谓引导至APP,其实就做两件事,一是重置MSP指针,二是重置PC指针。具体原因在OS章节有说明。


typedef  void (*pAppFunction)(void);

#define BOOT_APP_MAIN_ADDR 0x800E000

static VOID BOOT_GoToApp(VOID)

{

    pAppFunction Jump_To_Application;

    unsigned long jumpAddress;

   

    //跳转至用户代码

    jumpAddress = *(volatile U32*)(BOOT_APP_MAIN_ADDR + 4);

    Jump_To_Application = (pAppFunction)jumpAddress;

   

    //初始化用户程序的堆栈指针

    __set_MSP(*(volatile U32*) BOOT_APP_MAIN_ADDR);

    Jump_To_Application();

}


重启功能设计(涉及看门狗)
DRV_IWDG_Init(); /* 利用看门狗复位芯片 */



文件传输功能设计(涉及XMODEM协议)

文件传输采用Xmodem协议,该协议非常简单,如下,

报文格式:

  • 串口配置为异步,8位数据,no校验,no停止位
  • 报文格式说明

Byte1,Start Of Hearder, 如下,

SOH(01H) – Xmodem数据头

EOT(04H) – 发送结束

ACK(06H) – 认可响应

NAK(15H) – 不认可响应

CAN(18H) – 撤销传送

Byte2,Packet Number ,报文序列码,从1开始,每包递加,FF后循环

Byte3,~(Packet Number),报文序列码的补码

Byte4-131,Packet Data,报文数据,每个报文都是128个字节,如果不足128,则用1AH补充

Byte132-133,16bit CRC,Byte132-CRC高位,Byte133-CRC地位,只对128个数据做CRC16运行,多项式为X16+X12+X^5+1。

  • 交互流程

Tx方发生SOH数据报文

Rx方收到且数正确,回ACK,不正确会NAK

文件传输完毕,Tx发EOT通知Rx,Rx回ACK

任何时候,收到CAN,则强制停止

  • 代码如下,

#define XMODEM_SOH  0x01  /* Xmodem数据头 */

#define XMODEM_STX  0x02  /* 1K-Xmodem数据头 */

#define XMODEM_EOT  0x04  /* 发送结束 */

#define XMODEM_ACK  0x06  /* 认可响应 */

#define XMODEM_NAK  0x15  /* 不认可响应 */

#define XMODEM_CAN  0x18  /* 撤销传送 */

#define XMODEM_CTRLZ 0x1A /* 填充数据包 */


#define XMODEM_TIMEOUT 2000

#define XMODEM_MAXPKTLEN 133

#define XMODEM_PKTBUFLEN 128


static U16 XMODEM_Crc16(IN const U8 *buf, IN U8 len)

{

    U8 i = 0;

    U16 crc = 0;


    while (len--)

    {

        crc ^= *buf++ << 8;


        for (i = 0; i < 8; ++i)

        {

            if( crc & 0x8000 )

            {

                crc = (crc << 1) ^ 0x1021;

            }         

            else

            {

                crc = crc << 1;

            }

        }

    }

    return crc;

}


static S32 XMODEM_Check(IN BOOL isCrc, IN const U8 *buf, U8 sz)

{

    U16 crc = 0;

    U16 tcrc = 0;

    U8 i = 0;

    U8 cks = 0;


    if (TRUE == isCrc)

    {

        crc = XMODEM_Crc16(buf, sz);

        tcrc = (buf[sz]<<8)+buf[sz+1];

        if (crc != tcrc)

        {

            APP_ERROR("%u, %u", crc, tcrc);

            return OS_ERROR;

        }

    }

    else

    {

        for (i = 0; i < sz; ++i)

        {

            cks += buf;

        }

        if (cks != buf[sz])

        {

            APP_ERROR("%u, %u", cks, buf[sz]);

            return OS_ERROR;

        }

    }


        return OS_OK;

}


static S32 XMODEM_GetOnePkt(IN U8 pktNum)

{

    U8 ch = 0;

    S32 ret = OS_OK;

    U8 i = 0;

    U8 xbuff[XMODEM_MAXPKTLEN] = {0};


    for (i = 1; i < XMODEM_MAXPKTLEN; i++)

    {

        ret = DRV_UART1_GetChar(XMODEM_TIMEOUT, &ch);

        if (ret != OS_OK)

        {

            APP_ERROR("ret=%d", ret);

            return OS_ERROR;

        }

        xbuff[i-1] = ch;

    }


    if (xbuff[0] != (U8)(~xbuff[1]))

    {

        APP_ERROR("%u,%u", xbuff[0], xbuff[1]);

        return OS_ERROR;

    }


    ret = XMODEM_Check(TRUE, &xbuff[2], XMODEM_PKTBUFLEN);

    if (ret != OS_OK)

    {

        APP_ERROR("ret=%d", ret);

        return OS_ERROR;

    }


    if (pktNum != xbuff[0])

    {

        (VOID)APP_FILE_Write(APP_FILE_FD_APPINFLASH, &xbuff[2], XMODEM_PKTBUFLEN);

    }


    return OS_OK;

}


S32 APP_XMODEM_Recive(VOID)

{

    U8 ch = 0;

    S32 ret = OS_OK;

    U8 pktNum = 0;


    ret = DRV_UART1_GetChar(XMODEM_TIMEOUT, &ch);

    if (ret != OS_OK)

    {

        APP_ERROR("ret=%d", ret);

        return OS_CONTINUE;

    }


    switch (ch)

    {

        case XMODEM_SOH:

            ret = XMODEM_GetOnePkt(pktNum);

            if (ret != OS_OK)

            {

                DRV_UART1_PutChar(XMODEM_NAK);

                break;

            }

            pktNum++;

            DRV_UART1_PutChar(XMODEM_ACK);

            break;

        case XMODEM_EOT:

            DRV_UART1_PutChar(XMODEM_ACK);

            return OS_OK;

        case XMODEM_CAN:

            DRV_UART1_PutChar(XMODEM_ACK);

            return OS_ERROR;

        case 'q':

            return OS_ERROR;

    }


    return OS_CONTINUE;

}


static VOID XMODEM_FillPkt(IN U8 cmd , IN U8 index, IN U8 *buffer)

{

    U16 crc = 0;


    buffer[0] = cmd;

    buffer[1] = index;

    buffer[2] = (U8)(~index);

    crc = XMODEM_Crc16(&buffer[3], XMODEM_PKTBUFLEN);

    buffer[XMODEM_PKTBUFLEN+3] = (crc >> 8);

    buffer[XMODEM_PKTBUFLEN+4] = crc;


    return;

}


static S32 XMODEM_SendSohPkt(IN U8 fd)

{

    BOOL resend = FALSE;

    U8 index = 1;

    U8 ch = 0;

    S32 ret = OS_OK;

    U8 buffer[XMODEM_MAXPKTLEN] = {0};

    U8 retryCount = 0;


    for (;;)

    {

        if (FALSE == resend)

        {

            retryCount = 0;

            memset(buffer, 0, XMODEM_MAXPKTLEN);

            ret = APP_FILE_Read(fd, XMODEM_PKTBUFLEN, &buffer[3]);

            if (ret != OS_OK)

            {

                return OS_OK;

            }

            XMODEM_FillPkt(XMODEM_SOH, index, buffer);

        }


        DRV_UART1_SendBuf(buffer, XMODEM_MAXPKTLEN);


        ret = DRV_UART1_GetChar(XMODEM_TIMEOUT, &ch);

        if (ret != OS_OK)

        {

            resend = TRUE;

            retryCount++;

        }

        switch (ch)

        {

            case XMODEM_ACK:

                    index++;

                    resend = FALSE;

                break;

            case XMODEM_NAK:

                resend = TRUE;

                retryCount++;

                break;

            case XMODEM_CAN:

                return OS_ERROR;

        }


        if (retryCount > 16)

        {

            return OS_ERROR;

        }

    }

}


static VOID XMODEM_SendEotPkt(VOID)

{

    U8 retryCount = 0;

    S32 ret = OS_OK;

    U8 buffer[XMODEM_MAXPKTLEN] = {0};

    U8 ch = 0;


    XMODEM_FillPkt(XMODEM_EOT, 1, buffer);

    DRV_UART1_SendBuf(buffer, XMODEM_MAXPKTLEN);


    while (1)

    {

        retryCount++;

        ret = DRV_UART1_GetChar(XMODEM_TIMEOUT, &ch);

        if (ret != OS_OK)

        {

            DRV_UART1_SendBuf(buffer, XMODEM_MAXPKTLEN);

        }

        else

        {

            switch (ch)

            {

                case XMODEM_ACK:

                    return;

                case XMODEM_NAK:

                    DRV_UART1_SendBuf(buffer, XMODEM_MAXPKTLEN);

                    break;

                case XMODEM_CAN:

                    return;

            }

        }

        if (retryCount > 16)

        {

            return;

        }

    }

}


static VOID XMODEM_SendCanPkt(VOID)

{

    U8 buffer[XMODEM_MAXPKTLEN] = {0};


    XMODEM_FillPkt(XMODEM_CAN, 1, buffer);

    DRV_UART1_SendBuf(buffer, XMODEM_MAXPKTLEN);

}


S32 APP_XMODEM_Send(IN U8 fd)

{

    S32 ret = OS_OK;


    ret = XMODEM_SendSohPkt(fd);

    if (OS_OK == ret)

    {

        XMODEM_SendEotPkt();

        return OS_OK;

    }

    else if (OS_ERROR == ret)

    {

        XMODEM_SendCanPkt();

        return OS_ERROR;

    }


    return OS_OK;

}




使用特权

评论回复
地板
tpgf|  楼主 | 2021-11-3 16:58 | 只看该作者
本地文件读写功能设计(涉及FMC和FLASH操作)

本地文件分两种,

​ 一种是FLASH读写,在前面已经说过了,

​ 另一种是ROM读写,即FMC,本节会说明下

本质上这两种读写是一样的,因此做了一个抽象层用于同一访问接口

文件读写抽象层,提供open,write,read,seek文件操作接口


VOID APP_FILE_Open(IN U8 fd)

{

    if (APP_FILE_FD_APPINFLASH == fd)

    {

        DRV_GD25Q40_BulkErase();

        gFileInFlashAddrWrite = 0;

        gFileInFlashAddrRead = 0;

    }

    else if (APP_FILE_FD_APPINROM == fd)

    {

        DRV_FMC_Erase(APP_FILE_INROM_MAX, APP_FILE_INROM_START);

        gFileInRomAddrWrite = APP_FILE_INROM_START;

        gFileInRomAddrRead = APP_FILE_INROM_START;

    }

}



S32 APP_FILE_Write(IN U8 fd, IN U8 *buffer, IN U16 numByteToWrite)

{

    if (APP_FILE_FD_APPINFLASH == fd)

    {

        if (APP_FILE_INFLASH_MAX <= (gFileInFlashAddrWrite + numByteToWrite))

        {

            return OS_ERROR;

        }

        DRV_GD25Q40_BufferWrite(buffer, gFileInFlashAddrWrite, numByteToWrite);

        gFileInFlashAddrWrite += numByteToWrite;

    }

    else if (APP_FILE_FD_APPINROM == fd)

    {

        if ((APP_FILE_INROM_MAX+APP_FILE_INROM_START) <= (gFileInRomAddrWrite + numByteToWrite))

        {

            return OS_ERROR;

        }

        DRV_FMC_WriteBuffer(gFileInRomAddrWrite, buffer, numByteToWrite);

        gFileInRomAddrWrite += numByteToWrite;

    }

    return OS_OK;

}


S32 APP_FILE_Read(IN U8 fd, U16 numByteToRead, OUT U8 *buffer)

{

    if (APP_FILE_FD_APPINFLASH == fd)

    {

        if (APP_FILE_INFLASH_MAX <= (gFileInFlashAddrRead + numByteToRead))

        {

            return OS_ERROR;

        }

        DRV_GD25Q40_BufferRead(buffer, gFileInFlashAddrRead, numByteToRead);

        gFileInFlashAddrRead += numByteToRead;

    }

    else if (APP_FILE_FD_APPINROM == fd)

    {

        if ((APP_FILE_INROM_MAX+APP_FILE_INROM_START) <= (gFileInRomAddrRead + numByteToRead))

        {

            return OS_ERROR;

        }

        DRV_FMC_ReadBuffer(gFileInRomAddrRead, numByteToRead, buffer);

        gFileInRomAddrRead += numByteToRead;

    }

   

    return OS_OK;

}


VOID APP_FILE_Seek(IN U8 fd, IN U32 offset)

{

    if (APP_FILE_FD_APPINFLASH == fd)

    {

        gFileInFlashAddrRead = offset;

    }

    else if (APP_FILE_FD_APPINROM == fd)

    {

        gFileInRomAddrRead = offset;

    }

}


VOID APP_FILE_SeekStartOfFile(IN U8 fd)

{

    if (APP_FILE_FD_APPINFLASH == fd)

    {

        gFileInFlashAddrRead = 0;

    }

    else if (APP_FILE_FD_APPINROM == fd)

    {

        gFileInRomAddrRead = APP_FILE_INROM_START;

    }

}



ROM操作,即FMC操作

FMC,闪存控制器,其本质上是FLASH,应有和Flash一样的操作特性,只是因为在芯片内部集成,所以芯片提供了一套全新的操作寄存器,操作方法如下,


VOID DRV_FMC_Erase(IN U32 addrMax, IN U32 addrStart)

{

    volatile U32 NbrOfPage = 0x00;

    volatile U32 EraseCounter = 0x00;

   

    /* Unlock the Flash Bank1 Program Erase controller */

    FMC_Unlock();

   

    /* Define the number of page to be erased */

    NbrOfPage = (addrMax) / DRV_FMC_PAGE_SIZE;

   

    /* Clear All pending flags */

    FMC_ClearBitState(FMC_FLAG_EOP | FMC_FLAG_WERR | FMC_FLAG_PERR );

   

    /* Erase the FLASH pages */

    for(EraseCounter = 0; EraseCounter < NbrOfPage; EraseCounter++)

    {

        (VOID)FMC_ErasePage(addrStart + (DRV_FMC_PAGE_SIZE * EraseCounter));

        FMC_ClearBitState(FMC_FLAG_EOP | FMC_FLAG_WERR | FMC_FLAG_PERR );

    }


    FMC_Lock();


    return;

}


/* len长度不能超过buf空间长度 */

VOID DRV_FMC_ReadBuffer(IN U32 addr, IN U32 len, OUT U8 *buf)

{   

    U32 i = 0;

   

    for (i = 0; i < len; i++)

    {   

        buf = *(U8 *)(addr+i);

    }

   

    return;

}


/* buf空间必须是4的倍数,len长度不能超过buf空间长度 */

VOID DRV_FMC_WriteBuffer(IN U32 addr, IN U8 *buf, IN U32 len)

{

    U32 i = 0;

    U32 offset = 0;

    DrvFmc_u data;

   

    /* Unlock the Flash Bank1 Program Erase controller */

    FMC_Unlock();


    /* Clear All pending flags */

    FMC_ClearBitState(FMC_FLAG_EOP | FMC_FLAG_WERR | FMC_FLAG_PERR );   

    for (i = 0; i < len; i += 4)

    {

        memcpy(data.c_data, buf + offset, 4);

        (VOID)FMC_ProgramWord(addr + offset, data.i_data);

        FMC_ClearBitState(FMC_FLAG_EOP | FMC_FLAG_WERR | FMC_FLAG_PERR );   

        offset += 4;

    }

    FMC_Lock();

   

    return;

}




使用特权

评论回复
5
tpgf|  楼主 | 2021-11-3 16:58 | 只看该作者
升级功能设计(涉及FLASH和FMC操作)
升级是一个把APP文件从片外FLASH,写到片内ROM的一个过程,如下,


VOID APP_UPGRADE_Updating(VOID)
{
    U32 i = 0;
    U8 Buf[APP_UPGRADE_PAGE] = {0};


    APP_FILE_Open(APP_FILE_FD_APPINROM);
   
    for (i = 0; i < APP_UPGRADE_APP_MAX; i++)
    {
        APP_FILE_Read(APP_FILE_FD_APPINFLASH, APP_UPGRADE_PAGE, Buf);
        APP_FILE_Write(APP_FILE_FD_APPINROM, Buf, APP_UPGRADE_PAGE);
    }
}



使用特权

评论回复
6
xsyh| | 2021-11-5 14:27 | 只看该作者
大神,求源码。

使用特权

评论回复
7
cyclefly| | 2021-11-6 11:44 | 只看该作者
有PDF的文档么

使用特权

评论回复
8
chenqianqian| | 2021-11-7 17:18 | 只看该作者
有源码比?

使用特权

评论回复
9
huquanz711| | 2021-11-7 17:26 | 只看该作者
学习了,整理一下代码。

使用特权

评论回复
10
redone| | 2021-11-8 16:16 | 只看该作者
代码看花眼了~~~

使用特权

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

本版积分规则

1900

主题

15572

帖子

11

粉丝