logo
+7 (495) 997-37-74
Москва, ул.Международная, 15

ATSHA204A — Запись конфигурации 2

Продолжим знакомство с записью конфигурационной зоны микросхемы ATSHA204A начатое в предыдущей статье. Эту часть начнём с разбора записи блоков Slot Configuration, отвечающих за режимы работы и доступа к 16-и слотам зоны данных (Data Zone).

Таблица зоны конфигурации

Для начала приведём уже знакомую вам таблицу конфигурационной зоны ATSHA204A из даташита.

Запись Slot Configuration (0–15)

Slot Configuration (0–15) — это блоки конфигурации работы и доступа к 16-и слотам зоны данных (Data Zone) микросхемы ATSHA204A. Каждый блок состоит из 16-и битов (2-х байт), которые управляют использованием и доступом для данного конкретного слота (ключа).

Если зона данных заблокирована, то блок SlotConfig интерпретируется в соответствии с нижеприведённой таблицей. Когда Data зона разблокирована, эти ограничения не применяются и все слоты могут быть свободно записаны, но ни один из них не может быть прочитан.

В качестве основы мы возьмём скетч из предыдущих статей о чтении блоков конфигурации работы и доступа к 16-и слотам зоны данных (Data Zone). Добавим в него функции записи блоков и прочие необходимые изменения и дополнения. Полный код нового скетча:

/* 
  ATSHA204 Write Config Slots
*/

#include <sha204_library.h>

#define ATSHA204_PIN A3

byte bufTx[SHA204_CMD_SIZE_MAX];
byte bufRx[SHA204_RSP_SIZE_MAX];

#define SLOT_LEN 2
byte bufSlot[SLOT_LEN];

String func[] = {"ReadKey", "ReadKey", "ReadKey", "ReadKey",
                 "CheckOnly",
                 "SingleUse",
                 "EncryptRead",
                 "IsSecret",
                 "WriteKey", "WriteKey", "WriteKey", "WriteKey",
                 "WriteConf", "WriteConf", "WriteConf", "WriteConf"};

byte  slots[16] = {5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12};
byte shifts[16] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};

#define SLOT_NUM 15

byte slot  =  slots[SLOT_NUM];
byte shift = shifts[SLOT_NUM];

#define BUF_WRITE_LEN 4
byte bufWrite[BUF_WRITE_LEN];

byte blockNew[] = {0x00, 0xFF};

atsha204Class sha204(ATSHA204_PIN);


void setup() {
  Serial.begin(115200);
  Serial.println("ATSHA204 Write Config Slots start...");

  Serial.print(F("Slot: ")); Serial.println(SLOT_NUM);
  
  // Read 1
  readAndPrint();

  // Write
  setNew(blockNew);
  writeConfig();

  // Read 2
  readAndPrint();
}

// Print

void printBuffer(byte* data, byte len) {
  for (size_t i = 0; i < len; i++) {
    if (data[i] < 10) {Serial.print('0');}
    Serial.print(data[i], HEX);
    if (i < len - 1) {Serial.print(' ');}
  }
}

void printBit(byte n, byte b, String s) {
  Serial.print(F("Bit ")); Serial.print(n); Serial.print(F(": "));
  Serial.print(b);
  Serial.print(F(" (")); Serial.print(s); Serial.println(F(")"));
}

void printBits() {
  Serial.println(F("Byte #0:"));
  for (byte i = 0; i < 8; i++) {printBit(    i, bitRead(bufSlot[0], i), func[i]);}
  Serial.println(F("Byte #1:"));
  for (byte i = 0; i < 8; i++) {printBit(8 + i, bitRead(bufSlot[1], i), func[8 + i]);}
}

// Read

byte addr(byte slot) {
  return slot * 4;
}

void readConf() {
  byte retCode = 0;

  retCode = sha204.sha204m_read(bufTx, bufRx, SHA204_ZONE_CONFIG, addr(slot));
  bufSlot[0] = bufRx[SHA204_BUFFER_POS_DATA + 0 + shift*2];
  bufSlot[1] = bufRx[SHA204_BUFFER_POS_DATA + 1 + shift*2];

  bufWrite[0] = bufRx[SHA204_BUFFER_POS_DATA + 0];
  bufWrite[1] = bufRx[SHA204_BUFFER_POS_DATA + 1];
  bufWrite[2] = bufRx[SHA204_BUFFER_POS_DATA + 2];
  bufWrite[3] = bufRx[SHA204_BUFFER_POS_DATA + 3];
}

