Описание драйверов HAL STM32F4xx, частичный перевод


Делюсь небольшой проделанной работой — это частичный перевод оригинального описания

Введение

STM32Cube является оригинальной разработкой STMicroelectronics, предназначенной для разработчиков программного обеспечения (ПО), встроенного в микроконтроллеры STM32. STM32Cube облегчает разработку ПО за счет снижения усилий, времени и затрат, и охватывает всё семейство микроконтроллеров STM32.

STM32CubeTM версии 1.x включают в себя:
  • STM32CubeMX — утилита с графическим интерфейсом, предназначенная для генерации кода инициализации STM32 и встроенной в микроконтроллер периферии.
  • Комплексное программное обеспечение для встраиваемых платформ, сконфигурированное для конкретной серии (например, STM32CubeF4 для серии STM32F4):
    • STM32Cube HAL, встраеваемое программное обеспечение уровня абстракции HAL, для STM32, обеспечивающее максимальную переносимость кода внутри семейства STM32
    • Набор встраиваемых компонентов ПО, таких как RTOS, USB, FatFS, TCP/IP, Graphics, настроенный для их совместной работы
    • Полный комплект примеров, для всех программых компонентов и утилит, находящихся в наборе ПО.

Драйверы уровня HAL представляют собой комплект универсальных, многофункциональных, и одновременно простых интерфейсов API, предназначенных для взаимодействия МК с верхним слоем ПО (основной программой, библиотеками и стеками). Драйверы могут иметь как общий (generic), так и расширенный (extension) API.

HAL разработан для применения такой архитектуры программирования, когда необходимые функции выполняются верхним слоем приложения, за счет применения промежуточного уровня HAL. При такой архитектуре программирования верхний уровень приложения не «привязан» к микроконтроллеру (МК), т.к обращается к ресурсам МК только через библиотеку драйверов HAL. Такая структура пользовательского приложения улучшает повторное использование кода, и гарантирует его легкую переносимость на другие устройства STM32.

Драйверы HAL предоставляют полный набор готовых к использованию API, которые упрощают реализацию пользовательского приложения. В качестве примера — встроенные устройства коммуникации (связи) содержат интерфейсы API для инициализации и настройки устройства, управления передачей данных на основе опроса, в прерываниях или через DMA, а так же для управления ошибками связи.

API-интерфейсы драйверов HAL, делятся на две категории: 1) Общие (generic) API, которые обеспечивают общие, для всех серий STM32, функции. 2) Расширенные (extension) API, которые содержат специфические или индивидуальные функции для данного семейства или его части.

Драйверы HAL являются функционально-ориентированными, а не ориентированны на внутренние периферийные устройства. Например, API таймера делится на несколько категорий, по функциям, предоставляемым внутренним устройством таймера: базовый таймер (basic timer), захвата (capture), широтно-импульсной модуляции (PWM), и т.д…

Исходный код библиотеки драйверов разработан в соответствии со Strict ANSI-C, что делает код независимым от инструментов разработки. Весь исходный код проверен с помощью инструмента статистического анализа CodeSonarTM, полностью документирован и является MISRA-C 2004 совместимым.

Драйверы слоя HAL реализуют обнаружение ошибок во время выполнения (run-time failure detection), HAL проверяет входные значения всех функций. Такая динамическая проверка способствует повышению надежности встроенного ПО. Обнаружение ошибок во время выполнения программы, также, способствует ускорению разработки пользовательских приложений и процесса отладки.

Далее — в приложенном файле

Сразу скажу, что переведена, фактически, только 2 глава, в которой описано, как устроен HAL. Старался перевести максимально «корректно», а как получилось…
Если кем-то будут замечены ляпусы — исправлю.
Обсуждение на форуме
  • +9
  • 07 марта 2015, 14:48
  • avtoneru
  • 1
Файлы в топике: HAL F4 описание.zip

Комментарии (34)

