2023-11-04 06:28 AM
I have a problem where Im developing a bare metal USART Send Data for stm32f302r8 nucleo board. Im sending on USART2 which is PA2 and PA3 through the virtual COM. The TDR register is updating 1 byte by 1 byte. But, the TeraTerm is not showing any data. I have checked the nucleo board datasheet where the Virtual COM is enabled by default and I dont think I need to do any rework on the board.
Here is my application code:
/*
* uart_tx.c
*
* Created on: 22 Oct 2023
* Author: irsyad
*/
#include <string.h>
#include "stm32f30xx.h"
#include <stdio.h>
USART_Handle_t usart2_handle;
// tx buffer
uint8_t msg[1024] = "USART Tx testing...........\n\r";
void delay(void)
{
for (uint32_t i = 0; i < 200000; i++);
}
void USART2_GPIOInit(void)
{
GPIO_Handle_t usart2_pins;
usart2_pins.pGPIOx = GPIOA;
usart2_pins.GPIO_PinConfig.GPIO_PinAltFunMode = GPIO_MODE_ALTFN;
usart2_pins.GPIO_PinConfig.GPIO_PinOPType = GPIO_OP_TYPE_PP;
usart2_pins.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_PU;
usart2_pins.GPIO_PinConfig.GPIO_PinAltFunMode = 7;
usart2_pins.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_HIGH;
//TX
usart2_pins.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_2;
GPIO_Init(&usart2_pins);
//RX
usart2_pins.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_3;
GPIO_Init(&usart2_pins);
}
void USART2_Init()
{
usart2_handle.pUSARTx= USART2;
usart2_handle.USART_Config.USART_Baud = USART_STD_BAUD_115200;
usart2_handle.USART_Config.USART_HWFlowControl = USART_HW_FLOW_CTRL_NONE;
usart2_handle.USART_Config.USART_Mode = USART_MODE_ONLY_TX;
usart2_handle.USART_Config.USART_NoOfStopBits = USART_STOPBITS_1;
usart2_handle.USART_Config.USART_WordLength = USART_WORDLEN_8BITS;
usart2_handle.USART_Config.USART_ParityControl = USART_PARITY_DISABLE;
USART_Init(&usart2_handle);
}
void GPIO_ButtonInit(void)
{
//1. first create a variable for our GPIO handle
GPIO_Handle_t GpioBtn; //GpioLed;
/*======================PUSH BUTTON CONFIGURATION===========================*/
//1. now, we have to initialize
//mula2 select port
GpioBtn.pGPIOx= GPIOC;
//2. Then select pin number
GpioBtn.GPIO_PinConfig.GPIO_PinNumber = GPIO_PIN_NO_13;
//3.Select pin mode
GpioBtn.GPIO_PinConfig.GPIO_PinMode = GPIO_MODE_INPUT;
//4.Select speed (ni xpenting sgt, boleh biar default)
GpioBtn.GPIO_PinConfig.GPIO_PinSpeed = GPIO_SPEED_HIGH;
//5. enable internal resistor sebab output type open drain
GpioBtn.GPIO_PinConfig.GPIO_PinPuPdControl = GPIO_NO_PUPD;
//6.enable peripheral clock
GPIO_PeriClockControl(GPIOC, ENABLE);
//7.Call GPIO_init()
GPIO_Init(&GpioBtn); //send address GpioLed
/*======================PUSH BUTTON CONFIGURATION===========================*/
}
int main()
{
GPIO_ButtonInit();
USART2_GPIOInit();
USART2_Init();
USART_PeripheralControl(USART2, ENABLE);
while (1)
{
// wait for button press
while(GPIO_ReadFromInputPin(GPIOC, GPIO_PIN_NO_13) );
delay();
// send some data to the slave
USART_SendData(&usart2_handle, (uint8_t *)msg, strlen((char *)msg));
}
return 0;
}
and here is my USART Send data API:
void USART_SendData(USART_Handle_t *pUSARTHandle, uint8_t *pTxBuffer, uint32_t Len)
{
uint16_t *pdata;
//1.loop over until 'Len' number of bytes are transferred.
for(uint32_t i = 0;i < Len;i++)
{
//2.wait until TXE flag is set in the ISR (It indicates the data is ready at the shift register)
while(! USART_GetFlagStatus(pUSARTHandle->pUSARTx,USART_FLAG_TXE));
//3.Check the USART_WordLength item for 9BIT or 8BIT in a frame
if(pUSARTHandle->USART_Config.USART_WordLength == USART_WORDLEN_9BITS)
{
//if 9BIT, then we have to load 9 bit to the DR.
// to extract 9 bits, we use masking.
//Bit masking is a technique that involves performing bitwise operations on data blocks to extract the required bits
//0x01FF is used to mask out 9bits from the 16bit data.
pdata = (uint16_t*) pTxBuffer;//This is why pTxBuffer is typecasted to 16bit to extract 2bytes of data which only 9bit are loaded into the data register
pUSARTHandle->pUSARTx->TDR = (*pdata & (uint16_t)0x01FF);
//references:https://fastbitlab.com/microcontroller-embedded-c-programming-lecture-116-bit-extraction/
//check for USART_ParityControl
if(pUSARTHandle->USART_Config.USART_ParityControl == USART_PARITY_DISABLE)
{
//If the parity is disabled,
//No parity is used in this transfer. so, 9bits of user data will be sent
//So, its like sending 2bytes, sbb utk hold 9 bits, it requires 2 bytes size.
//hence, increment pTxBuffer twice
pTxBuffer++; //1byte
pTxBuffer++; //1byte
}
else
{
//Parity bit is used in this transfer . so , 8bits of user data will be sent
//The 9th bit will be replaced by parity bit by the hardware
pTxBuffer++; //1byte
}
}
else
{
//8-bit data transfer
//Doing this (bitwise AND with 0xFF) ensures that only 8-bits are taken from pTxBuffer.
pUSARTHandle->pUSARTx->TDR = (*pTxBuffer & (uint8_t)0xFF);
//increment the buffer address
pTxBuffer++;
}
}
//4.wait until TC flag is set in the ISR
while( ! USART_GetFlagStatus(pUSARTHandle->pUSARTx,USART_FLAG_TC));
}
Anyone knows the solution?
2023-11-04 07:12 AM
Check pins with a scope. Ensure baud rate as expected. Perhaps output a long patterns of 'U' characters.
Ensure clocks are enabled and register content correct. Especially PP/AF settings
Test with code build with usual libraries, not custom, confirm that's working. The compare and contrast registers.
2023-11-04 08:04 AM
Upload your whole project. I have that same Nucleo board to test your code on.
2023-11-04 08:19 AM
Here is the project:
https://drive.google.com/drive/folders/1XBS8sRM1MYGMVE_CQiCMaR59pj58yTBV?usp=drive_link
You just need to build the uart_tx.c from the Src folder:
2023-11-04 05:07 PM
I am not able to get your code to transmit to the outside world even when TDR is loaded with data. So it's something in your custom code that you've done incorrectly. With HAL UART driver it works just fine. See what the HAL driver does that you're not doing when initializing the UART.
2023-11-04 07:11 PM
I have found something, why when I just click Start debugging, the TXE Flag is already SET? The program is not yet executed even 1 line. Does that mean the communication is taken over by other process?