41380

[i] Программирование памяти OTP микроконтроллера 1986ВК025

Дата последнего изменения: 28.07.2022 15:19:40

Объём OTP-памяти микросхемы 1986ВК025 составляет 16 Кбайт. В данной OTP хранится загрузочная программа, а оставшийся объём свободен для использования (кроме последнего байта, имеющего специальное назначение – установка защищенных адресных пространств FLASH-памяти и блокировка отладочного интерфейса JTAG). Кроме того, при необходимости микросхемы поставляются с пустым OTP для самостоятельной разработки загрузочной программы.

Со второй ревизии микроконтроллера были зарезервированы дополнительные адреса памяти OTP. Они содержат специальную информацию (рисунок 1 статьи, также отражено в спецификации в п. "Загрузочное OTP и режимы работы микроконтроллера", следует ориентироваться на спецификацию для получения более полных и актуальных сведений).

Рисунок 1 - Описание специальных полей в памяти OTP (источник - спецификация К1986ВК025, версия 0.7.0)

Программирование OTP реализовано на автоматах, необходимо только задать число тактов задержки для формирования пауз 20 нс (биты DELAY_20NS), 70 нс (биты DELAY_70NS), 50 нс (биты DELAY_50NS) и 1 мкс (биты DELAY_01US) в регистре DELAY_0 и число тактов задержки для формирования паузы 16 мкс (биты DELAY_16US) в регистре DELAY_1. Все последовательности для чтения и программирования модуль однократно программируемой памяти формирует самостоятельно.

Помимо программирования, модуль позволяет читать данные из OTP по шине AHB и осуществлять блокировку отладочного интерфейса (под блокировкой отладочного интерфейса следует понимать следующее: при подаче питания отладочный интерфейс запрещён, и при считывании последнего байта OTP он или разрешается, или остаётся заблокированным).

Стоит обратить внимание, что OTP-память имеет две области отображения – одна начинается с адреса 0x0002_0000 и называется BOOT_OTP, другая начинается с адресов 0x7000_0000 и называется OTP_MEM. При размещении данных обращение к OTP-памяти может быть осуществлено по любому из этих базовых адресов. Однако, эти адреса неравнозначны: загрузочная программа запускается с адресов BOOT_OTP, поэтому она должна быть скомпилирована именно для базового адреса BOOT_OTP 0x0002_0000. Аналогичное справедливо для всего кода: вызов кода должен осуществляться из тех адресов BOOT_OTP или OTP_MEM, для которых он был скомпилирован.

Чистая OTP-память заполнена 0, и программирование осуществляется записью 1.

Модуль OTP-памяти позволяет осуществить блокировку чтения и блокировку записи областей памяти OTP. Одна область памяти OTP составляет 2048 байт, всего 8 областей от 0 до 7 (область 0 - адреса 0-2047, область 1 - адреса 2048-4095, и так далее). Запрет записи/чтения для каждой области осуществляется однократно, записью 1 в n-ый бит для n-ой области памяти OTP в регистры WRITE_PROTECT_REG и READ_PROTECT_REG (более подробно процедура блокировки чтения/записи приведена в описании регистров WRITE_PROTECT_REG/READ_PROTECT_REG блока контроллера OTP в спецификации). 

В статье описана работа с OTP-памятью, разработка загрузочной программы и запись её в OTP-память. В конце статьи приложен архив с проектами для среды Eclipse, в котором содержится пример чтения и программирования слова OTP-памяти (OTP_Word), пример загрузочной программы (Bootloader), и программа, осуществляющая программирование OTP скомпилированной загрузочной программой (Loader).
В SPL реализован необходимый функционал для работы с памятью OTP:
  • Функция OTP_Init() конфигурирует все необходимы задержки на основании значения переменной RST_CLK_HclkSpeed - соответственно, необходимо правильно настроить частоту работы периферийных блоков.
  • Функция OTP_WriteBit() осуществляет запись и верификацию бита данных. Функция OTP_WriteByte() является "оберткой" над функцией OTP_WriteBit(), так как запись аппаратно осуществляется битами.
  • Функция OTP_Read() осуществляет чтение байта данных.
  • Функции OTP_ReadReadProtection()OTP_SetReadProtection()OTP_ReadWriteProtection() и OTP_SetWriteProtection() осуществляют чтение состояния или установку защиты на чтение или записи областей памяти OTP.

