8-900-374-94-44
[email protected]
Slide Image
Меню

Описание hal stm32 – Описание драйверов HAL STM32F4xx, частичный перевод / STM32 / Сообщество EasyElectronics.ru

Описание драйверов HAL STM32F4xx, частичный перевод / STM32 / Сообщество EasyElectronics.ru


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

Введение

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. Старался перевести максимально «корректно», а как получилось…
Если кем-то будут замечены ляпусы — исправлю.
Обсуждение на форуме

we.easyelectronics.ru

Проект STM32 HAL на C++ – Radiotech

Если вы как я любитель писать на C++ для микроконтроллеров STM32, то наверняка в курсе данной проблемы, а именно то, что при использовании утилиты CubeMX генерируется HAL проект только с поддержкой Си, тогда как HAL в принципе поддерживает C++.

Я использую Atollic TrueSTUDIO в разработке и соответственно импорт из CubeMX делаю в него и в итоге получаю Си проект с HAL. Но у меня овердофига готовых классов на C++, которые я хочу добавить в проект, и мне нужен проект C++. Сконвертировать проект на самом деле не сложно и делается это в 3 простых шага:

  1. Для начала копируем содержимое main.c в main.cpp и удаляем main.c (Важно, не пытайтесь оставить оба файла в проекте).
  2. Далее добавьте в .project файл проекта в секцию <natures> строку <nature>org.eclipse.cdt.core.ccnature</nature> 
  3.  Следующим шагом дублируем соответствующие настройки Си проекта в C++ как показано ниже:
Копируем внимательно, чтобы не забыть ни одной строки

Собственно тоже самое проделывается с настройками Symbols, Optimiztion и т.д., если есть необходимость.

Теперь проект просто необходимо закрыть и открыть заново. чтобы изменения вступили в силу. В результате получаем: все компилируется и линкуется без ошибок, отладка работает корректно, из main.cpp вызывается HAL код и HAL callback функции могут вызываться в .cpp файлах.

Модификатор extern “C”  может быть необходим в .cpp файлах, если .cpp сторона вызывает функции на стороне .c кода или из .c кода вызывается callback функция, определенная в .cpp файле.

Если вы выполняете повторную генерацию проекта из CubeMX для внесения изменений данные изменения попадут в main.c и не попадут в main.cpp, поэтому необходимо их вносить вручную.

На этом вроде все, если когда-нибудь появится хак, который будет делать все это автоматически будет очень неплохо, а пока делаю все ручками)

Спасибо, что дочитали до конца. Подписывайтесь на нашу группу в ВК и заходите общаться в наш чат.

blog.radiotech.kz

Микроконтроллеры STM32: работа с внешним EEPROM

Одна из проблем с микроконтроллерами STM32 заключается в том, что большинство из них не имеют встроенного EEPROM. Исключением являются только микроконтроллеры серий STM32L0 и STM32L1 с ультра низким энергопотреблением. Это довольно странно после работы с AVR, где EEPROM есть у всех микроконтроллеров. Существует несколько решений, но в рамках этой заметки мы рассмотрим самое очевидное — использование внешнего EEPROM на примере чипа с I2C-интерфейсом 24LC64.

Дополнение: Альтернативное решение заключается в том, чтобы воспользоваться встроенной backup memory микроконтроллеров STM32. Подробности по этой теме вы найдете в посте Микроконтроллеры STM32: использование встроенных RTC.

Цифра 64 в названии говорит о том, что устройство имеет 64 килобит памяти, или 8 Кбайт. Есть аналогичные чипы от разных производителей и с разными объемами памяти — я видел от 128 байт (например, M24C01 от компании ST) до 256 Кбайт (AT24CM02 производства Atmel). В плане распиновки и интерфейса все они абсолютно взаимозаменяемы. Далее я буду говорить о 24LC64, производимом компанией Microchip, так как сам использовал именно его.

Распиновка 24LC64 выглядит так (даташит [PDF]):

