利用I2C總線實(shí)現(xiàn)ATmega88的在應(yīng)用編程
摘要:提出了一種利用I2C總線實(shí)現(xiàn)ATmega88微控制器在應(yīng)用編程的方法,詳述了Bootloader程序及與其相應(yīng)的上位機(jī)程序設(shè)計(jì),以及利用PC機(jī)串口握手信號模擬I2C總線的方法。實(shí)踐證明,該方法可成功實(shí)現(xiàn)I2C總線上多個ATmega88微控制器的在線調(diào)試與升級,也可用于其他AVR系列微控制器的在應(yīng)用編程。
關(guān)鍵詞:I2C總線;ATmega88微控制器;在應(yīng)用編程;PC串口
引言
隨著嵌入式系統(tǒng)技術(shù)的發(fā)展,電可擦除的Flash存儲器由于具有容量大、成本低、編程方便等優(yōu)點(diǎn),在微控制器領(lǐng)域得到了廣泛的應(yīng)用Flash微控制器在正常運(yùn)行前必須將Flash寫入用戶應(yīng)用程序,目前對微控制器的Flash程序存儲器進(jìn)行編程的方法主要有出廠固化、編程器編程、在系統(tǒng)編程(In System Programming,ISP)和在應(yīng)用編程(In Application programming,IAP)4種。
其中,出廠固化和編程器編程方法都要求微控制器在焊接前將程序?qū)懭?,這顯然不滿足開發(fā)階段的調(diào)試和日后升級的需要。目前比較普及的是在板可編程的ISP和IAP方法。ISP是通過微控制器的串行編程寫入應(yīng)用程序,需要少量的外部電路輔助實(shí)現(xiàn);IAP將Flash映射為用戶程序和Bootloader兩個存儲區(qū),Bootloader可通過系統(tǒng)已有的USB、串口、SPI、I2C總線等各種通信接口,對用戶程序進(jìn)行更新而不需要外部電路輔助,實(shí)現(xiàn)更加靈活,可方便地實(shí)現(xiàn)程序的在線及遠(yuǎn)程升級。
在利用ATmega88微控制器開發(fā)四旋翼飛行器的無感無刷直流電機(jī)驅(qū)動器時,由于定時器PWM輸出口與SPI接口存在引腳共用問題,用SPI口進(jìn)行ISP編程時會使MOS管誤導(dǎo)通而燒毀。由于驅(qū)動器中的4個ATmega88微控制器是通過I2C總線通信的,為了調(diào)試和升級方便,提出并實(shí)現(xiàn)了通過I2C總線對AVR微控制器進(jìn)行在應(yīng)用編程的方法,包括Bootloader程序、I2C總線的PC機(jī)串口模擬、上位機(jī)程序及相關(guān)的通信協(xié)議。實(shí)踐證明,該方法可成功實(shí)現(xiàn)I2C總線上多個ATmega88微控制器的在線升級。
1 ATmega88微控制器的Bootloader設(shè)計(jì)
ATmega88是一款基于AVR增強(qiáng)RISC體系結(jié)構(gòu)的CMOS低功耗8位微處理器,它通過執(zhí)行強(qiáng)大的單周期指令,達(dá)到接近1 MIPS/MHz的運(yùn)算效率。ATmega88的Flash被分為128個大小為64字節(jié)的頁面,F(xiàn)lash的編程操作都是以頁面為單位進(jìn)行的。為了用戶程序的安全性,以及用戶的ISP和IAP編程需要,ATmega88的Flash存儲空間被分為引導(dǎo)程序區(qū)(Bootloader Section)和應(yīng)用程序區(qū)(Application Program Section)兩部分。
引導(dǎo)程序區(qū)為非同時讀寫區(qū),應(yīng)用程序區(qū)為同時讀寫區(qū)。在非同時讀寫區(qū)內(nèi)執(zhí)行的代碼可以對同時讀寫區(qū)內(nèi)的頁面進(jìn)行編程操作,根據(jù)這一機(jī)制我們可以編制Bootloader程序并將其存儲于引導(dǎo)程序區(qū)內(nèi),以實(shí)現(xiàn)應(yīng)用程序區(qū)代碼的在線與遠(yuǎn)程升級。
由于ATmega88分配給引導(dǎo)程序區(qū)的空間大小有限(最大2 KB),Bootloader程序一定要簡潔而高效,圖1給出了以I2C總線為通信接口的Bootloader程序流程圖。
為了能夠執(zhí)行Bootloader程序,ATmega88熔絲位中的BOOTRST應(yīng)設(shè)為零,這樣在系統(tǒng)上電或應(yīng)用程序接收到升級命令利用看門狗復(fù)位后,系統(tǒng)就能從引導(dǎo)程序區(qū)運(yùn)行Bootloader程序。Bootloader程序中維持了一個溢出時間為2 s的定時器,該定時器利用TIM1以查詢的方式實(shí)現(xiàn)。沒有程序更新或程序更新完畢,程序在2 s內(nèi)沒有從I2C總線接收到數(shù)據(jù)幀時則利用(*((void(*)(void))(0x0000)))()函數(shù)跳轉(zhuǎn)到應(yīng)用程序區(qū)執(zhí)行應(yīng)用程序,在2s內(nèi)接收到數(shù)據(jù)幀后,則將定時器重置,以繼續(xù)接收數(shù)據(jù)幀更新應(yīng)用程序。
在Bootloader實(shí)現(xiàn)中,ATmega88的I2C總線工作在從模式,上位機(jī)的I2C總線工作在主模式。上位機(jī)發(fā)送的數(shù)據(jù)幀由2字節(jié)的Flash頁面地址、64字節(jié)的頁面數(shù)據(jù)、1字節(jié)的密碼和1字節(jié)的異或校驗(yàn)和構(gòu)成。Bootloader接收到數(shù)據(jù)幀后會用數(shù)據(jù)長度、密碼、異或校驗(yàn)和對數(shù)據(jù)幀進(jìn)行校驗(yàn),校驗(yàn)正確的話則根據(jù)數(shù)據(jù)幀中Flash的頁面地址和數(shù)據(jù)相應(yīng)的Flash頁面進(jìn)行編程,并將flag置1;校驗(yàn)錯誤的話,則丟棄數(shù)據(jù)幀等待重發(fā)的數(shù)據(jù)幀。
上位機(jī)在發(fā)送數(shù)據(jù)幀后讀取flag,并根據(jù)其狀態(tài)重發(fā)數(shù)據(jù)幀或發(fā)送下一頁面的數(shù)據(jù)幀。flag被讀取后Bootloader程序?qū)⑵淝辶?,這樣就形成了一個簡潔而有效的差錯控制機(jī)制。Flash中頁面的編程由頁擦除和頁編程兩個過程組成,頁擦除由AVR庫函數(shù)中的boot_page_erase(addr)函數(shù)實(shí)現(xiàn),addr為相應(yīng)頁面中的字節(jié)地址。
ATmega88的Flash是以頁為單位進(jìn)行擦除和寫入操作的,因此在進(jìn)行Flash頁面寫入前,要多次調(diào)用boot_page_fill(addr,data)函數(shù)將整頁的程序代碼寫入臨時緩沖區(qū),其中addr為指令所要寫入的字節(jié)地址,data為相應(yīng)的由2個字節(jié)構(gòu)成的16位程序指令。Flash頁面的寫入由boot_page_write(addr)函數(shù)實(shí)現(xiàn),addr為相應(yīng)頁面中的字節(jié)地址。
為了程序安全,F(xiàn)lash執(zhí)行頁擦除和編程操作時要求CPU處于等待狀態(tài),因此Flash的頁擦除和寫入函數(shù)執(zhí)行后都要調(diào)用boot_spm_busy_ wait()函數(shù)等待操作完成。此時,I2C總線也處于掛起狀態(tài),等所有操作完成后才能將總線釋放。上位機(jī)軟件在發(fā)送完數(shù)據(jù)幀后就一直監(jiān)聽總線狀態(tài),等總線釋放后再讀取flag狀態(tài),并決定是重發(fā)還是發(fā)送下一幀,這樣就實(shí)現(xiàn)了有效的通信流量控制。
整個Bootloader程序編譯完成后,大小為506字節(jié)。因此,熔絲位中的BOOTSZI和BOOTSZ0應(yīng)設(shè)為1和0,將引導(dǎo)程序區(qū)設(shè)置為地址0x1E00~0x1FFF、大小為512字節(jié)的區(qū)域。為了使Bootloader程序能正確寫入到該區(qū)域,程序編譯時要將程序起始地址設(shè)定在0x1E00,在WinAVR中可以通過在Makefile中添加“LDFLAGS+=-W1,——section—start=.text=0x1E00”實(shí)現(xiàn)。編譯完成的Bootloader可以在ATmega88確定PCB前,通過編程器或ISP寫入到Flash中。
2 PC端編程軟件設(shè)計(jì)
2.1 Intel Hex文件格式
ATmega88微控制器的目標(biāo)程序代碼是采用IntelHex文件格式保存的。Intel Hex文件包含了目標(biāo)代碼及相應(yīng)的地址信息,這些實(shí)現(xiàn)在應(yīng)用編程必需的信息由PC機(jī)端的上位機(jī)程序提取,并重新以頁面為單位裝幀后發(fā)送給Bootloader便可實(shí)現(xiàn)Flash的編程。
Intel Hex文件格式將二進(jìn)制的目標(biāo)機(jī)器代碼以ASCII碼的文本形式記錄,在文件中,每一行都是一個由十六進(jìn)制機(jī)器碼或數(shù)據(jù)常量組成的Hex記錄。記錄格式如表1所列。
每條Hex記錄都是以“:”開頭的,表1中所述的每個字節(jié)在記錄中是由兩個ASCII碼表示的,這樣的兩個十六進(jìn)制數(shù)為一個字節(jié);長度表示的是記錄中數(shù)據(jù)項(xiàng)的長度;地址為數(shù)據(jù)項(xiàng)在Flash中的起始地址;記錄的類型總共有6種,分別為數(shù)據(jù)記錄(00)、文件結(jié)束記錄(01)、擴(kuò)展段地址記錄(01)、開始段地址記錄(03)、擴(kuò)展線性地址記錄(04)、開始線性地址記錄(05)。數(shù)據(jù)是與記錄類型相對應(yīng)的可變長度的數(shù)據(jù)組。校驗(yàn)字節(jié)計(jì)算如下:首先,將每條記錄中除記錄頭和校驗(yàn)外所有ASCII碼以2個ASCII碼轉(zhuǎn)換為1個字節(jié)的形式轉(zhuǎn)換為二進(jìn)制。然后計(jì)算上述二進(jìn)制字節(jié)的累加和,最后將累加和的低字節(jié)取反加1即為校驗(yàn)字節(jié)。
ATmega88目標(biāo)代碼的Hex文件由數(shù)據(jù)記錄和文件結(jié)束記錄兩種類型的記錄構(gòu)成。上位機(jī)程序在解析過程中以行為單位讀取文件中的記錄,并根據(jù)上述記錄的格式進(jìn)行解析,獲得Flash每一頁面的地址和相應(yīng)的數(shù)據(jù),遇到文件結(jié)束記錄后則停止解析。
2.2 I2C總線的PC機(jī)串口模擬
PC機(jī)端的編程軟件是通過I2C總線與ATmega88的Bootloader通信的,I2C總線在微控制器中是廣泛存在的,一般的微控制器都集成了I2C總線控制模塊。但PC機(jī)基本沒有I2C總線接口,需要專用的USB轉(zhuǎn)I2C總線協(xié)議芯片或其他接口的I2C總線模塊才能實(shí)現(xiàn)PC機(jī)與微控制器之間的I2C總線通信。這種方法成本高且實(shí)現(xiàn)麻煩,本文給出了一種利用PC機(jī)串口的握手信號模擬I2C總線的方法,相比專用協(xié)議轉(zhuǎn)換芯片或模塊的方法,這種方法更加簡單、高效。為了實(shí)現(xiàn)PC機(jī)RS232串口與微控制器I2C總線的電平匹配,設(shè)計(jì)了如圖2所示的接口電路。
圖2中,PC機(jī)串口的RTS輸出用來模擬I2C總線的SCI,時鐘信號;DTR輸出模擬I2C總線的SDA輸出數(shù)據(jù)信號;CTS輸入用于接收SDA輸入數(shù)據(jù)。PC機(jī)串口的RS232的高電平為15 V,低電平為-15 V;I2C總線的高電平為+5 V,低電平為0 V。因此,將PC串口的握手信號轉(zhuǎn)換成I2C總線信號時需要進(jìn)行相應(yīng)的電平轉(zhuǎn)換,PC機(jī)串口RS232電平與I2C總線FTL電平之間的轉(zhuǎn)換是由電阻R1、R2和5.1V穩(wěn)壓管D1、D2實(shí)現(xiàn)的。
當(dāng)RTS輸出+15 V高電平時,由于電阻和穩(wěn)壓管的作用,SCL端電平被穩(wěn)定在+5.1 V;而當(dāng)RTS輸出-15 V低電平時,由于二極管D2導(dǎo)通,SCL電平被鉗位在-0.7 V。這樣,便實(shí)現(xiàn)了±15 V的RS232電平到0~5 V CMOS電平的轉(zhuǎn)換;電阻同時也起著限流作用。DTR輸出到SDA信號的電平轉(zhuǎn)換也是同樣的原理,而當(dāng)SDA處于輸入狀態(tài)時,由于CMOS電平可以滿足RS232電平的輸入容限,因此無需進(jìn)行電平轉(zhuǎn)換。
由于用PC機(jī)串口模擬I2C總線時僅僅用到了串口的握手信號,而沒有用到串口的波特率、數(shù)據(jù)長度、奇偶校驗(yàn)等設(shè)置功能及輸入/輸出緩沖區(qū)的管理功能,本文直接采用Windows提供的API函數(shù)實(shí)現(xiàn)串口編程。串口的打開和關(guān)閉分別采用CreateFile函數(shù)和CloseHandle函數(shù)實(shí)現(xiàn)。RTS和DTR信號高低電平的控制由EscapeCommFunction函數(shù)將串口作為文件操作實(shí)現(xiàn),調(diào)用該函數(shù)后程序要有一定時間的延時以實(shí)現(xiàn)通信波特率的控制。CTS的電平狀態(tài)則由GetCommModemStatus函數(shù)查詢得到。
在實(shí)現(xiàn)了RTS、DTR的電平控制與CTS電平狀態(tài)的獲取后,借鑒單片機(jī)用I/O口模擬I2C總線的方法,可以通過控制RTS、DTR電平與查詢CTS狀態(tài)來模擬I2C總線。在總線的時序處理與讀寫操作方面,兩種方法的唯一不同在于;用單片機(jī)I/O口模擬I2C總線時,I2C總線的SDA信號由輸出模式轉(zhuǎn)換到輸入模式是通過將單片機(jī)I/O口從輸出轉(zhuǎn)換為輸入實(shí)現(xiàn)的;由于串口握手信號無法實(shí)現(xiàn)雙向通信,因此,SDA信號的輸入功能是通過將DTR置高電平后讀取CTS狀態(tài)實(shí)現(xiàn)的,之所以將DTR置高電平是因?yàn)槲⒖刂破鞫说腎2C總線的集電極開漏輸出結(jié)構(gòu)需要DTR置高后才能輸出高電平,這類似于I2C總線上拉電阻的功能。
2.3 上位機(jī)程序設(shè)計(jì)
PC端上位機(jī)程序的主要功能為:解析應(yīng)用程序的Hex格式文件,并從中提取Flash中每一頁面的地址與數(shù)據(jù)信息;設(shè)置串口號與所需升級的ATmega88的I2C總線地址,利用串口的握手信號模擬I2C總線通信,將Hex文件中的程序代碼準(zhǔn)確無誤地發(fā)送給相應(yīng)地址的Bootloader以實(shí)現(xiàn)應(yīng)用程序的在線更新。
根據(jù)上述功能設(shè)計(jì)了如圖3所示的上位機(jī)程序界面,開發(fā)環(huán)境采用Borland C++builder 5.0,串口操作通過Windows API接口函數(shù)實(shí)現(xiàn)。
I2C總線通信的波特率設(shè)置為10 kbps,這是通過每次EscapeCommFunction函數(shù)調(diào)用后運(yùn)行相應(yīng)時間的延時函數(shù)實(shí)現(xiàn)的,這樣也可以使RTS和DTR信號在改變電平后有足夠的穩(wěn)定時間。點(diǎn)擊“燒錄程序”按鈕后,上位機(jī)程序通過I2C總線向相應(yīng)地址的ATmega88發(fā)送復(fù)位命令,然后循環(huán)發(fā)送Flash第一頁的數(shù)據(jù)幀;ATmega88接收到復(fù)位命令利用看門狗復(fù)位或人工上電復(fù)位后,跳轉(zhuǎn)運(yùn)行Bootloader程序,開始接收數(shù)據(jù)幀并對相應(yīng)的Flash頁面進(jìn)行編程。Bootloader接收到一幀數(shù)據(jù)后將I2C總線拉低,使總線處于忙狀態(tài),此時上位機(jī)一直查詢SDA狀態(tài)直到SDA恢復(fù)高電平后再操作I2C總線,這樣便實(shí)現(xiàn)了有效的通信流量控制。Bootloader對數(shù)據(jù)幀進(jìn)行校驗(yàn)后對flag進(jìn)行標(biāo)記,上位機(jī)發(fā)送完數(shù)據(jù)幀等I2C總線空閑后,讀取flag并根據(jù)其狀態(tài)重發(fā)數(shù)據(jù)幀或發(fā)送下一幀數(shù)據(jù),這樣便實(shí)現(xiàn)了通信的差錯控制,保證寫入程序代碼的正確性。所有Flash頁面編程完畢后,上位機(jī)程序關(guān)閉串口,Bootloader在2 s內(nèi)接收不到數(shù)據(jù)幀后,就能跳轉(zhuǎn)去運(yùn)行升級后的應(yīng)用程序。
結(jié)語
本文給出了一套完整的利用I2C總線實(shí)現(xiàn)ATmega88微控制器在應(yīng)用編程的方法,包括Bootloader程序、I2C總線的PC串口模擬、上位機(jī)程序及相關(guān)的通信協(xié)議。該方法應(yīng)用于四旋翼飛行器的無感無刷直流電機(jī)驅(qū)動板,成功通過I2C總線實(shí)現(xiàn)了4個ATmega88微控制器的在線調(diào)試與升級。該方法經(jīng)過少量針對具體微控制器的代碼修改后也可用于其他AVR系列微控制器的在應(yīng)用編程。