RSS свернуть / развернуть
Спасибо за труд! Подскажите опыт разработки с HAL драйверами есть у кого-нибудь? Как у них со стабильностью. Выглядит все в паре с кьюбмикс очень привлекательно.
0
А кьюбмикс это что?
честно в первый раз вижу это слово.
0
сори STM32cubeMX
0
Как стартовый конфигуратор проекта CubeMX очень удобная штука. По поводу HAL могу сказать, что они местами до того доабстрагировались, что погубили функционал периферии своей либой. СПЛ не давала полной абстракции, но зато давала гибкость. Она предоставляла базовые обертки, которые можно было использовать как заблагорассудится. Здесь же все продумали за тебя, не оставив варианта для маневра. Не буду распыляться, простой пример: для того, чтобы отловить событие приема пакета по уарту нужно заранее знать его длинну (sic!), потому, что колбэк, через который можно отловить прием данных будет вызван только при приеме заранее установленного количества байт, а других механизмов, которые бы позволяли определить наличие данных во входящем буфере в либе попросту нет. С I2C тоже есть один вопиющий пример: если настроить его как слейв, задать количество байт на передачу мастеру, а мастер потом попытается вычитать с тебя хоть на один байт больше, то слейв повиснет в прерывании(!!!). Так что вот такие пироги с этими либами, приходится допиливать местами, но основная часть библиотек все же для использования пригодны и не насколько безнадежны, как могло показаться из моего рассказа. Просто описал негативные моменты, с которыми столкнулся сам. Что касается удобства использования, то работать с ними реально удобно и мне нравится больше, чем с SPL.
P.S. Описанные проблемы встречены в библиотеке HAL из STM32CubeF4. В других семействах может все быть по-другому, пока не сталкивался.
0
Не буду распыляться, простой пример: для того, чтобы отловить событие приема пакета по уарту нужно заранее знать его длинну (sic!), потому, что колбэк, через который можно отловить прием данных будет вызван только при приеме заранее установленного количества байт, а других механизмов, которые бы позволяли определить наличие данных во входящем буфере в либе попросту нет.
Насколько я понял, Вы использовали режим DMA. По-моему, этот режим, сам по себе, стоит использовать или когда на вход идет «нескончаемый» поток данных, или если известна минимальная длинна пакета. В противном случае — нужен или режим опроса или по прерываниям. Хотя должно получиться посмотреть состояние через встроенный макрос, находящийся в DMA — уарт использует для работы в DMA API-интерфейсы HAL…
0
В том то и дело, что я пытался использовать режим работы по прерываниям.
0
С прерываниями вообще, не должно быть проблем — буфер реализуем сами, а прием идет по 1 единице данных…
0
Проблем и не будет, если дописать недостающий функционал самостоятельно. Как минимум, функию, которая будет принимать указатель на хэндлер уарта и возвращать количество байт в буфере. А еще лучше организовать нормальный fifo и не извращаться.
0
fifo — есть DMA, правда встроенный макрос выдает скудную информацию о состоянии заполнения буфера, без количества байт. Остается только собственная реализация.
Честно скажу, что с потоковыми данными плотно не занимался, пока всё на уровне теории. А скоро — надо будет 4 МК по I2C связать, правда формат пакетов и протокол уже почти дорисовал…
0
Хотел спросить, а правильно — хэндлер или дескриптор? когда переводил — были сомнения…
0
Вот честно, понятия не имею. Сейчас Vga прийдет и расставит точки над і))
0
Ребят, подскажите что такое хэндер — так понимаю что это функция -обработчик че-го но не прерывания. Часто вижу это имя а вот смысл именно такого имени не могу понять
0
Это транслетированный термин от handle, так же может называться дескриптором, т.е. описание чего-либо. В случае с HAL в структуре дескриптора функций HAL хранятся, в том числе и указатели на другие функции, используемые при определенном процессе — например указатели на колбэки (функции обратного вызова)
0
блин, не на колбэки, а просто на другие функции… колбэки прописаны жестко, их только реализовать надо…
0
начал вчера попытки портировать библиотеку u8glib на stm32f1 с использованием hal драйверов… зарылся глубоко… пока больше вопросов. Хочется все же на HAL драйверочках это сделать. Скажу так большого опыта с stm32 у меня нет но есть достаточно времени на это дело
0
зависит от контекста еще
дескриптор это обычно некоторая структура, которая описывает набор данных, которые возвращает функция
например ты открыл файл и там содержится некоторая инфа, но не сам файл в плане его содержимого

