[Из песочницы] Программирование SPI Flash с помощью Arduino и SD-карты

Предыстория


Во время очередной уборки был случайно выключен удлинитель, к которому были подключены работающие системный блок и монитор. Системный блок состоит из:
  • материнская плата — ASRock B75 Pro 3
  • процессор — Intel Core i5–3570
  • блок питания — Corsair CX750M

После включения системник начал издавать пять противных писков, что вроде как соответствует неисправности процессора. Процессор, судя по Яндекс.Маркету, на данный момент стоит от 11000 руб. Покупать довольно накладно, а недорогой, но слабенький не хочется. В общем, немного испугался…

Порылся в интернете, выяснил, что точная причина неисправности может быть совсем другая. Это вселило небольшую надежду. Но надо как-то найти эту самую причину.

В первую очередь подключил другой старенький БП — комп не запускается.

Для дальнейших проверок принес домой автомобильный комп. Состав:

  • материнская плата — ASRock B75M-ITX
  • процессор — Intel Pentium G640T

Как хорошо, что компоненты оказались взаимозаменяемыми.

Вытащил из автомобильного компа процессор, вставил его в домашний — комп не запускается. Но появилась надежда, что процессор все таки цел, а неисправна материнка, которая дешевле (хотя новые на чипсетах не H61 и H67 — дефицит).

Далее домашний процессор вставил в автомобильный комп — комп заработал. Следовательно, процессор живой, а проблема в материнке. Начал грешить на BIOS (Winbond 25Q64BVAIG).

Собственно, программирование


Хорошо, что микросхема BIOS не впаяна, а на обычной панельке DIP-8. Программатора у меня нет, заказывать в Китае и ждать месяц — не выход. Решил сделать программатор из ноутбука и Arduino Nano. Покопался в интернете… Везде в основном прошивка заливается через USB, я же решил прошивать с карты памяти. Набросал схему подключения.

image

На макетной плате собрал схему.

image

Для начала набросал скетч, который считывает содержимое SPI Flash и записывает его в файл на карту памяти.

ReadFlash_WriteSD.ino
/*
Подключение SPI-Flash:
	CS   - D9
	MOSI - D11
	MISO - D12
	CLK  - D13
Подключение SD-Card Shield:
	CS   - D10
	MOSI - D11
	MISO - D12
	CLK  - D13
*/

#include 
#include 

#define Flash_CS 9
#define SD_CS    10
#define FILENAME "BIOS.ROM"

File     myFile;
SPIFlash flash(Flash_CS);

void setup() {
	Serial.begin(115200);
	while (!Serial) {
		; // Ждем подключения последовательного порта
	}
	
	pinMode(SD_CS,    OUTPUT);
	pinMode(Flash_CS, OUTPUT);
	//pinMode(10,       OUTPUT); // Нужно, если к D10 не подключен ни один CS
	
	// Инициализация SD-карты
	Serial.println("Initializing SD card...");
	if (!SD.begin(SD_CS)) {
		Serial.println("Initialization SD card failed!");
		return;
	}
	Serial.println("Initialization done.");
	
	// Удаляем старый файл, если есть
	Serial.print(FILENAME);
	if (SD.exists(FILENAME)) {
		Serial.println(" exists, removing...");
		SD.remove(FILENAME);
	} else {
		Serial.println(" doesn't exist.");
	}
	
	// Создаем файл и открываем его для записи
	Serial.print("Creating ");
	Serial.print(FILENAME);
	Serial.println("...");
	myFile = SD.open(FILENAME, FILE_WRITE);
	
	// Если удалось создать и открыть файл - будем записывать в него
	if (myFile) {
		
		// Инициализация SPI Flash
		Serial.println("Initializing SPI Flash...");
		flash.begin();
		
		// Читаем/записываем блоками/страницами по 256 байт
		uint8_t data_buffer[256];
		
		// Количество страниц
		uint32_t maxPage = flash.getMaxPage();
		
		// Checksum (32 bit)
		uint32_t checkSum = 0;
		
		for (int page = 0; page < maxPage; page++) {
			// Выводим прогресс работы
			if ((page % 1000) == 0) {
				Serial.print(page + 1);
				Serial.print("/");
				Serial.println(maxPage);
			}
			// Читаем страницу SPI Flash
			flash.readByteArray(page, 0, &data_buffer[0], 256);
			// Записываем блок в файл на карте памяти
			myFile.write(data_buffer, 256);
			// Обновляем контрольную сумму
			for (int i = 0; i < 256; i++) {
				checkSum += data_buffer[i];
			}
		}
		// Закрываем файл на карте памяти
		myFile.close();
		
		// Выводим контрольную сумму
		Serial.print("Checksum (32 bit): 0x");
		Serial.println(String(checkSum, HEX));
		Serial.println("Done.");
	} else {
		// Если файл не создался, то выводим сообщение об ошибке
		Serial.println("Error creating ");
		Serial.println(FILENAME);
	}
}

void loop() {
	// Пустой цикл
}


Запустил скетч, получившийся файл сравнил с оригинальным BIOS — получилось около 140000 несовпадающих байт.

Далее написал скетч, который читает файл с карты памяти и записывает его на SPI Flash, попутно вычисляя контрольную сумму по методу Checksum-32, т.е. простым суммированием.