1. Чтение и программирование OTP-памяти

Как было сказано выше, модуль OTP самостоятельно выполняет все операции для программирования, и для подготовки модуля необходимо только указать число тактов паузы в соответствующих регистрах, так как модуль может работать на разных частотах.

Алгоритм чтения байта памяти с помощью модуля OTP:

  1. Проверка защиты чтения данной области в регистре READ_PROTECT.

  2. Ожидание сброса флага BUSY регистра STAT_CTRL в ноль - флаг является индикацией выполнения модулем OTP каких-либо действий.

  3. Запись битового адреса в функциональные биты ADDR регистра RW_CMD. Младшие 3 бита игнорируются, так как чтение осуществляется байтами.

  4. Установка функционального бита WRITE в 0, а READ в 1 регистра RW_CMD (чтение производится только при наличии 0 в поле WRITE и 1 в поле READ, при условии отсутствия защиты выбранной области от чтения. При чтении флаг BUSY устанавливается в 1).

  5. Ожидание сброса флага BUSY регистра STAT_CTRL в ноль.

  6. Чтение байта данных из поля DATA_0[7:0] регистра READ_DATA. В случае ошибки в данных битах установлена константа 0xEF.

Кроме того, модуль OTP позволяет осуществлять чтение не только через регистры, но и непосредственно из областей памяти BOOT_OTP и OTP_MEM (по шине AHB) - в таком случае ограничения на объём считываемых данных в 1 байт нет.

Алгоритм записи бита памяти в OTP:

  1. Проверка защиты записи данной области в регистре WRITE_PROTECT.

  2. Ожидание сброса флага BUSY регистра STAT_CTRL в ноль.

  3. Запись битового адреса в функциональные биты ADDR регистра RW_CMD.

  4. Запись бита данных в функциональный бит DATA_0 регистра RW_CMD. Если DATA_0=0, запись не производится, так как 0 - это начальное состояние OTP. Записываются 1 без возможности стирания. Также программирование не производится, если выбранная область OTP защищена от записи.

  5. Установка функционального бита WRITE в 1, а READ в 0 регистра RW_CMD (запись производится только при наличии 1 в поле WRITE и 0 в поле READ, при условии отсутствия защиты выбранной области от записи. При записи флаг BUSY устанавливается в 1).

  6. Ожидание сброса флага BUSY регистра STAT_CTRL в ноль.

  7. Опционально - верификация данных с помощью чтения OTP.

Важно обратить внимание, что, не смотря на байтовую адресацию микроконтроллера, адрес в поле ADDR битовый, а не байтовый. При этом запись в OTP аппаратно производится битами, а чтение - байтами, и при чтении 3 младшие бита, записанные в поле ADDR, игнорируются.

Проект OTP_Word реализует пример чтения, программирования и верификации 32-битного слова в пустую область OTP-памяти (в микросхемах с инженерным загрузчиком адрес 0x000207D0 не занят, чем и обоснован выбор данного адреса). Проект использует функции SPL, в качестве источника частоты устанавливается внешний HSE, так как является более точным. Стоит обратить внимание, что без тримминга реальная частота внутреннего HSI составляет порядка 5.4 МГц, и требования к его стабильности не предъявляются, поэтому вместо HSI используется более точный HSE.

Для отладки проектов с чистой OTP-памятью необходимо в настройках отладки среды Eclipse указать Debug in RAM, тогда отладчик всегда будет перемещать program counter на начало программы (startup файла).

2. Разработка загрузочной программы для чистой OTP-памяти

Перед программированием чистой OTP-памяти загрузочной программой её необходимо разработать и отладить из других регионов памяти, например, из Flash-памяти. Однако следует учитывать ограничение по объёму памяти в 16 Кбайт.

В качестве шаблона можно, например, взять проект Template из статьи «Создаем проект для МК К1986ВК025 в IDE Eclipse», и оставить в подключаемых библиотеках SPL только заголовочный файл, где реализован минимально необходимый функционал для разработки программы на регистрах. В архиве в конце статьи для загрузочной программы реализован проект Bootloader, который реализует описанное в спецификации поведение загрузочной программы.

