Передача STM32F04 UART с прерываниями

Я прототипировал свой проект с помощью STM32F103 «Bluepill», и для конечного продукта я хочу перейти на STM32F042F6, который имеет меньшую площадь TSSOP-20. Мне нужно использовать UART для связи с устройством, поэтому я попытался создать простую программу передачи UART, чтобы проверить, правильно ли работает периферийное устройство UART. Вот мой код.

#include "stm32f0xx.h"
#include "stm32f0xx_hal.h"
#include "stm32f0xx_hal_conf.h"

void Startup_Sequence(void);
void Error_Handler(void);
void SystemClock_Config(void);
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle);

UART_HandleTypeDef UartHandle;
__IO ITStatus UartReady = RESET;

int main(void)
{
    HAL_Init();
    //SystemInit();
    SystemClock_Config();

    GPIO_InitTypeDef  GPIO_InitStruct;
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_USART1_CLK_ENABLE();

   // Setup LED Pin
   GPIO_InitStruct.Pin = GPIO_PIN_4;
   GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; 
   GPIO_InitStruct.Pull = GPIO_NOPULL;
   GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

   // Setup UART Tx Pin
  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  // Setup UART Rx pin
  GPIO_InitStruct.Pin = GPIO_PIN_10;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  //Setup UART Instance
  UartHandle.Instance = USART1;
  UartHandle.Init.BaudRate = 9600;
  UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
  UartHandle.Init.StopBits = UART_STOPBITS_1;
  UartHandle.Init.Parity = UART_PARITY_NONE;
  UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  UartHandle.Init.Mode = UART_MODE_TX_RX;
  UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
  UartHandle.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  UartHandle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

  //Error handling
  if(HAL_UART_Init(&UartHandle) != HAL_OK) {
      Error_Handler();
  }

  Startup_Sequence();

  HAL_NVIC_SetPriority(USART1_IRQn, 0, 1);
  HAL_NVIC_EnableIRQ(USART1_IRQn);  

  char hello[6] = "hello\n";

  while(1) {
      if(HAL_UART_Transmit_IT(&UartHandle, (uint8_t *)hello, 6) != HAL_OK) {
          Error_Handler();
      }     
  }
}

void Startup_Sequence(void) {
    int i;
    for (i=1; i<50;i++) {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);
        HAL_Delay((1.0/i) * 1000);
    }
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
}

void Error_Handler(void) {
    while(1) {
        HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_4);
        HAL_Delay(1000);
    }
}

/**
  * Associates the interrupt handler with the UartHandle
 */
void USART1_IRQHandler(void) {
    HAL_UART_IRQHandler(&UartHandle);
}

/**
 * This function is called when transmitting
 * @param UartHandle [Pointer to UartHandle]
 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle) {
    UartReady = SET;
}

/**
 * This function is called when receiving
 * @param UartHandle [Pointer to UartHandle]
 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) {
    UartReady = SET;
}

void SystemClock_Config(void) {
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_PeriphCLKInitTypeDef PeriphClkInit;

    /**Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48;
    RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_ClkInitStruct.ClockType = 
    RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                           |RCC_CLOCKTYPE_PCLK1;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != 
    HAL_OK)
    {
        Error_Handler();
    }

    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
    PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
        Error_Handler();
    }

    /**Configure the Systick interrupt time 
    */
    HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

    /* SysTick_IRQn interrupt configuration */
    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
} 

Периферийное устройство UART инициализируется правильно, поскольку обработчик ошибок не вызывается до тех пор, пока не завершится Startup_Sequence(). Так почему же при попытке передачи вызывается ErrorHandler? Я пытался отправить с использованием режима блокировки, но каждый раз просто истекает время ожидания.

РЕДАКТИРОВАТЬ: я отследил ошибку до функции инициализации. Вот журнал GDB https://hastebin.com/xopohaniyu.coffeescript , но я нигде не могу найти, где HAL_OK не возвращается.

Что-то не так с моей настройкой периферийного устройства UART? Или проблема с системными часами? Пожалуйста, порекомендуйте.

Почему вы без необходимости занимаетесь математикой с плавающей запятой при расчете задержки? Просто разделите 1000 на целочисленный делитель. В более общем смысле проблема с вашим кодом заключается в том, что непонятно, что скопировано из какого-то источника, а что является оригинальным. Возможно, вам следует попытаться заставить какой-то существующий фрагмент кода работать без изменений , прежде чем пытаться модифицировать его, чтобы иметь лучшее представление о том, откуда могут возникнуть последующие проблемы. Также убедитесь, что ваша сборка предназначена исключительно для серии STM32F0 и не включает файлы, принадлежащие к довольно другой серии STM32F1, которую вы использовали ранее.
Наконец, поставьте точку останова на обработчике ошибок, а затем выполните обратную трассировку, чтобы увидеть, как он туда попал — ваш журнал отладки не включает фактический сбой, поэтому он не очень полезен.

Ответы (1)

Настройка GPIO несколько сложнее на F0. Здесь также следует установить GPIO_InitStruct.Alternate = GPIO_AF1_USART1, иначе она получит какое-то случайное значение, потому что это унитаризованная автоматическая переменная. Включите предупреждения в компиляторе и обратите на них внимание, они не просто так.

HAL_UART_Transmit_IT()вызывается снова до завершения предыдущей передачи. Вы должны подождать, пока UartReadyфлаг не будет установлен, и сбросить его перед повторением.