Arduino spi флеш

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Но с ним схема не заработала.

Источник

Чтение и запись флеш-памяти с помощью Arduino на примере микросхемы 25L8005

1 Микросхема флеш-памяти25L8005

Поэтому сначала нужно сделать так, чтобы мы могли с лёгкостью подключиться к микросхеме флеш-памяти. Для этого можно воспользоваться либо специальным переходником, к которому придётся припаять микросхему, либо (что предпочтительнее) использовать панель с нулевым усилением (т.н. панель ZIF , купить можно на Али).

Флеш-память припаяна к плате-переходнику

А вот так выглядит микросхема флеш-памяти в ZIF-панели:

Флеш-память в переходной панели с нулевым усилением

И под микроскопом:

Флеш-память в панели с нулевым усилением под микроскопом

Купить ПЗУшку можно, например, в Китае.

Теперь мы можем использовать макетную плату (бредборд) и с лёгкостью подключаться к микросхеме.

2 Подключение Arduino к микросхеме flash-памяти 25L8005

Назначение выводов микросхемы флеш-памяти 25L8005

Кстати, datasheet на микросхему флеш-памяти 25L8005 можно скачать в конце статьи.

Будем использовать для программирования флэш-памяти интерфейс SPI , поэтому подключимся к стандартным SPI выводам Arduino:

Вывод микросхемы флеш-памяти Вывод платы Arduino
CS# цифровой пин 10
SI цифровой пин 11
SO цифровой пин 12
SCLK цифровой пин 13
WP# 3V3
HOLD# 3V3
VCC 3V3
GND GND

Здесь символом решётки # отмечены выводы, которые активируются логическим нулём.

Соберём электрическую схему подключения микросхемы флеш-памяти MX25L8005 к Arduino.

Схема подключения микросхемы флеш-памяти 25L8005 к Arduino

Флеш-память на ZIF-панели, подключённая к Arduino Флеш-память на ZIF-панели, подключённая к Arduino

3 Очистка флеш-памяти с помощью Arduino

Перед тем как записывать данные в флеш-память, необходимо стереть тот сектор или страницу, в который мы собираемся записывать. Если записываемых данных немного (в нашем учебном примере это будут всего 16 байт), то достаточно стереть 1 сектор. Из документации на микросхему мы видим, что последовательность стирания такая: выставить разрешение на запись (1 байт), послать команду на стирание (1 байт) и адрес (3 байта), выставить запрет записи (1 байт). Данная последовательность приведена на рисунке ниже:

Диаграмма очистки одного сектора флеш-памяти 25L8005

Именно это и делает приведённый ниже скетч:

Загрузим этот скетч в Arduino с подключённой по приведённой выше схеме микросхемой памяти. После того как он отработал, флешка готова к записи.

4 Запись данных в флеш-память с помощью Arduino

Теперь запишем на неё данные. Для примера возьмём небольшой массив из 16-ти байтов. Как видно из документации, для записи данных во флеш сначала нужно выставить разрешение на запись (1 байт), затем послать команду на запись (1 байт), передать начальный адрес (3 байта) и данные (в нашем примере 16 байт), а в конце выставить запрет записи (1 байт):

Диаграмма записи данных во флеш-память 25L8005

Напишем скетч, который записывает массив из 16-ти байт данных в ПЗУ :

Загрузим скетч в Arduino. Кстати, вот так выглядит на логическом анализаторе обмен по SPI между Arduino и ПЗУ 25L8005, когда выполняется данный скетч.

Временная диаграмма записи в ПЗУ массива данных по SPI

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

4 Чтение данных из флеш-памяти с помощью Arduino

Согласно документации, чтение из флешки выполняется посредством такой последовательности: отправка команды на чтение (1 байт), начальный адрес (3 байта), а далее запрашивается столько байтов, сколько хотим прочитать из ПЗУ . Собственно, мы будем передавать в ПЗУ 16 нулей. Так как SPI – синхронный интерфейс, нам в ответ вернутся 16 записанных в ПЗУ байтов. Вот такая диаграмма приводится в описании к микросхеме:

Диаграмма чтения данных из флеш-памяти 25L8005

Напишем скетч для чтения наших заветных 16-ти байт из микросхемы флеш-памяти 25L8005:

Загрузим скетч в Arduino и откроем монитор последовательных портов. В мониторе, как и ожидалось, 1 раз в секунду будет выводиться наш массив, считанный из флеш-памяти с помощью Arduino.

Чтение из флеш-памяти с помощью Arduino и вывод в монитор последовательных портов

Временная диаграмма чтения данных из ПЗУ по SPI

