UART Receive and Transmit Using FreeRTOS, Queue and Semaphore

hi,

i'm trying to receive string from computer then transmit to another device by using freertos. when i start on proteus, i only see one message although i'm sending different things. here is my code and screenshot:

int main()
{
  uart_start();
  uart_sendstr(uart0, "hello, i'm a transmitter\n\r");
  if ( xSerialSemaphore == NULL )  // Check to confirm that the Serial Semaphore has not already been created.
  {
    xSerialSemaphore = xSemaphoreCreateMutex();  // Create a mutex semaphore we will use to manage the Serial Port
    if ( ( xSerialSemaphore ) != NULL )
      xSemaphoreGive( ( xSerialSemaphore ) );  // Make the Serial Port available for use, by "Giving" the Semaphore.
  }

  queue = xQueueCreate(10, sizeof(char));
  if (queue == NULL) {
    uart_sendstr(uart0, "Queue can not be created");
  }
  
  xTaskCreate(
    TaskRead
    ,  "Receive"  // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  1  // Priority, with 1 being the highest, and 4 being the lowest.
    ,  NULL );

  xTaskCreate(
    TaskTransmit
    ,  "Transmit"
    ,  128  // Stack size
    ,  NULL
    ,  2  // Priority
    ,  NULL );
  vTaskStartScheduler();
 /* while(1)
  {
     uart_sendstr(uart0, uart_getstring(uart1, 1));
     _delay_ms(100);
  }*/
}

void loop()
{
  // put your main code here, to run repeatedly:
}

void TaskRead(void *pvParameters)
{
  while(1)
  {
    char* receive;
    if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
    {
     receive = uart_getstring(uart1, 10);
     xQueueSend(queue, &receive, portMAX_DELAY);
     xSemaphoreGive( xSerialSemaphore ); // Now free or "Give" the Serial Port for others.
    }
    vTaskDelay(1);
  }
}

void TaskTransmit(void *pvParameters)
{
  char* received;
  while(1){
    if (xSemaphoreTake (xSerialSemaphore, (TickType_t)5) == pdTRUE)
    {
      if(xQueueReceive(queue, &received, portMAX_DELAY) == pdPASS)
      {
        uart_sendstr(uart1, received);
      }
      xSemaphoreGive(xSerialSemaphore);
    }
    vTaskDelay(1);
  }
}

Untitled.png

Untitled.png

For some reason this question is appearing several times.

If you can redirect me to these questions, I will thank you. In addition, When I use xQueueSend(), the program is working only 1-2 seconds.

I take it your not using a ESP32?

Stack sizes of only 128 bytes. Quite small.

Using the Arduino IDE?


h =1 character, e =2 character, l =3 character, l =4 character, o=5 character, space= 6 character, i =7 character, a =8 character, m =9, space = 10 characters as one can see that 10 character queue will fill up quickly.
queue = xQueueCreate(10, sizeof(char));

Anyways, I suspect the OP did not post all the code.

Works quite well to receive Serial data.

/////////////////////////////////////////////////////////////////////////////////////////////////////
void fReceiveSerial_LIDAR( void * parameters  )
{
  bool BeginSentence = false;
  char OneChar;
  char *str;
  str = (char *)ps_calloc(300, sizeof(char) ); // put str buffer into PSRAM
  for ( ;; )
  {
    EventBits_t xbit = xEventGroupWaitBits (eg, evtReceiveSerial_LIDAR, pdTRUE, pdTRUE, portMAX_DELAY);
    if ( LIDARSerial.available() >= 1 )
    {
      while ( LIDARSerial.available() )
      {
        OneChar = LIDARSerial.read();
        if ( BeginSentence )
        {
          if ( OneChar == '>')
          {
            if ( xSemaphoreTake( sema_ParseLIDAR_ReceivedSerial, xSemaphoreTicksToWait10 ) == pdTRUE )
            {
               xQueueOverwrite( xQ_LIDAR_Display_INFO, ( void * ) &str );
              xEventGroupSetBits( eg, evtParseLIDAR_ReceivedSerial );
            }
            BeginSentence = false;
            break;
          }
          strncat( str, &OneChar, 1 );
        }
        else
        {
          if ( OneChar == '<' )
          {
            strcpy( str, ""); // clear string buffer
            BeginSentence = true; // found beginning of sentence
          }
        }
      } //  while ( LIDARSerial.available() )
    } //if ( LIDARSerial.available() >= 1 )
    xSemaphoreGive( sema_ReceiveSerial_LIDAR );
  }
  free(str);
  vTaskDelete( NULL );
} //void fParseSerial( void * parameters  )

Be aware that queues can be sent ‘by copy’ or ‘by original’ both have their own pluses and minuses.

Shouldn't you be making a receive container the same size as the send container

 char* received;
     ...
        uart_sendstr(uart1, received);

?

thank you for all,

i changed my board to uno and code. in real world, code below is working, but when i try to implement to mega, there is no result. i’m simulating mega on proteus.

