STM32L152 скорости передачи UART с использованием HSE

Я пытаюсь настроить скорость передачи данных USART1 на STM32L152. При использовании внешних часов скорость передачи составляет половину от того, что я настроил (например, 57600 вместо 115200). Однако при использовании внутреннего HSI все правильно. Внутренняя частота составляет 16 МГц, а внешняя - это кристалл 8 МГц, который используется для управления PLL для системных часов 32 МГц.

Это код инициализации RCC, который, по-моему, довольно стандартный.

int RCC_Configuration(void)
{
  /* DISABLE HSI and target clocks prior to clock config */
  RCC_HSICmd(DISABLE);
  RCC_PLLCmd(DISABLE);
  RCC_HSEConfig(RCC_HSE_OFF);

  /* Set HSE as sys clock*/
  RCC_SYSCLKConfig(RCC_SYSCLKSource_HSE);

  /* Enable ADC & SYSCFG clocks */
  RCC_APB2Periph_SYSCFG , ENABLE);

  /* Allow access to the RTC */
  PWR_RTCAccessCmd(ENABLE);

  /* Reset RTC Backup Domain */
  RCC_RTCResetCmd(ENABLE);
  RCC_RTCResetCmd(DISABLE);

  /* LSI used as RTC source clock */
  /* The RTC Clock may varies due to LSI frequency dispersion. */
  /* Enable the LSI OSC */
  RCC_LSICmd(ENABLE);

  /* Wait until LSE is ready */
  while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);

  /* Select the RTC Clock Source */
  RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

  /* Enable the RTC */
  RCC_RTCCLKCmd(ENABLE);

  /* Wait for RTC APB registers synchronisation */
  RTC_WaitForSynchro();

  // ENABLE HSE
  RCC_HSEConfig(RCC_HSE_ON);
  ErrorStatus HSEStartUpStatus = RCC_WaitForHSEStartUp();

  if(HSEStartUpStatus == SUCCESS)
  {
      /* 32Mhz = 8Mhz * 12 / 3 */
      RCC_PLLConfig(RCC_PLLSource_HSE, RCC_PLLMul_12, RCC_PLLDiv_3);

      /* Enable PLL */
      RCC_PLLCmd(ENABLE);

      /* Wait till PLL is ready */
      while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
      {
      }

      /* Select PLL as system clock source */
      RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

      /* Wait till PLL is used as system clock source */
      while(RCC_GetSYSCLKSource() != 0x0C)  // 0x0C = PLL
      {
      }

      /* Enable the PWR clock */
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
      PWR->CR = PWR_CR_VOS_0;                /* Select the Voltage Range 1 (1.8V) */
      while((PWR->CSR & PWR_CSR_VOSF) != 0); /* Wait for Voltage Regulator Ready  */

      /* HCLK = SYSCLK */
      RCC_HCLKConfig(RCC_SYSCLK_Div1);

      /* PCLK1 = HCLK/2 */
      RCC_PCLK1Config(RCC_HCLK_Div2);

      /* PCLK2 = HCLK */
      RCC_PCLK2Config(RCC_HCLK_Div1);

      /* Enable the GPIOs clocks */
      RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC| RCC_AHBPeriph_GPIOD| RCC_AHBPeriph_GPIOE| RCC_AHBPeriph_GPIOH, ENABLE);
      /* Enable comparator, LCD and PWR mngt clocks */
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_COMP | RCC_APB1Periph_LCD | RCC_APB1Periph_PWR,ENABLE);
  }

  return 0;

}

Я использую STDperiph для настройки UART1, который на этом mcu будет работать на PCLK2. Проверены все методы init и содержимое реестра. Мантисса и фракция регистра скорости передачи данных рассчитаны правильно и должны давать правильную скорость передачи данных независимо от значения PCLK.

Это код инициализации UART:

void usartinit(void)
{
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;

USART_InitStructure.USART_BaudRate = 115200 ;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

/* Enable GPIO clock */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

GPIO_PinAFConfig(USARTx_GPIO, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(USARTx_GPIO, GPIO_PinSource10, GPIO_AF_USART1);

/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Pin = USARTx_TX;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(USARTx_GPIO, &GPIO_InitStructure);

/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Pin = USARTx_RX;
GPIO_Init(USARTx_GPIO, &GPIO_InitStructure);

/* USART configuration */
USART_Init(USART1, &USART_InitStructure);

/* Enable USART */
USART_Cmd(USART1, ENABLE);
}

Единственная возможность, о которой я могу думать прямо сейчас, - это то, что кристалл составляет всего 4 МГц, но это плата Nucleo, а MCO из подключенного STLink используется для HSE, который определенно составляет 8 МГц.

Какую вопиющую ошибку я совершаю?

3 ответа

Решение

Хорошо, наконец, понял это. На платах Nucleo в конфигурации по умолчанию часы HSE подключены к выходу часов MCO программатора STLink на плате. Однако на нескольких моих платах этот тактовый сигнал искажается настолько, что целевой УК только видит 4 МГц. Если я выведу HSE на MCO цели, то получится прямоугольная волна 4 МГц со странным рабочим циклом 75%. При измерении входного сигнала MCO с помощью области измерения емкости датчика достаточно для получения правильного входа 8 МГц.

Так что, я полагаю, не доверяйте вашим оценочным платам... Теперь возьмите несколько кристаллов и установите "настоящие" внешние часы на этих досках.

Я думаю, что предыдущий ответ правильный. При использовании HSI ваша системная тактовая частота составляет 16 МГц, тогда как при использовании HSE ваша системная тактовая частота составляет 32 МГц.

Я подозреваю, что значение HSE установлено на 16 МГц.

Вы также можете проверить это, установив множитель 4 и делитель 2, чтобы системные тактовые частоты составляли 16 МГц при работе HSE.

Значение HSE будет где-то в коде запуска.

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

Кажется, что часы испорчены. Проверьте макрос HSE_VALUE в вашем коде. Это может быть использование значения кристалла платы разработчика по умолчанию. Я бы посоветовал изменить это значение на тот кристалл, который вы используете. Вы можете использовать эту ссылку, чтобы установить тактовую частоту.

Другие вопросы по тегам