3

I am beginner in embedded systems. I am trying to write data on UART2 of STM32F103C8 (i. e., the Blue Pill board) and want to see the data in one of the ports of my computer using an FTDI adapter, which is connected to UART2 of the STM32F103C8 board. But on my console I receive some random square block instead of the character which I want to transmit.

Here is my code written in Keil IDE.

#include "stm32f10x.h"                  // Device header

void usart2_init(void);
void USART_write(int data);
void delayMs(int delay);

int main(void)
{
    usart2_init();
    while(1)
    {
       USART_write('A');
       delayMs(5000);
    }
}

void usart2_init(void)
{
       // Enable clock source for USART2
       RCC->APB1ENR |= 0x20000;           // 0b 0000 0000 0000 0010 0000 0000 0000 0000
       RCC->APB2ENR |= 0x4;
       GPIOA->CRL |= 0x900;               // Set PA2 as TX pin (AF)
       USART2->BRR  = 0x341;              // Setting Baudrate to 9600 @8 MHz.
       USART2->CR1 |= 0x00008;            // Enable TX only
       USART2->CR1 |= 0x02000;            // Enable USART module by setting bit 13 to 1 i
       USART->CR1 register
}

void USART_write(int data)
{
    // We need to wait until Tx buffer is empty for sending data.
    while(!(USART2->SR & 0x0080));        // 0x0080
    USART2->DR = (data & 0xFF);
}

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

Below I attached the screenshot while debugging.

Click here to see screenshot.

You can see the unwanted square block instead of character instead of the characters I want to transmit. In the image you can also see the UART registers and their values. I am using ST-LINK2 to upload the firmware.

Am I missing some information or doing some mistake while dealing with FTDI and Tera Term? This is my Tera Term configuration:

  • Baud rate = 9600
  • Data = 8 bit
  • Parity = none
  • Stop bit = 1
  • Control flow = none

How can I fix this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • 1
    A random square block, sounds like an unprintable character. Print the hex value of the byte rather than the byte and I bet its less than 0x20 or more than 126 – Code Gorilla Apr 30 '20 at 15:29
  • 1
    The setting of BRR (Baud Rate Register) is wrong. This register holds a 12bits divider and 4bits fractional divider. Other error the clock for usart peripheral is 36MHz, not 8MHz.For correct settings get a copy of STM32F10X manual and find values on table 192. Or simply use libopencm3 very simple to use. – Frankie_C Apr 30 '20 at 15:44
  • Hi, @Frankie_C, thanks for help. My code works on frequency 36MHz. – Tushar Yadav May 01 '20 at 04:25
  • You're welcome. Keep in mind that those devices are as flexible as complicated to program. Don't suppose anything and always read carefully the datasheets. Google for libopencm3 it could be a big help, I prefer it to STM native HAL development. – Frankie_C May 01 '20 at 08:33

2 Answers2

1

When working with those devices you should have a careful reading of datasheets/reference manuals and possibly applicable AN (application notes) widely available from the producer site.

In the specific case, the STM32F10x family works generally with a system clock of 72 MHz generated by an internal PLL oscillator which use the external crystal, having frequency of 8 MHz on Blue Pill, as the reference for the PLL (phase-locked loop) circuitry that controls it. The 8 MHz crystal oscillator is called HSE, which stands for High Speed External oscillator.

I said 'generally' because the user can select different system clock frequencies by programming the specific prescalers and internal clock circuitry, which can become very complicated at first sight (and even at second…).

Now assuming the standard configuration the peripheral interfaces, where the system clock is selected at 72 MHz and the AHB prescaler to 1, the two peripheral clocks (PCLCKx) are set to 36 MHz (PCLCK1: prescaler = 2) and 72 MHz (PCLCK2), respectively.

On STM32F10x chips, only USART1 is clocked from PCLCK2, and all other are clocked from PCKLK1 (maximum 36 MHz).

So your device presumably is clocked at 36 MHz. To have a rate of 9600 baud, we need an overall divisor of 36 MHz / (9600 * 16) = 234.375.

The baud rate generator can handle fractional divisions by considering the integer and fractional parts separately. We get:

DIV_Fraction = 16 * 0.375 = 6 = 0x06
DIV_Mantissa = 234 = 0xEA
USART_BRR = (DIV_Mantissa << 4) | DIV_Fraction = 0xEA6

The notation 0dxx is taken from ST documentation and stands for decimal representation.

Conclusion

To operate on those devices, read carefully the documentation before starting to program, use helping libraries if possible. Personally I prefer libopencm3 over standard HAL libraries, which simplifies the use.

Frankie_C
  • 4,764
  • 1
  • 13
  • 30
  • nice answer! - Upvote. - I have taken the freedom to polish some points of your description. Please check if you agree on this re-formulation. – HelpingHand May 02 '20 at 16:12
  • 1
    @HelpingHand Thanks. I approved edit. Effectively I wrote the answer in some looks-like-english... – Frankie_C May 02 '20 at 18:37
0

this will work man, i tested it

void init_Usart(void)
{
  // Enable clock source for USART2
  RCC->APB1ENR |= 0x20000;           // 0b 0000 0000 0000 0010 0000 0000 0000 0000
  RCC->APB2ENR |= 0x4;
  GPIOA->CRL |= 0x900;               // Set PA2 as TX pin (AF)
  USART2->BRR  = 0xEA6;              // Setting Baudrate to 9600 @8 MHz.
  USART2->CR1 |= 0x00008;            // Enable TX only
  USART2->CR1 |= 0x02000;            // Enable USART module 
   
}

void USART_write(int data)
{
  // We need to wait until Tx buffer is empty for sending data.
  while(!(USART2->SR & 0x0080));        // 0x0080
  USART2->DR = (data & 0xFF);
}