• PIC24 通过USB在线升级 -- USB CDC bootloader


              了解bootloader的实现,请加QQ: 1273623966 (验证填bootloader);欢迎咨询或定制bootloader;我的博客主页www.cnblogs.com/geekygeek

              今年国庆完成了4个bootloader,前面介绍了2个,都是PIC32MZ的USB bootloader, 接着介绍2个PIC24 的USB bootloader, 首先是PIC24 USB CDC bootloader。PIC24 USB CDC bootloader 是我开发给我的PIC24FJ256GB106硬件板子的。

              开发环境

             1. IDE: MPLABX v4.01

             2. Compiler: XC16, v1.11

             3. Library&Example: c:/microchip_solutions_v2013-06-15/USB/Device-CDC-Basic Demo

             这个PIC24 CDC bootloader 是在MLA_v2013-06-15的USB CDC basic demo的基础上修改而成。bootloader 占用空间从0x400开始, 长度= 0x1C00。 CDC bootloader模拟UART通信,一行一行接收串口发送过来的hex原文,然后对每行的hex原文进行解析,将里面的bin数据烧写到对应的地址上。整个的逻辑实现都在我写的Boot_DoProcess()函数中,函数代码如下。

         

    uint8_t BOOT_DoProcess(uint8_t *buffer, uint16_t byteCount)
    {
        uint8_t i;
        
        uint8_t bcount, recType;
        DWORD_VAL pData;
        uint8_t retVal = 0;
        if (byteCount == 64)
        {
            return 1;
        }
        bcount = GetXbyte(buffer[LEN_NIBBLE1_INDEX],buffer[LEN_NIBBLE2_INDEX]);
    
        if (!Checksum(buffer, bcount))
        {
            retVal = 2;
            return retVal;
        }
        
        srcAddress.v[1] = GetXbyte(buffer[ADDRH_NIBBLE1_INDEX],buffer[ADDRH_NIBBLE2_INDEX]);
        srcAddress.v[0] = GetXbyte(buffer[ADDRL_NIBBLE1_INDEX],buffer[ADDRL_NIBBLE2_INDEX]);
        srcAddress.Val >>= 1;
        recType = GetXbyte(buffer[TYPE_NIBBLE1_INDEX],buffer[TYPE_NIBBLE2_INDEX]);
        switch(recType)
        {
        case LINEAR_ADDRESS:
            srcAddress.v[3] = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1],buffer[TYPE_NIBBLE2_INDEX+2]);
            srcAddress.v[2] = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+3],buffer[TYPE_NIBBLE2_INDEX+4]);
            retVal = 3;
            break;
        case DATA:
            if ((srcAddress.Val >= BOOT_START_ADDRESS) && (srcAddress.Val < APPL_RESET_ADDRESS))  // boot protection, avoid to overlap
            {
                retVal = 4;
                return retVal;
            }
            eraseAddress.Val = srcAddress.Val;
            if ((srcAddress.Val % ERASE_BLOCK) == 0)
            {
                NVM_EraseBlock(eraseAddress.Val);
            }
            for (i=0; i < 2*bcount;)
            {
                pData.byte.LB = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1+i+0],buffer[TYPE_NIBBLE2_INDEX+1+i+1]);
                pData.byte.HB = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1+i+2],buffer[TYPE_NIBBLE2_INDEX+1+i+3]);
                pData.byte.UB = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1+i+4],buffer[TYPE_NIBBLE2_INDEX+1+i+5]);
                pData.byte.MB = GetXbyte(buffer[TYPE_NIBBLE2_INDEX+1+i+6],buffer[TYPE_NIBBLE2_INDEX+1+i+7]);
                unsigned int error = NVM_WriteWord(srcAddress.Val, pData.Val);
                if ((error & 0x2000) > 0)
                {
                    retVal = 5;
                    return retVal;
                }
                error = 0;
                srcAddress.Val += 2;
                i += 8;
            }
            //retVal = 1;
            break;
        case END:
            retVal = 6;
            break;
        }
        return retVal;
    }
    

      在main.c中ProcessIO()函数中调用Boot_DoProcess(). ProcessIO改动很大,代码如下。

    void ProcessIO(void)
    {   
        BYTE numBytesRead;
        WORD status;
        //Blink the LEDs according to the USB device status
        BlinkUSBStatus();
        // User Application USB tasks
        if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;
    
        if(buttonPressed)
        {
            if(stringPrinted == FALSE)
            {
                if(mUSBUSARTIsTxTrfReady())
                {
                    putrsUSBUSART("Button Pressed -- 
    ");
                    stringPrinted = TRUE;
                }
            }
        }
        else
        {
            stringPrinted = FALSE;
        }
    
        if(USBUSARTIsTxTrfReady())
        {
            numBytesRead = getsUSBUSART(USB_Out_Buffer,64);
            if(numBytesRead != 0)
            {
                BYTE i;
                BYTE j;
                for(i=0;i<numBytesRead;i++)
                {
                    switch(USB_Out_Buffer[i])
                    {
                        case 0x0A:
                        case 0x0D:
                            USB_In_Buffer[i] = USB_Out_Buffer[i];
                            if (!BOOT_Handshake)
                            {
                                BOOT_Handshake = 1;
                            }
                            else
                            {
                                if ((BOOT_RecordSOF == 1) && (BOOT_RecordEOF == 0))
                                {
                                    BOOT_RecordBuffer[BOOT_RecordCounter++] = USB_Out_Buffer[i];
                                    BOOT_RecordEOF = 1;
                                    for (j=0; j<BOOT_RecordCounter; j++)
                                    {
                                        BOOT_OperationBuffer[j] = BOOT_RecordBuffer[j];
                                    }
                                    BOOT_OperationCounter = BOOT_RecordCounter;
                                    BOOT_RecordLineFlag = 1;
                                    BOOT_RecordSOF = 0;
                                    BOOT_RecordEOF = 0;
                                    BOOT_RecordCounter = 0;
                                }
                            }
                            break;
                        case ':':
                            USB_In_Buffer[i] = USB_Out_Buffer[i];
                            if (BOOT_Handshake)
                            {
                                if (!BOOT_RecordSOF)
                                {
                                    BOOT_RecordBuffer[BOOT_RecordCounter++] = USB_Out_Buffer[i];
                                    BOOT_RecordSOF = 1;
                                }
                            }
                            break;
                        default:
                            USB_In_Buffer[i] = USB_Out_Buffer[i];
                            if ((BOOT_Handshake == 1) && (BOOT_RecordSOF == 1))
                            {
                                BOOT_RecordBuffer[BOOT_RecordCounter++] = USB_Out_Buffer[i];
                                if (BOOT_RecordCounter == BOOT_RECORD_MAX)
                                {
                                    BOOT_RecordEOF = 1;
                                    for (j=0; j<BOOT_RecordCounter; j++)
                                    {
                                        BOOT_OperationBuffer[j] = BOOT_RecordBuffer[j];
                                    }
                                    BOOT_RecordLineFlag = 1;
                                    BOOT_OperationCounter = BOOT_RecordCounter;
                                    BOOT_RecordSOF = 0;
                                    BOOT_RecordEOF = 0;
                                    BOOT_RecordCounter = 0;
                                }
                            }
                            break;
                    }
                }
                putUSBUSART(USB_In_Buffer,numBytesRead);
                if (BOOT_RecordLineFlag)
                {
                    if (BOOT_OperationCounter == BOOT_RECORD_MAX)
                    {
                        putUSBUSART("XXXXXXXXXXXXXXXX
    ", 18);
                    }
                    else
                    {
                        status = BOOT_DoProcess(BOOT_OperationBuffer, BOOT_OperationCounter);
                        if (status == 6)
                        {
                            //TODO  Deinitialization
                            (*((void(*)(void))APPL_RESET_ADDRESS))();
                        }
                        else
                        {
                        //putUSBUSART("
    ", 1);
                        }
                    }
                    BOOT_RecordLineFlag = 0;
                }
            }
            if (!BOOT_Handshake)
            {
                BOOT_Timeout--;
                if (BOOT_Timeout == 0)
                {
                    // TODO  Jump to Application
                    // TODO  Deinitialization
                    (*((void(*)(void))APPL_RESET_ADDRESS))();
                }
                else if (BOOT_Timeout%20000 == 0)
                {
                    putUSBUSART(".", 1);
                }
            }
            else
            {
                if (!BOOT_ProgramRequired)
                {
                    BOOT_ProgramRequired = 1;
                    putUSBUSART("
    ",2);
                }
            }
        }
        CDCTxService();
    }        //end ProcessIO

           整个CDC bootloader就完成了。合着bootloader的Linker script编译完成后,通过PICKit3烧写到硬件板子中。CDC是模拟UART通信,所以通过USB线连接到电脑,电脑可以侦测到COM口。

           接着就是测试bootloader的功能了。写了个测试用的应用程序,应用程序地址是从0x2000开始到结束(地址分配参考AN1094)。应用程序合着客制的Linker script编译。测试时,我是通过超级终端发送应用程序的Hex原文。重启目标板,打开超级终端,选择CDC 模拟的COM口,配置成9600-8-none-1. 设置Line delay=40ms. 超级终端窗口出现”..."字符后,窗口中按下回车,菜单栏选择“发送文本文件”, 加载应用程序Hex, ,点击发送。然后就等着烧写完成。(上面贴的都是最终可以使用的完成函数代码,但是在实现过程中,修改几次,特别是测试过程中,发现不少问题,修改代码一一解决之后才最后完成)

            以下是烧写步骤:

    1. 打开超级终端

    2. 重启烧录好CDC bootloader的目标板

    3. 超级终端配置,选择CDC emulating后的出现的COM口,设置成9600-8-none-1, 设置Line Delay.

    4. 一旦超级终端窗口出现”..."字符,立即发送回车。

    5. 点击发送/发送文本文件..., 选择要发送的hex文件。

    6. 等待升级完成,CDC bootloader 每接收完一行都会原文返回。

  • 相关阅读:
    Ackerman 函数奇怪的函数
    HDU2871 Memory Control 线段树区间合并
    HDU3667 Hotel 线段树 经典空间合并
    图论
    HDU3016 Man Down 线段树
    HDU1878 欧拉回路 判定是否存在欧拉回路
    从今开始
    如何打开注册表编辑器
    ASP.NET中TextBox控件设置ReadOnly="true"后台取不到值
    学习笔记(2011年5月到9月)
  • 原文地址:https://www.cnblogs.com/geekygeek/p/pic24_cdc_bootloader.html
Copyright © 2020-2023  润新知