void readAndPrint() {
  readConf();
  
  Serial.print(F("Block: "));
  printBuffer(bufSlot, SLOT_LEN);
  Serial.println();

  printBits();
}

// Write

void setNew(byte* buf) {
  bufWrite[0 + shift*2] = buf[0];
  bufWrite[1 + shift*2] = buf[1];
}

void writeConfig() {
  byte retCode = sha204.sha204m_execute(SHA204_WRITE,
                                        SHA204_ZONE_CONFIG, slot,
                                        4, bufWrite,
                                        0, NULL,
                                        0, NULL,
                                        WRITE_COUNT_SHORT, bufTx,
                                        WRITE_RSP_SIZE,    bufRx);
}

void loop() {

}

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

Итак, рассмотрим все наши нововведения, по сравнению с базовым скетчем чтения 16-и блоков конфигурации Data Zone.

Определяем размер и вводим новый буфер для хранения данных одного слота (4 байта). Напомним, что чтение или запись в конфигурационную зону ATSHA204A производится блоками по 4 байта.

#define BUF_WRITE_LEN 4
byte bufWrite[BUF_WRITE_LEN];

Далее вводим тестовые значения для одного из 16-и блоков конфигурации (в наших экспериментах мы будем работать с 15-м блоком).

byte blockNew[] = {0x00, 0xFF};

Если вы посмотрите на справочную таблицу из даташита, приведённую в начале этой статьи, то увидите, что по умолчанию в 15-м блоке находятся значения AF и 8F. Наша задача записать на их места байты 0x00 и 0xFF, то есть в первом случае все биты будут равны нулям (0b00000000), а во втором — единицам (0b11111111). Эти значения выбраны исключительно из наглядности и в ваших проектах могут быть любыми нужными вам.

Логика работы скетча задаётся в функции setup().

void setup() {
  Serial.begin(115200);
  Serial.println("ATSHA204 Write Config Slots start...");

  Serial.print(F("Slot: ")); Serial.println(SLOT_NUM);
  
  // Read 1
  readAndPrint();

  // Write
  setNew(blockNew);
  writeConfig();

  // Read 2
  readAndPrint();
}

Сначала мы читаем (15-й) блок и выводим его значения на печать в виде байтов и отдельных битов.

  // Read 1
  readAndPrint();

Затем меняем нужные нам байты на новые и записываем их в микросхему ATSHA204A.

  // Write
  setNew(blockNew);
  writeConfig();

И затем снова читаем конфигурационную зону микросхемы ATSHA204A для того, чтобы убедиться в правильности внесённых изменений.

  // Read 2
  readAndPrint();

Теперь подробно разберём нюансы записи блоков конфигурации в нашем скетче. Чтение данных из памяти осуществляется функцией readConf().

void readConf() {
  byte retCode = 0;

  retCode = sha204.sha204m_read(bufTx, bufRx, SHA204_ZONE_CONFIG, addr(slot));
  bufSlot[0] = bufRx[SHA204_BUFFER_POS_DATA + 0 + shift*2];
  bufSlot[1] = bufRx[SHA204_BUFFER_POS_DATA + 1 + shift*2];

  bufWrite[0] = bufRx[SHA204_BUFFER_POS_DATA + 0];
  bufWrite[1] = bufRx[SHA204_BUFFER_POS_DATA + 1];
  bufWrite[2] = bufRx[SHA204_BUFFER_POS_DATA + 2];
  bufWrite[3] = bufRx[SHA204_BUFFER_POS_DATA + 3];
}

По сравнению с предыдущем скетчем, здесь мы добавили блок для заполнения буфера записи bufWrite.

  bufWrite[0] = bufRx[SHA204_BUFFER_POS_DATA + 0];
  bufWrite[1] = bufRx[SHA204_BUFFER_POS_DATA + 1];
  bufWrite[2] = bufRx[SHA204_BUFFER_POS_DATA + 2];
  bufWrite[3] = bufRx[SHA204_BUFFER_POS_DATA + 3];

Это понадобилось потому, что блок конфигурации занимает 2 байта, а слот чтения/записи ATSHA204A — 4 байта, а нам для записи нужны все эти 4 байта.

Далее в дело вступает функция setNew(), которая меняет в массиве bufWrite 2 байта нужного блока на новые значения, оставляя неизменными 2 байта соседнего блока (который нам по условию задачи изменять не нужно).

void setNew(byte* buf) {
  bufWrite[0 + shift*2] = buf[0];
  bufWrite[1 + shift*2] = buf[1];
}