#include <Arduino_FreeRTOS.h>
#include <semphr.h>
#include <queue.h>

QueueHandle_t queue;
SemaphoreHandle_t xCountingSemaphore;

void uart_start(uint32_t baud){
  uint16_t baudRate=F_CPU/baud/16-1;
  UBRR0H=(baudRate>>8);
  UBRR0L=baudRate;
  UCSR0B|=(1<<RXEN0)|(1<<TXEN0);
  UCSR0C|=(1<<UCSZ01)|(1<<UCSZ00);
}

uint8_t uart_receive(){
  while(!(UCSR0A & (1<<RXC0)));
  return UDR0;
}

void uart_transmit(uint8_t uData){
  while(!(UCSR0A & (1<<UDRE0)));
  UDR0=uData;
}

void setup()
{
  uart_start(9600); // Enable serial communication library.
  queue = xQueueCreate(10, sizeof(char));
  if (queue == NULL) {
  }

 // Create task for Arduino led 
  xTaskCreate(Task1, // Task function
              "Task1", // Task name
              128, // Stack size 
              NULL, 
              0 ,// Priority
              NULL );
   xTaskCreate(Task2, // Task function
              "Task2", // Task name
              128, // Stack size 
              NULL, 
              0, // Priority
              NULL );
   xCountingSemaphore = xSemaphoreCreateCounting(1,1);
   xSemaphoreGive(xCountingSemaphore);
   vTaskStartScheduler();
}

void loop() {}



void Task1(void *pvParameters)
{
  (void) pvParameters;
  uint8_t receive;
  for (;;) 
    {
      xSemaphoreTake(xCountingSemaphore, portMAX_DELAY); 
      receive = uart_receive();
      //uart_transmit('A');
      xQueueSend(queue, &receive, 0);
      //digitalWrite(LED_BUILTIN, HIGH);
      xSemaphoreGive(xCountingSemaphore);
      vTaskDelay(1);
    }
  }

void Task2(void *pvParameters)
{
  (void) pvParameters;
  uint8_t receive;
  for (;;) 
    {
      xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);
      xQueueReceive(queue, &receive, 0);
      if(receive)
      {
        uart_transmit(receive);
      }
      xSemaphoreGive(xCountingSemaphore);
      vTaskDelay(1);
  }
}

Wouldn't life be simpler without FreeRTOS ?

...R
Serial Input Basics - simple reliable non-blocking ways to receive data.

here is code of mega:

#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <semphr.h> 
#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <compat/twi.h>
#include <inttypes.h>
#include <stdlib.h>
#include <avr/sleep.h>
#include <avr/delay.h>

#define BAUD 9600
#define BUFF_LEN 700
#define BAUD_PRESCALE (((F_CPU / (BAUD * 16UL))) - 1)

QueueHandle_t queue;
SemaphoreHandle_t xCountingSemaphore;

char input_buffer[BUFF_LEN];

uint16_t read_spot;

typedef enum
{
  uart0 = 0,
  uart1 = 1
}uart_t;

//Got through and set up the registers for UART
void uart_start(void) {
  
    UCSR1B |= (1 << RXEN1) | (1 << TXEN1); //transmit side of hardware
    UCSR1C |= (1 << UCSZ10) | (1 << UCSZ11); //receive side of hardware

    UBRR1L = BAUD_PRESCALE; //set the baud to 9600, have to split it into the two registers
    UBRR1H = (BAUD_PRESCALE >> 8); //high end of baud register

    UCSR1B |= (1 << RXCIE1); //recieve data interrupt, makes sure we don't loose data
    
    UCSR0B |= (1 << RXEN0) | (1 << TXEN0); //transmit side of hardware
    UCSR0C |= (1 << UCSZ00) | (1 << UCSZ01); //receive side of hardware

    UBRR0L = BAUD_PRESCALE; //set the baud to 9600, have to split it into the two registers
    UBRR0H = (BAUD_PRESCALE >> 8); //high end of baud register

    UCSR0B |= (1 << RXCIE0); //recieve data interrupt, makes sure we don't loose data
}

void uart_sendint(uart_t uart, uint8_t data) {
    /*
    Use this to send a 8bit long piece of data
    */
    if (uart == uart1)
    {
      while ((UCSR1A & (1 << UDRE1)) == 0);//make sure the data register is cleared
      UDR1 = data; //send the data
      while ((UCSR1A & (1 << UDRE1)) == 0);//make sure the data register is cleared
      UDR1 = '\n';//send a new line just to be sure
    }
    else if(uart == uart0)
    {
      while ((UCSR0A & (1 << UDRE0)) == 0);//make sure the data register is cleared
      UDR0 = data; //send the data
      while ((UCSR0A & (1 << UDRE0)) == 0);//make sure the data register is cleared
      UDR0 = '\n';//send a new line just to be sure
    }
}