Необходимо учитывать, что в проекте Bootloader ячейка памяти OTP с адресом 0х0002_3FDF/0x7000_3FDF используется для хранения номера версии загрузочной программы. При необходимости номер версии можно не сохранять в памяти OTP, для этого требуется в файле main.c закомментировать строку с объявлением константы BootloaderVersion.

После разработки кода загрузочной программы и отладки его из Flash-памяти требуется скомпилировать программу для адресного пространства OTP.

В используемом linker-файле link_Flash.ld должна быть объявлена область BOOT_OTP 0x0002_0000:

MEMORY
{
            FLASH     (rx)      : ORIGIN = 0x10000000, LENGTH = 256K
            OTP       (rx)      : ORIGIN = 0x00020000, LENGTH = 16K
            TCMA_RAM  (xrw)     : ORIGIN = 0x80000000, LENGTH = 64K
            TCMB_RAM  (xrw)     : ORIGIN = 0x80010000, LENGTH = 32K
            AHB_RAM   (xrw)     : ORIGIN = 0x20000000, LENGTH = 16K
}

После этого необходимо изменить регион памяти для хранения программы. Для этого достаточно заменить строку с указанием адресов Flash-памяти в качестве региона загрузки:

  REGION_ALIAS("REGION_LOAD",    FLASH);

на строку с указанием адресов области BOOT_OTP в качестве региона загрузки:

  REGION_ALIAS("REGION_LOAD",    OTP);
Для удобства можно сохранить внесенные изменения в виде отдельного linker-файла link_OTP.ld и создать новую конфигурацию сборки - Debug_OTP. В результате повторной компиляции проекта в папке Debug_OTP появится файл в формате hex, который далее можно использовать для прошивки OTP загрузочной программой. Полученная в результате программа хранит все постоянные данные в области памяти REGION_LOAD, которая является областью памяти BOOT_OTP, с которой стартует загрузочная программа при подаче питания.

3. Программирование чистой OTP-памяти загрузочной программой

После получения hex-файла с загрузочной программой необходимо сгенерировать массив данных, который далее можно использовать в программе-загрузчике (в архиве в конце статьи это проект Loader) - которая будет программировать OTP-память загрузочной программой. Проект Loader реализует программирование памяти OTP массивом данных, полученным в результате разработки и компиляции проекта загрузочной программы Bootloader

Для генерации массива данных можно воспользоваться сторонними утилитами, например, srec_cat, которая позволяет получить из hex-файла массив байтов (в качестве типа выходного файла следует выбрать -C-Array с опцией -C_COMpressed). Кроме того, в конце этого файла генерируется информация о каждом сегменте данных: начальный адрес, конечный адрес и размер. Полученную информацию далее можно использовать в программе-загрузчике. Следует обратить внимание на начальный адрес: он должен равняться началу OTP-памяти 0x0002_0000.

Утилита srec_cat добавлена в проект загрузочной программы Bootloader. Данная утилита запускается при сборке конфигурации Debug_OTP с помощью скрипта post-build.bat, который расположен в корне проекта Bootloader. По завершении работы утилита srec_cat создает в папке Debug_OTP файл BootloaderCode.h с массивом данных и дополнительной информацией о сегментах. Файл BootloaderCode.h нужно скопировать в проект Loader, в папку src.

Программирование массивом данных осуществляется по описанному выше алгоритму.

Проект Loader реализует минимальный необходимый функционал, а именно:

1) Настройка тактовой частоты от внешнего резонатора HSE = 8 МГц.

2) Конфигурация контроллера OTP.

3) Программирование памяти указанным массивом по сегментам.

4) Верификация записанных данных по сегментам.

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

Использование внешнего источника частоты HSE необходимо для обеспечения точного времени пауз для контроллера OTP. При использовании резонатора HSE с частотой, отличной от 8 МГц, или при использовании генератора необходимо внести соответствующие изменения. Верификация записанных данных также является необходимым этапом, так как OTP-память имеет такой параметр, как коэффициент программируемости.

Запуск проекта Loader из памяти Flash может повлиять на последующие запуски, т.к. программа останется во Flash-памяти после снятия питания, поэтому рекомендуется запускать данный проект из ОЗУ.
Сохранить статью в PDF

Файлы для скачивания

Документация

Теги

Была ли статья полезной?