logo
+7 (951) 999-89-94
428003, г. Чебоксары, ул. Федора Гладкова, д.9, оф.319

Работа с памятью M25P40. Часть 9. Выборочное стирание секторов

В этой статье мы продолжим изучать работу с секторами памяти микросхемы M25P40VP, установленной на плате uniSensors nRF24, и разберём приёмы выборочного стирания её отдельных секторов. Это важный аспект работы с M25P40VP, поскольку выборочное стирание и запись в отдельные сектора памяти вам придётся использовать постоянно в своих проектах.

Организация памяти M25P40VP

Напомним, что вся память микросхемы M25P40VP разбита на несколько зон и доступ к записи и данным в этих зонах может осуществляться разными способами. Со всеми доступными способами вы можете ознакомиться в предыдущих статьях этого цикла, а здесь мы сосредоточимся на изучении посекторного доступа.

Посекторный доступ — это разбиение всего адресного пространства микросхемы M25P40VP на 8 секторов по 65536 байт в каждом. Вот таблица соответствий секторов и их шестнадцатеричных и десятичных адресов:

Сектор 0 — 00000h (0)

Сектор 1 — 10000h (65536)

Сектор 2 — 20000h (131072)

Сектор 3 — 30000h (196608)

Сектор 4 — 40000h (262144)

Сектор 5 — 50000h (327680)

Сектор 6 — 60000h (393216)

Сектор 7 — 70000h (458752)

Также нужно помнить, программирование (изменение) данных (битов) в памяти M25P40VP происходит от 1 к 0, а стирание (посекторно или целиком) от 0 к 1.

Выборочное стирание и запись в сектора

В прошлой статье мы разобрали запись произвольного значения байта в разные (во все восемь) сектора микросхемы M25P40VP, в этой статье мы продолжим эту тему и познакомимся с выборочным стиранием отдельных секторов и приёмами записи и сохранения данных при выборочном стирании секторов M25P40VP.

Итак, в этом скетче мы:
 

- Научимся стирать не всю память M25P40VP сразу, а по секторам и посмотрим отличия этих двух типов стирания.

- Отработаем приёмы работы с данными в режиме выборочного стирания секторов и научимся выборочно сохранять информацию в чипе M25P40VP после процедуры стирания.

Скетч будет похож на скетч из предыдущей статьи, а все различия мы подробно разберём и проанализируем чуть ниже. А пока код скетча M25P40 Random Erase, Read & Write sector byte:

/*
  M25P40 Random Erase, Read & Write sector byte
*/

#include <SPI.h>
#include <SPIFlash.h>

#define FLASH_SS 8

#define SECTOR_SIZE 65536

#define TEST_ADR 0

SPIFlash flash(FLASH_SS);

void setup() {
  Serial.begin(115200);
  Serial.println(F("M25P40 Random Erase, Read & Write sector byte start..."));

  Serial.print(F("Init "));
  if (flash.initialize()) {Serial.println(F("OK"));}
                     else {Serial.println(F("FAIL"));}
  
  eraseSectors(); Serial.println();
  readSectors();  Serial.println();

  writeSectors(); Serial.println();
  erase64K(1);
  erase64K(3);
  erase64K(5);
  erase64K(7);  Serial.println();
  readSectors();  Serial.println();
}

void eraseSectors() {
  for (byte i = 0; i < 8; i++) {
    erase64K(i);
  }
}

void readSectors() {
  for (byte i = 0; i < 8; i++) {
    read_Byte(i);
  }
}

void writeSectors() {
  for (byte i = 0; i < 8; i++) {
    write_Byte(i);
  }
}

uint32_t sectorAdr(byte i) {
  return SECTOR_SIZE * i;
}

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 erase64K(byte sec) {
  uint32_t adr = sectorAdr(sec);
  Serial.print(F("Sector "));
  Serial.print(sec);
  Serial.print(F(" ("));
  Serial.print(adr);
  Serial.print(F(" + 64K) erase..."));
  
  flash.blockErase64K(adr);
  checkBusy();
}