void uart_sendint16(uart_t uart, uint16_t data) {
    /*
    Use this to send a 16bit long piece of data
    */
    if(uart == uart1)
    {
      while ((UCSR1A & (1 << UDRE1)) == 0);//make sure the data register is cleared
      UDR1 = data;//send the lower bits
      while ((UCSR1A & (1 << UDRE1)) == 0);//make sure the data register is cleared
      UDR1 = (data >> 8); //send the higher bits
      while ((UCSR1A & (1 << UDRE1)) == 0);//make sure the data register is cleared
      UDR1 = '\n';//send a new line just to be sure
    }
    else if(uart == uart0)
    {
      while ((UCSR0A & (1 << UDRE0)) == 0);//make sure the data register is cleared
      UDR0 = data;//send the lower bits
      while ((UCSR0A & (1 << UDRE0)) == 0);//make sure the data register is cleared
      UDR0 = (data >> 8); //send the higher bits
      while ((UCSR0A & (1 << UDRE0)) == 0);//make sure the data register is cleared
      UDR0 = '\n';//send a new line just to be sure
    }
}

void uart_sendstr(uart_t uart, char *data) {
    /*
    Use this to send a string, it will split it up into individual parts
    send those parts, and then send the new line code
    */
    if (uart == uart1)
    {
      while (*data) {
        while ((UCSR1A & (1 << UDRE1)) == 0);//make sure the data register is cleared
        UDR1 = *data; //goes through and splits the string into individual bits, sends them
        data += 1;//go to new bit in string
      }
      while ((UCSR1A & (1 << UDRE1)) == 0);//make sure the data register is cleared
      UDR1 = '\n';//send a new line just to be sure
    }
    else if(uart == uart0)
    {
      while (*data) {
        while ((UCSR0A & (1 << UDRE0)) == 0);//make sure the data register is cleared
        UDR0 = *data; //goes through and splits the string into individual bits, sends them
        data += 1;//go to new bit in string
      }
      while ((UCSR0A & (1 << UDRE0)) == 0);//make sure the data register is cleared
      UDR0 = '\n';//send a new line just to be sure
    }
}

uint8_t uart_get(uart_t uart) {
    /*
    gets data from the register that the interrupt stored it
    in coming data into, returning it to the calling function as 8 bit long data
    */
    if(uart == uart1)
    {
      while(!(UCSR1A & (1<<RXC1)));
      return UDR1;
    }
    else if(uart == uart0)
    {
      while(!(UCSR0A & (1<<RXC0)));
      return UDR0;
    }
}

char * uart_getstring(uart_t uart, int len) {
    static char input[] = {};
    uint8_t i;
    char c;

    for(i = 0; i < len; i++) {
        c = uart_get(uart);
        if (c == '\n') break;
        input[i] = c;
        
    }
    input[i+1] = 0;

    return input;
}

void setup()
{
  uart_start();
  uart_sendstr(uart0, "hello, i'm a transmitter\n\r");

  queue = xQueueCreate(10, sizeof(char));
  if (queue == NULL) {
    uart_sendstr(uart0, "Queue can not be created");
  }
  
  xTaskCreate(
    TaskRead
    ,  "Receive"  // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  1  // Priority, with 1 being the highest, and 4 being the lowest.
    ,  NULL );

  xTaskCreate(
    TaskTransmit
    ,  "Transmit"
    ,  128  // Stack size
    ,  NULL
    ,  2  // Priority
    ,  NULL );

    
  xCountingSemaphore = xSemaphoreCreateCounting(1,1);
  xSemaphoreGive(xCountingSemaphore);
  vTaskStartScheduler();
 /* while(1)
  {
     uart_sendstr(uart0, uart_getstring(uart1, 1));
     _delay_ms(100);
  }*/
}

void loop()
{
  // put your main code here, to run repeatedly:
}

void TaskRead(void *pvParameters)
{
  (void) pvParameters;
  uint8_t receive;
  for (;;) 
    {
      xSemaphoreTake(xCountingSemaphore, portMAX_DELAY); 
      receive = uart_get(uart0);
      uart_sendstr(uart0, 'A');
      xQueueSend(queue, &receive, 0);
      //digitalWrite(LED_BUILTIN, HIGH);
      xSemaphoreGive(xCountingSemaphore);
      vTaskDelay(1);
    }
}

void TaskTransmit(void *pvParameters)
{
  (void) pvParameters;
  uint8_t receive;
  for (;;) 
    {
      xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);
      xQueueReceive(queue, &receive, 0);
      if(receive)
      {
        uart_sendint(uart0, receive);
      }
      xSemaphoreGive(xCountingSemaphore);
      vTaskDelay(1);
  }
}

it is a homework and i'm trying to communicate full-duplex.

Yes, it would be much simpler without freeRTOS on a mega or uno, they barely have enough arse to push freeRTOS and ram to cram freeRTOS into.

Aw shucks, I'm no longer interested if the OP keeps changing the game, how can I make troubleshooting progress. Good luck with your thing.