I have been working on STM32f091rc board, trying to get UART1 and UART2 work. I tried sending 8 bytes of packet from a controller to the STM board. Due to some reasons, my function is just displaying the last byte of the packet. My Receiving function is given below:-
uint8_t rxd[10];
void getChar (void) {
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) { // Check RXNE to
//see if there is data
for(j=0; j<8; j++) {
rxd[i] = (0xFF & (USART1->RDR));
}
What am i doing wrong? Can anyone please point me in the right direction? Thanks for your time.
The UART->RDR
register has no buffers, it holds only the last fully received byte. If another byte is received, it will be overwritten.
You should ensure that the value in RDR
is read out every time after a byte arrives, and before the next one is received. There are 3 basic ways to do it.
Check the RXNE
flag regularly, and read RDR
exactly once when it's set. Repeat until you have the whole data packet. Reading a byte from RDR
clears the RXNE
flag, wait until it's set again before you read the next byte.
Set the RXNEIE
bit in CR1
and enable the interrupt corresponding to the UART in NVIC
. The interrupt handler will be called every time a byte is received. The handler can be very simple at first, just reading RDR
and storing it in a buffer. Later you can add error checking and recovery. Don't forget to declare every variable the interrupt handler touches as volatile
.
Set up the DMA channel first (USART1
is mapped to DMA1_Channel3
by default, can be remapped, check the reference manual for others):
DMA1_Channel3->CPAR = (uint32_t)&USART1->RDR;
DMA1_Channel3->CMAR = (uint32_t)rxd; // start of receive array
DMA1_Channel3->CNDTR = 8; // 8 bytes to receive
DMA1_Channel3->CCR = DMA_CCR_MINC | DMA_CCR_EN; // Memory increment, enable
then set up the serial port, and enable DMA receive in USART1->CR3
. The end of transfer is signaled in the DMA1->ISR
register, you can check it regularly in the main program, or enable an interrupt in DMA1_Channel3->CCR
(and in NVIC
). You should clear the interrupt flag through DMA1->IFCR
, otherwise you'll get endless interrupts when enabled. To start another transfer, set the CNDTR
register again. Declare all variables touched by DMA or the interrupt handler as volatile
.