В этой статье мы продолжим знакомство с микросхемой Flash памяти M25P40VP, установленной на беспроводном контроллере uniSensors nRF24, и разберём работу функций записи и чтения байтов из этого чипа.
Read & Write byte
Сценарий этого скетча очень простой: вначале мы полностью стираем содержимое Flash памяти чипа M25P40VP, далее записываем тестовое значение байта в одну из ячеек памяти микросхемы и затем производим считывание байта по этому же адресу для контроля правильности записи.
Код тестового скетча M25P40 Read & Write byte:
/* M25P40 Read & Write byte */ #include <SPI.h> #include <SPIFlash.h> #define FLASH_SS 8 #define TEST_ADR 0 #define TEST_VAL 4 SPIFlash flash(FLASH_SS); void setup() { Serial.begin(115200); Serial.println(F("M25P40 Read & Write byte start...")); Serial.print(F("Init ")); if (flash.initialize()) {Serial.println(F("OK"));} else {Serial.println(F("FAIL"));} erase(); readTest(); writeTest(); readTest(); } String hexy(byte b) { String s = F("0x"); if (b < 16) {s += '0';} String s2 = String(b, HEX); s2.toUpperCase(); return s + s2; } void checkBusy() { uint32_t stt = millis(); while (flash.busy()) { } uint32_t del = millis() - stt; if (del) { Serial.print(F(" (")); Serial.print(del); Serial.print(F(" ms)")); } Serial.println(); } void erase() { Serial.print(F("Full erase...")); flash.chipErase(); checkBusy(); } void readTest() { byte res = flash.readByte(TEST_ADR); Serial.print(F("Read adr #")); Serial.print(TEST_ADR); Serial.print(F(": ")); Serial.print(hexy(res)); checkBusy(); } void writeTest() { flash.writeByte(TEST_ADR, TEST_VAL); Serial.print(F("Write adr #")); Serial.print(TEST_ADR); Serial.print(F(": ")); Serial.print(hexy(TEST_VAL)); checkBusy(); } void loop() { }
Вначале объявляем значение адреса тестовой ячейки памяти. В нашем случае это нулевая ячейка M25P40VP. Вы можете выбрать любой номер ячейки из диапазона от 0 до 524227.
#define TEST_ADR 0
Затем объявляем тестовое значение байта, которое мы будем записывать во Flash память. В нашем случае это 4 (или 0x04 в шестнадцатеричном формате).
#define TEST_VAL 4
Далее следует участок кода, который определяет весь функционал скетча: мы стираем всё содержимое чипа M25P40VP, читаем содержимое нулевой ячейки памяти, записываем в неё тестовое число и снова читаем для того, чтобы убедиться в корректности записи и работы нашего скетча.
erase(); readTest(); writeTest(); readTest();
Функцию erase() мы рассматривали в предыдущей статье, здесь я только замечу, что мы производим замер задержки выполнения при помощи функции checkBusy() (тоже подробно описанной в предыдущей статье).
void erase() { Serial.print(F("Full erase...")); flash.chipErase(); checkBusy(); }
Чтение байта из тестовой (в данном случае нулевой) ячейки памяти осуществляется функцией readTest().
void readTest() { byte res = flash.readByte(TEST_ADR); Serial.print(F("Read adr #")); Serial.print(TEST_ADR); Serial.print(F(": ")); Serial.print(hexy(res)); checkBusy(); }
Само чтение осуществляет библиотечная функция readByte().
byte res = flash.readByte(TEST_ADR);
Далее полученное значение выводится в Serial. Функция hexy() форматирует числа в шестнадцатеричном формате.
String hexy(byte b) { String s = F("0x"); if (b < 16) {s += '0';} String s2 = String(b, HEX); s2.toUpperCase(); return s + s2; }
Запись тестового значения осуществляется функцией writeTest().
void writeTest() { flash.writeByte(TEST_ADR, TEST_VAL); Serial.print(F("Write adr #")); Serial.print(TEST_ADR); Serial.print(F(": ")); Serial.print(hexy(TEST_VAL)); checkBusy(); }
А точнее библиотечной функцией writeByte() по заданному адресу в памяти M25P40VP.
flash.writeByte(TEST_ADR, TEST_VAL);
Функция checkBusy() везде осуществляет контроль длительности проведения операции. Вот результат работы нашего тестового скетча:
Как вы видите, после полного стирания памяти чипа значение нулевой ячейки равно 0xFF и далее мы смогли успешно записать число 0x04 в эту ячейку (и прочитать его).
Read & Write array
Теперь давайте немного усложним задачу и попробуем прочитать и записать массив байтов в память микросхемы M25P40VP. Для работы с массивами байтов в библиотеке SPIFlash существуют функции readBytes() и writeBytes(), разберём подробнее их работу.
Код скетча M25P40 Read & Write array:
/* M25P40 Read & Write array */ #include <SPI.h> #include <SPIFlash.h> #define FLASH_SS 8 SPIFlash flash(FLASH_SS); #define TEST_ADR 0 void setup() { Serial.begin(115200); Serial.println(F("M25P40 Read & Write array start...")); Serial.print(F("Init ")); if (flash.initialize()) {Serial.println(F("OK"));} else {Serial.println(F("FAIL"));} erase(); testArray(TEST_ADR); } void checkBusy() { uint32_t stt = millis(); while (flash.busy()) { } uint32_t del = millis() - stt; if (del) { Serial.print(F(" (")); Serial.print(del); Serial.print(F(" ms)")); } Serial.println(); } void erase() { Serial.print(F("Full erase...")); flash.chipErase(); checkBusy(); } void printArray(byte* data, byte len) { for (byte i = 0; i < len; i++) { if (data[i] < 16) {Serial.print('0');} Serial.print(data[i], HEX); if (i < len - 1) {Serial.print(' ');} } } void testArray(uint32_t adr) { byte data[10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}; byte res[10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; flash.readBytes (adr, res, 10); Serial.print(F("Before: ")); printArray(res, 10); Serial.println(); Serial.println(F("Write array...")); flash.writeBytes(adr, data, 10); flash.readBytes (adr, res, 10); Serial.print(F("After: ")); printArray(res, 10); Serial.println(); } void loop() { }
Вначале задаём начальный адрес в памяти для работы с массивом байтов. В нашем случае, для простоты, это нулевая ячейка.
#define TEST_ADR 0
Затем стираем всё содержимое чипа и приступаем к тестированию чтения и записи массива байтов.
erase(); testArray(TEST_ADR);
Выводить на печать содержимое тестового массива мы будем при помощи функции printArray().
void printArray(byte* data, byte len) { for (byte i = 0; i < len; i++) { if (data[i] < 16) {Serial.print('0');} Serial.print(data[i], HEX); if (i < len - 1) {Serial.print(' ');} } }
Вся основная работа скетча производится в функции testArray().
void testArray(uint32_t adr) { byte data[10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}; byte res[10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; flash.readBytes (adr, res, 10); Serial.print(F("Before: ")); printArray(res, 10); Serial.println(); Serial.println(F("Write array...")); flash.writeBytes(adr, data, 10); flash.readBytes (adr, res, 10); Serial.print(F("After: ")); printArray(res, 10); Serial.println(); }
Вначале мы объявляем 10-байтовый массив data[] и заполняем его тестовыми значениями. Это те байты, которые нам нужно будет далее записать в память микросхемы M25P40VP.
byte data[10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
Также мы объявляем (тоже 10-байтовый) массив res[] для получения и хранения результата чтения из памяти M25P40VP и заполняем его нулевыми значениями.
byte res[10] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Далее мы читаем содержимое первых 10-и байтов памяти нашей Flash микросхемы.
flash.readBytes (adr, res, 10);
И выводим их на печать. Поскольку чтение производится сразу после процедуры стирания памяти, то мы ожидаем, что все байты будут равны 0xFF.
Serial.print(F("Before: ")); printArray(res, 10); Serial.println();
Далее записываем тестовый массив data[] во Flash память.
Serial.println(F("Write array...")); flash.writeBytes(adr, data, 10);
И читаем результат из первых 10-и ячеек памяти M25P40VP.
flash.readBytes (adr, res, 10); Serial.print(F("After: ")); printArray(res, 10); Serial.println();
Вот результат работы нашего тестового скетча:
Всё происходит в точности с нашими теоретическими выкладками: задержка полного стирания микросхемы составляет чуть больше 3-х секунд (подробнее об этом см. предыдущую статью), сразу после операции стирания первые 10 байтов содержат значения 0xFF, а прочитанные после нашей записи байты полностью соответствуют нашему тестовому массиву, то есть операция записи массива байтов прошла успешно.
Заключение
В этой статье мы рассмотрели чтение и запись в память микросхемы M25P40VP как отдельных байтов, так и целых массивов. В следующей статье мы продолжим знакомство с M25P40VP и разберём работу с различными типами данных (их чтение и запись).
Ссылки по теме
Обзор контроллера uniSensors nRF24
Программирование uniSensors nRF24
Работа с памятью M25P40. Часть 1. Спецификации и библиотека
Работа с памятью M25P40. Часть 2. Sleep, Wakeup, Erase и Busy
Работа с памятью M25P40. Часть 3. Read и Write Byte и Arrays
Работа с памятью M25P40. Часть 4. Работа с беззнаковыми типами данных
Работа с памятью M25P40. Часть 5. Работа со знаковыми типами данных
Работа с памятью M25P40. Часть 6. Read и Write Float
Работа с памятью M25P40. Часть 7. Read и Write Char array и String
Работа с памятью M25P40. Часть 8. Работа с секторами
Работа с памятью M25P40. Часть 9. Выборочное стирание секторов
Работа с памятью M25P40. Часть 10. Копирование секторов
Работа с памятью M25P40. Часть 11. Восстановление (backup) секторов
Работа с памятью M25P40. Часть 12. Работа с блоками памяти
Работа с памятью M25P40. Часть 13. Пишем библиотеку для M25P40
Работа с памятью M25P40. Часть 14. Пишем библиотеку для M25P40 (2)
Работа с памятью M25P40. Часть 15. Пишем библиотеку для M25P40 (3)
Где купить?
uniSensors nRF24 в магазине «Electromicro»
Техническая поддержка
Мы внимательно относимся к потребностям наших клиентов и осуществляем техническую поддержку всей выпускаемой продукции. Вы можете написать нам письмо с вашим вопросом или позвонить по телефону и специалист нашей компании проконсультирует вас и поможет решить вашу проблему.
- Емейл для вопросов по нашей продукции: electromicro@bk.ru
- Наш телефон: +7 (495) 997-37-74