AnsweredAssumed Answered

STM32F4 + FreeRTOS + USART Interrupt: Receive: some of the letters received twice

Question asked by kupchyk.daniil on Feb 14, 2013
Latest reply on Feb 14, 2013 by Clive One
Good afternoon,

At the moment I'm trying to receive long char string with USART from RS232 device (weather station :) )
For logic level converting used MAX3232 Mikroe RS232 Module.

At first I send a message to device and message transmits well (checked with PC terminal program).
At second I wait for device answer message to receive it.
Problem happens in receiving process:
Some chars are randomly received two times. That means I have additional char but no one original message char has lost.

Experimentally was found that quantity of doubled chars depends from USART baudrate, the higher the speed, the less doublings

Looking forward for any ideas. Daniil

PS:
I'm using Keil IDE + FreeRTOS + CMSIS + SPL,   STM32F4Discovery board.
Received messages taken from debugger:

1R0,Dm=005D,Dx=036D,Sn=0.0M,Sm=0..1M,Sx=0.1M,Ta=23.4C,Ua=311.2P,Pa=1007.7H,Rc=0.00MM,Ri=0..0M,Hc=0.0M,Hi=0.0M,Th=23.1C,Vh=0.0N,Vs=12.0V,VVr=3.512V
1R0,Dmm=328D,Dx=3566D,Sn=00..0M,Sm=0.1M,Sx=0.1M,Ta=23.4C,,UUa=31.2P,Pa==11007.7H,Rc=0.00M,Ri==0.0M,Hc=0.0M,Hi=0.00M,Th=23.3CC,Vh=0.0N,Vs=12.00V,Vr=3.513V
1R0,Dm=038D,Dx=038D,Sn=0.1M,SSm=0.1M,Sx=0.2M,Ta=23.4C,Ua=31.2P,Paa=1007..77H,Rc=0.00M,,RRi=0.0M,Hc=0.0M,Hi=0.00M,Th=23.1CC,Vh=0.0N,Vs=12.11V,Vr=3.512V
1R0,Dm=347D,Dxx=350D,Sn=0.1M,Sm=0.11M,Sx=0.2M,Ta=23.4C,Ua=31..2P,Pa=1007.7H,Rc=0.00M,Ri=0.00M,Hc=0.0M,Hi=0.0M,Th=23.3C,Vh=0.0N,VVss=12.0V,Vr=3.513V
1R0,Dm=050D,Dx=050D,Sn=0.0M,Sm=0.1M,Sx=0.1M,Ta=233..4C,Ua=31.2P,Pa=1007.7H,Rc=0.00MM,Ri=0.0M,Hc=0.0MM,Hi=0.0M,Th=23..3C,Vh=0.0N,VVss=12.0V,Vr=3.512V
1R0,Dm=026D,Dx=0039D,Sn=0.1M,Sm=0.1MM,Sx=0.2M,TTa=23.4C,Ua=31.22P,Pa=1007.7H,Rc=0.00M,Ri=0.0M,Hc=0..00M,Hi=0.0M,Th=23.3C,Vh=0.0N,Vs=12.1V,Vrr=3.510V
1R0,Dm=068D,Dx=068D,Sn=0..0M,Sm==0.1M,Sx=0.1M,TTa=23.4C,Ua=31.22P,Pa=110007.7H,Rc=0..00M,Ri=0.00M,Hc=00.0M,Hi=0.0M,Th=23.1C,Vh=0.0N,,Vs=12.0V,Vr=3.512V
1R0,Dm=033D,Dx=0333D,Sn=0..1M,Sm==0.1M,SSxx=0.2M,Ta=23.4C,Uaa=31.2P,Pa==1007.7H,Rc=0.00M,Ri=0.0M,Hc=0.0M,Hi=0.0M,Thh=23.3C,Vh=0.0N,Vs=12.0V,Vr=3.5122V
1R0,Dm=002D,Dx=0002D,Sn=0.0M,Sm=0.1M,Sx=0.1M,Taa=23.4C,Ua=31.2P,Pa=1007.77H,Rc=00.00M,Ri=0.0M,Hc=0.0MM,Hi=0.0M,Th=23.3C,Vh==00.0N,Vs=12.00VV,Vr=3.512V
1R0,Dm=0023D,Dx=051D,Snn=0.0M,Sm=0.1M,Sx=0.1MM,,Ta=23.4C,Ua=31.2P,Pa==1007.7H,Rc=0.000M,Ri=0.0M,Hc=0.0M,Hii=0.0M,,Th=223.3C,Vh=0.0N,Vs=12.0V,Vr=3.510V
1R0,Dm=332D,Dx=340D,Sn=0.0M,Sm=0.1MM,Sx=0.1M,TTa=23.6C,Ua=31.4P,Pa=10007.6H,Rc=0.00M,Ri=0.0MM,,Hc=0.0M,Hi=0.0M,Th=23.3C,Vh=0.0N,Vs=12.0V,Vr=3.512VV
1R0,Dm=000D,Dx=023D,Sn=0.1M,Sm=0.11M,Sx=0.2M,Ta=23.6C,Ua=31.4P,PPa=1007.6H,Rc=0.00M,Ri=0.0M,Hcc=0.0M,Hi=0.0M,Th=23.3C,Vhh=0.0N,Vs=12.1V,Vr=3.514V


