cancel
Showing results for 
Search instead for 
Did you mean: 

USART bare metal programming fail to send data - STM32L4R5ZI

KHuyn
Associate II

I am new to embedded programming and trying to learn ARM with my STM32L4 board. I stick to the datasheet and stay away from HAL library to learn how the MCU and its peripherals work. Here I am trying to initiate USART3 and send a line using "printf" but fail to receive anydata from my FTDI chip. Did I miss something here?

#include <stdio.h>
#include <stdint.h>
#include "kfunction.h"
#include "kstm32l4r5xx.h"
/*--Define--------------------------------------------------------------------------------*/
/*--Global-Variable---------------------------------------------------------------------- */
/*--Function Prototypes-------------------------------------------------------------------*/
void initUSART3(void);
void initRCC(void);
void blinkBLUE(void);
void initPORT(void);
int putchar(int);
/*--Main----------------------------------------------------------------------------------*/
int main()
{
  initRCC(); 
  initPORT();
  initUSART3();
  while(1)
  {
    blinkBLUE();
    printf("this is USART3");
    putchar(12);
  }
} // EO Main
 
/*--Function------------------------------------------------------------------------------*/
/************************************************/
/*             Name: initUSART3                 */
/*-Initiating USART3 for STM32L4R5xx            */
/*-Oversampling 8 (OVER8=default/0)             */
/*-Baudrate: 9600-USARTDIV=4Mhz/9600=0x1A0(416) */
/*                                              */
/************************************************/
void initUSART3(void)
{
  USART3_BRR |= 0x1A0U;  //select baudrate for USART3=9600    <---edit baudrate first
  USART3_CR1 |= 0x9U;  // enable USART3 - Transmit Enable        <---enable USART after that
}
/************************************************/
/*             Name: initRCC                    */
/*-Initiating RCC for STM32L4R5xx               */
/*-MCU run on MSI clock 4Mhz(reset value)       */
/*-Open Clock Gate for USART3                   */
/*-Open AHB2 clockgate                          */
/*                                              */
/************************************************/
void initRCC(void)
{
  RCC_APB1ENR1 |= 1U<<18; //USART3 clockgate enable 
  RCC_AHB2ENR |= (1<<1); 	// Enable PB
  RCC_AHB2ENR |= (1<<3); //Enable PD
}
/************************************************/
/*             Name: Blink LED                  */
/*-Blink LED on port B 7 with delay()           */
/*                                              */
/************************************************/
void blinkBLUE(void)
{
 delay();
 GIPOB_ODR ^= (1<<7); // PB7 output = 1
 delay();
 GIPOB_ODR |= (1<<7); // PB7 output = 1
}
/************************************************/
/*             Name: initPORTB                  */
/*-initial PORTB                                */
/*                                              */
/************************************************/
void initPORT(void)
{
  GPIOB_MODER ^= (1U<<15); // Config PB7 general output
  GIPOB_ODR |= (1U<<7); 	// PB7 output = 1
  GPIOD_MODER ^= (1U<<17); // Config PD8 general output-USART3 TX
  GPIOD_MODER |= (1U<<16); // Config PD8 general output-USART3 TX      <---Set PORTD_8/USART3_TX as general output
}
/************************************************/
/*             Name: putchar                    */
/*-printf() from stdlib use putchar() for output*/
/* putchar() is device specific, so we need to  */
/* supply it                                    */
/*                                              */
/************************************************/
int putchar(int c)
{
  while(!USART3_TXE);           //<--define in header file
  USART3_TDR = c;
  return(c);
}

1 ACCEPTED SOLUTION

Accepted Solutions

Please don't edit the code in the initial post, rather, repost it, so that the progress/changes can be viewed.

+1 to what Piranha said above.

> <---Set PORTD_8/USART3_TX as general output

No, you want to set it as AF, i.e. 0b10.

You also want to set the relevant AF to value given for USART3_Tx in the pinmux table in the datasheet.

JW

View solution in original post

11 REPLIES 11

