47861

[i] Запуск микроконтроллера для управления двигателями К1986ВК01GI в режиме DUALCORE | IDE Keil

Дата последнего изменения: 17.10.2022 16:00:27

Микроконтроллер для управления двигателями К1986ВК01GI (Электросила 2.0) выполнен на базе двух ядер ARM Cortex-M4F. По сбросу два ядра МК работают в режиме LOCKSTEP. При этом первое ядро выполняет инструкции программы, а второе ядро только дублирует все операции первого ядра с задержкой в два такта. Данный режим применяется для обнаружения сбоев в работе МК путём сравнения поведения первого и второго ядра.
При необходимости режим LOCKSTEP может быть отключен, и тогда два ядра становятся независимыми (режим DUALCORE) и могут исполнять различные программы, что увеличивает общую производительность МК.

В данной статье рассмотрен пример перехода МК из режима LOCKSTEP в режим DUALCORE при использовании среды Keil, а также показаны некоторые особенности двухъядерной отладки.

Проект для работы МК в двухъядерном режиме

Процесс запуска МК в режиме DUALCORE рассмотрен на примере проекта "SMP" (Symmetric Multi-Processing) для среды Keil. Проект приложен в материалах к данной статье.

Для одновременной отладки сразу двух ядер в среде Keil подходят следующие отладчики:

В данной статье для отладки МК "Электросила" будет использован CMSIS-DAP совместимый программатор для микросхем с ядром CORTEX-M производства АО "ПКК Миландр".

Настройка среды Keil для двухъядерной отладки

Запустим проект "SMP" и выполним настройку среды Keil. 

Переходим в настройки отладчика "Options for Target→Debug→Settings". В поле "AP" осуществляется выбор ядра, к которому будет подключаться отладчик. Так как после сброса МК работает в режиме LOCKSTEP, то отладчик имеет доступ только к ядру 0, поэтому в "AP" указываем значение "0x00", как показано на рисунке 1. Для вывода информации в консоль отладки через порт ITM обязательно необходимо установить режим работы отладчика "SW (Serial Wire)".

Рисунок 1 - Настройки отладчика CMSIS-DAP

На рисунке 2 представлена структурная схема МК К1986ВК01GI, работающего в режиме LOCKSTEP.

Рисунок 2 - Структурная схема МК К1986ВК01GI в режиме LOCKSTEP

В примере "SMP" МК переводится в режим DUALCORE, поэтому после запуска данного проекта два процессорных ядра начнут работать независимо, при этом отладчик сможет подключиться ко второму ядру (рисунок 3).

Рисунок 3 - Структурная схема МК К1986ВК01GI в режиме DUALCORE

На рисунках 2 и 3 приведены частные случаи обращения ядер и блоков DMA к различным областям памяти, показывающие их параллельную и независимую работу. Подробная организация доступа системных шин к областям памяти приведена в спецификации, рисунок "Схема организации доступа системных шин к различным областям ИМС".
Остановимся подробнее на процессе перехода из режима LOCKSTEP в режим DUALCORE.

Процесс перехода из режима LOCKSTEP в режим DUALCORE

Переход из режима LOCKSTEP в режим DUALCORE и обратно должен быть следующим.

Рекомендуемая процедура переключения из режима LOCKSTEP в режим DUALCORE:

Процедура выполняется при выключенных DMA, кэш и прерываниях.
1. Разблокировать запись в регистры батарейного домена, записав ключ в регистр BKP_KEY.
2. Установить бит LOCKSTEP_DIS регистра REG_60_SYS.
3. Очистить конвейер инструкцией DSB.
4. В зависимости от выполнения условия CPUID==0 передать управление на разные участки кода, загрузить разные значения в указатели стека.

Рекомендуемая процедура переключения из режима DUALCORE в режим LOCKSTEP:

1. Разблокировать запись в регистры батарейного домена, записав ключ в регистр BKP_KEY.
2. Сбросить бит LOCKSTEP_DIS регистра REG_60_SYS.
3. Очистить конвейер инструкцией DSB.
4. Выполнить сброс процессора, установив бит SYSRESETREQ регистра AIRCR.

В проекте "SMP" переход в режим DUALCORE осуществляется в файле startup.s, обработчик Reset_Handler(). Программа обработчика Reset_Handler() приведена во фрагменте кода 1.

Фрагмент кода 1 - Обработчик Reset_Handler()

LDR R0, =BKP_BASE_KEY ; Запись ключа в регистр KEY контроллера BKP
LDR R1, =BKP_KEY
STR R1, [R0]
  
LDR R0, =BKP_RG60_0 ; Формирование значения с установленным режимом DUALCORE для регистра REG60
LDR R1,[R0]
AND R1,#~0x7E00
ORR R1,R1,#0x0200  

DMB.W              ; Очистка конвейера инструкций 
DSB.W
ISB.W

STR R1,[R0,#0x00]  ; Запись сформированного значения в регистр REG60, переход в DUALCORE

DMB.W              ; Очистка конвейера инструкций 
DSB.W
ISB.W

После исполнения данного кода произойдёт переход в режим DUALCORE, при этом ядро 0 и ядро 1 продолжат выполнять программу уже по отдельности.

Чтобы два ядра могли совместно исполнять программу, необходимо указать для каждого из них отдельный стек и кучу. В проекте это сделано в файле startup.s, функция __user_setup_stackheap, которая вызывается библиотекой C во время запуска программы, т.е. после перехода в __main. Подробнее про это описано на официальном сайте Keil. Описание функции __user_setup_stackheap приведено во фрагменте кода 2.

Фрагмент кода 2 - Функция __user_setup_stackheap, осуществляющая выделение для ядер отдельных областей стека и кучи

 __user_setup_stackheap 
  LDR R0, =SMP_REG 
  LDR R0,[R0] 
  TST R0,#1 ; Если значение по адресу SMP_REG == 1, тогда перейти в функцию setup_core1
  BNE setup_core1

setup_core0
  LDR R0, =(Heap_Mem0 )
  LDR R2, =(Heap_Mem0 + Heap_Size )
  LDR sp, =(Stack_Mem )
  BX LR

setup_core1
  LDR R0, =(Heap_Mem1 )
  LDR R2, =(Heap_Mem1 + Heap_Size )
  LDR sp, =(Stack_Mem1 ) BX LR
Здесь и далее "SMP_REG" обозначает регистр идентификации ядра, который содержит один бит: при чтении данного регистра первое ядро получает значение 0, а второе ядро - значение 1. С помощью данного регистра можно легко передать управление на разные участки кода.

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

Запуск двухъядерной отладки

В проекте "SMP" показан пример взаимодействия двух ядер с использованием мьютексов. При этом ядро 0 осуществляет мигание синим светодиодом, а ядро 1 - красным.
В зависимости от номера версии отладочной платы могут отличаться выводы микроконтроллера, отвечающие за диоды указанных цветов.

Выполним запуск программы из памяти ОЗУ, для этого в настройках Keil необходимо выбрать конфигурацию "RAM CMSIS-DAP @0", которая запускает отладку 0-го ядра, как показано на рисунке 4.

Рисунок 4 -  Выбор конфигурации проекта "RAM ULINK2 @0"

За настройку запуска режима отладки отвечает файл инициализации "0x02000000_0.ini", в котором выполняются две операции, показанные в фрагменте кода 3.

Фрагмент кода 3 - Файл инициализации "0x02000000_0.ini"

Setup(0x02000000); // Установить значения SP (указатель стека), PC (счётчик команд), VT (начало таблицы векторов)
g ,main // Запустить выполнение программы с адреса, указанного в PC, и остановиться в начале функции main()

В настройках проекта "Options for Target→Debug" необходимо установить опцию "Load Application at Startup" для загрузки проекта при старте отладки, а также убрать опцию "Run to main()", так как данная операция уже выполняется в файле инициализации (рисунок 5). 

Рисунок 5 - Настройка проекта во вкладке "Options for Target→Debug"

После настройки проекта выполняем сборку и запускаем режим отладки. МК автоматически останавливается в функции main(). Слева внизу в окне "Command" отображается лог запуска отладки, в котором показано, что на момент запуска отладки режим DUALCORE был выключен (равен 0), а отлаживаемое ядро имеет номер 0, как показано на рисунке 6.

Рисунок 6 - Лог отладочной информации в окне "Command" после запуска отладки

Переход в режим DUALCORE и установка различных стеков производится в файле startup.s, поэтому на момент остановки в функции main() два ядра уже работают независимо.

После запуска отладки программатор подключается только к ядру 0 и останавливает его работу, при этом ядро 1 должно продолжать исполнять программу. Однако, здесь есть особенность. Так как программа исполняется из ОЗУ, то отладчик может ставить программные точки останова, т.е. подменять инструкции, на которых необходимо остановиться, на инструкции остановки типа "BKPT #0x00", например, как показано на рисунке 7.

Рисунок 7 - Программная точка останова в дизассемблере

При выполнении команды "g ,main" в файле инициализации такая программная точка останова ставится в начале main(), а так как оба ядра проходят по этому участку кода, то и остановлены они будут тоже оба. Такая ситуация даже удобна, так как точно известно, что оба ядра остановлены в main(), и запустив отладку второго ядра, можно смотреть за ходом выполнения программы. Однако, если необходимо чтобы второе ядро не останавливалось, достаточно закомментировать "g ,main" и при запуске отладки МК будет останавливаться в функции Reset_Handler().

После запуска отладки два ядра остановлены, при этом запустив выполнение программы с помощью клавиши F5, будет работать только ядро 0, на отладочной плате замигает синий светодиод. Теперь запустим отладку второго ядра. Для этого необходимо перейти в папку проекта "SMP" и ещё раз запустить пример (рисунок 8).

Рисунок 8 - Повторное открытие проекта "SMP" для отладки 1 ядра

В настройках Keil выбираем конфигурацию "RAM CMSIS-DAP @1", которая настроена для подключения к 1 ядру. Здесь необходимо обратить внимание, что в настройках отладчика выставлены не совсем типичные настройки, показанные на рисунке 9.

Рисунок 9 - Настройки отладчика CMSIS-DAP для отладки 1-го ядра

В поле "Connect" установлен параметр "without Stop", чтобы при подключении ядро 1 не сбрасывалось, так как оно уже остановлено в main(). Также в файле инициализации изменена опция LOAD, чтобы программа не записывалась заново в память ОЗУ, а загрузилась только отладочная информация (фрагмент кода 4). Это необходимо для Keil, иначе отладка будет только в дизассемблере.

Фрагмент кода 4 - Загрузка отладочной информации в файле инициализации "0x02000000_1.ini"

load %L incremental NOCODE // Загружает только отладочную информацию

Собираем проект и запускаем отладку. В открывшемся окне сессия отладки будет остановлена в начале функции main(), как показано на рисунке 10.

Рисунок 10 - Остановка 1 ядра при запуске сессии отладки

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

Особенности двухъядерной отладки

1. Как уже было отмечено ранее, если программа запускается из ОЗУ, то отладчик CMSIS-DAP или ULINK2 может установить программные точки останова, которые, в случае попадания на общие участки кода, будут останавливать оба ядра.

2. Если в режиме отладки установить точки останова до перехода в режим DUALCORE, то данные точки останова будут действовать на оба ядра даже после перехода в режим DUALCORE.

3. Ядро 0 (CPUA) является ведущим ядром. Использование инструкции синхронизации SEV возможно только от ведущего ядра.

4. Сброс по сигналу SYS_RESET_REQ осуществляет сброс микроконтроллера только при формировании его ведущим ядром CPUA. 

Сохранить статью в PDF

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

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

Теги

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