Portfolio Обо мне Блог

В этой заметке я соберу короткие заметки касательно работы в CubeIDE, думаю результатами можно будет воспользоваться для любой IDE на основе eclipse. Если (вдруг) вам интересно мое мнение, то лучше не используйте CubeIDE, а настройте VScode, об этом есть статья в блоге.

Как установить CubeIDE в линукс?

1) Необходимо на сайте выбрать STM32CubeIDE-Lnx (STM32CubeIDE Generic Linux Installer) и скачать его. 2) Далее необходимо распаковать и запустить st-stm32cubeide*.sh. 3) Соглашаемся с лицензией (не читая). 4) Соглашаемся установить STLinkServer и Udev rules для STLink и Jlink. 5) Прописываем папку для установки, я выбрал - /home/zen/STM32CubeIDE. 6) Вводим пароль от рута для установки софта из пункта 4. 7) Соглашаемся с 2-мя лицензиями. 8) ОТКАЗЫВАЕМСЯ от выставления Udev rules для Jlink, если вы ставили JlinkServer отдельно, т.к. это вызовет ошибки в его работе. 9) Создаем ссылку чтобы удобно запускать IDE через консоль:

 sudo ln -s /home/zen/STM32CubeIDE/stm32cubeide /usr/bin/cubeide

10) Перезагружаемся. (После установки некорректно применяется глобальная gtk тема оформления, из-за чего cube вылетает). 11) Ставим Darkest Dark тему в магазине Eclipse. Последний пункт сработает только если глобально стоит темная тема gtk, если нет, то лучше так не делать, будет только хуже.

Этот способ позволяет нормально обновляться из под самой IDE в отличии установки из DEB пакета.

Как добавить свою папку в проект?

Для этого вам нужно добавить новые пути в Properties текущего проекта, только для этого папки уже должны быть добавлены в директорию вашего проекта:

properties

А также указать компилятору, где искать новые хедеры:

source

Также папку с хедерами можно указать и для С++. После этого вы сможете без проблем добавлять новые файлы в проект через меню:

add_file

Как писать код на С++?

Для этого воспользуетесь пунктом Соединяем CPP и C в этой статье.

Как использовать printf?

Для его работы нужно переопределить в main.c функцию _write():

#include "stdlib.h"
#include "stdio.h"

int _write(int file, char *ptr, int len) {
  for (int i = 0; i < len; i++)
    HAL_UART_Transmit(&huart2, (uint8_t*) ptr++, 1, 100);
  return len;
}

Или если мы хотим использовать SWO:

int _write(int file, char *ptr, int len) {
  /* Implement your write code here, this is used by puts and printf for example */
  for (int i = 0; i < len; i++)
    ITM_SendChar((*ptr++));
  return len;
}

Также можно переопределить _read(), Это сделает возможным использование scanf(), но если вам интересно мое мнение НЕ ИСПОЛЬЗУЙТЕ printf() и прочее, т.к. эти функции динамически выделяют память.

Пишем во флеш на HAL

Запишем кусочек памяти:

photo_2020-09-22_20-56-57

HAL_FLASH_Unlock();
uint64_t data = (uint64_t)'g' + ((uint64_t)'o' << 8) + ((uint64_t)'o' << 16) + ((uint64_t)'d' << 24);

HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, 0x0807FFF8, data);
HAL_FLASH_Lock();

photo_2020-09-22_20-58-49

Теперь очистим страницу (забьем FF), и запишем 64-битное значение.

photo_2020-09-22_21-10-17

HAL_FLASH_Unlock();
uint32_t data_h = 0x12345678;
uint32_t data_l = 0x9abcdef0;
uint64_t data = ((uint64_t)data_l << 32) + (uint64_t)data_h;

static FLASH_EraseInitTypeDef EraseInitStruct;

EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Page = 127;
EraseInitStruct.NbPages = 1;
EraseInitStruct.Banks = FLASH_BANK_2;

uint32_t page_error = 0;

HAL_FLASHEx_Erase(&EraseInitStruct, &page_error);
HAL_FLASH_Lock();

HAL_FLASH_Unlock();
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, 0x0807FFF8, data);
HAL_FLASH_Lock();

photo_2020-09-22_21-18-12

IDLE регистр в STM32

Используем IDLE регистр в STM32 (нужен для того чтобы определить конец сообщения с непрерывной передачей байтов, выставляется если перерыв между байтами больше половины этого байта по времени). Для начала необходимо создать буфер:

#define BUFSIZE 100
uint8_t buf_terminal_read[BUFSIZE] = { 0 };

Далее необходимо включить прием массива байтов с прерыванием по окончанию, и включить прерывание IDLE байту.

HAL_UART_Receive_IT(&huart2, buf_terminal_read, BUFSIZE);
__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);

Далее нужно создать свой обработчик для данного прерывания.

void USER_UART_IRQHandler(UART_HandleTypeDef *huart) {
  if (USART2 == huart2.Instance) {
    if (RESET != __HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE))            {
      __HAL_UART_CLEAR_IDLEFLAG(&huart2);
      int len = BUFSIZE - huart->RxXferCount;
      buf_terminal_read[len] = '\0';

      HAL_UART_AbortReceive(&huart2);
      HAL_UART_Receive_IT(&huart2, buf_terminal_read, BUFSIZE);
      flag = 1;
    }
  }
}

В данном обработчике к принятой строке длинной len добавляется '\0', чтобы можно было найти конец принятой строки, если принимаются не стоковые данные то работать не будет. Последнее что нужно сделать, это добавить новый обработчик внутрь обработчика прерывания в файле ...xx_it.c и сделать extern нашего обработчика.

extern void USER_UART_IRQHandler(UART_HandleTypeDef *huart);

void USART3_IRQHandler(void)
{
  /* USER CODE BEGIN USART3_IRQn 0 */
  USER_UART_IRQHandler(&huart3);
  /* USER CODE END USART3_IRQn 0 */
  HAL_UART_IRQHandler(&huart3);
}