The approach will require you to know and implement a lot more, a pretty heavy lift for a beginner. Usually a better approach might be to use the libraries, and then replace a piece at a time. That way you start with something working rather discover a 1000 ways it won't work. I'm not much for the Edison approach.

You don't seem to initialize the pin properly, or associate the USART3 with it.

You should enable the USART as the last thing you do, ie need to set the BRR before, enable, as the enable (UE) locks it.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

> GPIOB_MODER ^= (1<<15); // Config PB7 general output

IMO this sets PB7 to AF; for GPIO Out you'd need to set the respective field to 0b01 i.e. set bit 14.

I don't see where do you set the MODER and AFR for the USART3_Tx pin.

> while(!USART3_TXE);

This compiles? What compiler is this?

Also, try to transmit "manually" first, don't rely on that the mechanisms linking putchar() to printf() will work at once.

JW

Thank you for the reply. I edited my main() follow your comment. I just try to enable USART and send something through it. Its effortless to use a sample on internet to perform the same thing, but I would not learn anything from that. This is just for learning purpose.

Thank you for the reply. I just edit my code, but still no output. The USART (or printf function) is still not up to run, cause if something wrong in baudrate setting, at least, I still have trash value in my PuTTy terminal. I used IAR, "USART3_TXE" is a defined value in my self-wrote header file.

/*PORTB control register */
#define GPIOB_MODER *((volatile unsigned int *)0x48000400U)	//for PORB mode
#define GIPOB_ODR *((volatile unsigned int *)0x48000414U)	//for PORB output data
/*PORTD control register */
#define GPIOD_MODER *((volatile unsigned int *)0x48000C00U)	//for PORD mode
#define GIPOD_ODR *((volatile unsigned int *)0x48000C14U)	//for PORD output data
/*USART_3 registers*/
#define USART3_CR1 *((volatile unsigned int *)0x40004800U)	//for USART3 base address, CR1 register
#define USART3_CR2 *((volatile unsigned int *)0x40004804U)	//Control register 2
#define USART3_CR3 *((volatile unsigned int *)0x40004808U)   //Control register 3
#define USART3_BRR *((volatile unsigned int *)0x4000480CU)	//baud rate register 
#define USART3_GTPR *((volatile unsigned int *)0x40004810U)	//guard time and prescaler register
#define USART3_RTOR *((volatile unsigned int *)0x40004814U)	//receiver timeout register
#define USART3_RQR *((volatile unsigned int *)0x40004818U)	//request register 
#define USART3_ISR *((volatile unsigned int *)0x4000481CU)	//interrupt and status register
#define USART3_ICR *((volatile unsigned int *)0x40004820U)	//interrupt flag clear register
#define USART3_RDR *((volatile unsigned int *)0x40004824U)	//receive data register 
#define USART3_TDR *((volatile unsigned int *)0x40004828U)	//USART transmit data register
#define USART3_PRESC *((volatile unsigned int *)0x4000482CU)	//prescaler register 
#define USART3_TXE ((USART3_ISR>>7)&1) // Transmit data empty bit
/*RCC control register */
#define RCC_CR *((volatile unsigned int *)0x40021000U)  /*RCC control register, RCC base address */
#define RCC_AHB2ENR *((volatile unsigned int *)0x4002104CU) //ABH2 enable
#define RCC_CCIPR *((volatile unsigned int *)0x40021088U) //Peripherals independent clock configuration register
#define RCC_APB1ENR1 *((volatile unsigned int *)0x40021058U) //RCC_CR + 0x58U) // APB1 peripheral enable

Piranha
Chief II

Just out of curiosity... I do completely understand and even support not using ST's drivers, but what's wrong with register definitions?

https://raw.githubusercontent.com/ARMmbed/mbed-os/master/targets/TARGET_STM/TARGET_STM32L4/TARGET_STM32L4R5xI/device/stm32l4r5xx.h

Please don't edit the code in the initial post, rather, repost it, so that the progress/changes can be viewed.

+1 to what Piranha said above.

> <---Set PORTD_8/USART3_TX as general output

No, you want to set it as AF, i.e. 0b10.

You also want to set the relevant AF to value given for USART3_Tx in the pinmux table in the datasheet.