Как видно, байты этого массива соответствуют кодам ASCII строки «HELLO, SOLTAU.RU», которые мы и записали в микросхему памяти 25L8005 :-)

Download attachments:

Поблагодарить автора:

Поделиться

Latest from aave

More in this category:

11 comments

Спасибо, все понятно написано, благодаря вашей статье быстро разобрался!

Гриша, я рад, что смог вам помочь!

Доброго времени суток!
Подскажите, инструкция подходит для работы с W25Q64 ?
Пока в наличии нет (жду посылку), ищу инструкцию для работы с указанной flash памятью.
Буду благодарен за помощь!

Никита, доброго времени!
Я не изучал подробно вашу ПЗУшку W25Q64, но с первого взгляда она очень похожа на описываемую здесь. По крайней мере, подключение аналогично (если берём в том же корпусе), а на 21-ой странице datasheet приведён набор инструкций SPI, в котором команды чтения, записи, разрешения записи и некоторые другие аналогичны. Надо, конечно, ознакомиться внимательнее, но в целом ничего сложного тут нет. Действуйте согласно документации разработчика. Соберите схему и начните изучать работу с микросхемой с чтения регистров. Хорошие кандидаты для начала — регистры Device ID (0x90), JEDEC ID (0x9F). Если «пощупаете» их, прочитаете значения, которые должны там быть согласно документации, то станет понятно, что вы на верном пути, и это придаст уверенности в дальнейшем изучении.

Большое спасибо за ответ!

Доброго времени суток! Прочитал и отработал ваши примеры в данной статье на микросхеме флэш памяти W25Q32FV. Спасибо за материал. Всё работает нормально. Начал экспериментировать с кодом.

В вашем примере адрес передается тремя байтами ADDR1, ADDR2, ADDR3. Разобрался по даташиту со структурой памяти W25Q32FV но всё равно возникли вопросы.

Как записать данные в другой адрес отличного от примера? То есть, как записать и как разбить, например адрес типа 8192 (0x2000h) начального байта сектора 2, на три байта и приписать их переменным ADDR1, ADDR2, ADDR3 . Пробовал по разному. У меня получилось только побитовой передачей в цикле for.

ПРИМЕР:
const byte ADDR[24] = <0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0>; //24-битный адрес 0x2000h в двоичном виде и в массиве
for(byte b=0; b = 24; b++) //предаём 24-битный адрес побитно, вставлял его вместо ADDR1. ADDR3

И ещё вопрос не по теме:
В ардуино к сожалению не работает оператор round с указанием количества знаков после запятой.
То есть, выражение:
float number = 1,674938;
float VOLT = round(number,2); //округление до двух знаков после запятой.
НЕ РАБОТАЕТ. Оператор «round» в ардуино умеет округлять только до целых чисел.

Работает следующий вариант:
float number = 1,674938;
int NUM = round(number * 100); //умножаем на 100 и округляем до целых чисел. Получаем 167.
float VOLT = float(NUM / 100); //167 делим на 100 и получаем 1.67

Это я проверял. Это правда или я что-то не так делаю?

Сергей, что касается записи ПЗУшек, то в двух словах, ADDR1. ADDR3 — это 24-разрядный адрес, который следует читать как одно большое число. Например, адрес 8192 будет записываться как 0x002000 — теми же 24-мя битами (3 байта). Судя по тому, что я вижу в даташите, в вашем случае адрес передаётся аналогично — 3-мя байтами. Адресное пространство ПЗУшки состоит из 64-х блоков по 64 кб, т.е. в каждом блоке адреса с 0x000000 по 0x00ffff.

А что касается округления чисел. В штатной библиотеке ардуино функция round() умеет округлять только до целого числа, так и есть. Ваш вариант с умножением и потом делением рабочий. Можно ещё вот так сделать:

double p = 3.14159265359;

void setup()
<
Serial.begin(9600);
Serial.println(p, 10); // выводим с точностью до 10 знаков
Serial.println(roundTo(p, 2), 10); // округляем до 2-х знаков и выводим 10 после запятой
Serial.println(roundTo(p, 3), 10); // округляем до 3-х и выводим 10
Serial.println(roundTo(p, 4), 10); // округляем до 4-х и выводим 10
>

double roundTo(double value, int decimal)
<
double pwr = pow(10, decimal);
return (round(value * pwr) / pwr);
>

Вывод данного скетча будет:
3.1415927410
3.1400003433
3.1420006752
3.1416006088
Если обратите внимание, даже вывод числа с такой большой точностью в первой строчке уже некорректен. Микроконтроллер не очень дружит с точной математикой.

Источник