Arduino作为编程器读写BIOS、bootloader、uboot或者breed

来源:互联网 发布:四知文言文阅读答案 编辑:程序博客网 时间:2024/06/06 20:02

极路由1S(HC5661A)刷breed刷错了,身边没有编程器写flash芯片(型号25Q128CS),因此就萌生了使用Arduino作为编程器的想法

参考了ZLBG这篇文章写得很不错

都是标准ISP协议,其他flash可以参考读写

电路图请参考ZLBG的博客文章,我贴一下Arduino接线

极路由flash位置

Arduino代码如下:

/*    communication with W25Q80BV (1 MBYTE SPI FLASH) using Arduino Pro Mini 3.3V/8MHz    Reference: http://www.instructables.com/id/How-to-Design-with-Discrete-SPI-Flash-Memory/?ALLSTEPS    Reference2: http://www.cnblogs.com/zlbg/p/4246721.html*/// the SPI bus uses pins 10 (SS), 11 (MOSI), 12 (MISO), and 13 (SCK)/*** 使用Arduino作为编程器将uboot写入flash(EEPROM)* 注意uboot不要超过芯片存储容量* 理论上支持所有EEPROM* * 测试机型:极路由1S(HC5661A),刷入breed*/#include <SPI.h>#define READ_JEDEC_ID 0x9F#define READ_STATUS_1 0x05#define READ_DATA 0x03#define WRITE_ENABLE 0x06#define PAGE_PROGRAM 0x02#define CHIP_ERASE 0xC7// uboot最后四个字节,用于判断写入已经结束// 我们可以使用winhex打开uboot文件查看最后四个字节static char END_CHARS[4] = {0x3B, 0x54, 0x05, 0x10};void setup(){    SPI.begin();    SPI.setDataMode(SPI_MODE0);    SPI.setBitOrder(MSBFIRST);    Serial.begin(115200);    ReadID();
    // 擦除flash    EraseChip();    Serial.println("inited");}// 检测是否写入完成,当最后四个字节和结束字节一样的时候写入结束bool isEnd(char check[4]) {    if (check[0] == END_CHARS[0] && check[1] == END_CHARS[1]         && check[2] == END_CHARS[2] && check[3] == END_CHARS[3]){        return true;    }    return false;}char buffer[64];        // 串口一次最多64字节char page[256];         // eeprom每页有256字节int currentPos = 0;     // 当前页当前位置int currentPage = 0;        // 当前页数bool writed = false;        // 写入完成标记bool start = false;     // 开始写入标记bool printed = false;       // 写入完成之后打印完成标记void loop() {    if(!writed && Serial.available() > 0) { // 如果写入未完成我们继续读取串口        if(!start) {            start = true;            Serial.println("start write");        }        int size = Serial.readBytes(buffer, 64);        if(size >= 0) {            if(size == 64) {                if(currentPos + size == 256) {      // 当读取恰好满一页时候我们写入flash一页                    for(int i=0; i<64; i++) {                        page[currentPos + i] = buffer[i];                    }                    WritePage(currentPage, page, 256);                    memset(page, 0, 256*sizeof(byte));                    currentPos = 0;                    currentPage++;            // 这个时候要判断是不是末尾,是的话我们完成写入操作                    char check[4] = {page[252], page[253], page[254], page[255]};                    if(isEnd(check)) {                        Serial.println("WRITE FINISH!!!");                        writed = true;                    }                } else {                    for(int i=0; i<64; i++) {                        page[currentPos + i] = buffer[i];                    }                    currentPos += 64;                }            } else {        // 如果读取不足一页证明已经到文件末尾了,这个时候数据要全部写入flash                for(int i=0; i<size; i++) {                    page[currentPos + i] = buffer[i];                }                WritePage(currentPage, page, currentPos + size);                memset(page, 0, 256*sizeof(byte));                currentPos = 0;                currentPage++;        // 完成写入操作                Serial.println("WRITE FINISH!!!");                writed = true;            }                    // 每次读完串口缓冲都要清零            memset(buffer, 0, 64*sizeof(byte));        }    }    // 写完而且未打印时候我们把flash里面数据按页读出来    // 我们可以复制黏贴串口调试助手里面的16进制数据到winhex    // 然后保存到一个文档和原uboot作对比看看写入是否正确    if(writed && !printed) {        for(int i=0; i<currentPage; i++) {            ReadPage(i, page, 256);            for(int i = 0; i < 256; i++)            {                Serial.print(char(page[i]));            }                        memset(page, 0, 256*sizeof(byte));                    delay(20);        }        printed = true;    }}void CheckBusy(){    digitalWrite(SS, HIGH);    digitalWrite(SS, LOW);    SPI.transfer(READ_STATUS_1);    while(SPI.transfer(0) & 0x01);     digitalWrite(SS, HIGH);}void ReadID(){    digitalWrite(SS, HIGH);    digitalWrite(SS, LOW);    SPI.transfer(READ_JEDEC_ID);    byte manuID = SPI.transfer(0);    byte memoType = SPI.transfer(0);    byte capa = SPI.transfer(0);    digitalWrite(SS, HIGH);    Serial.print("Manufacturer ID: "); Serial.println(manuID, HEX);    Serial.print("Memory Type: "); Serial.println(memoType, HEX);    Serial.print("Capacity : "); Serial.println(capa, HEX);    CheckBusy();}void ReadPage(word pageNumber, char pageBuffer[], int length) {    // pageNumber: 16-bit data    digitalWrite(SS, HIGH);    digitalWrite(SS, LOW);    SPI.transfer(READ_DATA);    SPI.transfer((pageNumber >> 8) & 0xFF);    SPI.transfer(pageNumber & 0xFF);    SPI.transfer(0);    for(int i = 0; i < length; i++)    {        pageBuffer[i] = SPI.transfer(0);    }    digitalWrite(SS, HIGH);    CheckBusy();}void WritePage(word pageNumber, char pageBuffer[], int length) {    digitalWrite(SS, HIGH);    digitalWrite(SS, LOW);      SPI.transfer(WRITE_ENABLE);    digitalWrite(SS, HIGH);    digitalWrite(SS, LOW);      SPI.transfer(PAGE_PROGRAM);    SPI.transfer((pageNumber >>  8) & 0xFF);    SPI.transfer(pageNumber & 0xFF);    SPI.transfer(0);    for(int i = 0; i < length; i++)    {        SPI.transfer(byte(pageBuffer[i]));    }    digitalWrite(SS, HIGH);    CheckBusy();}void EraseChip(){    digitalWrite(SS, HIGH);    digitalWrite(SS, LOW);      SPI.transfer(WRITE_ENABLE);    digitalWrite(SS, HIGH);    digitalWrite(SS, LOW);      SPI.transfer(CHIP_ERASE);    digitalWrite(SS, HIGH);    CheckBusy();}
接线完成之后打开串口调试助手sscom32,当串口显示begin时候选择breed文件发送到Arduino,Arduino会写到flash,写完之后会读取flash刚刚写入的数据到串口调试助手,这样子我们可以对比写入是否正确。

注意:写入之前建议备份flash,自己写read保存吧我就不写了

另外需要写入对应起始地址的话也需要自行修改


可惜最后还是没有救活,我焊工太差了电路板挂了快哭了

0 0