И далее функция writeConfig() записывает в микросхему ATSHA204A сформированный нами массив из 4-х байт (bufWrite).

void writeConfig() {
  byte retCode = sha204.sha204m_execute(SHA204_WRITE,
                                        SHA204_ZONE_CONFIG, slot,
                                        4, bufWrite,
                                        0, NULL,
                                        0, NULL,
                                        WRITE_COUNT_SHORT, bufTx,
                                        WRITE_RSP_SIZE,    bufRx);
}

Таким образом мы меняем нужный нам блок из 2-х байт (в нашем случае 15-й) в конфигурационной зоне микросхемы ATSHA204A и записываем в него нужные нам значения.

Далее мы повторяем процедуру чтения для того, чтобы убедиться в правильности внесённых изменений.

Теперь давайте посмотрим на скриншоты работы нашего скетча. На первом скриншоте видно, что работа происходит с 15-м слотом (блоком конфигурации) и его значения по умолчанию AF и 8F, что соответствует таблице из даташита. Красным выделена информация, относящаяся к начальному состоянию памяти ATSHA204A.

Далее производится запись выбранных нами значений и снова выводится состояние 15-го блока конфигурации Data Zone. Скриншот свидетельствует, что наш скетч корректно произвёл запись нужной нам информации в выбранный блок конфигурации ATSHA204A.

В этом примере использовалась работа с 15-м блоком конфигурации, аналогичным образом вы можете работать с любым из 16-и (0–15) блоков конфигурации Data Zone.

Запись Use Flag (0–7)

Байты Use Flag определяют количество раз, когда «одноразовыe» слоты 0–7 могут использоваться перед отключением. Как и в примере записи блоков Slot Configuration, за основу скетча записи байтов Use Flag мы возьмём скетч чтения этих байтов из предыдущих статей цикла.

Немного модифицируем его и добавим функции записи нужных нам байтов. Код скетча ATSHA204 Write Config Use Flag:

/* 
  ATSHA204 Write Config Use Flag
*/

#include <sha204_library.h>

#define ATSHA204_PIN A3

byte bufTx[SHA204_CMD_SIZE_MAX];
byte bufRx[SHA204_RSP_SIZE_MAX];

byte useFlag = 0;

byte  slots[8] = {13, 13, 14, 14, 15, 15, 16, 16};
byte shifts[8] = {0, 2, 0, 2, 0, 2, 0, 2};

#define SLOT_NUM 0

byte slot  =  slots[SLOT_NUM];
byte shift = shifts[SLOT_NUM];

#define BUF_WRITE_LEN 4
byte bufWrite[BUF_WRITE_LEN];

byte newVal = 5;

atsha204Class sha204(ATSHA204_PIN);

void setup() {
  Serial.begin(115200);
  Serial.println("ATSHA204 Write Config Use Flag start...");

  Serial.print(F("Slot: ")); Serial.println(SLOT_NUM);

  read();

  setNew(newVal);
  writeConfig();

  read();
}

// Read

byte addr(byte slot) {
  return slot * 4;
}

void readConf() {
  byte retCode = sha204.sha204m_read(bufTx, bufRx, SHA204_ZONE_CONFIG, addr(slot));
  useFlag = bufRx[SHA204_BUFFER_POS_DATA + shift];

  bufWrite[0] = bufRx[SHA204_BUFFER_POS_DATA + 0];
  bufWrite[1] = bufRx[SHA204_BUFFER_POS_DATA + 1];
  bufWrite[2] = bufRx[SHA204_BUFFER_POS_DATA + 2];
  bufWrite[3] = bufRx[SHA204_BUFFER_POS_DATA + 3];
}

void read() {
  Serial.print(F("Use Flag"));
  Serial.print(SLOT_NUM);
  Serial.print(F(": 0x"));
  readConf();
  Serial.println(useFlag, HEX);
}

// Write

void setNew(byte b) {
  bufWrite[shift] = b;
}

void writeConfig() {
  byte retCode = sha204.sha204m_execute(SHA204_WRITE,
                                        SHA204_ZONE_CONFIG, slot,
                                        4, bufWrite,
                                        0, NULL,
                                        0, NULL,
                                        WRITE_COUNT_SHORT, bufTx,
                                        WRITE_RSP_SIZE,    bufRx);
}

void loop() {

}

В данном примере мы будем работать со слотом 0 (первым из восьми возможных 0–7) и зададим соответствующее определение. Вы можете поменять это значение на любое из диапазона 0–7.