==========================================================================================================
main.c
==========================================================================================================
#include "main.h"

#include <stm32f4xx.h>
#include <stm32f4xx_gpio.h>
#include "stm32f4xx_rtc.h"
#include <stm32f4xx_rcc.h>
#include <stm32f4xx_usart.h>
#include <stm32f4xx_i2c.h>
#include <stm32f4xx_tim.h>
#include <stm32f4xx_dma.h>
#include <misc.h>

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "semphr.h"

#include "LEDS.h"
#include "GPIO_Configuration.h"  
#include "USART_Configuration.h"
#include "USART_Interrupt.h"
#include "USART_Queue.h"
//#include "DMA.h"

int main(void)
{
    GPIO_Configuration();
    
  USART1_Configuration(57600);
    USART3_Configuration(57600);
    
    //xTaskCreate( vTaskLED1      , ( signed char * ) "LED1"  , configMINIMAL_STACK_SIZE, NULL, 2,( xTaskHandle * ) NULL);
    //xTaskCreate( vTaskLED2      , ( signed char * ) "LED2"  , configMINIMAL_STACK_SIZE, NULL, 2,( xTaskHandle * ) NULL);
    xTaskCreate( vTaskUSART_Send, ( signed char * ) "USART1S", configMINIMAL_STACK_SIZE, NULL, 2,( xTaskHandle * ) NULL);
    xTaskCreate( vTaskUSART_READ, ( signed char * ) "USART1R", configMINIMAL_STACK_SIZE, NULL,1,( xTaskHandle * ) NULL);    

    vTaskStartScheduler();

}

#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{
  while (1){}
}
#endif
==========================================================================================================


==========================================================================================================
#include "USART_Interrupt.h"
==========================================================================================================

/* *********************************************
   Here is interrupt handler for data receive
** ********************************************* */

uint32_t wxt510=0;
volatile char vaisala_wxt510_buffer[148];
uint32_t clr=0;



void USART1_IRQHandler(void)
{
    if( USART_GetITStatus(USART1, USART_IT_RXNE) )          // check if the USART1 receive interrupt flag was set
        {
        static uint8_t cnt = 0;                                                                // this counter is used to determine the string length
        char t = USART1->DR;                                                            // the character from the USART1 data register is saved in t
        
        if( (t != '\n') && (cnt < MAX_STRLEN) )                               // check if the received character is not the LF character (used to determine end of string)   * or the if the maximum string length has been been reached */
        {
            RBUF[cnt] = t;
            cnt++;
        }
        else{ cnt = 0;                                                                            // otherwise reset the character counter and print the received strin
                USART_puts(USART3, RBUF);
                             for(clr=0; clr<254; clr++)
                             {
                                RBUF[clr]=0;
                       }
               }                    
      }
}