а хендлер это тоже может быть переменная, обычно это указатель
а может быть какая-то вспомогательная функция-обработчик
0
Контекст укажи. Обычно это разные вещи: хэндлер — обработчик, дескриптор — идентификатор. Еще, правда, в WinAPI дескриптор хэндлом (не хэндлером) именуют, но больше нигде не видел такого.
+1
P.S. Еще дескрипторами описатели называются, вроде дескрипторов USB.
+1
Обработчик прерывания это тоже хендлер? Он вроде как вектором называется. Или вектор это адрес обработчика а handler это сама функция
0
Хэндлер — функция-обработчик прерывания (собственно, «handler» дословно как «обработчик» и переводится). ННасчет вектора не уверен, но полагаю что да, вектор — это адрес, по которому располагается хэндлер (либо адрес хэндлера, в зависимости от архитектуры).
0
satips.blogspot.ru/2012/09/file-descriptior-vs-file-handle-in.html
В двух словах — в Си функции должен быть handle, т.е. хендлер… перепишу
ИМХО терминология не строгая, обзывают кому как понравилось, а гуголь вообще обзывает ручкой…
0
Спасибо. Мне просто для лучшего понимания это нужно. Обозвать то можно как угодно но есть определенные правила культурного кода-). После ардуины конечно тяжелова-то дается stm32. Там за неделю вечеров уже можно сервера писать-). Но руки там подсвязаны — отладки можно сказать вообще нет.
0
Обычно есть куча терминов со схожим смыслом и называют каждый кто во что горазд. Ядро, например, может называться Core, Kernel или еще парой слов — кому как нравится.
Для идентификаторов тоже куча вариантов — id, handle, descriptor, etc…
+1
В двух словах — в Си функции должен быть handle, т.е. хендлер…

Нет, так вы всех запутаете :) Handle (хэндл) это да, в данном смысле можно привести как дескриптор. А вот handler (хэндленр) это «обработчик» – код который что-то обрабатывает, например exception handler
+1
handle — хэндл, хэндлер — handler. Не надо путать, разница как между «фрезером» и «фрезеровщиком».

Что до приведенной ссылки — в ней хэндл и дескриптор по большому счету одно и то же, по разному названное в разных системах (это если рассматривать вопрос в общем, а в статье рассматривается разница между конкретными случаями).
а гуголь вообще обзывает ручкой…
Так и есть, в переводе это «ручка», так что у нас обычно называют просто «хэндл».
В двух словах — в Си функции должен быть handle, т.е. хендлер… перепишу
Ты бы все же показал тот кусок переводимого текста, который вызывает сомнения (да, мне лень качать аттач, оригинал и изучать их).
+1
Для остановки уарта я выставляю таймаут.
Приём заканчивается когда заполнен буфер или когда партнёр по передаче замолчал.
Альтернативно можно искать последовательность конца передачи в /* USER CODE BEGIN USART1_IRQn 0 */

Обработка пакета происходит в основном потоке выполнения.

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  __HAL_TIM_SET_COUNTER(&htim6, 1);

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

/* USER CODE BEGIN 4 */

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
  HAL_TIM_Base_Stop_IT(&htim6);
  received_bytes = RECV_CHUNK - huart->RxXferCount;
  huart->RxXferCount = 0;
  HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_12);
  uart_receive_trigger = 1;
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
  __HAL_TIM_SET_AUTORELOAD(&htim6, 1000000 / 115200 * (8+1+1) * 3 );
  __HAL_TIM_SET_COUNTER(&htim6, 0);
  __HAL_TIM_CLEAR_IT(&htim6, TIM_IT_UPDATE);
  HAL_TIM_Base_Start_IT(&htim6);
  HAL_UART_Receive_IT(huart, (uint8_t*)uart_rbuf, RECV_CHUNK);
}