JW

Yep,That's my plan too. I gonna move to use this header file right after I finish this experiment project.

Thank you for your support. At first I have no idea about "set the relevant AF to value given for USART3_Tx in the pinmux table in the datasheet" yet. After spending time to go through all GPIO register and read the "implement section" for configuring GPIO to use alternative function. I known that I had missed the >>>GPIO alternate function high register (GPIOx_AFRH)<<<.

So it took me awhile to realize that "datasheet" and "reference manual" are 2 different documents, that's why I could not find the "alternative function mapping" at the first place. So I go to ST website and try to download "datasheet" for my chip.

Using the map, I have the correct value to put in the GPIOD_AFRH register to mux pin PD8 with USART3_TX => success using printf to send data through USART3

This is my new code - BOARD Nucleo STM32L4R5 144pins - STM32L4R5ZITx - IAR complier

/******************************************************************************************/
/*                                Name: USART                                             */
/*                                Author: Khoa Huynh                                      */
/*                                Date: 30-July-2019                                      */
/*                                Desciption:                                             */
/*-Perform the communicate via UART on Nucleo STM32L4R5ZITx                               */
/*                                                                                        */
/******************************************************************************************/
/*--Header--------------------------------------------------------------------------------*/
#include <stdio.h>
#include <stdint.h>
#include "kfunction.h"
#include "kstm32l4r5xx.h"
/*--Define--------------------------------------------------------------------------------*/
/*--Global-Variable---------------------------------------------------------------------- */
/*--Function Prototypes-------------------------------------------------------------------*/
void initUSART3(void);
void initRCC(void);
void blinkBLUE(void);
void initPORT(void);
int putchar(int);
/*--Main----------------------------------------------------------------------------------*/
int main()
{
  initRCC(); 
  initPORT();
  initUSART3();
  while(1)
  {
    blinkBLUE();
    printf("this is USART3\n");
  }
} // EO Main
 
/*--Function------------------------------------------------------------------------------*/
/************************************************/
/*             Name: initUSART3                 */
/*-Initiating USART3 for STM32L4R5xx            */
/*-Oversampling 8 (OVER8=default/0)             */
/*-Baudrate: 9600-USARTDIV=4Mhz/9600=0x1A0(416) */
/*                                              */
/************************************************/
void initUSART3(void)
{
  USART3_BRR |= 0x1A0U;  //select baudrate for USART3=9600
  USART3_CR1 |= 0x9U;  // enable USART3 - Transmit Enable
}
/************************************************/
/*             Name: initRCC                    */
/*-Initiating RCC for STM32L4R5xx               */
/*-MCU run on MSI clock 4Mhz(reset value)       */
/*-Open Clock Gate for USART3                   */
/*-Open AHB2 clockgate                          */
/*                                              */
/************************************************/
void initRCC(void)
{
  RCC_APB1ENR1 |= (1U<<18); //USART3 clockgate enable
  RCC_AHB2ENR |= (1U<<1); 	// Enable PB
  RCC_AHB2ENR |= (1U<<3); //Enable PD
}
/************************************************/
/*             Name: Blink LED                  */
/*-Blink LED on port B 7 with delay()           */
/*                                              */
/************************************************/
void blinkBLUE(void)
{
  	delay();
	GPIOB_ODR ^= (1<<7); // PB7 output = 1
	delay();
	GPIOB_ODR |= (1<<7); // PB7 output = 1
}
/************************************************/
/*             Name: initPORTB                  */
/*-initial PORTB                                */
/*                                              */
/************************************************/
void initPORT(void)
{
  GPIOB_MODER ^= (1U<<15); // Config PB7 general output
  GPIOB_ODR |= (1U<<7);    // PB7 output = 1
  GPIOD_MODER ^= (1U<<16); // Config PD8 alternate output-USART3 TX
  GPIOD_MODER |= (1U<<17); // Config PD8 alternate output-USART3 TX
  GPIOD_OTYPER = 0x00000000U; // All pin push-pull
  GPIOD_AFRH = 0x7U; // USART3_TX alternate function to pin 8 
}
/************************************************/
/*             Name: putchar                    */
/*-printf() from stdlib use putchar() for output*/
/* putchar() is device specific, so we need to  */
/* supply it                                    */
/*                                              */
/************************************************/
int putchar(int c)
{
  while(!USART3_TXE);
  USART3_TDR = c;
  return(c);
}