ReadSD_WriteFlash.ino
/*
Подключение SPI-Flash:
	CS   - D9
	MOSI - D11
	MISO - D12
	CLK  - D13
Подключение SD-Card Shield:
	CS   - D10
	MOSI - D11
	MISO - D12
	CLK  - D13
*/

#include 
#include 

#define Flash_CS 9
#define SD_CS    10
#define FILENAME "B75PRO31.90"

File     myFile;
SPIFlash flash(Flash_CS);

void setup() {
	Serial.begin(115200);
	while (!Serial) {
		; // Ждем подключения последовательного порта
	}
	
	pinMode(SD_CS,    OUTPUT);
	pinMode(Flash_CS, OUTPUT);
	//pinMode(10,       OUTPUT); // Нужно, если к D10 не подключен ни один CS
	
	// Инициализация SD-карты
	Serial.println("Initializing SD card...");
	if (!SD.begin(SD_CS)) {
		Serial.println("Initialization SD card failed!");
		return;
	}
	Serial.println("Initialization done.");
	
	if (!SD.exists(FILENAME)) {
		Serial.print(FILENAME);
		Serial.println(" doesn't exist.");
		return;
	}
	
	// Открываем файл для чтения
	Serial.print("Opening ");
	Serial.print(FILENAME);
	Serial.println("...");
	myFile = SD.open(FILENAME, FILE_READ);
	
	// Если удалось открыть файл - будем читать из него
	if (myFile) {
	
		Serial.print("File ");
		Serial.print(FILENAME);
		Serial.println(" is open.");
		
		// Инициализация SPI Flash
		Serial.println("Initializing SPI Flash...");
		flash.begin();
		
		// Стираем чип
		if (flash.eraseChip()) {
			Serial.println("Chip erased.");
		} else {
			Serial.println("Error erasing chip.");
			return;
		}
	  
		// Читаем/записываем блоками/страницами по 256 байт
		uint8_t data_buffer[256];
		
		// Количество страниц
		uint32_t maxPage = flash.getMaxPage();
		
		// Checksum (32 bit)
		uint32_t checkSum = 0;
		
		for (int page = 0; page < maxPage; page++) {
			// Выводим прогресс работы
			if ((page % 1000) == 0) {
				Serial.print(page + 1);
				Serial.print("/");
				Serial.println(maxPage);
			}
			// Читаем блок с карты памяти
			myFile.read(data_buffer, 256);
			// Записываем блок в страницу SPI Flash
			flash.writeByteArray(page, 0, &data_buffer[0], 256);
			// Обновляем контрольную сумму
			for (int i = 0; i < 256; i++) {
				checkSum += data_buffer[i];
			}
		}
		// Закрываем файл на карте памяти
		myFile.close();
		
		// Выводим контрольную сумму
		Serial.print("Checksum (32 bit): 0x");
		Serial.println(String(checkSum, HEX));
		Serial.println("Done.");
	} else {
		// Если файл не открылся - выводим сообщение об ошибке
		Serial.print("Error opening ");
		Serial.println(FILENAME);
	}
}

void loop() {
	// Пустой цикл
}


Запустил, подождал, скетч вывел контрольную сумму, она совпала с контрольной суммой оригинального файла. Но это контрольная сумма файла на карте памяти, мне же нужна контрольная сумма содержимого SPI Flash.

Написал третий скетч, который считает контрольную сумму содержимого SPI Flash по тому же алгоритму.

ChecksumFlash.ino
/*
Подключение SPI-Flash:
	CS   - D9
	MOSI - D11
	MISO - D12
	CLK  - D13
*/

#include 

#define Flash_CS 9

SPIFlash flash(Flash_CS);

void setup() {
	Serial.begin(115200);
	while (!Serial) {
		; // Ждем подключения последовательного порта
	}
	
	pinMode(Flash_CS, OUTPUT);
	pinMode(10, OUTPUT); // Нужно, если к D10 не подключен ни один CS
	
	// Инициализация SPI Flash
	Serial.println("Initializing SPI Flash...");
	flash.begin();
	
	// Читаем страницами по 256 байт
	uint8_t data_buffer[256];
	
	// Количество страниц
	uint32_t maxPage = flash.getMaxPage();
	
	// Checksum (32 bit)
	uint32_t checkSum = 0;

	for (int page = 0; page < maxPage; page++) {
		// Выводим прогресс работы
		if ((page % 1000) == 0) {
			Serial.print(page + 1);
			Serial.print("/");
			Serial.println(maxPage);
		}
		// Читаем страницу SPI Flash
		flash.readByteArray(page, 0, &data_buffer[0], 256);
		// Обновляем контрольную сумму
		for (int i = 0; i < 256; i++) {
			checkSum += data_buffer[i];
		}
	}
	
	// Выводим контрольную сумму
	Serial.print("Checksum (32 bit): 0x");
	Serial.println(String(checkSum, HEX));
	Serial.println("Done.");
}

void loop() {
	// Пустой цикл
}


Контрольная сумма SPI Flash совпала с контрольной суммой оригинального файла. После вставки прошитой микросхемы BIOS в домашний комп — он благополучно заработал.

В среде Arduino IDE необходимо установить библиотеку SPIFlash через управление библиотеками. С обновленной библиотекой SD почему-то не инициализируется SD-карта, откатился на версию 1.0.9.

Контрольную сумму вычислял с помощью HEX-редактора HxD.

Комментарии (0)

© Habrahabr.ru