В этой документации (перевод апноута AN3155 [1]) описывается протокол USART, используемый загрузчиком (bootloader) микроконтроллера STM32 (MCU), с подробным описанием каждой поддерживаемой команды.
Примечание: эта документация применима к MCU, в которые встроена любая версия загрузчика, как это описано в апноуте AN2606 [2]. Совместимые MCU перечислены в таблице 1, и в этом документе для простоты они обозначены как STM32. Дополнительную информацию по требуемым аппаратным ресурсам USART и требованиям к загрузчику см. в вышеупомянутом AN2606 [2].
Таблица 1. MCU STM32, которые могут использоваться с загрузчиком USART.
Как только STM32 вошел в режим загрузки (system memory boot mode) и было сконфигурировано его ядро (основанное на технологии Arm® [2]), код загрузчика начинает опрос вывода USARTx_RX, ожидая получения фрейма с байтом 0x7F: старт-бит, биты данных 0x7F, бит четности (even parity bit) и стоп-бит.
Длительность этого фрейма данных измеряется с помощью таймера Systick. Значение счетчика таймера затем используется для вычисления соответствующего коэффициента скорости USART (baud rate factor) по отношению к текущей системной частоте тактов. Далее код соответствующим образом инициализирует последовательный интерфейс USART. На вычисленной скорости передачи в ответ хосту отправляется байт подтверждения (0x79), который сигнализирует о готовности STM32 принять команды загрузчика.
Рис. 1. Основной алгоритм загрузчика STM32 USART.
[Вычисление скорости USARTx]
Вычисление скорости USARTx, основанное на первом принятом байте, позволяет загрузчику работать в широком диапазоне скоростей. Однако для гарантии правильной передачи данных от хоста загрузки к STM32 (и обратно) следует придерживаться верхнего и нижнего пределов скорости.
Максимальная девиация между внутренней инициализированной скорости USARTx STM32 и реальной скоростью хоста должна быть меньше 2.5%. Эта девиация (fB, в процентах) между скоростями хоста (speedHost) и STM32 (speedSTM32) вычисляется по формуле:
speedSTM32 - speedHost fB = ------------------------ x 100% speedSTM32
Девиация скорости fB это нелинейная функция, зависящая от тактовой частоты MCU и скорости хоста. Максимум функции (fB) увеличивается с увеличением скорости хоста. Причина в том, что для достижения высокой скорости должны быть применены меньшие значения прескалера скорости (baud rate prescale factors), с подразумеваемой более высокой ошибки квантования.
Минимальная скорость. Предел минимальной скорости (BLow) установлен 1200 бод. Скорости ниже BLow приводят к переполнению счетчика таймера SysTick, при этом USARTx не может быть корректно инициализирован.
Максимальная скорость. Верхний проверенный предел скорости (BHigh) составляет 115200 бод. Все стандартные скорости между BLow и BHigh удовлетворяют заданному пределу девиации 2.5%.
[Команды загрузчика]
Поддерживаемые команды bootloader перечислены в таблице 2.
Таблица 2. Команды USART bootloader.
Команда(1)
Код
Описание команды
Get(2)
0x00
Получение от загрузчика его версии и допустимых команд, поддерживаемых в текущей версии загрузчика.
Get Version & Read Protection Status(2)
0x01
Получение версии загрузчика и состояния защиты Flash от чтения.
Get ID(2)
0x02
Получение идентификатора чипа.
Read Memory(3)
0x11
Чтение до 256 байт памяти, начиная с указанного в команде адреса.
Go(3)
0x21
Переход к выполнению кода приложения пользователя, находящегося во внутренней памяти Flash или в RAM.
Write Memory(3)
0x31
Запись до 256 байт в RAM или Flash, начиная с указанного адреса.
Erase(3)(4)
0x43
Стирание одной, нескольких, или всех страниц Flash.
Extended Erase(3)(4)
0x44
Стирает одну, несколько или все страницы Flash с использованием режима двухбайтной адресации (команда доступна только в версии v3.0 USART bootloader и в более свежих версиях).
Write Protect
0x63
Разрешает защиту от записи для некоторых секторов.
Write Unprotect
0x73
Запрет защиты от записи для всех секторов Flash.
Readout Protect
0x82
Разрешает защиту от чтения.
Readout Unprotect(2)
0x92
Запрещает защиту от чтения.
Примечания:
(1) Если принята запрещенная команда или произошла ошибка при выполнении команды, загрузчик отправит обратно байт NACK и снова перейдет в режим получения и проверки команд. (2) Защита от чтения. Когда активна опция RDP (ReaD Protection), доступен только ограниченный набор команд (защита от несанкционированного доступа к коду приложения STM32). В ответ на все другие команды будет выдан NACK, и они не окажут никакого влияния на MCU. Только после удаления RDP будут доступны другие команды. (3) См. даташит на используемый STM32 и апноут AN2606 [2], чтобы определить допустимые области памяти для этих команд. (4) Команды Erase (x043) и Extended Erase (0x44) взаимоисключающее. Устройство может поддерживать либо команду Erase, либо команду Extended Erase, но не обе эти команды.
Поддержка целостности передаваемых данных. Весь обмен между утилитой программирования (программа, работающая на хосте PC) и программируемым MCU проверяется следующим образом:
1. Контрольная сумма: принятые блоки байт данных подвергаются операции XOR. Байт, содержащий вычисленное значение XOR всех предыдущих байт (байт контрольной суммы) добавляется в конец каждого сеанса обмена. Если сложить операцией XOR все принятые байты пакета и байт контрольной суммы, то должен в результате получиться 0 (0x00). 2. Для каждой команды хост отправляет байт и его комплемент (XOR = 0x00). 3. UART: активирована проверка четности (even parity).
Каждый пакет подтверждается положительно (ответ ACK) или отрицательно, т. е. отбрасывается (ответ NACK):
ACK = 0x79 NACK = 0x1F
Ниже во врезках приведено подробное описание команд загрузчика.
Команда Get позволяет узнать версию bootloader и поддерживаемые команды. Когда bootloader получает команду Get, он передаст свою версию и поддерживаемые коды команд, как показано на рис. 2.
Рис. 2. Работа команды Get на стороне хоста.
Рис. 3. Работа команды Get на стороне STM32.
Поток байт, который отправляет STM32, следующий:
Байт 1: ACK. Байт 2: N = 11, что равно количеству байт, которое идет далее – 1 (кроме текущего байта и байт ACK-ов). Байт 3: Bootloader version (0 < version < 255), например 0x10 означает version 1.0. Байт 4: 0x00 команда Get. Байт 5: 0x01 команда получения версии и состояния защиты от чтения (Read Protection Status). Байт 6: 0x02 команда Get ID. Байт 7: 0x11 команда Read Memory. Байт 8: 0x21 команда Go. Байт 9: 0x31 команда Write Memory. Байт 10: 0x43 или 0x44, команда Erase или Extended Erase. Байт 11: 0x63 команда Write Protect. Байт 12: 0x73 команда Write Unprotect. Байт 13: 0x82 команда Readout Protect. Байт 14: 0x92 команда Readout Unprotect. Байт 15: ACK.
Команда используется для получения версии загрузчика (Version) и текущего статуса защиты чтения памяти (Read Protection Status). После получения этой команды загрузчик передаст свою версию состояние защиты и количество раз, сколько защита была разрешена и запрещена хостом.
Рис. 4. Работа команды Get Version & Read Protection Status на стороне хоста.
Рис. 5. Работа команды Get Version & Read Protection Status на стороне STM32.
Поток байт, который отправляет STM32, следующий:
Байт 1: ACK. Байт 2: версия загрузчика (0 < version < 255), например 0x10 означает version 1.0. Байт 3: первый байт опции: 0x00 для совместимости со старым протоколом (generic bootloader protocol). Байт 4: второй байт опции: 0x00 для совместимости со старым протоколом (generic bootloader protocol). Байт 5: ACK.
Команда Get ID используется для получения версии чипа (chip ID, идентификация). Когда загрузчик получает эту команду, от передаст хосту идентификатор продукции (product ID, сокращенно PID).
Рис. 6. Работа команды Get ID на стороне хоста.
Рис. 7. Работа команды Get ID на стороне STM32.
Поток байт, который отправляет STM32, следующий:
Байт 1: ACK. Байт 2: N, равное количеству байт - 1 (для STM32 значение N = 1) без текущего байта и ACK-ов. Байты 3 и 4: PID, где байт 3 = 0x04, байт 4 = 0xXX. Байт 5: ACK.
Команда Read Memory используется для чтения данных из любого допустимого адреса (см. даташит на используемый STM32 и апноут AN2606 [2]) в RAM, памяти Flash и информационного блока (system memory или область байта опций).
Рис. 8. Работа команды Read Memory на стороне хоста.
Примечание: некоторые STM32 могут возвратить два NACK-а вместо одного NACK, когда активна защита от чтения (ReaD Protection, RDP), или активен уровень 1 этой защиты (ReaD Protection level 1). Чтобы узнать, какой STM32 вернет один NACK, а какой два, см. в [2] описание известных ограничений.
Описание алгоритма работы хоста: хост посылает байты 1-2: 0x11 + 0xEE, затем ждет от STM32 ответа ACK. После этого посылает байты адреса 3 .. 6, где байт 3 это старший байт адрес (MSB), байт 6 это младший байт (LSB). Отправляется байт 7 с контрольной суммой XOR (сумма вычисляется от байт 3, 4, 5 и 6). После этого ждет ACK от STM32. После получения ACK передается байт 8: количество читаемых байт -1 (0 < N ≤ 255) и затем байт 9 контрольной суммы (XOR байта 8, т. е. комплемент байта 8).
Рис. 9. Работа команды Read Memory на стороне STM32.
Описание алгоритма работы STM32: Когда загрузчик принимает команду Read Memory, он передает байт ACK. После передачи ACK загрузчик ждет адрес (4 байта, где первый байт в последовательности MSB, и четвертый байт LSB) и байт контрольной суммы, после чего проверяет полученный адрес. Если адрес допустимый, и контрольная сумма правильная, загрузчик передает ACK иначе передаст NACK (NACK оборвет выполнение команды).
Когда адрес допустимый, и контрольная сумма правильная, загрузчик ждет количество передаваемых байт -1 (N, где N может быть в диапазоне от 0 до 255) и его байт комплемента (контрольную сумму XOR). Если контрольная сумма правильная, загрузчик передаст хосту запрошенное количество байт (N + 1), начиная с указанного адреса. Если контрольная сумма неправильная, загрузчик передаст NACK перед обрывом выполнения команды.
Команда Go используется для запуска загруженного или любого другого кода путем безусловного перехода по указанному адресу. Когда загрузчик принял команду Go, он передает обратно байт ACK. После передачи байта ACK загрузчик ждет адрес (4 байта, 1-й байт MSB и 4-й LSB) и байт контрольной суммы, после чего проверяет полученный адрес. Если адрес допустимый, и контрольная сумма корректная, загрузчик передает байт, иначе передаст байт NACK и обрывает выполнение команды.
Когда адрес правильный, и контрольная сумма корректна, загрузчик выполняет следующее:
• Инициализирует регистры периферийных устройств, которые использовались загрузчиком, в их исходное состояние после сброса. • Инициализирует основной указатель стека приложения пользователя. • Делает jump на адрес (address + 4), где address это принятый в команде Go адрес (соответствует адресу обработчика сброса приложения, application reset handler).
Например, если принятый адрес 0x08000000, то bootloader делает безусловный переход (jump) по адресу 0x08000004. В общем случае хост должен передать в команде Go адрес, где находится запрограммированный адрес начального безусловного перехода приложения (команда jump, находящаяся на месте обработчика сброса).
Рис. 10. Работа команды Go на стороне хоста.
Для команды Go допустим адрес, указывающий на код в RAM или во Flash (см. даташит на используемый STM32 и AN2606 [2] для дополнительной информации по допустимым адресам). Все другие адреса считаются недопустимыми, и на команду Go с недопустимым адресом загрузчиком будет в ответ выдан байт NACK.
Когда приложение загружено в RAM, и jump делается на область в RAM, программа должна быть сконфигурирована для запуска со смещением, чтобы избежать перекрытия с первой областью памяти, которую использует firmware загрузчика (подробности также см. в даташите на используемый STM32 и апноут AN2606 [2]).
Jump в приложение корректно сработает только если в приложении установлена корректная таблица векторов прерываний, чтобы она указывала на адрес приложения.
Примечание: некоторые STM32 могут возвратить 2 байта NACK вместо одного, когда активна защита чтения (ReaD Protection, RDP), или когда активен уровень защиты 1 (ReaD Protection level 1). Чтобы узнать, какой STM32 возвратит 1 или 2 байта NACK в этой ситуации, см. описание известных ограничений в AN2606 [2].
Рис. 11. Работа команды Go на стороне STM32.
Хост отправит в STM32 следующее:
Байт 1: 0x21 Байт 2: 0xDE Затем хост ждет ACK, и отправит в байтах 3..6 адрес старта (байт 3 MSB, байт 6 LSB), после чего отправит байт 7 с контрольной суммой (результат XOR байт 3, 4, 5 и 6).
Команда Write Memory используется для записи данных в любую допустимую область память (см. примечание ниже), например в RAM, во Flash или в область байта опций.
Когда загрузчик принял команду Write Memory, он передает хосту обратно байт ACK. После передачи ACK загрузчик ждет получения адреса (4 байта, 1-й байт MSB и 4-й LSB) и байт контрольной суммы, после чего проверяет полученный адрес. Для области байта опций начальный адрес должен быть базовым адресом области байта опций (option byte area, см. примечание), чтобы избежать неуместной записи в этой области.
Если принятый адрес допустимый, и контрольная сумма корректна, то загрузчик передаст байт ACK, иначе передаст байт NACK и оборвет выполнение команды. Когда адрес допустим, и контрольная сумма корректна, загрузчик делает следующее:
• Получает байт N, который содержит количество принимаемых байт (количество равно N+1). Значение N+1 должно нацело делиться на 4. • Принимает данные (N + 1 байт) и контрольную сумму (XOR от значения N и всех байт данных). • Программирует данные в память, начиная с указанного (принятого) адреса. • По завершению команды, если операция записи была успешной, загрузчик передаст байт ACK; иначе будет отправлен байт NACK, и выполнение команды обрывается.
Максимальная длина записываемого блока для STM32 равна 256 байтам.
Если команда Write Memory была выдана для option byte area, то все байты в этой области будут стерты перед записью новых значений, и по завершению команды загрузчик генерирует системный сброс, чтобы установки новых значений байт опций вступили в силу.
Примечание: при записи в RAM пользователь не должен перекрыть первую область памяти, используемую firmware загрузчика. Не будет возвращена ошибка при выполнении операции записи в сектора, запрещенные для записи. Не будет возвращена ошибка, когда начальный адрес неправильный.
Рис. 12. Работа команды Write Memory на стороне хоста.
Примечание: некоторые STM32 могут возвратить 2 байта NACK вместо одного, когда активна защита чтения (ReaD Protection, RDP), или когда активен уровень защиты 1 (ReaD Protection level 1). Чтобы узнать, какой STM32 возвратит 1 или 2 байта NACK в этой ситуации, см. описание известных ограничений в AN2606 [2].
Хост отправляет байты к STM32 следующим образом:
Байт 1: 0x31 Байт 2: 0xCE Затем ждет ACK от STM32, и передает байты адреса 3 .. 6 (байт 3 MSB, байт 6 LSB). Байт 7: контрольная сумма (XOR от байт 3, 4, 5 и 6). Затем хост ждет ACK. Байт 8: N, количество передаваемых байт (0 < N ≤ 255), что соответствует передаче N+1 байт данных (максимум 256 байт). Байт контрольной суммы: XOR от N и от N+1 байт данных.
Рис. 13. Работа команды Write Memory на стороне STM32.
Команда Erase Memory позволяет хосту стереть страницы памяти Flash STM32. Когда загрузчик примет команду Erase Memory, он передает хосту байт ACK, после чего загрузчик принимает один байт количества стираемых страниц, коды страницы памяти Flash и байт контрольной суммы. Если контрольная сумма корректна, то загрузчик сотрет память и отправит хосту байт ACK, иначе отправит NACK и оборвет выполнение команды.
Как работает команда Erase Memory:
1. Загрузчик принимает байт, в котором содержится значение N, соответствующее количеству стираемых страниц -1. Значение N = 255 зарезервировано для запросов глобального стирания (mass erase). Для 0 ≤ N ≤ 254, будет стерто (N+1) страниц. 2. Загрузчик примет (N+1) байт, где каждый байт содержит номер страницы Flash.
Примечание: не будет возвращена ошибка, когда выполняются операции стирания на секторах, запрещенных на запись.
Рис. 14. Работа команды Erase Memory на стороне хоста.
Примечание: после отправки команды Erase Memory с контрольной суммой, если хост отправил 0xFF, за которым идут данные, отличающиеся от 0x00, то полное стирание (mass erase) не выполнится, но STM32 вернет ACK.
Рис. 15. Работа команды Erase Memory на стороне STM32.
Хост посылает байты в STM32 следующим образом:
Байт 1: 0x43 Байт 2: 0xBC Хост ждет ACK. Байт 3: 0xFF или количество стираемых страниц –1 (0 ≤ N ≤ максимальное количество страниц). Байт 4: 0x00 (в случае global erase) или (N + 1) байт (номера страниц) и затем контрольную сумму XOR (от N, и от N+1 байт).
Эта команда позволяет хосту очистить страницы памяти Flash STM32, используя двухбайтных режим адресации. Когда загрузчик принимает команду Extended Erase Memory, он в ответ передаст хосту байт ACK. После передачи ACK загрузчик получает 2 байта (количество стираемых страниц), коды страниц Flash (каждый код двухбайтовый, где MSB идет первым) и в завершение байт контрольной суммы (операция XOR над отравленными байтами). Если контрольная сумма корректна, то загрузчик сотрет память и отправит хосту байт ACK, иначе отправит байт NACK и выполнение команды будет оборвано.
Как работает команда Extended Erase Memory:
1. Загрузчик принимает одно полуслово (2 байта), которое содержит N, количество стираемых страниц:
a) Для N = 0xFFFY (где Y в диапазоне от 0 до F) выполняется специальное стирание: - 0xFFFF для глобального стирания (mass erase) - 0xFFFE для bank 1 mass erase - 0xFFFD для bank 2 mass erase - коды 0xFFFC .. 0xFFF0 зарезервированы.
b) Для других значений 0 ≤ N < максимальное количество страниц: будет стерто (N+1) страниц.
2. Загрузчик принимает:
a) В случае специальной очистки один байт, контрольную сумму от предыдущих байт: - 0x00 для 0xFFFF - 0x01 для 0xFFFE - 0x02 для 0xFFFD.
b) В случае стирания N+1 страниц загрузчик примет (2 x (N+1)) байт, где каждое полуслово содержит номер стираемой страницы. Номер страницы кодируется двумя байтами полуслова, где первый байт старший (MSB). После этих байт принимается байт контрольной суммы (XOR от всех предыдущих байт).
Примечание: не будет возвращена ошибка, когда выполняются операции стирания над секторами, запись в которые запрещена. Максимальное количество страниц зависит от используемого STM32 и оно должно соблюдаться.
Рис. 16. Работа команды Extended Erase Memory на стороне хоста.
Рис. 17. Работа команды Extended Erase Memory на стороне STM32.
Хост отправляет байты в STM32F1xxx следующим образом:
Байт 1: 0x44 Байт 2: 0xBB Хост ждет ACK. Байты 3-4: - special erase (0xFFFF, 0xFFFE или 0xFFFD) ИЛИ – количество стираемых страниц N+1, где 0 ≤ N < максимальное количество страниц).
Остальные байты:
– контрольная сумма байт 3-4 в случае special erase (0x00 если 0xFFFF, или 0x01 если 0xFFFE, или 0x02 если 0xFFFD). ИЛИ – (2 x (N + 1)) байт (номера страниц, закодированные двумя байтами, где байт MSB первый), и затем контрольная сумма для байт 3-4 и всех последующих байт).
Команда Write Protect используется для разрешения защиты от записи для некоторых или всех секторов памяти Flash. Когда загрузчик принимает команду Write Protect, он передает хосту байт ACK. После передачи байта ACK загрузчик ждет количество принимаемых байт (номера защищаемых секторов), и затем принимает коды секторов памяти Flash.
По окончании команды Write Protect загрузчик передает байт ACK и генерирует системный сброс, чтобы вступила в силу новая конфигурация байта опций.
Примечание: см. даташит на используемый STM32 и AN2606 [2] для получения подробностей по размеру сектора.
Команда Write Protect работает следующим образом:
• Загрузчик принимает один байт, который содержит N, количество защищаемых секторов –1 (0 ≤ N ≤ 255). • Загрузчик принимает (N + 1) байт, где в каждом байте содержится код защищаемого сектора.
Примечание: общее количество секторов и номер сектора для защиты не проверяется, т. е. не будет возвращена ошибка, когда команда передала неправильное количество секторов для защиты или неправильный номер сектора. Если будет выполнена вторая команда Write Protect, то сектора памяти Flash, которые были защищены первой командой, перестанут быть защищенными, и будут защищены только те сектора, которые были переданы во второй команде Write Protect.
Рис. 18. Работа команды Write Protect на стороне хоста.
Рис. 19. Работа команды Write Protect на стороне STM32.
Команда Write Unprotect используется для запрета защиты от записи для всех секторов памяти Flash. Когда загрузчик получает команду Write Unprotect, он передаст хосту байт ACK. После передачи байта ACK, загрузчик запретит защиту от записи всех секторов памяти Flash. После операции снятия защиты загрузчик передаст байт ACK.
По окончанию команды Write Unprotect загрузчик передаст байт ACK и сгенерирует системный сброс для того, чтобы вступила в действие новая конфигурация байта опций.
Рис. 20. Работа команды Write Unprotect на стороне хоста.
Рис. 21. Работа команды Write Unprotect на стороне STM32.
Команда Readout Protect используется для разрешения защиты от чтения памяти Flash (RDP). Когда загрузчик получит команду Readout Protect, он передаст хосту байт ACK. После передачи байта ACK загрузчик активирует защиту от чтения памяти Flash.
По окончанию команды Readout Protect command загрузчик передаст байт ACK и сгенерирует системный сброс для того, чтобы вступила в действие новая конфигурация байта опций.
Рис. 22. Работа команды Readout Protect на стороне хоста.
Рис. 23. Работа команды Readout Protect на стороне STM32.
Команда Readout Unprotect используется для запрета (отмены) защиты от чтения памяти Flash (RDP). Когда загрузчик получит команду Readout Unprotect command, он передаст хосту байт ACK. После передачи байта ACK загрузчик сотрет всю память Flash и деактивирует защиту от чтения памяти Flash. Если операция стирания была успешной, загрузчик деактивирует RDP.
Если же операция стирания была неудачной, загрузчик передаст NACK, и защита от чтения RDP останется активной.
По окончанию команды Readout Unprotect загрузчик передаст ACK и сгенерирует системный сброс, чтобы вступила в силу новая конфигурация байта опций.
Примечание: для большинства процессоров STM32 операция снятия защиты запускает процесс полной очистки (mass erase) памяти Flash, поэтому хост должен подождать достаточное количество времени после получения второго ACK и перед перезапуском соединения. Чтобы узнать, какое количество времени занимает эта операция, обратитесь к параметру mass erase time (когда оно указано) в даташите на используемый STM32.
Рис. 24. Работа команды Readout Unprotect на стороне хоста.
Рис. 25. Работа команды Readout Unprotect на стороне STM32.
[Эволюция версий загрузчика USART]
Таблица 3. Версии загрузчиков и их особенности.
Версия
Описание
V2.0
Первоначальная версия загрузчика.
V2.1
– Обновлена команда Go для инициализации основного указателя стека. – Обновлена команда Go, чтобы возвратить NACK, когда jump-адрес находится в области байта опций (option byte area) или в области системной памяти (system memory area). – Обновлена команда Get ID, чтобы возвратить device ID в 2 байтах. – Обновлена версия загрузчика (bootloader version) до V2.1.
V2.2
– Обновлены команды Read Memory, Write Memory и Go, чтобы запретить доступ (с ответом NACK) к первым байтам RAM, используемым в загрузчике. – Обновлена команда Readout Unprotect, чтобы инициализировать все содержимое RAM значением 0x0 перед операцией запрета RDP.
V3.0
– Добавлена команда Extended Erase, чтобы поддерживать большее, чем 256, количество страниц Flash, и реализовать полную очистку банков по отдельности (separate bank mass erase). – Команда Erase не была модифицирована в этой версии, однако было добавлено, что команда Extended Erase не поддерживается (команды Erase и Extended Erase взаимоисключающие, т. е. они не поддерживаются одновременно).
V3.1
– Ограниченное исправление следующей ошибки: "Когда команда Read Memory или команда Write Memory выдается с не поддерживаемым адресом памяти, и при этом контрольная сумма адреса корректа (например, адрес 0x60000000), выполнение команды обрывается загрузчиком, но NACK (0x1F) хосту не отправляется. В результате следующие 2 байта (т. е. количество байт для чтения/записи и их контрольная сумма) считаются новой командой и её контрольной суммой"(1). – Нет изменений в спецификации, но реализация продукта (MCU и его загрузчик) была скорректирована.
Примечание (1): если "number of data - 1" (N-1) для чтения/записи (read/write) не соответствует допустимому коду команды (0x00, 0x01, 0x02, 0x11, 0x21, 0x31, 0x43, 0x44, 0x63, 0x73, 0x82 или 0x92), тогда ограничение не воспринимается от хоста как команда, и по-любому завершается отрицательным подтверждением NACK (как неподдерживаемая новая команда).