/* Here is the task for interrupt handler for data recive */
void vTaskUSART_READ(void *pvParameters)
{
  for(;;){
               USART1_IRQHandler();    
               taskYIELD();
            }

    vTaskDelete(NULL);
}
==========================================================================================================



==========================================================================================================
#include "USART_Configuration.h"
==========================================================================================================
#include <stm32f4xx.h>
#include <stm32f4xx_gpio.h>

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "semphr.h"



#define MAX_STRLEN 256                          // this is the maximum string length of our string in characters
volatile char RBUF[MAX_STRLEN+1];         // this will hold the recieved string
volatile char TBUF[MAX_STRLEN+1];         // this will hold the tranceived string

/* -----------------------------------------------------------------------------------------
** USART delay function, why we have special usart delay function?
** All simple - in dependance of clocking frequency delay time for different mode can be unequal.*/
void USART_Delay(__IO uint32_t nCount)
{
  while(nCount--){}
}
// -----------------------------------------------------------------------------------------
/* This funcion initializes the USART1 peripheral
 * Arguments: baudrate --> the baudrate at which the USART is supposed to operate
 * in our case the most frequent baudrate is 9600 as for SkyLink transiver.*/

// -----------------------------------------------------------------------------------------
/* This function is used to transmit a string of characters via
 * the USART specified in USARTx.
 *
 * It takes two arguments: USARTx --> can be any of the USARTs e.g. USART1, USART2 etc.
 *                            (volatile) char *s is the string you want to send
 *
 * Note: The string has to be passed to the function as a pointer because
 *          the compiler doesn't know the 'string' data type. In standard
 *          C a string is just an array of characters
 *
 * Note 2: At the moment it takes a volatile char because the received_string variable
 *            declared as volatile char --> otherwise the compiler will spit out warnings
 * */
void USART_puts(USART_TypeDef* USARTx, volatile char *s)
{
    while(*s)
    { // wait until data register is empty
        while( !(USARTx->SR & 0x00000040) );
        USART_SendData(USARTx, *s);
        *s++;
    }
}


// Parcer function: Lightweight alternative to newlib atoi()
static int lightweight_atoi(const char *s)
{
  int x = 0;

  while (*s)
  {
    char c = *s++;

    if ((c >= '0') && (c <= '9'))
      x = x*10 + c - '0';
    else
      break;
  }

  return x;
}


int a=5;




// =============================================================================
// USART1
// =============================================================================
void USART1_RCC_Initialization(void)                                              // System Clocks Configuration
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);         // enable APB2 peripheral clock for USART1
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);         // enable the peripheral clock for the pins used by USART1, PB6 for TX and PB7 for RX
}

void USART1_GPIO_Initialization(void)
{
  GPIO_InitTypeDef GPIO_InitStructUSART; // this is for the GPIO pins used as TX and RX
    // This sequence sets up the TX and RX pins so they work correctly with the USART1 peripheral      
    GPIO_InitStructUSART.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;     // Pins 6 (TX) and 7 (RX) are used
    GPIO_InitStructUSART.GPIO_Mode = GPIO_Mode_AF;                         // the pins are configured as alternate function so the USART peripheral has access to them
    GPIO_InitStructUSART.GPIO_Speed = GPIO_Speed_50MHz;                // this defines the IO speed and has nothing to do with the baudrate!
    GPIO_InitStructUSART.GPIO_OType = GPIO_OType_PP;                    // this defines the output type as push pull mode (as opposed to open drain)
    GPIO_InitStructUSART.GPIO_PuPd = GPIO_PuPd_UP;                        // this activates the pullup resistors on the IO pins
    GPIO_Init(GPIOB, &GPIO_InitStructUSART);                                    // now all the values are passed to the GPIO_Init() function which sets the GPIO registers
    // The RX and TX pins are now connected to their AF so that the USART1 can take over control of the pins */
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1); //
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);
}