#define SLOT_NUM 0

Далее определяем размер и вводим новый буфер для хранения данных одного слота размером 4 байта (чтение или запись в конфигурационную зону ATSHA204A производится блоками по 4 байта).

#define BUF_WRITE_LEN 4
byte bufWrite[BUF_WRITE_LEN];

Затем вводим новое значение для нулевого байта Use Flag. Значение 5 взято для примера и оно может быль любым из диапазона 0–255. Напомним, смысл этого значения и самого байта Use Flag — это количество раз, когда «одноразовыe» слоты могут использоваться перед отключением.

byte newVal = 5;

Логика работы скетча задаётся в функции setup()

  read();

  setNew(newVal);
  writeConfig();

  read();

и состоит она в чтении значения выбранного слота из памяти микросхемы ATSHA204A, вывода в Serial нужного нам значения Use Flag, записи нового значения в память микросхемы и контрольного чтения нового значения из ATSHA204A, чтобы убедиться в успешности изменения нужного нам байта.

Чтение данных из памяти осуществляется функцией readConf()

void readConf() {
  byte retCode = sha204.sha204m_read(bufTx, bufRx, SHA204_ZONE_CONFIG, addr(slot));
  useFlag = bufRx[SHA204_BUFFER_POS_DATA + shift];

  bufWrite[0] = bufRx[SHA204_BUFFER_POS_DATA + 0];
  bufWrite[1] = bufRx[SHA204_BUFFER_POS_DATA + 1];
  bufWrite[2] = bufRx[SHA204_BUFFER_POS_DATA + 2];
  bufWrite[3] = bufRx[SHA204_BUFFER_POS_DATA + 3];
}

в которую мы добавили блок заполнения массива bufWrite.

  bufWrite[0] = bufRx[SHA204_BUFFER_POS_DATA + 0];
  bufWrite[1] = bufRx[SHA204_BUFFER_POS_DATA + 1];
  bufWrite[2] = bufRx[SHA204_BUFFER_POS_DATA + 2];
  bufWrite[3] = bufRx[SHA204_BUFFER_POS_DATA + 3];

Изменение нужного нам байта Use Flag начинается с функции setNew(), которая записывает новое значение байта на соответствующее место в прочитанном слоте (пока только в массиве bufWrite).

void setNew(byte b) {
  bufWrite[shift] = b;
}

И, далее, функция writeConfig() непосредственно осуществляет запись модифицированного нами массива bufWrite (выбранного слота) в память микросхемы ATSHA204A, на соответствующее место в конфигурационной зоне (см. таблицу из даташита в начале этой статьи).

void writeConfig() {
  byte retCode = sha204.sha204m_execute(SHA204_WRITE,
                                        SHA204_ZONE_CONFIG, slot,
                                        4, bufWrite,
                                        0, NULL,
                                        0, NULL,
                                        WRITE_COUNT_SHORT, bufTx,
                                        WRITE_RSP_SIZE,    bufRx);
}

Затем осуществляется повторное чтение памяти микросхемы для контроля правильности произведённых изменений.

  read();

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

В слоте 0 (из диапазона 0–7) значение по умолчанию 0xFF (255) заменено на 0x5 (5), то есть, другими словами, количество раз, когда «одноразовый» слот 0 может быть использован перед отключением изменилось с 255 до 5 раз.

Заключение

В этом материале из цикла статей о ATSHA204A мы рассмотрели запись блоков Slot Configuration и байтов Use Flag в конфигурационной зоне микросхемы, в следующих статьях мы продолжим эту тему, а также разберём прочие аспекты работы с ATSHA204A.

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

Работа с SHA-256

ATSHA204 - Обзор

ATSHA204 - Спецификации

ATSHA204 - Библиотека и примеры

ATSHA204A - Чтение зоны конфигурации 1

ATSHA204A - Чтение зоны конфигурации 2

ATSHA204A - Чтение зоны конфигурации 3

ATSHA204A - Запись конфигурации 1

ATSHA204A - Запись конфигурации 3

ATSHA204A - Запись конфигурации 4

ATSHA204A - Config Lock

ATSHA204A - Работа в режиме Config Lock

ATSHA204A - Работа с зонами памяти

ATSHA204A - Запись зоны OTP

ATSHA204A - Data Lock

ATSHA204A - Чтение Data и OTP зон памяти

ATSHA204A - Команда MAC

ATSHA204A - Аутентификация. Базовый блок

ATSHA204A - Аутентификация. Датчик