void read_Byte(byte sec) {
  uint32_t adr = sec * SECTOR_SIZE;
  byte res = flash.readByte(adr);
  Serial.print(F("Read adr #")); Serial.print(adr); Serial.print(F(": ")); Serial.print(hexy(res));
  checkBusy();
}

void write_Byte(byte sec) {
  uint32_t adr = sec * SECTOR_SIZE;
  flash.writeByte(adr, sec);
  Serial.print(F("Write adr #")); Serial.print(adr); Serial.print(F(": ")); Serial.print(hexy(sec));
  checkBusy();
}

void loop() {
  
}

Разберём подробно работу скетча. Вначале мы определяем размер каждого из секторов микросхемы M25P40VP.

#define SECTOR_SIZE 65536

Затем определяем смещение (номер ячейки) для записи байта в каждом из секторов памяти. Для простоты это будет нулевая (самая первая) ячейка каждого сектора.

#define TEST_ADR 0

Далее мы стираем содержимое памяти чипа M25P40VP, но не всё сразу, как делали в предыдущей статье, а отдельно по каждому сектору

  eraseSectors(); Serial.println();

при помощи функции eraseSectors()

void eraseSectors() {
  for (byte i = 0; i < 8; i++) {
    erase64K(i);
  }
}

которая, в свою очередь, вызывает функцию erase64K() посекторного стирания информации в памяти M25P40VP, которой в качестве параметра передаётся номер текущего (нужного нам в данный момент) сектора.

void erase64K(byte sec) {
  uint32_t adr = sectorAdr(sec);
  Serial.print(F("Sector "));
  Serial.print(sec);
  Serial.print(F(" ("));
  Serial.print(adr);
  Serial.print(F(" + 64K) erase..."));
  
  flash.blockErase64K(adr);
  checkBusy();
}

Далее проводим операцию выборочного чтения нужных нам байт из изо всех 8-и секторов.

  readSectors();  Serial.println();

Поскольку читаем мы из всех 8-и секторов, то перебор и вызов функции read_Byte() выполняет цикл в функции readSectors().

void readSectors() {
  for (byte i = 0; i < 8; i++) {
    read_Byte(i);
  }
}

Само чтение байтов осуществляется функцией read_Byte(), которой мы в качестве параметра передаём номер текущего сектора.

void read_Byte(byte sec) {
  uint32_t adr = sec * SECTOR_SIZE;
  byte res = flash.readByte(adr);
  Serial.print(F("Read adr #")); Serial.print(adr); Serial.print(F(": ")); Serial.print(hexy(res));
  checkBusy();
}

Здесь мы вычисляем реальный («линейный») адрес нужной нам ячейки памяти.

  uint32_t adr = sec * SECTOR_SIZE;

И производим чтение по этому адресу.

  byte res = flash.readByte(adr);

Далее выводим результат чтения на печать для контроля корректности результата.

  Serial.print(F("Read adr #")); Serial.print(adr); Serial.print(F(": ")); Serial.print(hexy(res));

Функция hexy() форматирует вывод под шестнадцатеричное представление чисел (это нужно только для «красивого» вывода данных).

String hexy(byte b) {
  String s = F("0x");
  if (b < 16) {s += '0';}
  String s2 = String(b, HEX);
  s2.toUpperCase();
  return s + s2;
}

Далее следует блок в котором мы сначала записываем тестовые данные во все сектора памяти, затем выборочно стираем 1-й, 3-й, 5-й и 7-й сектора и снова производим тестовое чтение для контроля корректности работы скетча.

  writeSectors(); Serial.println();
  erase64K(1);
  erase64K(3);
  erase64K(5);
  erase64K(7);  Serial.println();
  readSectors();  Serial.println();

Мультисекторная запись осуществляется функцией writeSectors(), где в цикле перебираются все 8 секторов памяти M25P40VP.

