Как правильно настроить регистр USART_BRR в STM32L476RG uC?

Я пытаюсь написать собственный драйвер для USART_TX на плате Nucleo STM32L476RG. Здесь таблица и справочное руководство.

Я использую Keil uVision 5 и в диалоговом окне «Управление» установил:

  • CMSIS ›Ядро
  • Устройство ›Запуск
  • Xtal = 16 МГц

Я хочу создать односимвольный передатчик. Согласно инструкции в гл. 40 p 1332 Я написал этот код:

// APB1 connects USART2
// The USART2 EN bit on APB1ENR1 is the 17th
// See alternate functions pins and label for USART2_TX! PA2 is the pin and AF7 (AFRL register) is the function to be set


#include "stm32l4xx.h"                  // Device header

#define MASK(x) ((uint32_t) (1<<(x)));

void USART2_Init(void);
void USART2_Wr(int ch);
void delayMs(int delay);

int main(void){
    USART2_Init();
    

    while(1){
    USART2_Wr('A');
    delayMs(100);
        
        
    }
}

void USART2_Init(void){
    RCC->APB1ENR1 |= MASK(17); // Enable USART2 on APB1
    // we know that the pin that permits the USART2_TX is the PA2, so...
    RCC->AHB2ENR |= MASK(0); // enable GPIOA
    
    // Now, in GPIOA 2 put the AF7, which can be set by placing AF7=0111 in AFSEL2 (pin2 selected)
    // AFR[0] refers to GPIOA_AFRL register
    // Remember: each pin asks for 4 bits to define the alternate functions. see pg. 87 
    // of the datasheet
    GPIOA->AFR[0] |= 0x700; 
    GPIOA->MODER &= ~MASK(4);// now ... we set the PA2 directly with moder as alternate function "10"
    
    // USART Features -----------
    
    //USART2->CR1 |=MASK(15); //OVER8=1
    USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?
    //USART2->BRR = 0x1A1; //This one works!!!
    USART2->CR1 |=MASK(0); //UE
    USART2->CR1 |=MASK(3); //TE
    
}

void USART2_Wr(int ch){
    //wait when TX buffer is empty
    while(!(USART2->ISR & 0x80)) {} //when data is transfered in the register the ISR goes 0x80.
        //then we lock the procedure in a while loop until it happens
        USART2->TDR =(ch & 0xFF); 

}

void delayMs(int delay){
int i;
    for (; delay>0; delay--){
        for (i=0; i<3195; i++);
    }
}

Теперь проблема:

Система работает, но не корректно. Я имею в виду: если я использую RealTerm со скоростью 9600 бод, как настроено с помощью 0x683 в USART_BRR reg, он показывает мне неправильный символ, но если я устанавливаю 2400 в качестве скорости передачи в реальном времени, это работает!

Чтобы извлечь 0x683 в регистре USART_BRR, я обратился к сек. 40.5.4 Генерация скорости передачи данных USART, и в нем говорится, что если OVER8 = 0, USARTDIV = BRR. В моем случае USARTDIV = 16MHz / 9600 = 1667d = 683h.

Я думаю, что проблема в этой строке кода:

USART2->BRR = 0x683; //USARTDIV=16Mhz/9600?

потому что если я заменю его как

USART2->BRR = 0x1A1; //USARTDIV=16Mhz/9600?

Система работает со скоростью 9600 бод.

Что не так в моем коде или в понимании вычислений USARTDIV?

Спасибо заранее за вашу поддержку.

С уважением, GM


person g.mezzina23    schedule 12.10.2019    source источник


Ответы (1)


Источником синхронизации по умолчанию для USART является PCLK1 (рисунок 15), PCLK1 равно SYSCLK / AHB_PRESC / AHB1_PRESC. Если 0x1A1 дает скорость передачи 9600, это означает, что PCLK1 = 4 МГц.

Частота процессора по умолчанию (и PCLK1) при запуске при работе от внутреннего генератора MSI RC составляет 4 МГц. Таким образом, наиболее вероятное объяснение заключается в том, что вы не настроили дерево часов и не работаете с 16-мегагерцовой HSE, как вы думаете.

Либо настройте свое дерево часов для использования источника 16 МГц, либо выполните вычисления на частоте MSI. Точность MSI примерно достаточно хороша в нормальном температурном диапазоне, чтобы поддерживать достаточно точную скорость передачи данных, но она не идеальна.

person Clifford    schedule 12.10.2019
comment
st.com/content/ccc/resource/training/technical/product_training/ Спасибо. Я нахожу здесь кое-что о вашем ответе. - person g.mezzina23; 12.10.2019
comment
@ g.mezzina23 в большинстве случаев часы настраиваются в коде запуска среды выполнения C. - person Clifford; 12.10.2019