在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁 > 嵌入式系統(tǒng) > 設計應用 > AVR BootLoader應用范例

            AVR BootLoader應用范例

            作者: 時間:2016-11-13 來源:網(wǎng)絡 收藏

            /***********************************************
            **** AVR BootLoader應用范例 ***
            **** ***
            **** 作者: HJJourAVR ***
            **** 編譯器:WINAVR20050214 ***
            **** ***
            ****www.OurAVR.com2005.10.17 ***
            ***********************************************/
            //程序參考 馬潮老師的M128 Boot_load應用的實例,ICCAVR版本
            //Stephen更改:9600bps, MEGA16, 8M INTERNAL RC,BOOTSZ1=0, BOOTSZ0=0, BOOTRST=1
            /*
            本程序簡單的示范了AVR ATMEGA16的IAP應用,實現(xiàn)智能升級
            Boot Loader
            XMODEM-CRC傳輸協(xié)議
            CRC16校驗

            出于簡化程序考慮,各種數(shù)據(jù)沒有對外輸出,學習時建議使用JTAG ICE硬件仿真器。
            熔絲位設置
            BOOTSZ1=0
            BOOTSZ0=0 Boot區(qū)為1K字(2K字節(jié))大小。
            BOOTRST=0 復位向量位于Boot區(qū)。//Stephen: 設BOOTRST=1,允許啟動

            makefile中的程序基地址偏移
            LDFLAGS += -Wl,--section-start=.text=0x3800 //0x3800字節(jié)=0x1C00字

            移植程序時,可根據(jù)實際大小設定Boot區(qū),但要注意更改makefile和更改BootAdd常數(shù),以及頁寫的大小分配;

            本文引用地址:http://www.biyoush.com/article/201611/316385.htm

            采用115200bps的通訊速率,升級14KB程序需要耗時約5秒[上位機是WINDOWS 2000的超級終端]

            疑問:
            1 用HEX文件燒錄工作正常,但elf仿真有問題。
            用AVRstudio仿真elf(熔絲設定BOOTRST=0,程序基地址偏移=0x3800)時,所有SRAM變量丟失初始化,
            表現(xiàn)為put_s()的都是亂碼或不可見字符。
            但如果改成應用程序(熔絲設定BOOTRST=1,沒有程序基地址偏移),則put_s()可以正常顯示

            2 XMODEM的結束應答(EOT/CAN)后需加 delay_ms(500)的延時(程序優(yōu)化,統(tǒng)一寫在跳轉到用戶程序前),
            否則在下面的情況將會無法正常結束XMODEM的傳輸,但其實程序已經(jīng)升級成功
            特殊情況:用戶程序里面使用了串口,而且波特率較低(如9600bps)且開機即發(fā)送大量數(shù)據(jù)

            */

            #include <avr/io.h>
            #include
            //時鐘定為外部晶體7.3728MHz,F_CPU=7372800 使用USART,115200bps
            #include
            /*
            boot_page_erase ( address )
            擦除FLASH 指定頁,其中address 是以字節(jié)為單位的FLASH 地址
            boot_page_fill ( address, data )
            填充BootLoader 緩沖頁,address 為以字節(jié)為單位的緩沖頁地址(對mega16 :0~128),
            而data 是長度為兩個字節(jié)的字數(shù)據(jù),因此調(diào)用前address 的增量應為2。
            此時data 的高字節(jié)寫入到高地址,低字節(jié)寫入到低地址。
            boot_page_write ( address )
            boot_page_write 執(zhí)行一次的SPM 指令,將緩沖頁數(shù)據(jù)寫入到FLASH 指定頁。
            boot_rww_enable ( )
            RWW 區(qū)讀使能

            根據(jù)自編程的同時是否允許讀FLASH 存儲器,F(xiàn)LASH 存儲器可分為兩種類型:
            可同時讀寫區(qū)( RWW Read-While-Write ) 和 非同時讀寫區(qū)( NRWW NotRead-While-Write)。
            對于MEGA16 RWW 為前14K 字節(jié) NRWW 為后2K 字節(jié)。
            引導加載程序?qū)WW 區(qū)編程時MCU 仍可以從NRWW 區(qū)讀取指令并執(zhí)行,而對NRWW 區(qū)編程時MCU 處于掛起暫停狀態(tài)。
            在對RWW 區(qū)自編程(頁寫入或頁擦除)時,由硬件鎖定RWW 區(qū) , RWW 區(qū)的讀操作被禁止
            在對RWW 區(qū)的編程結束后應當調(diào)用boot_rww_enable() 使RWW 區(qū)開放。
            */
            #include
            /*
            GCCAVR內(nèi)置函數(shù),可以不用頭痛CRC16了
            關于CRC的詳細說明,可以查看一下網(wǎng)站:
            http://www.nongnu.org/avr-libc/user-manual/group__avr__crc.html
            函數(shù)原形
            static __inline__ uint16_t _crc16_update(uint16_t __crc, uint8_t __data);
            多項式Polynomial: x^16 + x^15 + x^2 + 1 (0xa001)
            crc初始值Initial value: 0xffff
            通常用于磁盤控制器(disk-drive controllers)
            static __inline__ uint16_t _crc_xmodem_update(uint16_t __crc, uint8_t __data);
            多項式Polynomial: x^16 + x^12 + x^5 + 1 (0x1021)
            crc初始值Initial value: 0x0
            專用于XMODEM通訊協(xié)議,等效于C寫的
            uint16_t crc_xmodem_update (uint16_t crc, uint8_t data)
            {
            int i;
            crc = crc ^ ((uint16_t)data << 8);
            for (i=0; i<8; i++)
            {
            if (crc & 0x8000)
            crc = (crc << 1) ^ 0x1021;
            else
            crc <<= 1;
            }
            return crc;
            }
            static __inline__ uint16_t _crc_ccitt_update (uint16_t __crc, uint8_t __data)
            多項式Polynomial: x^16 + x^12 + x^5 + 1 (0x8408)
            crc初始值Initial value: 0xffff
            專用于PPP和IrDA通訊協(xié)議
            */

            //管腳定義
            #define PIN_RXD 0 //PD0
            #define PIN_TXD 1 //PD1

            //常數(shù)定義
            #define SPM_PAGESIZE 128 //M16的一個Flash頁為128字節(jié)(64字)
            #define DATA_BUFFER_SIZE SPM_PAGESIZE //定義接收緩沖區(qū)長度
            #define BAUDRATE 9600 //115200 //波特率采用115200bps
            //#define F_CPU 7372800 //系統(tǒng)時鐘7.3728MHz

            //定義Xmoden控制字符
            #define XMODEM_NUL 0x00
            #define XMODEM_SOH 0x01
            #define XMODEM_STX 0x02
            #define XMODEM_EOT 0x04
            #define XMODEM_ACK 0x06
            #define XMODEM_NAK 0x15
            #define XMODEM_CAN 0x18
            #define XMODEM_EOF 0x1A
            #define XMODEM_WAIT_CHAR C

            //定義全局變量
            struct str_XMODEM
            {
            unsigned char SOH; //起始字節(jié)
            unsigned char BlockNo; //數(shù)據(jù)塊編號
            unsigned char nBlockNo; //數(shù)據(jù)塊編號反碼
            unsigned char Xdata[128]; //數(shù)據(jù)128字節(jié)
            unsigned char CRC16hi; //CRC16校驗數(shù)據(jù)高位
            unsigned char CRC16lo; //CRC16校驗數(shù)據(jù)低位
            }
            strXMODEM; //XMODEM的接收數(shù)據(jù)結構

            unsigned long FlashAddress; //FLASH地址
            #define BootAdd 0x3800 //Boot區(qū)的首地址(應用區(qū)的最高地址)
            /* GCC里面地址使用32位長度,適應所有AVR的容量*/

            unsigned char BlockCount; //數(shù)據(jù)塊累計(僅8位,無須考慮溢出)

            unsigned char STATUS; //運行狀態(tài)
            #define ST_WAIT_START 0x00 //等待啟動
            #define ST_BLOCK_OK 0x01 //接收一個數(shù)據(jù)塊成功
            #define ST_BLOCK_FAIL 0x02 //接收一個數(shù)據(jù)塊失敗
            #define ST_OK 0x03 //完成


            //長延時 max 65536ms
            void delay_ms(unsigned int t)
            {
            while(t--)
            {
            _delay_ms(1);
            }
            }

            //更新一個Flash頁的完整處理
            void write_one_page(void)
            {
            unsigned char i;
            unsigned char *buf;
            unsigned int w;
            boot_page_erase(FlashAddress); //擦除一個Flash頁
            boot_spm_busy_wait(); //等待頁擦除完成
            buf=&strXMODEM.Xdata[0];
            for(i=0;i {
            w =*buf++;
            w+=(*buf++)<<8;
            //boot_page_fill(FlashAddress+i, w); //原句
            boot_page_fill(i, w); //只是低7位(128字節(jié)/頁)有效
            }
            boot_page_write(FlashAddress); //將緩沖頁數(shù)據(jù)寫入一個Flash頁
            boot_spm_busy_wait(); //等待頁編程完成
            }

            //發(fā)送采用查詢方式
            void put_c(unsigned char c) //發(fā)送采用查詢方式
            {
            loop_until_bit_is_set(UCSRA,UDRE);
            UDR=c;
            }

            //發(fā)送字符串
            void put_s(unsigned char *ptr)
            {
            while (*ptr)
            {
            put_c(*ptr++);
            }
            put_c(0x0D);
            put_c(0x0A); //結尾發(fā)送回車換行
            }


            //接收指定字節(jié)數(shù)據(jù)(帶超時控制,Timer0的1ms時基)
            // *ptr 數(shù)據(jù)緩沖區(qū)
            // len 數(shù)據(jù)長度
            // timeout 超時設定,最長65.536S
            // 返回值 已接收字節(jié)數(shù)目
            unsigned char get_data(unsigned char *ptr,unsigned char len,unsigned int timeout)
            {
            unsigned count=0;
            do
            {
            if (UCSRA & (1< {
            *ptr++=UDR; //如果接收到數(shù)據(jù),讀出
            count++;
            if (count>=len)
            {
            break; //夠了?退出
            }
            }
            if(TIFR & (1< {
            TIFR|=(1< timeout--; //倒計時
            }
            }
            while (timeout);
            return count;
            }

            //計算CRC16
            unsigned int calcrc(unsigned char *ptr, unsigned char count)
            {
            unsigned int crc = 0;
            while (count--)
            {
            crc =_crc_xmodem_update(crc,*ptr++);
            }
            return crc;
            }

            //主程序
            //int main() __attribute__((section(".stephen_bootloader"))); //stephen_bootloader
            int main()
            {
            unsigned char c;
            unsigned char i;
            unsigned int crc;
            //考慮到BootLoader可能由應用程序中跳轉過來,所以所用到的模塊需要全面初始化
            DDRA=0x00;
            DDRB=0x00;
            DDRC=0x00;
            PORTA=0xFF; //不用的管腳使能內(nèi)部上拉電阻。
            PORTB=0xFF;
            PORTC=0xFF;
            PORTD=0xFF;
            DDRD=(1< GICR = (1< GICR = (0<asm volatile("cli": : ); //關全局中斷
            //這個BootLoader沒有使用中斷。

            //初始化USART 115200 8, n,1 PC上位機軟件(超級終端)也要設成同樣的設置才能通訊
            UCSRC = (1< UBRRL = (F_CPU/BAUDRATE/16-1)%256; //設定波特率
            UBRRH = (F_CPU/BAUDRATE/16-1)/256;
            UCSRA = 0x00;
            UCSRB = (1< //初始化T/C0,CTC模式,256分頻,1ms自動重載
            OCR0 = 28;
            TCCR0 = (1< //CTC模式下,溢出標志是輸出比較匹配OCF0,對應的中斷是輸出比較匹配中斷;

            //向PC機發(fā)送開始提示信息
            put_s("************************************************************");
            //put_s(" ");
            put_s("IC ATMega16 Firmware 智能升級引導程序(Bootloader)VER20070107");
            put_s(" 使用Windows2000/xp 超級終端 串口發(fā)送 9600bps,8-N-1 ");
            put_s("如需更新用戶程序,請在3秒鐘內(nèi)按下[d]鍵,否則3秒后運行用戶程序 ");
            put_s(">");

            //3秒種等待PC下發(fā)“d”,否則退出Bootloader程序,從0x0000處執(zhí)行應用程序
            c=0;
            get_data(&c,1,3000); //限時3秒,接收一個數(shù)據(jù)
            if ((c==d)||(c==D))
            {
            STATUS=ST_WAIT_START; //并且數(shù)據(jù)=d或D,進入XMODEM
            put_s("請選擇BIN文件,使用XMODEM協(xié)議傳輸,最大14KB");
            }
            else
            {
            STATUS=ST_OK; //退出Bootloader程序
            }

            //進入XMODEM模式
            FlashAddress=0x0000;
            BlockCount=0x01;
            while(STATUS!=ST_OK) //循環(huán)接收,直到全部發(fā)完
            {
            if (STATUS==ST_WAIT_START)
            {//XMODEM未啟動
            put_c(XMODEM_WAIT_CHAR); //發(fā)送請求XMODEM_WAIT_CHAR
            }
            i=get_data(&strXMODEM.SOH,133,1000); //限時1秒,接收133字節(jié)數(shù)據(jù)
            if(i)
            {
            //分析數(shù)據(jù)包的第一個數(shù)據(jù) SOH/EOT/CAN
            switch(strXMODEM.SOH)
            {
            case XMODEM_SOH: //收到開始符SOH
            if (i>=133)
            {
            STATUS=ST_BLOCK_OK;
            }
            else
            {
            STATUS=ST_BLOCK_FAIL; //如果數(shù)據(jù)不足,要求重發(fā)當前數(shù)據(jù)塊
            put_c(XMODEM_NAK);
            }
            break;
            case XMODEM_EOT: //收到結束符EOT
            put_c(XMODEM_ACK); //通知PC機全部收到
            STATUS=ST_OK;
            put_s(" 用戶程序升級成功!");
            break;
            case XMODEM_CAN: //收到取消符CAN
            put_c(XMODEM_ACK); //回應PC機
            STATUS=ST_OK;
            put_s("警告:用戶取消升級,用戶程序可能不完整");
            break;
            default: //起始字節(jié)錯誤
            put_c(XMODEM_NAK); //要求重發(fā)當前數(shù)據(jù)塊
            STATUS=ST_BLOCK_FAIL;
            break;
            }
            }
            if (STATUS==ST_BLOCK_OK) //接收133字節(jié)OK,且起始字節(jié)正確
            {
            if (BlockCount != strXMODEM.BlockNo)//核對數(shù)據(jù)塊編號正確
            {
            put_c(XMODEM_NAK); //數(shù)據(jù)塊編號錯誤,要求重發(fā)當前數(shù)據(jù)塊
            continue;
            }
            if (BlockCount !=(unsigned char)(~strXMODEM.nBlockNo))
            {
            put_c(XMODEM_NAK); //數(shù)據(jù)塊編號反碼錯誤,要求重發(fā)當前數(shù)據(jù)塊
            continue;
            }
            crc=strXMODEM.CRC16hi<<8;
            crc+=strXMODEM.CRC16lo;
            //AVR的16位整數(shù)是低位在先,XMODEM的CRC16是高位在先
            if(calcrc(&strXMODEM.Xdata[0],128)!=crc)
            {
            put_c(XMODEM_NAK); //CRC錯誤,要求重發(fā)當前數(shù)據(jù)塊
            continue;
            }
            //正確接收128個字節(jié)數(shù)據(jù),剛好是M16的一頁
            if (FlashAddress<(BootAdd-SPM_PAGESIZE))
            { //如果地址在應用區(qū)內(nèi)
            write_one_page(); //將收到128字節(jié)寫入一頁Flash中
            FlashAddress+=SPM_PAGESIZE; //Flash頁加1
            }
            else
            {
            put_c(XMODEM_CAN); //程序已滿,取消傳送
            put_c(XMODEM_CAN);
            put_c(XMODEM_CAN);
            STATUS=ST_OK;
            put_s(" 程序已滿,取消傳送!");
            break;
            }
            put_c(XMODEM_ACK); //回應已正確收到一個數(shù)據(jù)塊
            BlockCount++; //數(shù)據(jù)塊累計加1
            }
            }

            //退出Bootloader程序,從0x0000處執(zhí)行應用程序
            put_s("退出Bootloader升級程序!");
            delay_ms(500); //很奇怪,見頂部的說明
            loop_until_bit_is_set(UCSRA,UDRE); //等待結束提示信息回送完成
            GICR = (1< GICR = (0< /* 無論BootLoader是否使用中斷,將中斷向量表遷移到應用程序區(qū)頭部,會增強程序的健壯性*/
            boot_rww_enable (); //RWW區(qū)讀允許,否則無法馬上執(zhí)行用戶的應用程序
            asm volatile("jmp 0x0000": : ); //跳轉到Flash的0x0000處,執(zhí)行用戶的應用程序
            }

            /*
            FLASH程序存儲器的編程方法常見的有以下幾種:

            (1)傳統(tǒng)的并行編程方法;
            (2)通過串行口進行在線編程ISP(In System Programmability) 對器件或電路甚至整個系統(tǒng)進行現(xiàn)場升級或功能重構;
            (3)在運行中,應用程序控制下的應用在線編程IAP (In Applocation Programing) 簡單地說就是在某一個section中運行程序,同時對另一個section進行擦除、讀取、寫入等操作。
            ISP方式相對于傳統(tǒng)方式有了極大的進步,它不需要將芯片從電路板上卸下就可對芯片進行編程,減少了開發(fā)時間,簡化了產(chǎn)品制造流程,并大大降低了現(xiàn)場升級的困難。
            而IAP方式是對芯片的編程處于應用程序控制之下,對芯片的編程融入在通信系統(tǒng)當中,通過各種接口(UART/SPI/IIC 等)來升級指定目標芯片的軟件。

            BootLoader 功能介紹
            BootLoader 提供我們通常所說的IAP(In Applicaion Program)功能。
            多數(shù)Mega系列單片機具有片內(nèi)引導程序自編程功能(BootLoader)。
            MCU 通過運行一個常駐FLASH 的BootLoader 程序,利用任何可用的數(shù)據(jù)接口讀取代碼后寫入自身FLASH存儲器中 ,實現(xiàn)自編程目的

            基本設計思想(參考了馬潮老師的文章)
            1. Boot Loader程序的設計要點
            Boot Loader程序的設計是實現(xiàn)IAP的關鍵,它必須能過通過一個通信接口,采用某種協(xié)議正確的接收數(shù)據(jù),再將完整的數(shù)據(jù)寫入到用戶程序區(qū)中。本例Boot Loader程序的設計要點有:
            1 采用ATmega16的USART口實現(xiàn)與PC之間的簡易RS232三線通信;
            2 采用Xmodem通信協(xié)議完成與PC機之間的數(shù)據(jù)交換;
            3 用戶程序更新完成后自動轉入用戶程序執(zhí)行;
            2. Xmodem通信協(xié)議
            Xmodem協(xié)議是一種使用撥號調(diào)制解調(diào)器的個人計算機通信中廣泛使用的異步文件運輸協(xié)議。
            這種協(xié)議以128字節(jié)塊的形式傳輸數(shù)據(jù),并且每個塊都使用一個校驗和過程來進行錯誤檢測。
            如果接收方關于一個塊的校驗和與它在發(fā)送方的校驗和相同時,接收方就向發(fā)送方發(fā)送一個認可字節(jié)。
            為了便于讀者閱讀程序,下面簡要說明該協(xié)議的主要特點,有關Xmoden的完整的協(xié)議請參考其它相關的資料。
            1 Xmodem的控制字符: 01H、 04H、 06H、 15H、 18H、 1AH、c 43H。
            2 XMODEM有兩種校驗模式:
            一種是一字節(jié)的checksum校驗模式,不常用。
            另一種是2字節(jié)的CRC16校驗模式(X^16 + X^12 + X^5 + 1),糾錯率高達99.9984%。
            兩種模式的選擇由接收端發(fā)送的啟動控制符來決定,啟動發(fā)送后不能切換。
            當發(fā)送端收到“NAK”控制字符時,它將會開始以checksum校驗方式發(fā)送數(shù)據(jù)塊。
            當發(fā)送端收到“C”控制字符時,它將會開始以CRC校驗方式發(fā)送數(shù)據(jù)塊。
            3 Xmodem-CRC傳輸數(shù)據(jù)塊格式:“ <255-BlockNO> <…128個字節(jié)的數(shù)據(jù)塊…> ”。
            其中為起始字節(jié);
            為數(shù)據(jù)塊編號字節(jié),每次加一;
            <255-BlockNO>是前一字節(jié)的反碼;
            接下來是長度為128字節(jié)的數(shù)據(jù)塊;
            最后的是128字節(jié)數(shù)據(jù)的CRC校驗碼,長度為2個字節(jié),crc16hi,crc16lo。
            5 接收端收到一個數(shù)據(jù)塊并校驗正確時,回送;接收錯誤回送;而回送表示要發(fā)送端停止發(fā)送。
            6 BlockNO的初值為0x01,每發(fā)送一個新的數(shù)據(jù)塊加1,加到OxFF后下一個數(shù)據(jù)塊的為零,即8位無符號數(shù)。
            7 發(fā)送端收到后,可繼續(xù)發(fā)送下一個數(shù)據(jù)塊(BlockNO+1);而收到則可再次重發(fā)上一個數(shù)據(jù)塊。
            8 發(fā)送端發(fā)送表示全部數(shù)據(jù)發(fā)送完成。如果最后需要發(fā)送的數(shù)據(jù)不足128個字節(jié),用填滿一個數(shù)據(jù)塊。

            */

            makefile中的程序基地址偏移
            LDFLAGS += -Wl,--section-start=.text=0x3800 //0x3800字節(jié)=0x1C00字

            即增加下圖中的27行

            然后在options 中勾擇Use External Makefile 選中剛才改的Makefile


            這是,編譯完成的hex文件大約15k?? 好像是5k

            升級的程序,不能是HEX文件,因為HEX文件是內(nèi)含格式且每行信息可以不等長的(下圖)。對于這個BOOTLOADER升級程序,只能接
            收原始的二進制文件信息并覆寫到相應的flash區(qū)內(nèi),因此只能使用BIN格式。將HEX轉為BIN有一個小軟件



            而BIN文件是連續(xù)且等長的



            關鍵詞: AVRBootloade

            評論


            技術專區(qū)

            關閉