HEADER FILE

/******************************* Name: kstm32l4r5xx.h *************************************/
/*                                Author: Khoa Huynh                                      */
/*                                Date: 18-July-2019                                      */
/* Desciption:  This header file include peripheral address for stm32l4r5                 */
/******************************************************************************************/
/*PORTB control register */
#define GPIOB_MODER *((volatile unsigned int *)0x48000400U)	//for PORB_7 mode
#define GPIOB_ODR *((volatile unsigned int *)0x48000414U)	//for PORB_7 output data
/*PORTD control register */
#define GPIOD_MODER *((volatile unsigned int *)0x48000C00U)	//for PORD_7 mode
#define GPIOD_OTYPER *((volatile unsigned int *)0x48000C04U) // output type register
#define GPIOD_ODR *((volatile unsigned int *)0x48000C14U)	//for PORD_7 output data
#define GPIOD_AFRH *((volatile unsigned int *)0x48000C24U) // alternating function for Port D pin 8-15
/*USART_3 registers*/
#define USART3_CR1 *((volatile unsigned int *)0x40004800U)	//for USART3 base address, CR1 register
#define USART3_CR2 *((volatile unsigned int *)0x40004804U)	//Control register 2
#define USART3_CR3 *((volatile unsigned int *)0x40004808U)   //Control register 3
#define USART3_BRR *((volatile unsigned int *)0x4000480CU)	//baud rate register 
#define USART3_GTPR *((volatile unsigned int *)0x40004810U)	//guard time and prescaler register
#define USART3_RTOR *((volatile unsigned int *)0x40004814U)	//receiver timeout register
#define USART3_RQR *((volatile unsigned int *)0x40004818U)	//request register 
#define USART3_ISR *((volatile unsigned int *)0x4000481CU)	//interrupt and status register
#define USART3_ICR *((volatile unsigned int *)0x40004820U)	//interrupt flag clear register
#define USART3_RDR *((volatile unsigned int *)0x40004824U)	//receive data register 
#define USART3_TDR *((volatile unsigned int *)0x40004828U)	//USART transmit data register
#define USART3_PRESC *((volatile unsigned int *)0x4000482CU)	//prescaler register 
#define USART3_TXE ((USART3_ISR>>7)&1) // Transmit data empty bit
/*RCC control register */
#define RCC_CR *((volatile unsigned int *)0x40021000U)  /*RCC control register, RCC base address */
#define RCC_CFGR *((volatile unsigned int *)0x40021008U) /*RCC config register */
#define RCC_AHB2ENR *((volatile unsigned int *)0x4002104CU) //ABH2 enable
#define RCC_AHB2RSTR *((volatile unsigned int *)0x4002102C) //ABH2 peripheral reset register
#define RCC_CCIPR *((volatile unsigned int *)0x40021088U) //Peripherals independent clock configuration register
#define RCC_APB1RSTR1 *((volatile unsigned int *)0x40021038) /*APB1 peripheral reset register 1 */
#define RCC_APB1ENR1 *((volatile unsigned int *)0x40021058U) //RCC_CR + 0x58U) // APB1 peripheral enable

AVI-crak
Senior

khoahuynh - �?транное им�?...

There are many more documents than 2. You need to start the study from the largest - to a lot of pages.

Examples of USART, as well as all possible modes of this interface are described in RM0432, pages 1514 to 1591.

And yes, your example is not a bare metal example, it is something strange and stupid.

You cannot use magic numbers, by the way you yourself have already become entangled in them.

To write a numerical value with an offset into the register, _VAL2FLD (field, value) is used.

To read the state, a bit name mask is used - otherwise, read the entire register.

Why reinvent the wheel if it is already in the stm32l4r5xx.h file. This file, as well as all that is needed, can be found in the Repository from the STM32Cube utility.