void writeSectors() {
  for (byte i = 0; i < 8; i++) {
    write_Byte(i);
  }
}

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

void write_Byte(byte sec) {
  uint32_t adr = sec * SECTOR_SIZE;
  flash.writeByte(adr, sec);
  Serial.print(F("Write adr #")); Serial.print(adr); Serial.print(F(": ")); Serial.print(hexy(sec));
  checkBusy();
}

А точнее, функцией flash.writeByte().

  flash.writeByte(adr, sec);

Далее результат выводится на печать.

  Serial.print(F("Write adr #")); Serial.print(adr); Serial.print(F(": ")); Serial.print(hexy(sec));

И проверяется задержка выполнения операции микросхемой M25P40VP (о задержках выполнения операций читайте в предыдущих статьях этого цикла).

Следующий блок выборочно стирает нужные нам сектора.

  erase64K(1);
  erase64K(3);
  erase64K(5);
  erase64K(7);  Serial.println();

И далее мы снова проводим тестовое чтение контрольных данных.

  readSectors();  Serial.println();

Вот результат работы нашего скетча:

Разберём подробнее этот скриншот. В первом блоке мы видим вывод о посекторном стирании памяти чипа M25P40VP, которое происходит за 8 приёмов по одному сектору и занимает примерно 0,5 секунды на сектор. То есть полное стирание происходит примерно за 4,5 секунды.

Обратите внимание на следующий момент: полное стирание чипа одной командой происходит за 3,5 сек., а посекторное суммарно — за 4,5 сек. Это значит, что если вам нужно полностью стиреть чип, то лучше это делать не посекторно, а одной командой.

Одновременно, если вам нужно стереть только какой-то отдельный участок памяти M25P40VP, то разумнее пользоваться именно посекторным стиранием с задержкой примерно 0,5 сек. на сектор.

Затем мы видим чтение из нулевых (самых первых) ячеек памяти каждого сектора, и видим, что во всех протестированных ячейках находятся значения 0xFF (255 в десятичном формате или b11111111 в двоичном) и задержку операции чтения из некоторых ячеек в 2 миллисекунды.

Значения 0xFF в ячейках говорят о том, что операция стирания памяти чипа прошла успешно и он готов для записи в него новой информации.

Далее мы пишем в нужные нам ячейки (согласно заданию) байты данных. В данном случае (для теста) в каждую ячейку записывается номер сектора, содержащего эту ячейку. В случае успешной записи мы должны прочитать из этих ячеек эти же байты.

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

0-й сектор, 0-я ячейка — 0x00

1-й сектор, 0-я ячейка — 0x01

2-й сектор, 0-я ячейка — 0x02

3-й сектор, 0-я ячейка — 0x03

4-й сектор, 0-я ячейка — 0x04

5-й сектор, 0-я ячейка — 0x05

6-й сектор, 0-я ячейка — 0x06

7-й сектор, 0-я ячейка — 0x07

И, наконец, выборочно стираем 1-й, 3-й, 5-й и 7-й сектора памяти микросхемы M25P40VP. Здесь мы подразумеваем, что выборочно стерев некоторые сектора памяти, мы при проверке обнаружим нетронутыми остальные данные, а на месте данных в стёртых секторах мы обнаружим ожидаемые значения байтов 0xFF.

Что полностью подтверждается чтением после всех наших манипуляций — тестовые ячейки в стёртых секторах содержат ожидаемые значения 0xFF, а остальные тестовые ячейки содержат записанные в них данные (номера содержащих их секторов). Отличный и полностью корректный результат!

Заключение

На этом уроке мы научились выборочно посекторно стирать информацию в памяти микросхемы M25P40VP и сохранять нужные нам данные в других секторах памяти. На следующем уроке мы научимся копировать и сохранять информацию внутри чипа M25P40VP и разберём соответствующие примеры.

Ссылки по теме

Обзор контроллера uniSensors nRF24

Спецификации 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

Аналогичные товары