'HAL' - Hardware Abstraction Layer, или же уровень аппаратных абстракций, это набор программных модулей, управляющих различными инструментами микроконтроллера. Под инструментами подразумевается вся перифирия, различные вычислительные модули, вынесенные из ядра процессора, и т.д. В ChibiOS HAL абсолютно независим и может использоваться отдельно от операционной системы и не является необходимым для работы RT модуля.
В отличии от реализаций, связанных с автогенерацией кода в зависимости от выбранных настроек, в ChibiOS модули уже написаны под все поддерживаемые платформы и хранятся в виде исходного кода в недрах папки chibios203, а точнее в /os/hal. Так как все эти файлы довольно много весят, а зачастую еще и конфликтуют, при компиляции в сборку попадают далеко не все. За то чтобы случайно не использовать файлы не от того контроллера отвечает makefile, а чтобы не подключать ненужную периферию используются заголовочные файлы halconf.h и mcuconf.h, находящиеся в папке cfg в корне проекта.
Чтобы подключить к проекту желаемый модуль необходимо установить соответствующий define в файле halconf.h в состояние TRUE. Неиспользуемые модули лучше выключать написав FALSE, хотя катастрофы, конечно, не произойдет.
Также, если промотать файл вниз можно найти дополнительные опции, связанные с работой модулей. Например, использование внешних прерываний для модуля PAL или использование функций Advanced таймера.
Помимо включения вмодуля в принципе в большинстве случаев еще надо будет включить конкретный драйвер. Разделение на драйверы связано с тем, что внутри контроллера может быть множество одинаковых модулей. Например, всегда есть несколько таймеров, или может быть несколько независимых модулей i2c. Для этого надо найти в файле mcuconf.h блок определений, связанный с необходимым модулем. Выбрав желаемый драйвер точно так же переводим его в состояние TRUE.
Некоторые дрейвера могут конфликтовать друг с другом. Например, модули GPT и PWM на самом деле используют одни и те же таймеры. Поэтому если попытаться включить TIM1 и PWM1 получим ошибку. Здесь же для некоторых модулей можно задать канал DMA или какие-либо специфичные настройки, но тут об этом говорить не будем.
Обычно, между разными драйверами одного модуля отличий нет. Хотя, например, таймеров много разных, причем отличия достаточно существенные. Возможная причина выбрать тот или иной драйвер заключается в используемых им ногах. Если модуль может использовать каки-либо ноги микроконтроллера, а это, например, все модули периферии, то разные драйвера будут использовать разные ноги. Узнать какие ноги на каком драйвере висят можно из даташита, а именно в табличке альтернативных функций. Здесь приведен пример для отладочной платы NUCLEO-F767ZI, но найти на любой другой контроллер семейства STM32 проблемы не должно составить.
В целом, использование будет уникально для каждого модуля, и будет описано в отдельных инструкциях. Однако можно выделить несколько общих моментов:
- Все доступные для использования функции (так называемый
API) пишутся только с помощьюCamel Caseи начинаются с префикса по имени модуля. Например,palSetLineMode(). Если нашли что-нибудь написанное с помощьюSnake Case, напримерpal_lld_setport(), не надо этим пользоваться! - Все функции делятся на классы:
Normal Class- функции этого класса можно вызывать только в потоках. Например, вmain()или любой функции, которую из мейна вызвали. По сути это значит, что нельзя такую функцию вызывать из прерывания илиLockзон. В имени функции никаких отличительных знаков нет.S-Class- функцииSкласса можно вызывать только критических зон потока. Подробнее можно почитать тут. Фунцкии заканчиваются на буквуS. Примера изHALне нашел.I-Class- ФункцииIкласса можно вызывать прерываний, критических зон потока и критических зон прерываний. Прерываниями являются всеcallbackфункции, которые могут вызывать различные модули. Например, прерывание по таймеру, прерывание по изменению состояния на ноге, прерывание по окончанию передачи данных поSPIи так далее. Функции заканчиваются на буквуI, напримерadcStartConversionI()X-Classможно вызывать откуда угодно. Функции заканчиваются на буквуX, напримерicuGetWidthX().Specialне относятся к функциям какого-либо класса и по большей части функциями они и не являются. Сюда относится вся работа с ногами, напримерpalToggleLine(). ОтличитьNormal ClassотSpecialможно только с помощью хелпа.
- Любой модуль (кроме
PAL) надо запустить с помощью функцииxxxStart()(xxx- префикс модуля), в которую передаются указатель на зупускаемый драйвер и указатель на заполненную структуру конфигурации. Если затем модуль надо выключить, сделать это можно с помощьюxxxStop(). Подробнее будет описано в инструкциях к отдельным модулям.
Причин почему тот или иной модуль не работает может быть очень много. Но прежде чем начать рвать на себе волосы и задумываться о покупке ардуины, можно попробовать свериться со следующим чеклистом:
- Включен ли модуль в
halconf.h? Если нет, то при попытке воспользоваться функциями этого модуля будут возникать ошибки или предупреждения при компиляции, напримерimplicit declaration of function. - Включен ли драйвер модуля и тот ли это драйвер который планировался? Вообще, если не включить ни одного драйвера в
mcuconf.hпри включенном модулеChibiOSдолжна возмутиться, но от включения неправильного драйвера особенно не защититься. - Правильно ли задана структура конфига? Стоит проверить нет ли там каких-либо незаполненных полей и допустимые ли значения используются в принципе.
- В правильном ли режиме работает нога? Для большинства модулей надо перевести ногу в альтернативный режим, иначе чуда не произойдет. Подробнее смотри инструкцию к
PALи/или тому модулю, который нужно включить. - Нет ли ошибки в подключении? Сведены ли земли, нужна ли подтяжка к земле/питанию, запитано ли устройство с которым пытаемся связаться (если оно есть)?
- Нет ли конфликта внутри
STM? Прежде чем принять решение что ничего не работает стоит попытаться воспользоваться только этим драйвером без подключения каких-либо других.
Во всех остальных случаях может помочь осциллограф и дебагер.