Synchronizing multiple tasks

cwallen-89 wrote on Wednesday, September 20, 2017:

Hello,

I am currently developing software that initiates SPI communication between 2 SPI ports. I currently only have 1 task that accomplishes this (Figure 1):

/* Task1 */
void vTask1(void *pvParameters)
{
spiDAT1_t dataconfig1_t;

dataconfig1_t.CS_HOLD   = FALSE;
dataconfig1_t.WDEL         = TRUE;
dataconfig1_t.DFSEL        = SPI_FMT_0;
dataconfig1_t.CSNR         = 0xF7;

for(;;)
{
    /* Initiate SPI2 Transmit and Receive through Interrupt Mode */
    spiSendAndGetData(spiREG2, &dataconfig1_t, 16, TX_Data_Slave, RX_Data_Slave);

    /* Initiate SPI1 Transmit and Receive through Polling Mode */
    spiTransmitAndReceiveData(spiREG1, &dataconfig1_t, 16, TX_Data_Master, RX_Data_Master);
}

}

What I would like to do is split this task into two separate tasks. The first task will use the spiSendAndGet() function and the second will use the spiTransmitAndRecieveData() function. I believe creating two tasks from this one task won’t be too difficult. What I’m worried about is synchronizing the two tasks. I am relatively new to RTOS and I’m not too sure how I could make sure that the two tasks would not conflict with one another. Any information regarding this topic would be greatly appreciated!

Calvin Wallen IV

rtel wrote on Wednesday, September 20, 2017:

The two tasks would be using different SPI ports, so there would not be
a hardware conflict. Can you be more specific about what it is you are
worried will conflict?

cwallen-89 wrote on Thursday, September 21, 2017:

Edit: response was moved to Real Time Engineers ltd. reply thread

cwallen-89 wrote on Thursday, September 21, 2017:

Example: Task1 is responsible for the setup of the SPI1 (MASTER) register and Task2 is responsible for the setup of the SPI2 (SLAVE) register. Is it possible that Task1 could interfere with the execution of Task2 or vice versa? Or do the tasks execute simultaneously without any sort of timing issues?

rtel wrote on Thursday, September 21, 2017:

The tasks run independently. If they are writing to different registers
then there is no problem. You would only get a problem if they wrote to
the same register. I would recommend downloading the free pdf book
here: http://www.freertos.org/Documentation/RTOS_book.html

cwallen-89 wrote on Thursday, September 21, 2017:

So this is my current attempt at implementing the above code as two separate tasks:

spiDAT1_t dataconfig1_t;

/* Define Task Handles */
xTaskHandle xTask1Handle;
xTaskHandle xTask2Handle;

uint16 TX_Data_Master[16] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10 };
uint16 RX_Data_Master[16] = { 0 };
uint16 TX_Data_Slave[16] = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20 };
uint16 RX_Data_Slave[16] = { 0 };

/* Task1 */
void vTask1(void *pvParameters)
{
dataconfig1_t.CS_HOLD = FALSE;
dataconfig1_t.WDEL = TRUE;
dataconfig1_t.DFSEL = SPI_FMT_0;
dataconfig1_t.CSNR = 0xF7;

for(;;)
{
    /* Initiate SPI2 Transmit and Receive through Interrupt Mode */
    spiSendAndGetData(spiREG2, &dataconfig1_t, 16, TX_Data_Slave, RX_Data_Slave);
}

}

/* Task2 */
void vTask2(void *pvParameters)
{
dataconfig1_t.CS_HOLD = FALSE;
dataconfig1_t.WDEL = TRUE;
dataconfig1_t.DFSEL = SPI_FMT_0;
dataconfig1_t.CSNR = 0xF7;

for(;;)
{
    /* Initiate SPI1 Transmit and Receive through Polling Mode */
    spiTransmitAndReceiveData(spiREG1, &dataconfig1_t, 16, TX_Data_Master, RX_Data_Master);
}

}
/* USER CODE END */

/** @fn void main(void)

  • @brief Application main function
  • @note This function is empty by default.
  • This function is called after startup.
  • The user can use this function to implement the application.
    */

/* USER CODE BEGIN (2) /
/
USER CODE END */

void main(void)
{
/* USER CODE BEGIN (3) */

spiInit();

/* Create Task 1 */
if (xTaskCreate(vTask1,"Task1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle) != pdTRUE)
{
    /* Task could not be created */
    while(1);
}

/* Create Task 2 */
if (xTaskCreate(vTask2,"Task2", configMINIMAL_STACK_SIZE, NULL, 1, &xTask2Handle) != pdTRUE)
{
    /* Task could not be created */
    while(1);
}

/* Start Scheduler */
vTaskStartScheduler();

/* Run forever */
while(1);

/* USER CODE END */
}

Initially, I only had one task which initiated both spi registers. Here I am trying to create two tasks which each initiate a different SPI port. I assumed that they would simply communicate properly with the same setup. However, this is not the case. When I run the code, RX_Data_Slave ends up with a scrambled assortment of the values from TX_Data_Master; some values are missing and TX_Data_Master is overwritten by different values; and RX_Data_Master sometimes gets nothing and sometimes gets something similar to RX_Data_Slave. I’m thinking I have to have the two tasks communicate with each other in some way in order to prevent this from happening. I’m just not entirely sure how. I attached a snip of an example of what happens with the buffer data (it’s not consistent as the values change almost every time I run the program). The formatting is a bit off so you may have to just download it in order to view it if you need to.

rtel wrote on Thursday, September 21, 2017:

Is there anything the two tasks are sharing. You have only mentioned
registers so far, and the registers for the two SPI ports are different.
Are they sharing anything else? It sounds like they are using the
same buffer, so one is overwriting the other. Also, are you doing the
spi timing (toggling pins, etc.) in the software, or relying on the
hardware peripherals to do that? If you are toggling pins then the
timing could change when you have two tasks, and you need to check that
the functions that toggle the pins are ‘thread safe’, which means they
are not accessing the same registers or ports at the same time.

cwallen-89 wrote on Friday, September 22, 2017:

So I think the problem is that the spiSendAndGetData() function is being called repeatedly while the spiTransmitAndReceive() function is being executed. I have the SPI2 function being triggered on both a high and a low (so always), and I have nothing allowing the transmit to finish (as you said). For now, I’m going to leave them in the same function and figure out a different application for a second task.

asifrtosasif wrote on Friday, September 22, 2017:

https://www.youtube.com/watch?v=mtjcoL-sGEM&t=82s