cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with easy UART transmission. I would like some help, Thanks

Lars1
Associate II

I am trying to spam the character 'A' over UART.

I've done a lot of digging in the reference manual and online but can't get it to work.

I think there is something wrong with the buad rate but it is just a guess.:grinning_face_with_sweat:

The MCU is a STM32F103C8.

Functions not in main.c explained below.

#include <stdint.h>
 
#include "setup.h" // Defines things like GREEN_LED pins which are specific to my setup
#include "../gpio.h" // Includes some GPIO functions I wrote to make interfacing it easier
 
volatile uint32_t *RCC_APB2ENR = (volatile uint32_t*) 0x40021018; // RCC_APB2ENR +0x18 RCC_BASE: 0x40021000
 
volatile uint32_t *USART1_SR = (volatile uint32_t*) 0x40013800; // ALso SR register
volatile uint32_t *USART1_DR = (volatile uint32_t*) 0x40013804; // Data register
volatile uint32_t *USART1_BRR = (volatile uint32_t*) 0x40013808; // Baud rate register
volatile uint32_t *USART1_CR1 = (volatile uint32_t*) 0x4001380C; // Control register 1
volatile uint32_t *USART1_CR2 = (volatile uint32_t*) 0x40013810; // Control register 2
volatile uint32_t *USART1_CR3 = (volatile uint32_t*) 0x40013814; // Control register 3
 
void enableIOPortClocks()
{
	// GPIO Enable
	*RCC_APB2ENR |= (1UL << 0); // Enable alternate funciton clock
	*RCC_APB2ENR |= (1UL << 2); // Enable port a
	*RCC_APB2ENR |= (1UL << 3); // Enable port b
	*RCC_APB2ENR |= (1UL << 4); // Enable port c
}
 
// Configures LED pins to have to correct output mode.
// simplePinMode( ... ) does the same as pinMode( ... ) here
void setupLEDs()
{
	pinMode(PORTB, RED_LED, PIN_MODE.out50MHz, PIN_CNF_OUTPUT.pushPull);
	simplePinMode(LED_PORT, GREEN_LED, pinModes.output);
	pinMode(PORTB, WHITE1_LED, PIN_MODE.out50MHz, PIN_CNF_OUTPUT.pushPull);
	pinMode(PORTB, WHITE2_LED, PIN_MODE.out50MHz, PIN_CNF_OUTPUT.pushPull);
}
 
void setupUSART1()
{
	// Set TX and RX pins
	pinMode(PORTA, 9, PIN_MODE.out50MHz, PIN_CNF_OUTPUT.altPushPull);
//	PORTA->CRH |= (0b1011 << 4); // Same as line above
	pinMode(PORTA, 10, PIN_MODE.in, PIN_CNF_INPUT.floating);
	*RCC_APB2ENR |= (1UL << 14); // Enable USART1 clock
	*USART1_BRR &= ~(0xFFFF); // Clear buadrate
	*USART1_BRR |= 0x1D4C; // Set buadrate
	*USART1_CR1 |= (1UL << 3); // Transmitter enable
//	*USART1_CR1 |= (1UL << 2); // Reciever enable. Does not matter
	*USART1_CR1 |= (1UL << 13); // USART enable
 
}
 
int main()
{
	enableIOPortClocks();
	setupLEDs();
	setupUSART1();
 
	if (*USART1_CR1 & (1UL << 13)) // Simple and unnecessary check if usart enable bit is set
	{
		digitalWrite(LED_PORT, GREEN_LED, HIGH);
	}
 
	while (1)
	{
		// wait till transmit data register is empty
		while (!(*USART1_SR & (1UL << 7)))
		{
			digitalWrite(LED_PORT, WHITE2_LED, HIGH); // Turns on LED on breadboard
		}
		digitalWrite(LED_PORT, WHITE2_LED, LOW); // Turns off LED on breadboard
 
		for (int i = 0; i < 500000; i++) // So the LED off tine is long enough to be visible.
		{
			// Wait
		}
 
		// Send character
		*USART1_DR = ('A' & 0xFF);
	}
}

(simple)pinMode(); Sets pin MODE and CNF bits.

digitalWrite(); Sets pin high or low;

I am using STM32CubeIDE and used a empty STM32 project.

Thank you for reading this! It would be amazing if you could spot the mistake!=)

9 REPLIES 9

Read out content of related GPIO and UART registers and check/post.

System clock/APB clock in RCC is set how?

Did you observe the USART pin using an oscilloscope?

JW

Thanks for the reply!​

I'll double check all the RCC registers.

I use a FTDI to program the chip. I don't know any way of sending back data to my pc without to use of USART. (I should probably get an st link, can that read out registers?)

I​ do not have an oscilloscope, I am in high school thus I can't afford a lot of equipment.

I​ did check the USART pin with a volt meter and it seems okay.

My com port is picking up data on a lower buad rate then I am trying to use.​ The data are weird unknown symbols.

Do you know any part of my USART setup that is most definitely correct? So I can narrow the search area.​

Thanks for helping!​

Piranha
Chief II

You are turning off the white LED before delay loop...

Looking at your code, I have few comments and questions. First one is not really for you, but the world developers in general. Arduino API is made to be very simple and limited - that's exactly what's needed for an education! But what's the point of making an API, which looks like Arduino API, but is not actually compatible with it? That's idiotic! If you brake the compatibility, you make a better and more flexible API, not as dumb as some education level one.

OK, now back to Lars's code.. =) You don't need to define registers and bits, as these are already defined by the manufacturer:

https://github.com/STMicroelectronics/STM32CubeF1/blob/master/Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f103xb.h

> I don't know any way of sending back data to my pc without to use of USART. (I should probably get an st link, can that read out registers?)

