先安裝好 binutils-avr gcc-avr avr-libc:
sudo apt-get install binutils-avr gcc-avr avr-libc
使用 open source 的 grbl 當範例程式(官網 https://github.com/gnea/grbl/releases), 下載解壓縮後, 進入主目錄並編譯 :
wget https://github.com/grbl/grbl/archive/master.zip && unzip master.zip
cd grbl-master && make
安裝燒
程式:錄
sudo apt-get install avrdude
參考資料:https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266AVRISP
空的
avr uP 必須先透過 ICP (in-circuit programing) 的方式預先燒錄一段內建 ISP(n-System programing)的
bootloader, 之後才能透過 serial port 來更新軔體
(Firmaware), 另一種是花錢買 ICSP (in-circuit serial programming)燒錄
器, 而 AVR 的 uP 像是 ATmega328P 能透過 SPI 介面來燒
內部的 flash錄
.
我之前買過一個 ESP8266 的開發板, 本身也可以拿來當作 AVR ICSP
的燒
, 安裝完 ESP8266 的 arduino 後, 打開位在 ~/home/mint/.arduino15/packages/esp8266/hardware/esp8266/2.7.4/libraries/ESP8266AVRISP, 可以將他複製到專案裏,稍作修改, 編譯後再燒錄
器錄
到 ESP8266, 他就變成一個名副其實的
無線 AVRISP 燒
. 燒錄器
流程要使用 avrdude 命令, 把 Hex 檔案傳送給 ESP8266, 由 ESP8266 用自身的 SPI 介面燒寫到 ATmega328P錄 AVR uP
的 flash 上, 命令列執行格式:
avrdude -C avrdude.conf -c avrisp -p ATmega328P
-P net:avrisp -U flash:w:grbl.hex:i
上述 -C
avrdude.conf
是
avrisp 是 esp8266 執行 mdns 的 localhost:port(例如用 -P net:esp8266.local:328), 或是直接用 -P net:ip:port, 例如 -P net:192.168.1.12:328, 至於 grblavrdude 的事前設定檔(可以將參數放在檔案裏面), 而 -P net: 參數中的
.hex
正是前面
編譯 grbl 完, 要燒錄
的軔體
程式(hex 格式檔),至於 esp8266 與 ATmega328P
接線方式要參考
原始碼裡面的 README.rst 說明AVRISP
-----------------+-------------
|ESP8266 IO/JTAG |AVR
SPI|ICSP/
|================+============|
| GPIO14(D5/TMS)>| SCK |
|----------------+------------|
| GPIO12(D6/TDI)<| MISO |
|----------------+------------|
| GPIO13(D7/TCK)>| MOSI |
|----------------+------------|
| GPIO16(D0) >| RESET |
-----------------+-------------
AVR ICSP SPI(Slave)/ESP8266 SPI(Master):
MISO --|1 2|-- VCC
SCK --|3 4|-- MOSI
RESET --|5 6|-- GND
ESP8266 的 GPIO12(TDI), GPIO13(TCK), GPIO14(TMS), GPIO15(TDO) 是內建的 SPI/JTAG 硬體介面,
RESET 腳, 要注意的是 ESP8266 是 3.3V 的裝置, 介面之間的邏輯準位若電壓太高恐會把 IC 弄壞或是造成無法開機. 我改用 GPIO16(D0) 作為
另外因為在
ESP8266 來說是輸入接腳, 可以簡單用 1k 串聯 2k 下地電阻的分壓器(Voltage divider)作為 Level shifter 來連接, 而 MISO (GPIO12)對於
UNO(Arduino
板子上的 RESET 接腳有個 10k Ohm 提升電阻拉到 5V, ATmega328P
)
為免影響 ESP8266 開機,
在 ESP8266 端加個電晶體
可以(buffer)
隔開, 亦或是把它
簡單用 1.5k 下地電阻把把它拉到 0.7V 以下
.
以下執行命令
不使用 -C
avrdude.conf
, 而是直接下命令燒錄 grbl.hex, 假設 esp8266 在區域網路獲得的 ip 位址是 192.168.12.106, 而 service tcp port 是 328, 執行
avrdude
燒錄:
avrdude -c avrisp -p ATmega328P -P net:192.168.12.106:328 -U flash:w:grbl.hex:i
警告:使用 avrdude 直接燒錄若下的參數錯誤, 恐會造成無法再燒錄的悲劇,
因為可能會清掉
原來的 bootloader
, 若是內部的 fuse 燒入錯誤, 將造成無法透過 SPI 再更新軔體!
若真的想要燒入內部 fuse 可先參考
https://www.engbedded.com/fusecalc
燒錄程序畫面截錄:
avrdude: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.01s
avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: NOTE: "flash" memory has been specified, an erase cycle will be performed
To disable this feature, specify the -D option.
avrdude: erasing chip
avrdude: reading input file "grbl.hex"
avrdude: writing flash (29864 bytes):
Writing | ################################################## | 100% 8.66s
avrdude: 29864 bytes of flash written
avrdude: verifying flash memory against grbl.hex:
avrdude: load data flash data from input file grbl.hex:
avrdude: input file grbl.hex contains 29864 bytes
avrdude: reading on-chip flash data:
Reading | ################################################## | 100% 7.34s
avrdude: verifying ...
avrdude: 29864 bytes of flash verified
avrdude: safemode: Fuses OK (E:FD, H:DA, L:FF)
avrdude done. Thank you.
後記:
使用 arduino SDK 修改 AVRISP 程式啟用 TCP port 328 當 sevice port, 以及
GPIO16 作為
RESET 腳:
#include <ESP8266AVRISP.h>
ESP8266AVRISP avrISP(328, 16);
void setup(){
Serial.begin(115200);
// ...
avrISP.begin();
}
void loop() {
// ...
static AVRISPState_t last_state = AVRISP_STATE_IDLE;
AVRISPState_t new_state = avrISP.update();
if (last_state != new_state) {
switch (new_state) {
case AVRISP_STATE_IDLE: Serial.printf("[AVRISP] idle\n");
break;
case AVRISP_STATE_PENDING:Serial.printf("[AVRISP] pending\n");
break;
case AVRISP_STATE_ACTIVE:
Serial.printf("[AVRISP] programming\n");
break;
default: break;
}
last_state = new_state;
}
if (last_state != AVRISP_STATE_IDLE) avrISP.serve();
}
沒有留言:
張貼留言