This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F280039C: Address-Bit Multiprocessor Mode combined with FreeRTOS

Part Number: TMS320F280039C
Other Parts Discussed in Thread: SYSCONFIG

Hello,

I have the following scenario, which I would like to implement:

I use the Address-Bit Multiprocessor Mode to synchronize the messages on a UART bus with several participants. A FreeRTOS is running on each participant, whose task for the UART communication is triggered by the interrupt of an incoming address byte via "give" a semaphore. This also works so far.

However, I have the problem that I can read the subsequent data bytes incorrectly or not at all. I do not use a FIFO, as this cannot be combined with the address bit mode according to my programming experience. At the moment my program works as follows:


1. Interrupt through address byte (address bit = 1)

2. Read the incoming address of the input buffer using the SCI_readCharBlockingNonFIFO() function, defined in the sci.h file
3. Check if the address matches
4. If the address is matching, disable Sleep Mode
5. Read the following data also using the SCI_readCharBlockingNonFIFO() function, defined in the sci.h file (which does not work properly)

Are there any examples for this or is there anything special I need to consider when looking at the following data bytes?

Regards

Joshua

  • Hi Joshua,

    We unfortunately do not have any examples showcasing multiprocessor mode, but hopefully I can help. Is the F280039C being used to transmit (acting as the commander of the participants) or to receive (acting as one of the participants?) The steps in your program sound correct, what exactly is the issue you are seeing? One note about using SCI in non-FIFO mode, if you are using the F280039C to transmit with an interrupt, data needs to be initially written to the TX buffer in order to get any TX interrupts. This is because the TXRDY flag is set when data is shifted out of the TX buffer, rather than when the buffer is empty.

    Best Regards,

    Delaney

  • Hi Delaney,

    thanks for your reply.

    At the moment I use the F280039C for both (receiver and transmitter), to avoid hardware specific incompatibility problems. But I have the issue with receiving/reading the data in the receiver.

    Sending works without problems (I do that exactly like you explained) and the receive interrupt is also triggered at the receiver, but I cannot read out the subsequent data appropriately.

    Is it possible that I have to pay attention to something special because no FIFO is used?

    Best Regards,

    Joshua

  • Hi Joshua,

    Calling the SCI_readCharBlockingNonFIFO() function in the RX interrupt like you describe should be the correct way to go about this. Can you elaborate on how the received data is incorrect? Is the correct data being shown in the RX buffer during debug but when read is being corrupted? Or is the data in the RX buffer incorrect? Could you also show a scope capture of the receive line? The RX interrupt should be triggered in the case of a break detect and framing error as well as when there is an address byte received. Can you check which error flags in the SCIRXST register are set when the interrupt is called?

    Best Regards,

    Delaney

  • Hi Delaney,

    as far as I can tell during debugging, the data in the RXBuffer is already incorrect. This is the scope capture of the message on the receiver side (works correctly):

    I have created a new "small" example, based on the FreeRTOS SDK example for debug purpose (code see below) and now I have the problem that the interrupt is just called once in the beginning. It consists of a master that sends a request every second and a slave that should actually save this request in the processdata[8] array. The messages of the master are sent correctly (checked it with the oscilloscope).
    If I use the same example without FreeRTOS, it works without any problems (almost same code, just the instructions that were previously processed in the task are processed directly in the ISR).

    I already suspected that because the ISR of the SCI module has a higher priority in hardware than the ISR of Timer2, which is used in this port for the tick interrupts, causes a problem. But this should only delay the call of the scheduler and not block it. Doesn't it?

    Code:
    __________________________________________________________________________________________________

    Master Software (sends a simple "request" every second):

    /********************************************//**
    * @file Master_Simulator_C2000.c (Master Software)
    *
    * @date 2024-03-21
    *
    * @version 1.2
    *
    ***********************************************/
    
    // Included Files
    #include "driverlib.h"
    #include "device.h"
    #include "board.h"
    
    #include "stdint.h"
    
    // Defines
    
    // Function prototypes
    void sendaddress(uint16_t addr);
    void sendData(uint16_t data[]);
    
    // Globals
    uint16_t address1 = 0x0000;
    uint16_t address2 = 0x008C;
    uint16_t processdata[7] = {0x0003, 0x0030, 0x0033, 0x0044, 0x0055, 0x0000, 0x003E};
    
    // Main
    void main(void) {
    // Configure PLL, disable WD, enable peripheral clocks.
    Device_init();
    
    // Disable pin locks and enable internal pullups.
    Device_initGPIO();
    
    // Initialize interrupt controller and vector table.
    Interrupt_initModule();
    Interrupt_initVectorTable();
    
    // Disable all CPU interrupts and clear all CPU interrupt flags.
    DINT;
    IER = 0x0000;
    IFR = 0x0000;
    
    // Set up CPUTimer1, LEDs
    Board_init();
    
    SCI_setAddrMultiProcessorMode(SCIB_BASE);
    
    SCI_disableSleepMode(SCIB_BASE);
    
    for(;;) {
    
    sendaddress(address1);
    sendData(processdata);
    DEVICE_DELAY_US(1000000);
    
    }
    }
    
    
    
    void sendaddress(uint16_t addr) {
    HWREGH(SCIB_BASE + SCI_O_CTL1) |= SCI_CTL1_TXWAKE; // Next sent byte is an address byte
    SCI_writeCharBlockingNonFIFO(SCIB_BASE, addr);
    HWREGH(SCIB_BASE + SCI_O_CTL1) &= ~SCI_CTL1_TXWAKE; // Clear TXWAKE bit (following bytes are data)
    GPIO_togglePin(22U);
    }
    
    
    
    void sendData(uint16_t data[]) {
    int i;
    for (i = 0; i < 7; i++) {
    SCI_writeCharBlockingNonFIFO(SCIB_BASE, data[i]); // Next sent bytes are process data
    }
    while (SCI_isTransmitterBusy(SCIB_BASE)) {
    // Wait till the transmission is complete
    }
    }
    
    // End of File

    __________________________________________________________________________________________________

    Slave Software:

    Slave Software:
    
    /********************************************//**
    * @file main.c (Slave Software)
    *
    * @date 2024-03-21
    *
    * @version 1.2
    *
    ***********************************************/
    
    // Included Files
    #include "driverlib.h"
    #include "device.h"
    #include "FreeRTOS.h"
    #include "FreeRTOSConfig.h"
    #include "board.h"
    #include "c2000_freertos.h"
    #include "stdint.h"
    
    // Globals
    uint16_t address1 = 0x0000;
    uint16_t address_temp;
    uint16_t processdata[8];
    
    // Function Prototypes
    void vApplicationStackOverflowHook(TaskHandle_t pxTask, char *pcTaskName);
    void vApplicationMallocFailedHook( void );
    __interrupt void AddressBitReceivedISR(void);
    
    // Task Functions
    void ReadMessageTask(void * pvParameters);
    
    // Main
    void main(void)
    {
    Device_init(); // Initialize device clock and peripherals
    
    Device_initGPIO(); // Initialize GPIOs
    Interrupt_disable(INT_SCIB_RX);
    
    Interrupt_initModule(); // Initializes PIE and clears PIE registers. Disables CPU interrupts.
    Interrupt_initVectorTable(); // Initializes the PIE vector table with pointers to the shell Interrupt Service Routines (ISR).
    
    Interrupt_register(INT_SCIB_RX, AddressBitReceivedISR); // Register the SCIB Interrupt Service Routine
    SCI_setAddrMultiProcessorMode(SCIB_BASE); // Enable Address Byte Multiprocessor Mode
    
    Board_init(); // Set up CPUTimer1, LEDs
    
    SCI_enableInterrupt(SCIB_BASE, SCI_INT_RXRDY_BRKDT); // Enable local SCI Interrupt sources
    SCI_disableInterrupt(SCIB_BASE, (SCI_INT_RXERR | SCI_INT_TXRDY |
    SCI_INT_TXFF | SCI_INT_RXFF | SCI_INT_FE | SCI_INT_OE | SCI_INT_PE));
    SCI_performSoftwareReset(SCIB_BASE);
    Interrupt_enable(INT_SCIB_RX); // Enable SCIB RX Interrupt
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9); // Clear the Interrupt acknowledge bits
    
    SCI_enableSleepMode(SCIB_BASE); // SCI in sleep mode, only reacts for Address byte interrupts
    
    // Enable Global Interrupt (INTM) and real time interrupt (DBGM)
    EINT;
    ERTM;
    
    FreeRTOS_init(); // Configure FreeRTOS, start Scheduler
    
    while(1) // Loop forever. This statement should never be reached.
    {
    }
    }
    
    
    
    // ReadMessage FreeRTOS Task
    void ReadMessageTask(void * pvParameters)
    {
    for(;;)
    {
    if (xSemaphoreTake( binarySem1Handle, portMAX_DELAY ) == pdTRUE) // no special waiting time is defined (waits forever if necessary, scheduler can proceed other tasks)
    {
    uint16_t length, i;
    GPIO_togglePin(20U);
    length = SCI_readCharBlockingNonFIFO(SCIB_BASE);
    processdata[1] = length;
    for (i = 2; i < (length + 5); i++) {
    processdata[i] = SCI_readCharBlockingNonFIFO(SCIB_BASE);
    }
    SCI_enableSleepMode(SCIB_BASE);
    }
    }
    }
    
    
    
    // Address Bit Interrupt Service Routine
    __interrupt void AddressBitReceivedISR(void)
    {
    address_temp = SCI_readCharBlockingNonFIFO(SCIB_BASE);
    
    if (address_temp == address1) {
    processdata[0] = address_temp;
    SCI_disableSleepMode(SCIB_BASE);
    
    SCI_clearOverflowStatus(SCIB_BASE); // Not necessary, just for debugging purpose
    SCI_clearInterruptStatus(SCIB_BASE, SCI_INT_RXRDY_BRKDT);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    
    static BaseType_t xHigherPriorityTaskWoken = pdFALSE; // Local variable for the release of the semaphore
    xSemaphoreGiveFromISR( binarySem1Handle, &xHigherPriorityTaskWoken ); // Give the synchronization semaphore
    portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); // Start Scheduler
    }
    }
    
    // End of File


    The initialization of the hardware in both modules is programmed via SysConfig.

    Best Regards

    Joshua

  • Hi Joshua,

    To clarify: is data now being transmitted and received correctly via SCI in multiprocessor mode as expected when FreeRTOS is removed? If so, the issue is likely FreeRTOS or interrupt related and I can loop in another expert to help with that. If not, please put a breakpoint in the SCI RX ISR and send a screenshot of the contents of the SCIRXST Register View (with continuous refresh enabled) when the breakpoint is hit.

    Best Regards,

    Delaney 

  • Hi Delaney,

    yes the data is transmitted correctly via SCI in multiprocessor mode when FreeRTOS is removed. When I add FreeRTOS the SCI RX ISR is just called once.

    I have examined this again more closely and found that all error flags are set on the second RX ISR call (see screenshot).

    Is it possible that timing errors occur when the FreeRTOS task is called, whereby the buffer is read too late and then leads to framing errors?

    Best Regards,

    Joshua

  • Hi Joshua,

    One note is that the SCI module takes ~7/8 of bit time to branch to a RX ISR and that received data will not be shifted into the RX buffer until the RX ISR has finished executing. Meaning that if data is received during the execution of a RX ISR, it will be lost. If the FreeRTOS is for some reason delaying the call to the SCI RX interrupt further, it could be that the start bit of the second frame of data is lost and that when the subsequent bits are shifted in, the frame is misinterpreted. This would cause the framing and BRKDT errors you're seeing after the initial receive. 

    The next release of the F28003x TRM will include a note about this in the "SCI Port Interrupts" section. As of now it is included in the F28P65x TRM if you want to take a look there. The note includes some recommendations for how to avoid this situation.

    I will loop in a FreeRTOS expert to see if the FreeRTOS implementation could be blocking or delaying the SCI RX interrupt for any reason.

    Best Regards,

    Delaney

  • Hi Delaney,

    thank you for the reply and information.

    I will try out the recommendations of the F28P65x TRM in the next few days and then give feedback.

    Could it be that the processing of the ISR takes too long because the scheduler has to be executed via portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); before the buffer is read? Perhaps the FreeRTOS expert can answer this question.

    Best Regards,

    Joshua

  • Hi Joshua,

    I have sent this thread to the FreeRTOS expert for their input. They are currently out of office until Tuesday 4/2 so please expect their response to be delayed.

    Best Regards,

    Delaney

  • Hi Joshua,

    A couple of notes about the receiver side implementation:

    1. SCI read operations are performed in both the ISR as well as the read task. After the first address byte is read and SCI is taken out of sleep mode, you essentially have two SCI_readCharBlockingNonFIFO() operations per data byte (since interrupts are triggered for all subsequent data bytes in the block once the SCI is awake). This can lead to inconsistencies.

    2. In the read task, after taking the initial semaphore, you have blocking reads for all subsequent data bytes. This puts the task in a busy loop waiting for each byte. A better method (taking advantage of RTOS functionality) would be to block the task, allowing other tasks to execute until the next byte becomes available.

    I would suggest moving all the SCI read operations to either the task or the ISR and using appropriate synchronization between them. Queues / stream buffers also might help. If it still seems to be a timing issue like discussed earlier in this thread, you can try using task notifications to speed up the sync. operations.

    Thanks,

    Arnav

  • Hi,

    I have now tested a few things and have managed to solve the problem. I have extended the UART format from 8N1 to 8N2 in order to generate more time for processing the ISR. I also moved all read operations to the task so that the ISR is as short as possible. Now it works.

    I have taken note of the comments on the implementation with FreeRTOS, which I will now take into account when optimizing my code.

    Thank you for the help and best regards,

    Joshua