VSS и VCC, понятно, представляют собой минус и плюс питания, а SDA и SCL — это I2C шина. Устройство имеет I2C-адрес 0b1010zyx, где значения x, y и z определяются тем, к чему подключены пины A0, A1 и A2. Если пин подключен к земле, соответствующий бит адреса равен нулю, если же к плюсу — то единице. Таким образом, устройство может иметь адрес от 0x50 до 0x57. Наконец, пин WP — это write protection. Если пин подключен к земле, разрешено как чтение, так и запись. Если же пин подключен к плюсу, устройство доступно только на чтение.

Создаем новый проект в STM32CubeMX для вашей отладочной платы. Лично я все также использую плату Nucleo-F411RE, но если вы используете другую, отличия в проекте должны быть минимальными. В Peripherals включаем устройство I2C1, выбрав в выпадающем списке «I2C» вместо «Disable». Также мы будем передавать что-то компьютеру, поэтому включаем устройство USART2, как делали это в заметке Микроконтроллеры STM32: обмен данными по UART. Чтобы плату можно было использовать с Arduino-шилдами, несущими какие-то I2C-устройства, пины I2C1 нужно переназначить на PB9 и PB8 (по умолчанию будут назначены другие: PB7 и PB6). В итоге должна получиться такая картинка:

Затем генерируем код и подправляем Makefile, как обычно. Я лично просто взял Makefile из исходников к заметке про UART и дописал недостающие файлы в C_SOURCES, а именно:

$(FIRMWARE)/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c.c \
$(FIRMWARE)/Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_i2c_ex.c \

Для подключения 24LC64 к плате Nucleo я воспользовался Proto Shield от Arduino. Пришлось прорезать в нем отверстие Dremel’ем, чтобы иметь доступ к кнопкам на отладочной плате. В итоге у меня получился вот такой сэндвич:

Кто-то из читателей мог обратить внимание на то, что в I2C-шине должны использоваться резисторы, подтягивающие SCL и SDA к плюсу, но в этом проекте мы их не используем. Дело в том, что для моей платы и использованного в ней микроконтроллера STM32CubeMX автоматически включает встроенные подтягивающие резисторы на соответствующих пинах.

Убедиться в этом несложно, посмотрев код процедуры HAL_I2C_MspInit в файле ./Src/stm32f4xx_hal_msp.c:

// ...
    /**I2C1 GPIO Configuration    
    PB8     ------> I2C1_SCL
    PB9     ------> I2C1_SDA
    */  
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
// ...

Правда, не так очевидно, почему процедура HAL_I2C_MspInit вообще откуда-то вызывается. Ответ можно найти в файле stm32f4xx_hal_i2c.c где эта процедура объявляется с атрибутом

__weak и вызывается из процедуры HAL_I2C_Init. Атрибут __weak работает таким образом, что при сборке не-weak процедура из кода нашего проекта подменяет собой weak-процедуру из HAL, за счет чего она и будет вызвана.

Заметьте, однако, что встроенные подтягивающие резисторы доступны не во всех микроконтроллерах STM32. Насколько мне известно, для серии STM32F1 это работать не будет, и придется все-таки использовать внешние подтягивающие резисторы.

Наконец, рассмотрим основной код прошивки:

void init() {
    const char wmsg[] = "Some data";
    char rmsg[sizeof(wmsg)];
    // HAL expects address to be shifted one bit to the left
    uint16_t devAddr = (0x50 << 1);
    uint16_t memAddr = 0x0100;
    HAL_StatusTypeDef status;

    // Hint: try to comment this line
    HAL_I2C_Mem_Write(&hi2c1, devAddr, memAddr, I2C_MEMADD_SIZE_16BIT,
        (uint8_t*)wmsg, sizeof(wmsg), HAL_MAX_DELAY);

    for(;;) { // wait...
        status = HAL_I2C_IsDeviceReady(&hi2c1, devAddr, 1,

                                       HAL_MAX_DELAY);
        if(status == HAL_OK)
            break;
    }

    HAL_I2C_Mem_Read(&hi2c1, devAddr, memAddr, I2C_MEMADD_SIZE_16BIT,
        (uint8_t*)rmsg, sizeof(rmsg), HAL_MAX_DELAY);

    if(memcmp(rmsg, wmsg, sizeof(rmsg)) == 0) {
        const char result[] = "Test passed!\r\n";
        HAL_UART_Transmit(&huart2, (uint8_t*)result, sizeof(result)-1,
                          HAL_MAX_DELAY);
    } else {
        const char result[] = "Test failed :(\r\n";
        HAL_UART_Transmit(&huart2, (uint8_t*)result, sizeof(result)-1,
                          HAL_MAX_DELAY);
    }
}

Для работы с внешней памятью в HAL предусмотрены специальные процедуры HAL_I2C_Mem_Read и HAL_I2C_Mem_Write. Заметьте, что эти процедуры работают с I2C адресами, сдвинутыми на 1 бит влево. Связано это с тем, что в протоколе I2C семибитный адрес устройства и бит операции (чтение или запись) передаются в одном байте. Использование «сдвинутых» адресов позволяет выполнять чуть меньше ассемблерных инструкций, что нередко бывает важно в разработке встраиваемых систем. Еще стоит обратить внимание на то, что перед чтением с устройства мы должны дождаться его готовности с помощью процедуры HAL_I2C_IsDeviceReady. Наконец, здесь я забил на коды возврата большинства использованных процедур, чего в боевом коде, пожалуй, делать не стоит.

Fun fact! Вдумчивый читатель, конечно же, обратил внимание на тот факт, что адрес памяти имеет тип uint16_t. Спрашивается, как можно адресовать им более 64 Кбайт памяти, например, те же 256 Кбайт у AT24CM02? Само собой разумеется, никак. Чипы, имеющие более 64 Кбайт памяти, начинают использовать для адресации младшие биты I2С-адреса устройства. То есть, с точки зрения нашего кода, они будут выглядеть, как 2 или более отдельных I2C-устройства. Соответствующие пины, определяющие адрес устройства, при этом являются NC, то есть, ни к чему не подключаются.

При работе с EEPROM нужно учитывать еще пару важных моментов:

  • 24LC64 и его родственники хранят данные в страницах по 32 байта. За один вызов HAL_I2C_Mem_Write вы можете записать только одну страницу, причем нужно учитывать не только размер данных, но и их выравнивание. Если требутеся записать больше одной страницы, процедуру нужно вызывать в цикле. На чтение, насколько я смог выяснить, таких ограничений нет — читать можно сколько угодно и по любым смещениям;
  • Запись в EEPROM может быть прервана в любой момент (сел аккумулятор, пользователь выдернул кабель питания, …). Поэтому в боевом коде стоит хранить вместе с данными их контрольную сумму. В случае, если будет записана только часть данных, это позволит обнаружить проблему и использовать хотя бы параметры по умолчанию, а не какой-то мусор.

Полную версию исходников к этой заметке вы найдете на GitHub. В качестве небольшого домашнего задания можете модифицировать прошивку так, чтобы она дампила все содержимое EEPROM и передавала его по UART. Код форматирования бинарных данных в стиле того, как это делает hexdump, можно взять из поста Перехват сетевого трафика при помощи библиотеки libpcap (процедура print_data_hex). В итоге должен получиться приятный такой отладочный инструмент — простенький, но со вкусом.

А доводилось ли вам работать с внешней памятью, и если да, то с какой именно?

Дополнение: Также вас могут заинтересовать посты Микроконтроллеры STM32: работа с SPI на примере флеш-памяти AT45DB161E и Учимся работать с SDHC/SDXC-картами по протоколу SPI.

Метки: STM32, Электроника.

eax.me

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *