Pull to refresh

Программирование SPI Flash с помощью Arduino и SD-карты

Reading time 6 min
Views 51K

Предыстория


Во время очередной уборки был случайно выключен удлинитель, к которому были подключены работающие системный блок и монитор. Системный блок состоит из:

  • материнская плата — 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. Покопался в интернете… Везде в основном прошивка заливается через COM-порт, я же решил прошивать с карты памяти (так вроде гораздо быстрее).

Набросал схему подключения:



Собрал все на макетной плате:



Тип и объем карты памяти, способ ее форматирования, имя файла должны соответствовать требованиям библиотеки SD Arduino.

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

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 <SD.h>
#include <SPIFlash.h>

#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) {}	// Ждем подключения последовательного порта
	
	// Инициализация 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: 0x");
		Serial.println(checkSum, HEX);
		Serial.println("Done.");
	} else {
		// Если файл не создался, то выводим сообщение об ошибке
		Serial.println("Error creating ");
		Serial.println(FILENAME);
	}
}

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


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

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

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 <SD.h>
#include <SPIFlash.h>

#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) {}	// Ждем подключения последовательного порта
	
	// Инициализация 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: 0x");
		Serial.println(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 <SPIFlash.h>

#define Flash_CS 9

SPIFlash flash(Flash_CS);

void setup() {
	Serial.begin(115200);
	while (!Serial) {}	// Ждем подключения последовательного порта
	
	// Этот код нужен, чтобы не мешалась SD-карта
	pinMode(10, OUTPUT);
	digitalWrite(10, HIGH);
	
	// Инициализация 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: 0x");
	Serial.println(checkSum, HEX);
	Serial.println("Done.");
}

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


Контрольная сумма SPI Flash совпала с контрольной суммой оригинального файла.

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

В среде Arduino IDE необходимо установить библиотеку SPIFlash через управление библиотеками.

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

PS: Первоначально в качестве SD-модуля использовал вот такой:

Но с ним были частые глюки, не инициализировалась SD-карта. Помогало «горячее» переподключение самой SD-карты при подключенной к компу Arduino.

PPS: Вместо резисторов пробовал подключить двунаправленный конвертер сигналов:

Но с ним схема не заработала.
Tags:
Hubs:
+23
Comments 14
Comments Comments 14

Articles