Межпроцессорное взаимодействие (IPC) в многоядерных микроконтроллерах.
Часть 1. Микроконтроллеры с ядрами Cortex-M4 и Cortex-M0/M0+
Введение
При необходимости повышения производительности системы имеется два подхода для решения этой задачи:
- Увеличение количества процессоров и написание программного обеспечения таким образом, чтобы оно могло распараллеливать общий вычислительный процесс на несколько однотипных ядер. Это подход чаще всего применяется в «больших» многоядерных процессорах и многоядерных микропроцессорах.
- Вынесение части вычислений на процессор со специализированной системой команд или специализированным программным обеспечением. Такой подход чаще всего применяется в начавших появляться в последние годы многоядерных микроконтроллерах. Он позволяет разгрузить центральное ядро от выполнения сложных математических алгоритмов и/или операций ввода/вывода. При этом необходимо обеспечить эффективный механизм обмена данными (межпроцессорного взаимодействия) между ядрами микроконтроллера.
В статье рассмотрены механизмы межпроцессорного взаимодействия нескольких семейств микроконтроллеров от ведущих производителей полупроводниковых компонентов.
Начнем описание с семейства LPC43xxx от NXP.
Конфигурирование многоядерных микроконтроллеров LPC43xx/LPC43Sxx и их подсистемы межпроцессорного взаимодействия
Микросхемы LPC43xx/LPC43Sxx представляют собой многоядерные микроконтроллеры, содержащие одно ядро ARM Cortex-M4 и одно или два ядра ARM Cortex-M0. Все ядра имеют доступ к полной карте распределения памяти. Блок-схема микроконтроллеров семейств LPC43xx/LPC43Sxx представлена на рис. 1.
Ядро ARM Cortex-M4 используется в качестве основного процессора. Одно из ядер ARM Cortex-M0 (M0APP) может применяться как сопроцессор для разгрузки ядра ARM Cortex-M4 и выполнять задачи последовательного ввода/вывода данных. Другое ядро ARM Cortex-M0 (M0SUB), если оно доступно, обычно предназначено для управления специализированными линиями ввода/вывода (SGPIO) и SPI периферийными модулями. Это ядро подключается к основному процессору Cortex-M4 через специальный мост. Блок-схема связей между ядрами микроконтроллеров показана на рис. 2.
Общее описание
После сброса процессор ARM Cortex-M4 используется в качестве высокоуровневого системного контроллера. После подачи напряжения питания или выхода из режима пониженного энергопотребления (Deep power-down mode) ядро (или ядра) Cortex-M0 остается в состоянии сброса до тех пор, пока сигнал сброса не снимется программным обеспечением, выполняющимся на ядре Cortex-M4. Затем ядро Cortex-M4 может обмениваться данными с одним или обоими ядрами Cortex-M0 через разделяемую область памяти и прерывания. Блок-схема обмена данными между ядрами микроконтроллера дана на рис. 3.
Основы конфигурирования процессоров ARM Cortex-M0
Прикладной процессор Cortex-M0 (M0APP) конфигурируется следующим образом:
- Процессор Cortex-M0 сбрасывается сигналом M0APP_RST (reset #56) или общим сигналом сброса (Reset) микроконтроллера.
- После подачи напряжения питания процессор Cortex-M0 остается в состоянии сброса до тех пор, пока сигнал сброса не снимется очисткой соответствующего бита RESET_CTRL1 (табл. 12).
- Прерывание Cortex-M0 к слоту прерываний interrupt slot # 1 контроллера прерываний NVIC процессора Cortex-M4 и слоту прерываний
interrupt slot #31 подсистемы Cortex-M0SUB. - В таблице 2 приведено описание прерываний, подключенных к процессору Cortex-M0APPДля очистки прерывания Cortex-M0 используется регистр M0APPTXEVENT (табл. 6).
В таблице 1 дано описание тактирования и управления электропитанием.
Параметры |
Базовая частота |
Вспомогательная |
Максимальная |
Тактирование Cortex-M0 (для ядра M0APP) |
BASE_M4_CLK |
CLK_M4_M0 |
до 204 МГц |
Тактирование подсистемы Cortex-M0 (для ядра M0SUB) |
BASE_PERIPH_CLK |
CLK_CLK_PERIPH_CORE |
до 204 МГц |
ID прерывания |
Номер |
Смещение вектора |
Функция |
Флаг(и) |
0 |
16 |
0x40 |
M0_RTC |
– |
1 |
17 |
0x44 |
M0_M4CORE |
Прерывание от ядра M4 |
2 |
18 |
0x48 |
M0_DMA |
– |
3 |
19 |
0x4C |
– |
Зарезервировано |
4 |
20 |
0x50 |
M0_FLASHEEPROMAT |
Объединение по ИЛИ прерываний |
5 |
21 |
0x54 |
M0_ETHERNET |
Прерывание от Ethernet |
6 |
22 |
0x58 |
M0_SDIO |
Прерывание от SD/MMC |
7 |
23 |
0x5C |
M0_LCD |
– |
8 |
24 |
0x60 |
M0_USB0 |
Прерывание от OTG |
9 |
25 |
0x64 |
M0_USB1 |
– |
10 |
26 |
0x68 |
M0_SCT |
Комбинированное прерывание от SCTimer/PWM |
11 |
27 |
0x6C |
M0_RITIMER_OR_WWDT |
Объединение по ИЛИ прерываний от таймера RI и WWDT |
12 |
28 |
0x70 |
M0_TIMER0 |
– |
13 |
29 |
0x74 |
M0_GINT1 |
Глобальное прерывание 1 от GPIO |
14 |
30 |
0x78 |
PIN_INT4 |
Прерывание 4 от вывода GPIO |
15 |
31 |
0x7C |
M0_TIMER3 |
– |
16 |
32 |
0x80 |
M0_MCPWM |
ШИМ управления мотором |
17 |
33 |
0x84 |
M0_ADC0 |
– |
18 |
34 |
0x88 |
M0_I2C0_OR_I2C1 |
– |
19 |
35 |
0x8C |
M0_SGPIO |
– |
20 |
36 |
0x90 |
M0_SPI_OR_DAC |
Объединение по ИЛИ прерываний от SPI и ЦАП |
21 |
37 |
0x94 |
M0_ADC1 |
– |
22 |
38 |
0x98 |
M0_SSP0_OR_SSP1 |
Объединение по ИЛИ прерываний от SSP0 и SSP1 |
23 |
39 |
0x9C |
M0_EVENTROUTER |
Маршрутизатор событий |
24 |
40 |
0xA0 |
M0_USART0 |
– |
25 |
41 |
0xA4 |
M0_UART1 |
Прерывание от Modem/UART1 |
26 |
42 |
0xA8 |
M0_USART2_OR_C_CAN1 |
Объединение по ИЛИ прерываний от USART2 и C_CAN1 |
27 |
43 |
0xAC |
M0_USART3 |
– |
28 |
44 |
0xB0 |
M0_I2S0_OR_I2S1_QEI |
Объединение по ИЛИ прерываний от I2S0, I2S1 и QEI |
29 |
45 |
0xB4 |
M0_C_CAN0 |
– |
30 |
46 |
0xB8 |
M0_SPIFI_OR_ADCHS |
Объединение по ИЛИ прерываний от SPIFI и ADCHS |
31 |
47 |
0xBC |
M0_M0SUB |
Ядро M0SUB |
ID прерывания |
Номер |
Смещение вектора |
Функция |
Флаг(и) |
0 |
16 |
0x40 |
M0S_DAC |
– |
1 |
17 |
0x44 |
M0S_M4CORE |
Прерывание от ядра M4 |
2 |
18 |
0x48 |
M0S_DMA |
– |
3 |
19 |
0x4C |
– |
Зарезервировано |
4 |
20 |
0x50 |
M0S_SGPIO_INPUT |
Соответствие бита SGPIO |
5 |
21 |
0x54 |
M0S_SGPIO_MATCH |
Соответствие шаблона SGPIO |
6 |
22 |
0x58 |
M0S_SGPIO_SHIFT |
Сдвиг частоты тактирования SGPIO |
7 |
23 |
0x5C |
M0S_SGPIO_POS |
Захват частоты тактирования SGPIO |
8 |
24 |
0x60 |
M0S_USB0 |
Прерывание от OTG |
9 |
25 |
0x64 |
M0S_USB1 |
– |
10 |
26 |
0x68 |
M0S_SCT |
Комбинированное прерывание от SCTimer/PWM |
11 |
27 |
0x6C |
M0S_RITIMER |
Прерывание от таймера RI |
12 |
28 |
0x70 |
M0S_GINT1 |
Глобальное прерывание 1 от GPIO |
13 |
29 |
0x74 |
M0S_TIMER1 |
– |
14 |
30 |
0x78 |
M0S_TIMER2 |
– |
15 |
31 |
0x7C |
M0S_PIN_INT5 |
Прерывание 5 от вывода GPIO |
16 |
32 |
0x80 |
M0S_MCPWM |
ШИМ управления мотором |
17 |
33 |
0x84 |
M0S_ADC0 |
– |
18 |
34 |
0x88 |
M0S_I2C0 |
– |
19 |
35 |
0x8C |
M0S_I2C1 |
– |
20 |
36 |
0x90 |
M0S_SPI |
Прерывание от SPI |
21 |
37 |
0x94 |
M0S_ADC1 |
– |
22 |
38 |
0x98 |
M0S_SSP0_OR_SSP1 |
Объединение по ИЛИ прерываний от SSP0 и SSP1 |
23 |
39 |
0x9C |
M0S_EVENTROUTER |
Маршрутизатор событий |
24 |
40 |
0xA0 |
M0S_USART0 |
– |
25 |
41 |
0xA4 |
M0S_UART1 |
Прерывание от Modem/UART1 |
26 |
42 |
0xA8 |
MS0_USART2_OR_C_CAN1 |
Объединение по ИЛИ прерываний |
27 |
43 |
0xAC |
M0S_USART3 |
– |
28 |
44 |
0xB0 |
M0S_I2S0_OR_I2S1_OR_QEI |
Объединение по ИЛИ прерываний от I2S0, I2S1 и QEI |
29 |
45 |
0xB4 |
M0S_C_CAN0 |
– |
30 |
46 |
0xB8 |
M0S_SPIFI_OR_ADCHS |
Объединение по ИЛИ прерываний от SPIFI и ADCHS |
31 |
47 |
0xBC |
M0S_M0APP |
Ядро M0APP |
Подсистема Cortex-M0 (M0SUB) конфигурируется следующим образом:
- В таблице 1 описано тактирование и управление электропитанием.
- Подсистема Cortex-M0 сбрасывается сигналом M0SUB_RST (reset # 12) или общим сигналом сброса (Reset) микроконтроллера.
- После подачи напряжения питания подсистема Cortex-M0 остается в состоянии сброса до тех пор, пока сигнал сброса не снимется очисткой соответствующего бита RESET_CTRL0 bit (табл. 11).
- Прерывание от ядра подсистемы Cortex-M0 подключено к слоту прерываний slot # 50 контроллера прерываний NVIC процессора Cortex-M4 и слоту прерываний slot #31 контроллера прерываний NVIC процессора Cortex-M0APP. В таблице 3 приведено описание прерываний, подключенных к ядру подсистемы Cortex-M0.
- Для очистки прерываний подсистемы Cortex-M0 используется
регистр M0SUBTXEVENT (табл. 4).
Бит |
Символ |
Значение |
Описание |
Значение |
Права |
0 |
TXEVCLR |
– |
Событие TXEV от Cortex-M0SUB |
0 |
R/W |
0 |
Очистка события TXEV |
– |
– |
||
1 |
Нет эффекта |
– |
– |
||
31:1 |
– |
– |
Зарезервировано |
– |
– |
Аппаратное обеспечение
Вместо специализированного аппаратного обеспечения блок межпроцессорного обмена (IPC) использует существующие аппаратные компоненты. Под буферы разделяемой памяти можно отвести любую доступную область СОЗУ (SRAM). Указатели на буферы поддерживаются программным обеспечением. Прерывания захватываются процессорным контроллером вложенных векторных прерываний (NVIC) и очищаются в блоке CREG (табл. 5 и 6).
Бит |
Символ |
Значение |
Описание |
Значение |
Права |
0 |
TXEVCLR |
|
Событие TXEV от Cortex-M4 |
0 |
R/W |
0 |
Очистка события TXEV |
– |
– |
||
1 |
Нет эффекта |
– |
– |
||
31:1 |
– |
– |
Зарезервировано |
– |
– |
Бит |
Символ |
Значение |
Описание |
Значение |
Тип |
0 |
TXEVCLR |
– |
Событие TXEV от Cortex-M0APP |
0 |
R/W |
0 |
Очистка события TXEV |
– |
– |
||
1 |
Нет эффекта |
– |
– |
||
31:1 |
– |
– |
Зарезервировано |
– |
– |
Обработка прерываний
Ядра CPU выставляют прерывания к другому ядру или ядрам CPU, используя инструкцию TXEV. Если оба CPU настроены для ответа на одно и то же прерывание, то в архитектуру программного обеспечения необходимо добавить средства разграничения сообщений для различных CPU — например, команды в буфере команд должны содержать информацию о том, для какого CPU предназначена команда.
Процессоры Cortex-M4 и Cortex-M0 выставляют прерывания один для другого посредством регистров очистки прерывания (CREG) M4TXEVENT, M0SUBTXEVENT и M0APPTXEVENT (табл. 4–6). Прерывания от процессора Cortex-M4 к процессору Cortex-M0 и от процессора Cortex-M0 к процессору Cortex-M4 используют инструкцию SendEvent (SEV) для выставления сигнала TXEV. Сигнал захватывается одним из регистров CREG. Он должен быть очищен обработчиком прерываний принимающего ядра.
Доступ к M0SUB
Ядро M0SUB подключено к главной матрице шин AHB matrix посредством моста, который вносит задержку при прохождении сигнала от подсистемы M0sub к главной матрице шин AHB matrix. Для минимизации этой задержки мост применяет буфер записи; его по возможности следует использовать при доступе для записи.
Пример реализации протокола межпроцессорного взаимодействия
Межпроцессорное взаимодействие (IPC) поддерживает низкоуровневые интерфейсы, например интерфейс уровня регистров, но может быть реализовано и в виде высокоуровневого API.
В рассматриваемом примере главный процессор (CPU) с ядром Cortex-M4 является ведущим устройством (master). Он инициирует команды к процессору Cortex-M0, которые имитируют аппаратный интерфейс уровня регистров. Команды могут выдаваться либо синхронно (с ожиданием ответных сообщений), либо асинхронно (без ожидания ответных сообщений), в зависимости от приложения, запущенного на главном процессоре.
Процессор Cortex-M0 отвечает на команды, выданные процессором Cortex-M4, используя сообщения.
Поскольку процессоры Cortex-M4 и Cortex-M0 не могут одновременно осуществлять запись в одну и ту же область памяти, в таком варианте межпроцессорного взаимодействия требуется объект, осуществляющий синхронизацию (например, семафор).
Основные особенности межпроцессорного взаимодействия (IPC):
- Процессор Cortex-M4 инициализирует подсистему на процессоре Cortex-M0.
- Процессор Cortex-M4 обменивается данными с подсистемой на процессоре Cortex-M0 с помощью очереди команд (command queue).
- Очереди сообщений (message queue) расположены в адресном пространстве процессора Cortex-M4, поскольку процессор Cortex-M4 может быть блокирован от доступа к аппаратной подсистеме процессора Cortex-M0. Подсистему Cortex-M0 можно сделать более детерминированной (и защищенной), если в ней не будет происходить неизвестных операций. Клиентское приложение, выполняющееся на ядре Cortex-M4 в адресном пространстве Cortex-M0, может заблокировать работу самого ядра Cortex-M0 и, как следствие, вызвать проблемы с производительностью процессора Cortex-M0.
Очереди при межпроцессорном взаимодействии
Процессор Cortex-M4 имеет очередь выходных команд (command queue) и очередь входных сообщений (message queue). Параметры очереди задаются в четырех регистрах:
- Начальный адрес очереди (queue start address).
- Конечный адрес очереди (queue end address).
- Указатель на запись (write pointer).
- Указатель на чтение (read pointer).
Процессор Cortex-M4 инициализирует все четыре регистра, которые расположены в той же самой разделяемой области ОЗУ (shared SRAM), что и очереди, чтобы обеспечить синхронность изменений данных и значений регистров. Эта область является статической и ее расположение известно процессору Cortex-M0.
Сообщения проходят через очереди с использованием циклических буферов. Очередь заполняется командами или сообщениями с начального адреса (start address) по конечный адрес (end address). Когда указатель буфера выходит за пределы конечного адреса (end address), то возвращается к начальному адресу (start address). Когда указатель на чтение (read pointer) совпадает с указателем на запись (write pointer), очередь может быть либо пустой, либо полностью заполненной. Чтобы избежать этой неопределенности, очередь никогда не должна заполняться полностью (!). Таким образом, минимальный размер очереди составляет 3 слова (максимальный размер команды/сообщения + 1 слово). Совпадение указателей на запись (write pointer) и на чтение (read pointer) будет указывать на пустую очередь.
Очередь команд заполняется процессором Cortex-M4 и опустошается процессором Cortex-M0. Указатель записи (write pointer) увеличивается процессором Cortex-M4 каждый раз, когда он добавляет в очередь новую команду. Указатель чтения (read pointer) увеличивается процессором Cortex-M0 каждый раз, когда он извлекает команду из очереди.
Очередь сообщений (message queue) заполняется процессором Cortex-M0 и опустошается процессором Cortex-M4. Указатель записи (write pointer) увеличивается процессором Cortex-M0 каждый раз, когда он добавляет новое сообщение в очередь. Указатель чтения (read pointer) увеличивается Cortex-M4 каждый раз, когда он извлекает команду из очереди.
Если новая команда или сообщение добавляется в очередь и обновляется указатель записи (write pointer), выставляется прерывание к другому процессору. В ответ на команду возвращается сообщение (принято или отказано в обработке).
Процессоры Cortex-M4 и Cortex-M0 имеют только одну IPC-задачу на чтение и одну на запись.
При наличии нескольких экземпляров объекта локальный арбитр должен убедиться, что операции записи и чтения являются атомарными. После записи (чтения) данных указатель записи (чтения) обновляется, перед тем как начнется другая операция записи (чтения).
Процесс, производящий запись в очередь, должен убедиться, что очередь не заполнена полностью. Перед загрузкой нового элемента процесс должен получить подтверждение, что указатель записи (write pointer) не равен или больше указателя на чтение (read pointer) и в очереди имеется хотя бы одно свободное место. В то же время принимающая сторона должна оперативно обрабатывать записи и удалять их из очереди.
Явная обработка ошибок не выполняется. Предполагается, что процессор Cortex-M0 всегда способен отвечать на команды от процессора Cortex-M4.
Протокол межпроцессорного обмена
Процессор Cortex-M0 используется в качестве сопроцессора для разгрузки процессора Cortex-M4 и выполнения задач последовательного ввода/вывода. Процессор Cortex-M4 инициализирует задачи, выполняемые процессором Cortex-M0, и способен сигнализировать Cortex-M4 об успешном или неуспешном завершении этих задач, отвечая ему соответствующим сообщением. Такой интерфейс команд и сообщений напоминает аппаратный интерфейс уровня регистров с регистром команд (command register) и регистром состояния (status register).
Процессор Cortex-M4 направляет 32‑битные команды процессору Cortex-M0. Каждая команда начинается с аргумента id (P), за которым следует бит чтения/записи, а за ним — 16‑битный идентификатор ID, определяющий, к какой задаче относится данная команда. Младший значащий бит идентификатора задачи ID указывает на тип команды. За командой записи (Write command) следует 32‑битный операнд. Когда становится доступной новая команда, процессор Cortex-M4 сигнализирует об этом процессору Cortex-M0, выставляя прерывание.
Процессор Cortex-M0 возвращает процессору Cortex-M4 32‑битные сообщения, начинающиеся с аргумента id (P или S), за которым следует 16‑битный идентификатор ID, определяющий, к какой задаче относится данное сообщение. Младший значащий бит указывает на тип сообщения. За сообщением ответа на чтение (Read response message) следует 32‑битный операнд чтения. Когда становится доступным новое сообщение, процессор Cortex-M0 сигнализирует об этом процессору Cortex-M4, выставляя прерывание.
Небольшую передачу данных можно выполнить с помощью единственного чтения 32‑битных данных CMD_RD_ID и записи команд CMD_WR_ID. Эти команды используют 3‑байтовую схему адресации для поддержки пространства аргументов размером 212 = 4096 32‑битных слов. Передача больших объемов данных может оказаться эффективнее благодаря применению указателей (pointer). Высокоуровневые интерфейсы, основанные на вызовах API, также чаще всего используют основанные на указателях операции косвенного чтения и записи.
При одновременной реализации нескольких задач идентификаторы ID используются для различения команд и сообщений, относящихся к разным задачам. Для запуска команд, выполняющихся в задачах на процессоре Cortex-M0, должен применяться глобальный синтаксический анализатор (command parser).
То же самое справедливо и на стороне процессора Cortex-M4. Глобальный анализатор сообщений (message parser) направляет сообщения обратно в диспетчер задач, осуществляющийся на стороне процессора Cortex-M4.
В таблицах 7–9 приведено детальное описание протокола межпроцессорного взаимодействия (IPC).
Команда |
Битовая маска |
Описание |
CMD_RD_ID |
0xPPP0.TTTT |
Чтение 32-битного слова (WORD) с аргументом ID = 0xPPP для задачи с ID = 0xTTTT |
CMD_WR_ID |
0xPPP1.TTTT, WORD |
Запись 32-битного слова (WORD) с аргументом ID = 0xPPP для задачи с ID = 0xTTTT |
Сообщение |
Битовая маска |
Описание |
MSG_SRV_ID |
0xSS00.TTTT |
Процессор Cortex-M0 запрашивает обслуживание задачи с ID = 0xTTTT. Тип обслуживания кодируется байтами SS. Значение SS является уникальным для каждой задачи. |
MSG_RD_ID |
0xPPP1.TTTT, VALUE |
Процессор Cortex-M0 отвечает значением VALUE на чтение |
MSG_RD_STS_ID |
0xPPPR.TTTT |
Процессор Cortex-M0 отвечает на ошибку чтения слова WORD с аргументом ID = 0xPPP* из задачи с ID = 0xTTTT. Ошибка кодируется в R (R = 2–4): 2 = неверный аргумент; 3 = зарезервировано; |
MSG_WR_STS_ID |
0xPPPW.TTTT |
Процессор Cortex-M0 отвечает на запись с аргументом ID = 0xPPP* из задачи с ID = 0xTTTT. 5 = запись успешна; 6 = ошибка записи; |
Команда |
Возможный ответ |
Описание |
CMD_RD_ID |
MSG_RD_ID, VALUE |
Подтверждение чтения |
MSG_RD_STS_ID |
Ошибка чтения |
|
CMD_WR, WORD |
MSG_WR_STS_ID |
Подтверждение записи как успешной или ошибочной |
Пример
Предположим, некоторая задача с ID = 0x1234 должна выполняться на процессоре Cortex-M0. В частности, чтение данных из интерфейса уровня регистров, управляемое процессором Cortex-M0. Текст в угловых скобках (<>) указывает на регистры.
Регистры могут располагаться либо в ОЗУ (SRAM) процессора Cortex-M0 для более детерминированного времени доступа, либо в разделяемой области ОЗУ (shared SRAM). Если используется ОЗУ (SRAM) процессора Cortex-M0, то данные регистров необходимо копировать во время инициализации подсистемы. Копирование требует определенных затрат времени. Процессор Cortex-M4 может опрашивать регистр состояния (Status Register), чтобы определить момент завершения передачи данных.
Процессор Cortex-M4 инициализирует очереди команд и сообщений, загружая начальный и конечный адреса, а также указатели на чтение (read pointer) и запись (write pointer).
Затем процессор Cortex-M4 загружает значения регистров в зарезервированную область общего ОЗУ (SRAM). Альтернативным способом является последовательная запись регистров процессором Cortex-M4. Однако при передаче данных это требует больших накладных расходов, чем загрузка всех данных за один заход. После установки всех данных процессор Cortex-M0 может начинать выполнение задачи.
Пример реализации межпроцессорного взаимодействия (IPC) показан в таблице 10.
Шаг |
Команда |
Сообщение |
Значения байтов |
Описание |
1 |
CMD_WR |
|
0x<rst>11234, pointer |
Команда для инициализации задачи, |
Ядро Cortex-M0 обрабатывает регистры |
||||
2 |
|
MSG_WR_STS |
0x<rst>21234 |
Ядро Cortex-M0 обрабатывает сигналы записи данных |
3 |
|
MSR_SRV |
0x<serve>001234 |
Ядро Cortex-M0 запрашивает обслуживание, |
4 |
CMD_RD |
|
0x<status>11234 |
Ядро Cortex-M4 читает состояние |
5 |
|
MSG_RD,VALUE |
0x<status>11234, VALUE |
Ядро Cortex-M0 отвечает на состояние |
В зависимости от состояния ядро Cortex-M4 может принять решение о чтении дополнительных данных |
||||
6 |
CMD_RD |
|
0x<result>1234, 1 |
Ядро Cortex-M4 читает результаты |
7 |
|
MSG_RD,VALUE |
0x<result>11234, pointer |
Ядро Cortex-M0 отвечает указателем на результаты |
: |
: |
: |
: |
: |
n |
CMD_WR |
|
0x<stop>11234, value |
Команда остановки задачи |
n+1 |
|
MSG_WR_STS |
0x<stop>21234 |
Ядро Cortex-M0 обработало сигналы остановки задачи |
Регистр управления сбросом RGU
Регистр управления сбросом RGU позволяет программным путем активировать и очищать отдельные выходы сброса. Каждый бит соответствует отдельному выходу сброса, и запись в него «1» активирует этот выход. Выход сброса автоматически деактивируется после фиксированного периода задержки сброса с генерацией исключения M0APP_RST. Если выход сброса имеет ручную деактивацию, он остается активным после записи в него «1» до тех пор, пака в соответствующий бит регистра не будет записан «0». Это остается справедливым независимо от того, пришла ли активация сброса из регистра Reset Control Register или любого другого источника (табл. 11, 12).
Бит |
Символ |
Описание |
Значение |
Тип |
0 |
CORE_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
1 |
PERIPH_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
2 |
MASTER_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
3 |
– |
Зарезервировано |
0 |
– |
4 |
WWDT_RST |
Запись «1» не имеет эффекта |
0 |
– |
5 |
CREG_RST |
Запись «1» не имеет эффекта |
0 |
– |
6 |
– |
Зарезервировано |
0 |
– |
7 |
– |
Зарезервировано |
0 |
– |
8 |
BUS_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
9 |
SCU_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
10 |
– |
Зарезервировано |
0 |
– |
11 |
– |
Зарезервировано |
0 |
– |
12 |
M0_SUB_RST |
Запись «1» активирует сброс. Запись «0» очищает сброс. |
1 |
W |
13 |
M4_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
14 |
– |
Зарезервировано |
0 |
– |
15 |
– |
Зарезервировано |
0 |
– |
16 |
LCD_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
17 |
USB0_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
18 |
USB1_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
19 |
DMA_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
20 |
SDIO_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
21 |
EMC_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
22 |
ETHERNET_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
23 |
– |
Зарезервировано |
– |
– |
24 |
– |
Зарезервировано |
– |
– |
25 |
FLASHA_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0». |
0 |
W |
26 |
– |
Зарезервировано |
– |
– |
27 |
EEPROM_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
28 |
GPIO_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
29 |
FLASHB_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
30 |
– |
Зарезервировано |
– |
– |
31 |
– |
Зарезервировано |
– |
– |
Бит |
Символ |
Описание |
Значение |
Тип |
0 |
TIMER0_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
1 |
TIMER1_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
2 |
TIMER2_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
3 |
TIMER3_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
4 |
RITIMER_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
5 |
SCT_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
6 |
MOTOCONPWM_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
7 |
QEI_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
8 |
ADC0_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
9 |
ADC1_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
10 |
DAC_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
11 |
– |
Зарезервировано |
– |
– |
12 |
UART0_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
13 |
UART1_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
14 |
UART2_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
15 |
UART3_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
16 |
I2C0_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
17 |
I2C1_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
18 |
SSP0_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
19 |
SSP1_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
20 |
I2S_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
21 |
SPIFI_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
22 |
CAN1_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
23 |
CAN0_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
24 |
M0APP_RST |
Запись «1» активирует сброс. Запись «0» очищает сброс. |
1 |
W |
25 |
SGPIO_RST |
После 1 такта автоматически очищается в «0» |
0 |
W |
26 |
SPI_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
27 |
– |
Зарезервировано |
– |
– |
28 |
ADCHS_RST |
Запись «1» активирует сброс. После 1 такта автоматически очищается в «0» |
0 |
W |
29 |
– |
Зарезервировано |
– |
– |
30 |
– |
Зарезервировано |
– |
– |
31 |
– |
Зарезервировано |
– |
– |
Примечание. Задержка сброса измеряется в тактах IRC. Если частота тактирования ядра CCLK больше, чем частота IRC, необходимо добавить программную задержку в fCCLK/fIRC тактов между сбросом и доступом к любому периферийному блоку.
На этом описание интерфейса межпроцессорного взаимодействия микроконтроллеров семейств LPC43xx/LPC43Sxx NXP завершено. Перейдем к описанию реализации интерфейса в микроконтроллерах семейства LPC54xxx этого же производителя.
Почтовый ящик микроконтроллеров LPC5410x/LPC5411x
В микроконтроллере LPC5410x/LPC5411x интерфейс межпроцессорного взаимодействия реализован в виде почтового ящика (Mailbox). Рассмотрим, как он работает.
Основные особенности
Почтовый ящик обеспечивает функции межпроцессорного обмена данными (Inter-Processor Communication), позволяющие достаточно простым способом нескольким CPU разделять ресурсы и обмениваться сведениями между собой. Управление почтовым ящиком происходит с помощью прерываний. Каждый CPU выставляет своим партнерам до 32 определяемых пользователем прерываний. С помощью специального регистра происходит управление распределением общих ресурсов. Каждый CPU может претендовать на общий ресурс, если он доступен.
Базовая конфигурация
После сброса и загрузки почтовый ящик (Mailbox) оказывается отключенным, поскольку отключено его тактирование. Для запуска тактирования почтового ящика необходимо установить бит 26 (MAILBOX) регистра AHBCLKCTRL0 (табл. 13).
Бит |
Символ |
Описание |
Значение |
0 |
– |
Зарезервировано. Этот доступный только для чтения бит невозможно очистить |
1 |
1 |
ROM |
Разрешает тактирование Boot ROM. 0 = Запрещено; 1 = Разрешено |
1 |
2 |
– |
Зарезервировано. Значение при чтении не определено. Записываться должен только «0» |
0 |
3 |
SRAM1 |
Разрешает тактирование SRAM1. 0 = Запрещено; 1 = Разрешено |
1 |
4 |
SRAM2 |
Разрешает тактирование SRAM2. 0 = Запрещено; 1 = Разрешено |
0 |
6:5 |
– |
Зарезервировано. Значение при чтении не определено. Записываться должен только «0» |
0 |
7 |
FLASH |
Разрешает тактирование контроллера Flash-памяти. 0 = Запрещено; 1 = Разрешено. |
1 |
8 |
FMC |
Разрешает тактирование ускорителя Flash-памяти. 0 = Запрещено; 1 = Разрешено. |
1 |
10:9 |
– |
Зарезервировано. Значение при чтении не определено. Записываться должен только «0» |
0 |
11 |
INPUTMUX |
Разрешает тактирование мультиплексоров входов. 0 = Запрещено; 1 = Разрешено |
0 |
12 |
– |
Зарезервировано. Значение при чтении не определено. Записываться должен только «0». |
0 |
13 |
IOCON |
Разрешает тактирование блока IOCON. 0 = Запрещено; 1 = Разрешено |
0 |
14 |
GPIO0 |
Разрешает тактирование регистров порта GPIO0. 0 = Запрещено; 1 = Разрешено |
0 |
15 |
GPIO1 |
Разрешает тактирование регистров порта GPIO1. 0 = Запрещено; 1 = Разрешено |
0 |
17:16 |
– |
Зарезервировано. Значение при чтении не определено. Записываться должен только «0» |
0 |
18 |
PINT |
Разрешает тактирование блока прерываний от выводов микроконтроллера. 0 = Запрещено; 1 = Разрешено |
0 |
19 |
GINT |
Разрешает тактирование блока прерываний от сгруппированных выводов микроконтроллера. |
0 |
20 |
DMA |
Разрешает тактирование контроллера ПДП (DMA controller). 0 = Запрещено; 1 = Разрешено |
0 |
21 |
CRC |
Разрешает тактирование блока вычисления контрольных сумм (CRC engine). 0 = Запрещено; 1 = Разрешено |
0 |
22 |
WWDT |
Разрешает тактирование сторожевого таймера (Watchdog Timer). 0 = Запрещено; 1 = Разрешено |
0 |
23 |
RTC |
Разрешает тактирование часов реального времени (RTC). 0 = Запрещено; 1 = Разрешено |
0 |
25:24 |
– |
Зарезервировано. Значение при чтении не определено. Записываться должен только «0» |
0 |
26 |
MAILBOX |
Разрешает тактирование почтового ящика (Mailbox). 0 = Запрещено; 1 = Разрешено. |
0 |
27 |
ADC0 |
Разрешает тактирование регистрового интерфейса ADC0. 0 = Запрещено; 1 = Разрешено |
0 |
31:28 |
– |
Зарезервировано. Значение при чтении не определено. Записываться должен только «0» |
0 |
Регистр 0 управления тактированием AHB (AHBCLKCTRL0, адрес 0x4000 00C0)
Регистр AHBCLKCTRL0 разрешает/запрещает тактирование отдельных систем и периферийных блоков. Системный сигнал тактирования (bit 0) обеспечивает тактирование шины AHB, моста AHB-APB, процессорного ядра, блока SYSCON и модуля управления электропитанием PMU. Этот сигнал тактирования не может быть отключен.
Наиме- |
Тип |
Смещение |
Описание |
Значение |
Таблица |
IRQ0 |
R/W |
0x000 |
Регистр запроса на прерывание для CPU Cortex-M0+ |
0 |
485 |
IRQ0SET |
WO |
0x004 |
Установка битов в IRQ0 |
– |
486 |
IRQ0CLR |
WO |
0x008 |
Очистка битов в IRQ0 |
– |
487 |
IRQ1 |
R/W |
0x010 |
Регистр запроса на прерывание для CPU Cortex-M4 |
0 |
488 |
IRQ1SET |
WO |
0x014 |
Установка битов в IRQ1 |
– |
489 |
IRQ1CLR |
WO |
0x018 |
Очистка битов в IRQ1 |
– |
490 |
MUTEX |
R/W |
0x0F8 |
Регистр взаимного исключения * |
0x1 |
491 |
Примечание. *Чтение и запись имеют специфические побочные эффекты. Подробности изложены в описании регистра.
Описание регистров почтового ящика
Почтовый ящик управляется с помощью шести регистров прерываний (по три для каждого процессорного ядра) и регистра исключений. Назначение регистров приведено в таблице 14, а описание битов — в таблицах 15–21.
Регистр прерываний Cortex-M0+ (IRQ0, адрес 0x1C02 C000)
Регистр IRQ0 позволяет другим CPU выставлять запросы на прерывания для CPU Cortex-M0+. Это предоставляет возможность организовывать обмен данными между CPU. Например, один из CPU должен обслуживать некоторые периферийные модули и уведомлять другой CPU о готовности данных. Каждый бит может представлять различную ситуацию. Использование указанной функции полностью зависит от пользователя.
Бит |
Символ |
Описание |
Значение после сброса |
31:0 |
INTREQ |
При установке любого бита в контроллер прерываний Cortex-M0+ направляется запрос на прерывание |
0 |
Регистр установки прерываний Cortex-M0+ (IRQ0SET, адрес 0x1C02 C004)
Регистр IRQ0SET используется для установки битов регистра IRQ0.
Бит |
Символ |
Описание |
Значение после сброса |
31:0 |
INTREQ SET |
Запись «1» устанавливает соответствующий бит регистра IRQ0 |
– |
Регистр очистки прерываний Cortex-M0+ (IRQ0CLR, адрес 0x1C02 C008)
Регистр IRQ0SET используется для очистки битов регистра IRQ0.
Бит |
Символ |
Описание |
Значение после сброса |
31:0 |
INTREQ CLR |
Запись «1» очищает соответствующий бит регистра IRQ0 |
– |
Регистр прерываний Cortex-M4 (IRQ1, адрес 0x1C02 C010)
Регистр IRQ1 разрешает другому CPU выставить запрос на прерывание CPU Cortex-M4. Это позволяет организовывать обмен данными между CPU. Например, один из CPU должен обслуживать некоторые периферийные модули и уведомлять другой CPU о готовности данных. Каждый бит может представлять различную ситуацию. Использование функции полностью зависит от пользователя.
Бит |
Символ |
Описание |
Значение после сброса |
31:0 |
INTREQ |
При установке любого бита в контроллер прерываний Cortex-M4 направляется запрос на прерывание |
0 |
Регистр установки прерываний Cortex-M4 (IRQ1SET, адрес 0x1C02 C014)
Бит |
Символ |
Описание |
Значение после сброса |
31:0 |
INTREQ SET |
Запись «1» устанавливает соответствующий бит регистра IRQ1 |
– |
Регистр IRQ0SET используется для установки битов регистра IRQ1.
Регистр очистки прерываний Cortex-M4 (IRQ1CLR, адрес 0x1C02 C018)
Бит |
Символ |
Описание |
Значение после сброса |
31:0 |
INTREQ CLR |
Запись «1» очищает соответствующий бит регистра IRQ1 |
– |
Регистр IRQ1SET используется для очистки битов регистра IRQ1.
Регистр взаимного исключения (Mutual Exclusion, MUTEX, адрес 0x1C02 C0F8)
Бит |
Символ |
Описание |
Значение после сброса |
0 |
EX |
Очищается при чтении, устанавливается при записи |
1 |
31:1 |
– |
Зарезервировано |
– |
Этот регистр обеспечивает квитирование (handshake) межпроцессорного обмена данными (Inter-Processor Communication). При любой операции чтения будет возвращено текущее значение и произойдет очистка бита. Бит будет снова установлен при любой операции записи.
Это можно использовать для квитирования (handshake) распределения ресурсов между двумя CPU. Всякий раз, когда CPU захочет получить доступ к разделяемым ресурсам (возможно, к таблице распределения ресурсов в памяти), он будет читать регистр MUTEX. Если он увидит «1», то сможет получить управление выделением общего ресурса. После того как CPU произведет все необходимые изменения, он осуществит запись в регистр, вызывая повторную установку бита и предоставляя другому CPU возможность управления выделением разделяемых ресурсов. Если CPU прочитает «0», то перед доступом к информации о выделении разделяемых ресурсов он должен ожидать, пока бит не будет читаться как «1».
На этом описание почтового ящика (Mailbox) семейства микроконтроллеров LPC5410x от компании NXP завершено. Перейдем к описанию межпроцессорного взаимодействия СнК PSoC 6x BLE компании Cypress. Микросхемы позиционируются для использования в бурно развивающейся отрасли «Интернета вещей» (IoT), в том числе промышленного (IIoT), и достойны отдельного рассмотрения.
Межпроцессорный обмен данными (IPC) в СнК PSoC 6x BLE от Cypress
Микросхемы PSoC 6x BLE компании Cypress представляют собой двухъядерные (150‑МГц Cortex-M4F и 100‑МГц Cortex M0+) системы-на-кристалле (СнК), ориентированные на использование в малопотребляющих устройствах промышленного «Интернета вещей» (Industrial Internet of Things, IIoT) с беспроводными каналами обмена данными (BLE). Для связи между ядрами Cortex-M4F и Cortex M0+ служит блок межпроцессорного обмена данными (Inter-processor communication, IPC). Блок межпроцессорного взаимодействия обеспечивает возможность нескольким процессорам обмениваться данными и синхронизировать свои активности. На аппаратном уровне блок IPC реализован с помощью двух регистровых структур:
- Каналы межпроцессорного взаимодействия (IPC Channel) — с помощью этой структуры достигается обмен данными и синхронизация между процессорами.
- Прерывания (Interrupt) — каждая структура прерывания конфигурирует линию прерывания (interrupt line), которая может быть активирована по уведомлению или событию высвобождения разделяемых ресурсов от каналов IPC.
Основные функциональные особенности
Модуль межпроцессорного взаимодействия (IPC) имеет следующие функциональные особенности:
- Реализует блокировки взаимных исключений (mutual exclusion) между процессорами.
- Позволяет обмениваться сообщениями между процессорами.
- Поддерживает до 16 каналов обмена данными.
- Поддерживает до 16 прерываний, которые можно запускать, используя уведомления или события высвобождения разделяемых ресурсов от каналов IPC.
Каналы IPC
Канал межпроцессорного обмена (IPC) реализован в виде пяти аппаратных регистров, как показано на рис. 4. Регистры каналов IPC доступны всем процессорам в системе.
Описание регистров IPC приведено в таблице 22.
Наименование регистра |
Описание |
IPC_ACQUIRE |
Этот регистр определяет функцию блокировки IPC. Если поле SUCCESS возвращает «1», то при чтении была обнаружена блокировка. Если поле SUCCESS возвращает «0», то при чтении не была обнаружена блокировка. Следует отметить, что единственный доступ на чтение выполняет две функции:
Неделимость этих двух функций имеет важное значение в CPU с несколькими задачами, которые могут вытеснять друг друга. Кроме того, регистр имеет битовые поля, содержащие информацию о том, какое из процессорных ядер осуществило захват канала. При выделении канала этот регистр очищается записью любого значения в регистр IPC_RELEASE. Если регистр уже захвачен, то любая другая попытка прочитать его содержимое не сможет захватить его. |
IPC_NOTIFY |
Регистр используется для генерации уведомлений при межпроцессорном обмене (IPC notify event). Каждый бит регистра соответствует одной структуре IPC-прерываний. Уведомления (notify event), генерируемые каналами межпроцессорного взаимодействия (IPC), могут запускать одну или несколько структур прерываний (interrupt structure). |
IPC_RELEASE |
Любая запись в этот регистр будет освобождать канал IPC. Кроме того, регистр имеет биты, которые соответствуют каждой структуре прерываний IPC. Событие по освобождению, генерируемое каналом IPC, может запускать одну или несколько структур прерываний (interrupt structure). |
IPC_DATA |
Этот 32-битный регистр предназначен для хранения данных. |
IPC_LOCK_STATUS |
Этот регистр обеспечивает состояние немедленной блокировки канала IPC. |
Прерывания при межпроцессорном обмене
С каждой линией прерывания при межпроцессорном обмене (IPC interrupt line) в системе связана собственная структура IPC-пре-рывания IPC interrupt structure. Структура IPC-прерывания может быть запущена с помощью уведомления или события освобождения разделяемого ресурса от любого из каналов IPC в системе. Пользователь может замаскировать любой из источников этих событий посредством регистров IPC-прерываний (IPC interrupt register).
На рис. 5 показаны регистры в структуре прерываний при межпроцессорном обмене (IPC interrupt register), а в таблице 23 дано подробное описание каждого из регистров.
Наименование |
Описание |
IPC_INTR |
В регистре отображается мгновенное состояние источников прерываний. |
IPC_INTR_MASK |
Биты этого регистра маскируют источники прерываний. Только источники прерываний с активированными масками могут вызывать прерывания |
IPC_INTR_SET |
Запись «1» в этот регистр устанавливает прерывание |
IPC_INTR_MASKED |
В регистре содержатся мгновенные значения прерываний после того, как они были маскированы. |
Каналы и прерывания IPC
Блок IPC имеет связанный с ним набор IPC-прерываний. Каждая структура регистра прерываний IPC (IPC interrupt register structure) соответствует линии IPC-прерывания. Данное прерывание может активировать прерывание выполнения операций любого из процессоров системы. Подпрограмма обработчика прерываний для процессоров зависит от архитектуры микросхемы.
Каждый канал IPC имеет регистр освобождения ресурса и уведомлений, который может управляться событиями от любого
из IPC-прерываний. Взаимоотношение между IPC-каналами и структурой IPC-прерывания проиллюстрировано на рис. 6.
Реализация блокировок
Каналы IPC можно использовать для реализации блокировок, обычно применяемых в многопроцессорных системах для реализации определенной формы взаимоисключающего доступа к разделяемым ресурсам.
Когда несколько процессоров разделяют общие ресурсы, процессоры могут захватывать и высвобождать IPC-канал. Таким образом, процессор может рассматривать захваченный IPC-канал как блокировку. Семантикой этого кода является то, что доступ к разделяемому ресурсу определяется владельцем процессорного канала. Соответственно, перед доступом к разделяемому ресурсу процессору необходимо захватить IPC-канал.
Неспособность захватить IPC-канал означает, что разделяемый ресурс заблокирован, поскольку им управляет другой процессор. Следует отметить, что IPC-канал не знает, какой из процессоров захватил или высвободил его. Любой из процессоров может захватить, а затем высвободить IPC-канал, и семантика кода должна гарантировать, что захват и высвобождение канала будут производиться одним и тем же процессором.
Прохождение сообщений
Каналы IPC могут применяться для обмена сообщениями между процессорами. В таком сценарии канал используется совместно со структурами прерывания. Канал IPC используется для блокировки доступа к регистру данных (Data register). Канал IPC захватывается отправителем сообщения и предназначается для формирования сообщения. Получатель читает сообщение и затем высвобождает канал. Таким образом, между моментом, когда отправитель загрузил данные в канал, и моментом, когда получатель их прочитал, канал заблокирован для всех других задач. Отправитель использует уведомление (notify event) для генерации IPC-прерывания для получателя, чтобы сообщить ему об отправке сообщения. Получатель обрабатывает это прерывание и читает данные из регистра данных. После завершения приема сообщения получатель высвобождает канал и может сгенерировать событие по высвобождению канала (release event) для выставления отправителю IPC-прерывания. Следует отметить, что блокировка канала на аппаратном уровне не ограничивает доступ к регистру данных. Такая семантика должна осуществляться с помощью программного обеспечения.
На рис. 7 приведен пример, в котором отправитель (процессор A) посылает данные получателю (процессор B). Прерывание IPC interrupt A конфигурируется как прерывание к процессору Processor A.
Прерывание IPC interrupt B конфигурируется как прерывание к процессору Processor B.
- Отправитель попытается захватить канал IPC чтением регистра IPC_ACQUIRE. Если канал удалось захватить, отправитель становится владельцем канала для передачи данных. Если канал захватить не удалось, процессор должен ожидать до тех пор, пока канал не станет доступен для захвата. Это можно выполнить, опрашивая регистр IPC_LOCK_STATUS канала IPC.
- После захвата канала IPC отправитель начинает управлять каналом для обмена данными и размещает 32‑битное сообщение в регистре IPC_DATA.
- Теперь, когда сообщение помещено в канал IPC, отправитель генерирует уведомление (notify event) для линии прерывания приемника. Он делает это установкой соответствующего бита регистра канала IPC. Это событие приводит к созданию уведомления (notify event) для прерывания IPC interrupt B. Если уведомление (notify event) канала IPC разрешено установкой бита маски для прерывания IPC interrupt B, то оно сгенерирует прерывание в приемнике.
- После приема прерывания IPC interrupt B приемник может опросить регистр
IPC_INTR_MASKED, чтобы установить, какой из каналов IPC создал уведомление (notify event). Основываясь на полученной информации, приемник идентифицирует канал для чтения и распознает сообщение из регистра IPC_DATA канала IPC. Итак, приемник прочитал полученные данные, посланные отправителем. Далее необходимо высвободить канал, чтобы другие процессор/процессы могли его использовать. - Приемник высвобождает канал. Он также может сгенерировать необязательное событие (release event) для прерывания IPC interrupt A отправителя. Это создаст прерывание по событию высвобождения ресурса (release event interrupt) для отправителя, если соответствующее событие (release event) для канала было разрешено маскированием.
После получения прерывания по высвобождению ресурса (release interrupt) отправитель может выполнить основанное на событии действие в соответствии с требованиями приложения. Он может либо попытаться повторно захватить канал для дальнейшей передачи сообщения, либо перейти к другим задачам, поскольку текущий обмен данными завершен.
В предыдущем примере размер передаваемых данных был всего 32 бит. Сообщения большего размера можно отправлять, используя указатели (pointer).
Отправитель может выделить в памяти сообщение с более крупной структурой и разместить указатель (pointer) на него в 32‑битном регистре данных.
На рис. 8 показано такое применение регистра данных. Следует отметить, что в пользовательском коде должна быть реализована синхронизация процесса чтения сообщений:
- Программная реализация может оставить канал захваченным до тех пор, пока не будут прочитаны все данные в пакете сообщения, затем пакет сообщения может быть перезаписан. Такой вариант сценария является весьма расточительным, поскольку останавливает другие межпроцессорные обмены данными в ситуации, когда количество каналов IPC ограничено.
- Получатель может высвободить канал сразу после получения указателя (pointer) на пакет сообщения. В таком случае в сообщении должна быть реализована логика синхронизации, например в виде флага, который отправитель устанавливает после завершения записи, а получатель очищает по окончании чтения.
Заключение
Многоядерные микроконтроллеры и микропроцессоры с ядрами различного типа (так называемые гетерогенные кристаллы) позволяют распределить подготовку получения данных с внешних интерфейсов, подготовку к обработке и саму обработку, а также вывод обработанных данных между несколькими ядрами. Таким образом, может быть достигнуто снижение нагрузки на основное процессорное ядро, повышение производительности при выполнении сложных математических операций и сокращение общего энергопотребления, что особенно актуально в эпоху «Интернета вещей» (IoT). В статье были рассмотрены интерфейсы межпроцессорного обмена данными у появляющихся в последнее время многоядерных микроконтроллеров семейств LPC43xxx и LPC54xxx компании NXP и система-на-кристалле (СнК) PSoC 6x BLE компании Cypress. В следующей статье пойдет речь об интерфейсе межпроцессорного обмена микроконтроллеров Concerto корпорации Texas Instruments.
- LPC435x/3x/2x/1x. 32‑bit ARM Cortex-M4/
M0 MCU; up to 1 MB flash and 136 kB SRAM; Ethernet, two High-speed USB, LCD, EMC. Product data sheet. - UM10503. LPC43xx/LPC43Sxx ARM Cortex-M4/M0 multi-core microcontroller. User manual.
- LPC5410x. 32‑bit ARM Cortex-M4/M0+ MCU; 104 kB SRAM; 512 kB flash, 3 x I2C, 2 x SPI, 4 x USART, 32‑bit counter/timers, SCTimer/PWM, 12‑bit 5.0 Msamples/sec ADC. Product data sheet.
- LPC5411x. 32‑bit ARM Cortex-M4/M0+ MCU; 192 KB SRAM; 256 KB flash, Crystal-less USB operation, DMIC subsystem, Flexcomm Interface, 32‑bit counter/timers, SCTimer/PWM, 12‑bit 5.0 Msamples/sec ADC, Temperature sensor. Product data sheet.
- UM10850. LPC5410x User manual.
- UM10914. LPC5411x User manual.
- PSoC 6 MCU: PSoC 62 Datasheet.
- PSoC 6 MCU: PSoC 63 with BLE Datasheet.
- PSoC 6 MCU: PSoC 62 Architecture Technical Reference Manual (TRM).
- PSoC 63 with BLE Architecture Technical Reference Manual (TRM).