void handle_uart_receive() {
  int len;
  if (uart_receive_trigger == 0)
    return;

  uart_receive_trigger = 0;
  
  int sport = 0;
  int dport = 0;
  received_bytes = recv_packet(uart_frame_buf, uart_rbuf, received_bytes, &sport, &dport);
  if (received_bytes <= 0) {
    HAL_UART_TxCpltCallback(&huart1);
  }

  len = send_packet(uart_wbuf, uart_frame_buf+8, received_bytes, /*sport*/dport, /*dport*/ sport);
  HAL_UART_Transmit_IT(&huart1, (uint8_t*)uart_wbuf, len);
}

void realtime() {
  handle_uart_receive();
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
  if (htim->Instance == TIM6) {
    UART_HandleTypeDef *huart = &huart1;
    if (huart->RxXferCount == RECV_CHUNK)
      return;

    __HAL_UART_DISABLE_IT(huart, UART_IT_RXNE);

    /* Check if a transmit process is ongoing or not */
    if(huart->State == HAL_UART_STATE_BUSY_TX_RX)
    {
      huart->State = HAL_UART_STATE_BUSY_TX;
    }
    else
    {
      /* Disable the UART Parity Error Interrupt */
      __HAL_UART_DISABLE_IT(huart, UART_IT_PE);

      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
      __HAL_UART_DISABLE_IT(huart, UART_IT_ERR);

      huart->State = HAL_UART_STATE_READY;
    }
    HAL_UART_RxCpltCallback(huart);
  }
}

/* USER CODE END 4 */

0
Графическая утилита по настройке камешка с использованием драйверов HAL и генерацией кода
0
Графическая утилита по настройке камешка с использованием драйверов HAL и генерацией кода
ГУпнкСидHALигк
+1
разработан в соответствии со Strict ANSI-C
Это, интересно, что такое?
0
С89.
0
Помогите разобраться с hal. В библиотеки имеются готовые define для работы с флагами, например
#define __HAL_DMA_GET_TC_FLAG_INDEX(__HANDLE__) \
(((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA1_Stream0))? DMA_FLAG_TCIF0_4 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA2_Stream0))? DMA_FLAG_TCIF0_4 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA1_Stream4))? DMA_FLAG_TCIF0_4 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA2_Stream4))? DMA_FLAG_TCIF0_4 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA1_Stream1))? DMA_FLAG_TCIF1_5 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA2_Stream1))? DMA_FLAG_TCIF1_5 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA1_Stream5))? DMA_FLAG_TCIF1_5 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA2_Stream5))? DMA_FLAG_TCIF1_5 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA1_Stream2))? DMA_FLAG_TCIF2_6 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA2_Stream2))? DMA_FLAG_TCIF2_6 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA1_Stream6))? DMA_FLAG_TCIF2_6 :\
((uint32_t)((__HANDLE__)->Instance) == ((uint32_t)DMA2_Stream6))? DMA_FLAG_TCIF2_6 :\
DMA_FLAG_TCIF3_7)
Чтобы его использовать я так понимаю нужно определить handle. Для dma нужно hdma.
0

У меня выдает ошибку — use undeclared identifier. Подскажите как правильно использовать define, где у меня ошибка. Причем это не только ДМА касается ну остальной перифирии при попытки воспользоваться define.
0
Написано же — нет такой переменной (символа, точнее) — hdma. А значит, ты либо неправильно пишешь (скажем, не в том регистре), либо забыл включить хедер, где оно определяется. Ну или вообще должен сам этот хендл объявить и инициализировать (я новый HAL не изучал).
0
А чем она лучше обычных дров периферии, которые идут вместе CMSIS? По сути там уже все сделано, бери и используй.
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.