Yes, ST-LINK can read and write variables, registers, RAM, flash, stop execution on breakpoints, debug step-by-step and more things. It also has virtual COM port through the same USB interface. ST-LINK is onboard on ST's boards. For a beginner I suggest getting some Nucleo board with F3, F4, L4 or G4 series MCU, depending on your interest targets. With Nucleo you get a MCU development board, ST-LINK and virtual USART all in one board for a very nice price!

> ​I use a FTDI to program the chip. I don't know any way of sending back data to my pc without to use of USART. (I should probably get an st link, can that read out registers?)

Yes, coupled with a suitable program. IDEs are the easy way.

Probably the best way to obtain an STLink is to get a Nucleo or a Disco board. Make sure it is not the old V1 STLink, and better don't get the V2 either, but go for the V2-1 which is said to be "mbed enabled" and provides a virtual com port in PC. Maybe ask here before you buy one.

​> I​ do not have an oscilloscope, I am in high school thus I can't afford a lot of equipment.

I fully understand you. However, an oscilloscope, even an old battered N-th hand one, makes a huge difference. Or a friend who has one. Or a sympathetic teacher in a tech school.

Sometimes, a simple logic analyzer such as the Saleae ones, can also help, but it has a slightly different usage pattern than the oscilloscope.

> My com port is picking up data on a lower baud rate then I am trying to use.​ The data are weird unknown symbols.

That might be a good sign. Using Bray's terminal, you can quickly sweep through the most used baudrates. Set it to hex output, and post what you intend to transmit and what do you observe, together with what you think your system clock/apb clock/baudrate is and what was set on the PC.

JW

PS. What's wrong with the symbols defined in the CMSIS-mandated device headers?

Thanks for the advice.

There is nothing wrong with CMSIS I just could not find something like it when I started programming the STM32F103C8. Probably because I googled: 'STM32F103 device headers like ATmega has for avr.':grinning_face_with_sweat:

I downloaded CMSIS and then noticed it didn't contain the stm32f10x.h file that is used all the time.

So I downloaded the STM32F10x standard peripheral library added it to the project include path and got:

../Src/main.c:14:10: fatal error: stm32f10x.h: No such file or directory
 #include "stm32f10x.h"

So I changed the include path all the way to the folder of the stm32f10x.h file and the error stayed.

I include in Project > Properties > C/C++ General > Paths and Symbols > Includes and added it for both GNU C and GNU C++.

Do you know what is wrong?

Thank you in advance!

Edit: Got the includes to work!

Will have a look at the rest of the feedback and Piranha's comment now.

It's my intention to turn off the LED before the delay loop. This way the LED is on while transmitting.

I know I stole Arduino function names but I am trying to move away from Arduino, I want to learn how it works.

Thanks for the link! I've got another (does the same thing I think) header file doing it's work right now. (stm32f10x.h)

https://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32-standard-peripheral-libraries/stsw-stm32054.html

Thanks for explaining the ST-LINK. I currently have a 'Black Pill' almost the same as the 'Blue Pill'. I choose it because I can buy it in my hometown and it's cheap. Quick research shows it is programmable with an ST-LINK. Don't know if debugging uses extra wires but I'll look into that and consider a Nucleo board.

Thank you!=)

Okay progress!

I am trying to transmit 0x11, my favourite number, using the following code:

#define STM32F10X_MD
 
#include "stm32f10x.h"
 
int main()
{
	RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // Enable USART1 clock
	RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // Enable GPIOA
 
	// Configure pin 9, TX pin
	GPIOA->CRH |= GPIO_CRH_MODE9;
	GPIOA->CRH |= GPIO_CRH_CNF9_1;
	GPIOA->CRH &= ~(GPIO_CRH_CNF9_0);
 
	USART1->BRR = 0x1D4C; // Set buad rate to 9600
 
	USART1->CR1 |= USART_CR1_TE; // TX enable
	USART1->CR1 |= USART_CR1_UE; // UART enable
 
	while (1)
	{
		USART1->DR = 0x11;  //send data
 
		while (!(USART1->SR & USART_SR_TC));//wait for TX to be complete
 
		for (int i = 0; i < 20000; i++)
		{
			// waste time
		}
	}
 
}

Bray's terminal gives 0x00 for whatever I send. (Bray's terminal set to 9600 bauds)

Here is what is receive on other baud rates sending 0x11:

4800

F0 00 00 F0 00 00 repeating itself

2400

F8 0E 06 F8 0E 06 repeating

1200

FE 21 FE 21 FE 21 repeating

600

E0 E0 E0 E0 E0 E0 repeating

All higher baud rates where 00 00 00 00 00 etc.

Any suggestions?

You probably don't run the mcu at 72MHz as you expect, but at the default 16MHz from HSI.

Try to use a baudrate which matches 16MHz.

JW

You're the man!

It's actually running on 8Mhz from HSI but that's not the point.

I set the baud rate to 9600 and 800 to test using the following code:

USART1->BRR = 0x2710; // Set buad rate to 800 *** 8MHz
USART1->BRR = 0x341; // Set buad rate to 9600 *** 8MHz

Both speeds gave the same result.

Sending the following I recieved these patterns: (All hex)

11: 11 FF 11 FF 11 FF

7C: 7C 7C 7C 7C 7C 7C

1E: 1E FF 1E FF 1E FF

80: 80 80 80 80 80 80

81: 81 FF 81 FF 81 FF

82: 82 FF 82 FF 82 FF

83: 83 83 83 83 83 83

84: 84 FF 84 FF 84 FF

85: 85 85 85 85 85 85

86: 86 86 86 86 86 86

The FF were recieved in the same 'send cycle' as the other value.

Do you know why 0xFF is recieved sometimes?