I am developing a FreeRTOS application on a Cortex-M4 (NXP i.MX8MM) that creates 4 tasks.
The first task is waiting to receive a character on a UART. As soon as a buffer is received, it is sent to task 3 with xQueueSend.
The second task is the transmission task via the UART. It waits permanently for the reception of a buffer (sent by task 4) with xQueueReceive.
Currently, I manage to create these 4 tasks, but only the first 2 are executed. I have the impression that the second task, and particularly the “xQueueReceive” function, is blocking (or not executing properly) the execution of the last 2 tasks. If I comment out the “xQueueReceive” function, all tasks run without any problem. All configASSERT in the xQueueReceive function pass without problem.
Where do you think this can come from?
My code:
main.c
/* System includes */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Kernel includes */
#include "FreeRTOS.h"
#include "task.h"
#include "fsl_debug_console.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "board.h"
#include "rsc_table.h"
/* Other includes */
#include "A_version.h"
#include "A_rpmsg.h"
#include "A_ip_task.h"
#include "A_queue.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Globals
******************************************************************************/
/* Queue RPMSG -> UART RS-485 */
static QueueHandle_t rpmsg_to_uart_queue = NULL;
/* Queue RPMSG <- UART RS-485 */
static QueueHandle_t uart_to_rpmsg_queue = NULL;
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
/*!
* @brief Main function
*/
int main(void)
{
uint8_t status = 1;
/* Initialize standard SDK demo application pins */
/* Board specific RDC settings */
BOARD_RdcInit();
BOARD_InitBootPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
BOARD_InitMemory();
copyResourceTable();
#ifdef MCMGR_USED
/* Initialize MCMGR before calling its API */
(void)MCMGR_Init();
#endif /* MCMGR_USED */
PRINTF("Start Appli_metier: %s\r\n", NUM_ET_DATE_VERSION_CARTE_CM);
/* Chargement des paramètres de l'UART */
F_ip_485_load_params();
/* Initialisation de l'UART */
status = F_init_ip_485();
/* Initialisation de RPMsg */
if(status != 0)
{
PRINTF("ERROR INIT UART\r\n");
} else {
status = rpmsg_init();
}
rpmsg_to_uart_queue = xQueueCreate(10, sizeof(struct Message *));
if (rpmsg_to_uart_queue != NULL)
{
vQueueAddToRegistry(rpmsg_to_uart_queue, "RPMsg to UART queue");
}
uart_to_rpmsg_queue = xQueueCreate(10, sizeof(struct Message *));
if (uart_to_rpmsg_queue != NULL)
{
vQueueAddToRegistry(uart_to_rpmsg_queue, "UART to RPMsg queue");
}
/* Lancement des taches */
if(status != 0)
{
PRINTF("ERROR INIT RPMSG\r\n");
} else {
PRINTF("Avant F_ip_485_task\r\n");
/* Lancement de la tache UART */
F_ip_485_task(rpmsg_to_uart_queue, uart_to_rpmsg_queue);
PRINTF("Avant rpmsg_task\r\n");
/* Lancement de la tache RPMSG (cote A53) */
rpmsg_task(rpmsg_to_uart_queue, uart_to_rpmsg_queue);
}
vTaskStartScheduler();
PRINTF("Failed to start FreeRTOS on core0.\n");
for (;;)
;
}
tasks 1 and 2:
#include "A_ip_task.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "board.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "fsl_debug_console.h"
#include "A_ip_485.h"
#include "A_queue.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define IP_485_RX_TASK_STACK_SIZE (256)
#define IP_485_TX_TASK_STACK_SIZE (256)
#define MAX_BUF_TRAME_ETHERNET 1520
/* Task priorities. */
#define hello_task_PRIORITY (configMAX_PRIORITIES - 1)
#define TASK_DELAY_IP_485 200
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
typedef struct _uart_struct
{
QueueHandle_t my_queue_to_uart;
QueueHandle_t my_queue_to_rpmsg;
} uart_struct;
static uart_struct my_uart_struct;
static TaskHandle_t ip_485_rx_task_handle = NULL;
static TaskHandle_t ip_485_tx_task_handle = NULL;
STRUCT_parametre_uart S_device_UART[NBR_MAX_UART];
unsigned char TUCH_ip_485_buffer[MAX_BUF_TRAME_ETHERNET];
static void F_ip_485_rx_task(void *pvParameters)
{
uart_struct * param_struct = pvParameters;
Message st_msg;
uint16_t UI_lg;
/* Block for 5µs. */
const TickType_t xDelay = 5 / (portTICK_PERIOD_MS * 1000);
PRINTF("\r\nF_ip_485_rx_task running ...\r\n");
/* On attend la réception d'une trame sur la file */
for (;;)
{
if ((UI_lg = F_driverUART_read(UART_IP485, TUCH_ip_485_buffer, MAX_BUF_TRAME_ETHERNET)) != 0)
{
//TODO: F_traitement_RX_IP_485(TUCH_ip_485_buffer, UI_lg); /* Traitement dans MQX */
/* Remplacer par écriture dans la queue de RPMsg pour envoi vers Cortex-A53 */
st_msg.size = UI_lg;
xQueueSend(param_struct->my_queue_to_rpmsg, (void *)&st_msg, 10);
}
vTaskDelay(xDelay);
}
vTaskSuspend(NULL);
}
static void F_ip_485_tx_task(void *pvParameters)
{
uart_struct * param_struct = pvParameters;
Message rcv_msg;
/* Block for 5µs. */
const TickType_t xDelay = 5 / (portTICK_PERIOD_MS * 1000);
PRINTF("\r\nF_ip_485_tx_task running ...\r\n");
for (;;)
{
if (xQueueReceive(param_struct->my_queue_to_uart, (void *)&rcv_msg, 0) != pdTRUE)
{
PRINTF("Failed to receive queue.\r\n");
}
else
{
/* On envoie tous les octets */
F_driverUART_IP485_write(rcv_msg.body, rcv_msg.size);
}
vTaskDelay(xDelay);
}
vTaskSuspend(NULL);
}
void F_ip_485_task(QueueHandle_t r_to_u, QueueHandle_t u_to_r)
{
my_uart_struct.my_queue_to_uart = r_to_u;
my_uart_struct.my_queue_to_rpmsg = u_to_r;
if (xTaskCreate(F_ip_485_rx_task, "IP 485 RX", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, &ip_485_rx_task_handle) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
; }
if (xTaskCreate(F_ip_485_tx_task, "IP 485 TX", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, &ip_485_tx_task_handle) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
;
}
}
tasks 3 and 4:
#include "A_rpmsg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "board.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "rpmsg_lite.h"
#include "rpmsg_queue.h"
#include "rpmsg_ns.h"
#include "A_queue.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define RPMSG_LITE_SHMEM_BASE (VDEV0_VRING_BASE)
#define RPMSG_LITE_LINK_ID (RL_PLATFORM_IMX8MM_M4_USER_LINK_ID)
#define RPMSG_LITE_NS_ANNOUNCE_STRING "rpmsg-virtual-tty-channel-1"
#define RPMSG_RX_TASK_STACK_SIZE (128)
#define RPMSG_TX_TASK_STACK_SIZE (128)
#ifndef LOCAL_EPT_ADDR
#define LOCAL_EPT_ADDR (30)
#endif
/*******************************************************************************
* Prototypes
******************************************************************************/
typedef struct _rpmsg_struct
{
struct rpmsg_lite_endpoint *volatile my_ept;
volatile rpmsg_queue_handle my_queue;
struct rpmsg_lite_instance *volatile my_rpmsg;
QueueHandle_t my_queue_to_uart;
QueueHandle_t my_queue_to_rpmsg;
} rpmsg_struct;
static TaskHandle_t rpmsg_rx_task_handle = NULL;
static TaskHandle_t rpmsg_tx_task_handle = NULL;
static SemaphoreHandle_t mutex;
static rpmsg_struct my_rpmsg_struct;
static volatile uint32_t remote_addr;
static char app_rx_buf[1500]; /* Each RPMSG buffer can carry less than 512 payload */
static char app_tx_buf[1500]; /* Each RPMSG buffer can carry less than 512 payload */
static void rpmsg_rx_task(void *param)
{
rpmsg_struct * param_struct = param;
Message st_msg;
volatile uint32_t local_remote_addr;
void *rx_buf;
uint32_t len;
int32_t result;
void *tx_buf;
uint32_t size;
boolean init = false;
/* Block for 5µs. */
const TickType_t xDelay = 5 / (portTICK_PERIOD_MS * 1000);
for (;;)
{
/* Get RPMsg rx buffer with message */
result =
rpmsg_queue_recv_nocopy(param_struct->my_rpmsg, param_struct->my_queue, (uint32_t *)&remote_addr, (char **)&rx_buf, &len, RL_BLOCK);
if (result != 0)
{
assert(false);
} else {
PRINTF("RPMsg received !\r\n");
}
/* Copy string from RPMsg rx buffer */
assert(len < sizeof(app_rx_buf));
memcpy(st_msg.body, rx_buf, len);
st_msg.size = len;
xQueueSend(param_struct->my_queue_to_uart, (void *)&st_msg, 10);
//app_rx_buf[len] = 0; /* End string by '\0' */
if ((len == 2) && (app_rx_buf[0] == 0xd) && (app_rx_buf[1] == 0xa))
PRINTF("Get New Line From Master Side\r\n");
else
PRINTF("Get Message From Master Side : \"%s\" [len : %d]\r\n", app_rx_buf, len);
if(!init) {
local_remote_addr = remote_addr;
// Release the mutex so that the creating function can finish
xSemaphoreGive(mutex);
init = true;
}
/* Release held RPMsg rx buffer */
result = rpmsg_queue_nocopy_free(param_struct->my_rpmsg, rx_buf);
if (result != 0)
{
assert(false);
}
}
vTaskSuspend(NULL);
}
static void rpmsg_tx_task(void *param)
{
rpmsg_struct * param_struct = param;
Message rcv_msg;
volatile uint32_t local_remote_addr;
void *rx_buf;
uint32_t len;
int32_t result;
void *tx_buf;
uint32_t size;
/* Block for 5µs. */
const TickType_t xDelay = 5 / (portTICK_PERIOD_MS * 1000);
/* On attend de recevoir l'adresse de destination */
PRINTF("\r\nM4 waiting for destination address ...\r\n");
// Take the mutex
xSemaphoreTake(mutex, portMAX_DELAY);
local_remote_addr = remote_addr;
for (;;)
{
if (xQueueReceive(param_struct->my_queue_to_rpmsg, (void *)&rcv_msg, portMAX_DELAY) != pdTRUE)
{
PRINTF("Failed to receive queue.\r\n");
}
else
{
/* Get tx buffer from RPMsg */
tx_buf = rpmsg_lite_alloc_tx_buffer(param_struct->my_rpmsg, &size, RL_BLOCK);
assert(tx_buf);
/* Copy string to RPMsg tx buffer */
memcpy(tx_buf, rcv_msg.body, rcv_msg.size);
/* Echo back received message with nocopy send */
result = rpmsg_lite_send_nocopy(param_struct->my_rpmsg, param_struct->my_ept, local_remote_addr, tx_buf, rcv_msg.size);
if (result != 0)
{
assert(false);
} else {
PRINTF("RPMsg sent !\r\n");
}
}
}
vTaskSuspend(NULL);
}
uint8_t rpmsg_init(QueueHandle_t r_to_u, QueueHandle_t u_to_r)
{
uint8_t status;
#ifdef MCMGR_USED
uint32_t startupData;
/* Get the startup data */
(void)MCMGR_GetStartupData(kMCMGR_Core1, &startupData);
my_rpmsg = rpmsg_lite_remote_init((void *)startupData, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
/* Signal the other core we are ready */
(void)MCMGR_SignalReady(kMCMGR_Core1);
#else
my_rpmsg_struct.my_rpmsg = rpmsg_lite_remote_init((void *)RPMSG_LITE_SHMEM_BASE, RPMSG_LITE_LINK_ID, RL_NO_FLAGS);
#endif /* MCMGR_USED */
PRINTF("En attente du chargement du module RPMsg...\r\n");
while (0 == rpmsg_lite_is_link_up(my_rpmsg_struct.my_rpmsg))
;
my_rpmsg_struct.my_queue = rpmsg_queue_create(my_rpmsg_struct.my_rpmsg);
my_rpmsg_struct.my_ept = rpmsg_lite_create_ept(my_rpmsg_struct.my_rpmsg, LOCAL_EPT_ADDR, rpmsg_queue_rx_cb, my_rpmsg_struct.my_queue);
(void)rpmsg_ns_announce(my_rpmsg_struct.my_rpmsg, my_rpmsg_struct.my_ept, RPMSG_LITE_NS_ANNOUNCE_STRING, RL_NS_CREATE);
PRINTF("\r\nNameservice sent, ready for incoming messages...\r\n");
// Create mutex before starting tasks
mutex = xSemaphoreCreateMutex();
// Take the mutex
if(xSemaphoreTake(mutex, portMAX_DELAY) == pdTRUE)
{
status = 0;
} else {
status = -1;
}
return status;
}
void rpmsg_task(QueueHandle_t r_to_u, QueueHandle_t u_to_r)
{
my_rpmsg_struct.my_queue_to_uart = r_to_u;
my_rpmsg_struct.my_queue_to_rpmsg = u_to_r;
if (xTaskCreate(rpmsg_rx_task, "RPMSG RX", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, &rpmsg_rx_task_handle) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
;
}
if (xTaskCreate(rpmsg_tx_task, "RPMSG TX", configMINIMAL_STACK_SIZE + 100, NULL, tskIDLE_PRIORITY + 1, &rpmsg_tx_task_handle) !=
pdPASS)
{
PRINTF("Task creation failed!.\r\n");
while (1)
;
}
}