cancel
Showing results for 
Search instead for 
Did you mean: 

UART Misses Characters

meerd1
Associate II
Posted on December 30, 2013 at 11:32

Hello!

I have a STM32L151CB and I need to use the UART interface. At first it worked perfectly, but after I changed the system clock from HSI (16 MHz) to MSI (2 MHz) I only receive some characters.

E.g. when I send ''Hello'' I receive ''Hlo''.

The UART us configured as follows:

Baud rate: 115200

Word length: 8 bit

Stop bits: 1

Parity: no

Flow control: no

It works with a baud rate of 9600, but I would prefer 115200 baud.

Did I miss something or is it not possible to use a fast UART with the MSI clock?

Regards,

Daniel
11 REPLIES 11
meerd1
Associate II
Posted on January 02, 2014 at 15:56

@lowpowermcu

I've made a minimal example that I will paste below. The actual application uses a RTOS.

@clive1

The ISR is pretty short (especially in the example below). Tomorrow, I will check for any overrun errors.

main.c


/******************************************************************************/

/** \file main.c

******************************************************************************/


//----- Header-Files -----------------------------------------------------------

#include ''usart2.h''


//----- Macros -----------------------------------------------------------------


//----- Data types -------------------------------------------------------------


//----- Function prototypes ----------------------------------------------------

static
void
hw_init(
void
);

static
void
hw_pinout(
void
);


//----- Data -------------------------------------------------------------------


//----- Implementation ---------------------------------------------------------

int
main(
void
) {

hw_init();


usart2_puts(
''\r\n\n''
);

usart2_puts(
''================================\r\n''
);

usart2_puts(
''START DEBUG\r\n''
);


while
(1) {

}


return
0;

}



void
hw_init(
void
) {

// Enable HSI Clock

// RCC_HSICmd(ENABLE);

// while (RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET) {}

// RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);


NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);


/* Set the pinout of the uC and set state of all outpunt pins */

hw_pinout();


/* Initialize spi1 */

usart2_init();

}



void
hw_pinout(
void
) {

GPIO_InitTypeDef GPIO_InitStruct;


/* USART2 GPIO Configuration

* PA2 ------> USART2_TX

* PA3 ------> USART2_RX */


/* Enable or disable the AHB peripheral clock */

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);


/*Configure GPIO pin */

GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;

GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;

GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz;

GPIO_Init(GPIOA, &GPIO_InitStruct);


/*Configure GPIO pin alternate function */

GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);

GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);


RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);


/* Enable clock for syscfg */

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

}

usart2.c


/******************************************************************************/

/** \file usart2.c

******************************************************************************/


//----- Header-Files -----------------------------------------------------------

#include ''stm32l1xx_usart.h''

#include ''usart2.h''


//----- Macros -----------------------------------------------------------------


//----- Data types -------------------------------------------------------------


//----- Function prototypes ----------------------------------------------------

static
void
usart2_configInterrupt(
void
);

static
void
usart2_configUart(
void
);

static
void
usart2_putchar(
char
character);


//----- Data -------------------------------------------------------------------

static
int32_t flag_txBusy = 0;


static
char
recvArray[500];

static
int32_t recvIndex = 0;


//----- Implementation ---------------------------------------------------------

void
usart2_puts(
const
char
*string) {

while
(*string != 
'\0'
) {

usart2_putchar(*string);

string++;

}

}


void
usart2_init(
void
) {

/* Configure interrupts of usart2 */

usart2_configInterrupt();


/* USART2 configuration */

usart2_configUart();

}


void
USART2_IRQHandler(
void
) {

char
character;


if
(USART_GetITStatus(USART2, USART_IT_TXE) != RESET) {

flag_txBusy = 0;


/* Disable transmit Data Register empty interrupt. */

USART_ITConfig(USART2, USART_IT_TXE, DISABLE);

}


if
(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {

character = USART_ReceiveData(USART2);


/* Save char for debugging purposes. */

recvArray[recvIndex++] = character;


/* Show data on terminal. */

USART_SendData(USART2, character);

}

}


static
void
usart2_configInterrupt(
void
) {

NVIC_InitTypeDef NVICInitStructure;


/* Enabling interrupt from USART2 */

NVICInitStructure.NVIC_IRQChannel = USART2_IRQn;

NVICInitStructure.NVIC_IRQChannelPreemptionPriority = CONFIG_USART2_INT_PREEMPTION_PRIO;

NVICInitStructure.NVIC_IRQChannelSubPriority = CONFIG_USART2_INT_SUB_PRIORITY;

NVICInitStructure.NVIC_IRQChannelCmd = ENABLE;


NVIC_Init(&NVICInitStructure);


/* Receive Data register not empty interrupt */

USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

}


static
void
usart2_configUart(
void
) {

USART_InitTypeDef USARTInitStructre;

USART_ClockInitTypeDef USARTClockInitStructure;


USARTInitStructre.USART_BaudRate = CONFIG_USART2_BAUDRATE;

USARTInitStructre.USART_WordLength = USART_WordLength_8b;

USARTInitStructre.USART_StopBits = USART_StopBits_1;

USARTInitStructre.USART_Parity = USART_Parity_No;

USARTInitStructre.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

USARTInitStructre.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;


/* Initialize usart2 clock with default values */

USART_ClockStructInit(&USARTClockInitStructure);

USART_ClockInit(USART2, &USARTClockInitStructure);


/* Configure and enable USART2 */

USART_Init(USART2, &USARTInitStructre);

USART_Cmd(USART2, ENABLE);

}


static
void
usart2_putchar(
char
character) {

while
(flag_txBusy) {}

flag_txBusy = 1;


/* Enable transmit Data Register empty interrupt. */

USART_ITConfig(USART2, USART_IT_TXE, ENABLE);


USART_SendData(USART2, character);

}

usart2.h


#ifndef USART2_H_

#define USART2_H_

/******************************************************************************/

/** \file usart2.h

******************************************************************************/


//----- Header-Files -----------------------------------------------------------

#include ''startup/types.h''


//----- Macros -----------------------------------------------------------------

//#define CONFIG_USART2_BAUDRATE ( 9600 )

#define CONFIG_USART2_BAUDRATE ( 115200 )

#define CONFIG_USART2_INT_PREEMPTION_PRIO ( 5 )

#define CONFIG_USART2_INT_SUB_PRIORITY ( 0 )


//----- Data types -------------------------------------------------------------


//----- Function prototypes ----------------------------------------------------

extern
void
usart2_puts(
const
char
*string);

extern
void
usart2_init(
void
);

extern
void
USART2_IRQHandler(
void
);


//----- Data -------------------------------------------------------------------


#endif /* USART2_H_ */

________________

Attachments :

uart.zip : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006I0c7&d=%2Fa%2F0X0000000bbF%2FUU1Q2IJzvlCj73Jifuw26RMaUrnnempV7OxWtEZItqI&asPdf=false
Posted on January 02, 2014 at 16:24

You don't loop back physically Tx to Rx, do you?

JW

meerd1
Associate II
Posted on January 02, 2014 at 16:38

No, in the example I posted, the signal goes to a USB/RS232 Converter IC and then over USB to the computer. In the real application, the signal goes to a bluetooth chip.

Also, I looked at it with the KO. I could read the message ''Hi\r'', but the MCU only received ''H''.

Posted on January 02, 2014 at 16:55

Your use of USART_SendData() is less than ideal in this context.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
Posted on January 02, 2014 at 17:12

> Also, I looked at it with the KO.

What is KO?

> I could read the message ''Hi\r'', but the MCU only received ''H''.

Ah, so the problem is in the PC -> mcu direction, i.e. with the Rx on mcu side?

How do you know what did the mcu receive?

JW

meerd1
Associate II
Posted on January 02, 2014 at 17:27

@lowpowermcu

If I remember correctly, it works with 9600 baud. I will test it again tomorrow.

@clive1

Do you mean inside the IRQ handler? I will try it again without this function call. I added it to the example, so that it is easier to test. Before that, I used the array ''recvArray'' to save all incoming characters.

@waclawek.jan

Sorry, with ''KO'' I meant ''oscilloscope''. Yes, the problem is with the receiving side on the mcu.

meerd1
Associate II
Posted on January 03, 2014 at 10:40

So I tried the suggestions you made.

- It works with 9600 baud.

- I have no overrun errors (register USART_SR: 1010'0000)

- Deleting USART_SendData() inside the ISR doesn't bring any improvements (register USART_SR: 1110'0000)

The bits in USART_SR are:

bit 5: RXNE (Read data register not empty)

bit 6: TC (Transmission complete)

bit 7: TXE (Transmit data register empty)

Posted on January 03, 2014 at 14:47

The flag variable you are setting under interrupt should be ''volatile'', but I'm not looking to try and rework your code. Instead I'll offer some simpler echoing code that should allow you to make a determination if the 2 MHz 115200 baud option is viable.

// STM32L15x USART2 LOOP (PA.2 Tx, PA.3 Rx) - sourcer32@gmail.com
#include ''stm32l1xx.h''
/**************************************************************************************/
void RCC_Configuration(void)
{
/* --------------------------- System Clocks Configuration -----------------*/
/* USART2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
/* GPIOA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
}
/**************************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Configure USART Tx & Rx as alternate function */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_40MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Mux out USART2 Tx & Rx */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
}
/**************************************************************************************/
void USART2_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
/* USARTx configuration ------------------------------------------------------*/
/* USARTx configured as follow:
- BaudRate = 115200 baud
- Word Length = 8 Bits
- One Stop Bit
- No parity
- Hardware flow control disabled (RTS and CTS signals)
- Receive and transmit enabled
*/
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
}
/**************************************************************************************/
void OutString(char *s)
{
while(*s)
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); // Wait for Empty
USART_SendData(USART2, *s++);
}
}
/**************************************************************************************/
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
USART2_Configuration();
OutString(''This is an echo back test for USART2

'');
while(1) // Don't want to exit
{
uint16_t Data;
while(USART_GetITStatus(USART2, USART_IT_RXNE) == RESET); // Wait for Char
Data = USART_ReceiveData(USART2); // Collect Char
while(USART_GetITStatus(USART2, USART_IT_TXE) == RESET); // Wait for Empty
USART_SendData(USART2, Data); // Echo Char
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf(''Wrong parameters value: file %s on line %d

'', file, line) */
/* Infinite loop */
while (1);
}
#endif

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
meerd1
Associate II
Posted on January 04, 2014 at 11:53

Thanks for the example.

I had to make some small changes in the main loop to get it to work: - Change function calls USART_GetITStatus() to USART_GetFlagStatus() - Change USART_IT_RXNE to USART_FLAG_RXNE (the same for _TXE) Then the example echoed the whole string I sent to it! After some more tests, I think I found the problem. The timing is extremely tight. When I add some more commands to the while loop, it won't echo every character anymore (see code below). Therefore, the baudrate of 115200 is too high for a clock of 2 MHz. I will have to decide whether to change the baudrate or the clock frequency in my project. Thank you clive1 and everyone who gave some ideas!

while
(1) 
// Don't want to exit
{
uint16_t Data;
volatile
int
dummy = 0;
while
(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET); 
// Wait for Char
dummy = 5;
dummy = 11;
Data = USART_ReceiveData(USART2); 
// Collect Char
dummy = 20;
dummy = 41;
while
(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); 
// Wait for Empty
dummy = 80;
dummy = 161;
USART_SendData(USART2, Data); 
// Echo Char
dummy = 320;
dummy = 641;
}