cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F0 - two USARTs in half duplex mode

nick239955
Associate II
Posted on July 29, 2012 at 19:47

Hi,

I have a question regarding the USART functionality. The IC I have is supposed to receive data and relay it at a slightly higher rate.I have configured and enabled both USART1 and 2 in half duplex mode, one is running at 9600 bps and another at 11200 bps. Whenever one of the USARTs has received any data (saved to a buffer from within the interrupt handler) it should send it out on the other USART, and viceversa. What is happening though is only the first character gets sent back and forth apparently in an endless loop. I am guessing it's echo, but how can it be? I am changing the USART mode to TX and disabling RX when sending data.

if
(UART2_RX_size > 0){
for
(i=0; i<UART2_RX_size; i++)
UART_write_byte(USART1, UART2_RX_buffer[i]);
UART2_RX_size=0;
} 
if
(UART1_RX_size > 0){
for
(i=0; i<UART1_RX_size; i++)
UART_write_byte(USART2, UART1_RX_buffer[i]);
UART1_RX_size=0;
} 
// example interrupt handler
void
USART1_IRQHandler(
void
)
{
uint8_t data;
/* Pick up the character, prepare its binary form */
if
(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) ){
data = USART_ReceiveData(USART1);
// save it to the buffer
UART1_RX_buffer[UART1_RX_size] = data;
UART1_RX_size++;
}
} 
// example send function
void
UART_write_byte(USART_TypeDef* USARTx, uint8_t ch) 
{
USART_DirectionModeCmd(USARTx,USART_Mode_Rx, DISABLE); 
// enable RX mode // on startup
USART_DirectionModeCmd(USARTx,USART_Mode_Tx, ENABLE); 
// disable TX mode
/* Loop until transmit data register is empty */
while
(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){}
USART_SendData(USARTx, (uint8_t) ch);
while
(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){}
USART_DirectionModeCmd(USARTx,USART_Mode_Tx, DISABLE); 
// disable TX mode
USART_DirectionModeCmd(USARTx,USART_Mode_Rx, ENABLE); 
// enable RX mode // on startup
}

#stm32f0-usart #stm32f0-usart
5 REPLIES 5
Posted on July 29, 2012 at 20:12

I'd probably send all pending bytes rather than bang back and forth for each byte. Would also wait on TC (Transmit Complete) instead of TXE empty as that will reflect the holding register, not the shift register.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
nick239955
Associate II
Posted on July 29, 2012 at 20:30

Clive,

Thank you for replying. Indeed checking the TC flag instead of TXE helped, functionally it's fine now. I am getting some latency between bytes though due to the IRQ handler running the test(s). Is there a way to get rid of this echo completely? 

I did try disabling the receiver when sending data, but maybe I'm doing it wrong?

nick239955
Associate II
Posted on July 30, 2012 at 01:15

Seems a part of the problem was solved by waiting for RXNE to clear, instead of saving the data as soon as it was set... waiting for TC to clear also didn't help.

void
USART2_IRQHandler(
void
)
{
uint16_t data;
while
( USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET);
data = USART_ReceiveData(USART2);
UART2_RX_buffer[UART2_RX_size++] = data;
UART2_idle = 0;
}

Posted on July 30, 2012 at 05:00

That would depend a lot on how you've set it up to interrupt, which I can't see. If it is only interrupting on RXNE it would implicitly be set, if you have multiple interrupts set on the USART then you'll need to differentiate the sources.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
nick239955
Associate II
Posted on September 18, 2012 at 19:16

Hi Clive,

During UART init I am doing this:

NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );
USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);

Then the interrupt handler:

void
USART2_IRQHandler(
void
)
{
uint16_t data;
while
( USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET );
data = USART_ReceiveData(USART2);
if
(USART_GetFlagStatus(USART2, USART_FLAG_PE) == RESET){
UART2_RX_buffer[UART2_RX_size++] = data;
U2_rx_count++; 
}
}

This works perfect actually byte by byte, however I'd prefer having the possibility to buffer the data somehow. Previously I have tried implementing a wait time and would only send the data from the RX buffers when this wait time was reached by a counter incremented within main(). The counter was reset upon completion of every buffer empty operation. This didn't work out well, the UART started behaving erratically, missing characters etc, and I've tried different wait times - from 10 cycles to ~20 thousand.