LGT8FX8D/P系列的CPU能夠指令級兼容avr芯片,引腳定義也相近.將avr的程序移植到LGT8FX8D/P只需做少許的修改,並且加強了一些性能,價格卻更低,性價比高.
要將程序寫入空片,其flash燒寫方式與avr並不同,須要專門的調試下載器.使用說明
在LarduinoISP for LGT8FX8D公開了份代碼,其中實現了經過SWD接口實現LGT8FX8D的讀寫.咱們經過閱讀這份代碼來看看經過SWD通訊方式來實現flash燒寫的過程.git
需使用的引腳:github
引腳 | 傳輸方向 | 描述 |
---|---|---|
SWD | 輸入與輸出 | 用做傳輸數據比特,雙向 |
SWC | 輸出 | 用做時鐘信號 |
RST | 輸出 | SWD模式時RST拉低 |
SWD
對應PB5,SWC
對應PB4,RST
對應PB2ide
#define SWDIF_PIN PINB #define SWDIF_DIR DDRB #define SWDIF_PORT PORTB #define SWDIF_CLK (1 << 5) // PB5 #define SWDIF_DAT (1 << 4) // PB4 #define SWDIF_RSTN (1 << 2) // PB2
全部時序的實現,由CPU操做IO口完成.性能
在一個通訊時鐘週期會調用二次SWD_Delay()
即$12*2$個NOP
指令,再加上設置SWC
SWD
電平的指令,總約需30個指令週期,在16MHz的系統時鐘下,通訊速率可達500Kbps.若是一個位輸出中有更多的邏輯操做,則通訊頻率會更低一些.ui
#define SWD_Delay() do {\ NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \ NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \ } while(0);
//一個時鐘週期的模擬 SWC_CLR(); SWD_Delay(); SWD_CLR(); SWD_Delay(); SWC_SET(); SWD_Delay();
數據通訊由起始位SWD_CLR
開始,而後是輸出一個字節是由一串8比特數據加一個結束位SWD_SET
組成,若有多個字節輸出,則中間結束位爲SWD_CLR
,最後的結束位爲SWD_SET
.每一個字節的先輸出最低位,再到最高位的順序輸出,即LSB First. 調試
雙向引腳SWD
輸出數據時,在時鐘SWC
低電平時改變SWD
輸出數據,寫入目標芯片會在SWC
的上升沿檢測SWD
數據.code
void SWD_WriteByte(uint8_t start, uint8_t data, uint8_t stop) { volatile uint8_t cnt; if(start) { SWC_CLR(); SWD_Delay(); SWD_CLR(); SWD_Delay(); SWC_SET(); SWD_Delay(); } // send data for(cnt = 0; cnt < 8; cnt++) { SWC_CLR(); if(data & 0x1) SWD_SET(); else SWD_CLR(); SWD_Delay(); data >>= 1; SWC_SET(); SWD_Delay(); } SWC_CLR(); if(stop) SWD_SET(); else SWD_CLR(); SWD_Delay(); SWC_SET(); SWD_Delay(); }
雙向引腳SWD
輸入數據時,在時鐘SWC
高電平時設爲輸入並上拉,由寫入目標芯片控制SWD
,在SWC
的降低沿檢測SWD
數據.接口
uint8_t SWD_ReadByte(uint8_t start, uint8_t stop) { volatile uint8_t cnt; volatile uint8_t bRes = 0; if(start) { SWC_CLR(); SWD_CLR(); SWD_Delay(); SWC_SET(); SWD_Delay(); } SWD_IND(); //SWD_Delay(); for(cnt = 0; cnt < 8; cnt++) { bRes >>= 1; SWC_CLR(); SWD_Delay(); if(SWDIF_PIN & SWDIF_DAT) bRes |= 0x80; SWC_SET(); SWD_Delay(); } SWD_OUD(); SWC_CLR(); if(stop) SWD_SET(); else SWD_CLR(); SWD_Delay(); SWC_SET(); SWD_Delay(); return bRes; }
一些操做須要經過一些時序才能完成,故有些需加上SWD_Idle
等待.get
void SWD_Idle(uint8_t cnt) { volatile uint8_t i; SWD_SET(); for(i = 0; i < cnt; i++) { SWC_CLR(); SWD_Delay(); SWC_SET(); SWD_Delay(); } }
SWD_ReadSWDID()
flash
Unlock
操做至關於對芯片進行全芯片擦除,以後所讀數據所有爲0xff,並容許寫入操做.uint8_t SWD_UnLock() { ... SWD_UnLock0(); SWD_EEE_UnlockTiming(); SWD_UnLock1(); delayus(100); SWD_UnLock0(); delayus(100); SWD_UnLock1(); ... }
Read()
,因flash爲16位,參數addr
爲word地址,每次讀取兩個字節,返回一個word數據uint16_t SWD_EEE_Read(uint16_t addr) { volatile uint8_t hbyte, lbyte; SWD_EEE_CSEQ(0x00, addr); SWD_EEE_CSEQ(0xa0, addr); SWD_WriteByte(1, 0xaa, 1); lbyte = SWD_ReadByte(1, 0); hbyte = SWD_ReadByte(0, 1); SWD_Idle(10); SWD_EEE_CSEQ(0x00, addr); return (hbyte << 8) | lbyte; }
write()
,因flash爲16位,參數addr
爲word地址,每次寫入兩個字節,即一個word數據void SWD_EEE_Write(uint16_t data, uint16_t addr) { volatile uint8_t ib; volatile uint8_t timout = 0x1f; SWD_EEE_CSEQ(0x00, addr); SWD_EEE_DSEQ(data); SWD_EEE_CSEQ(0x04, addr); SWD_EEE_CSEQ(0x84, addr); SWD_EEE_CSEQ(0x02, addr); do { delayus(50); ib = SWD_EEE_GetBusy(); --timout; } while(ib == 1 && timout > 0); SWD_EEE_CSEQ(0x00, addr); }
以上16位地址和數據輸入輸出均爲低字節優先,而後再高字節,即little-endian模式.