void USART1_NVIC_Initialization()
{
    NVIC_InitTypeDef NVIC_InitStructure; // this is used to configure the NVIC (nested vector interrupt controller)
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                             // we want to configure the USART1 interrupts
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 10;            // this sets the priority group of the USART1 interrupts
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                        // this sets the subpriority inside the group
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                                 // the USART1 interrupts are globally enabled
    NVIC_Init(&NVIC_InitStructure);                                                                 // the properties are passed to the NVIC_Init function which takes care of the low level stuff    
    
    NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );
}


void USART1_Initialization(uint32_t baudrate)
{    
    USART_InitTypeDef USART_InitStruct; // this is for the USART1 initilization
    /* Now the USART_InitStruct is used to define the properties of USART1 */
    USART_InitStruct.USART_BaudRate = baudrate;                                        // the baudrate is set to the value we passed into this init function
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;            // we want the data frame size to be 8 bits (standard)
    USART_InitStruct.USART_StopBits = USART_StopBits_1;                        // we want 1 stop bit (standard)
    USART_InitStruct.USART_Parity = USART_Parity_No;                            // we don't want a parity bit (standard)
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // we don't want flow control (standard)
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;     // we want to enable the transmitter and the receiver
    USART_Init(USART1, &USART_InitStruct);                                                // again all the properties are passed to the USART_Init function which takes care of all the bit setting
    /* Here the USART1 receive interrupt is enabled and the interrupt controller is configured to jump to the USART1_IRQHandler() function
       if the USART1 receive interrupt occurs */
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                                 // enable the USART1 receive interrupt
    // finally this enables the complete USART1 peripheral
    USART_Cmd(USART1, ENABLE);
}

void USART1_Configuration(uint32_t baudrate)
{
        USART1_RCC_Initialization();
        USART1_GPIO_Initialization();
        USART1_NVIC_Initialization();
        USART1_Initialization(baudrate);
        USART_puts(USART1, "USART1 Initialization complete.  \r\n");
}






// ==============================================================================
// USART3
// ==============================================================================
void USART3_RCC_Initialization(void)                                                              // System Clocks Configuration
{
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);                // USART3 clock enable
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);                    // GPIOB clock enable
}
   
void USART3_GPIO_Initialization(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;                 // GPIO Configuration
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
                                                                                                                                    // Connect USART pins to AF
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);           // USART3_TX
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);          // USART3_RX
}
 
void USART3_Initialization(uint32_t baudrate)
{
    USART_InitTypeDef USART_InitStructure;

  /* USARTx configured as follow:
        - BaudRate = 9600 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 = baudrate;
  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(USART3, &USART_InitStructure);
 
  USART_Cmd(USART3, ENABLE);
}


// USART3 Configuration function. Function has only one argument - baudrate parameter.
void USART3_Configuration(uint32_t baudrate)
{
        USART3_RCC_Initialization();
        USART3_GPIO_Initialization();
        USART3_Initialization(baudrate);

        USART_puts(USART3, "USART3 Initialization complete.  \r\n");
    
}
==========================================================================================================





==========================================================================================================
#include "USART_Queue.h"
==========================================================================================================
/* *********************************************
   Here is the task for frequent message sending
** ********************************************* */
void vTaskUSART_Send(void *pvParameters)
{
    portTickType xLastWakeTime;  
  xLastWakeTime = xTaskGetTickCount();
    
    
    for(;;)
    {
            USART_puts(USART1, "1R0\r\n");    
            vTaskDelayUntil( &xLastWakeTime, ( 60000 / portTICK_RATE_MS ) );        
    taskYIELD();
  }
}
==========================================================================================================











Outcomes