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.

TMS320F280041C: FSI - USER_DATA and BUFFER do not match expected content

Part Number: TMS320F280041C

Hello,

I am using FSI in an application with F280041C DSP (with the LaunchPad) to do two things at the same time:

- Synchronizing the EPWMs of two F280041C microcontrollers

- Sending data between the microcontrollers

The way I am doing this (after handshake procedure) is the following:

- In 'master' device, I set one EPWM as external trigger source to trigger the PING frame transmission with a certain frequency. This ping will be used by the 'slave' DSP to synchronize the PWM. When the application wants to send data to the 'slave', the external ping transmission is disabled, and then software transmission is enabled. Buffer and USER_DATA is filled with custom data, and then transmission is started. When the transmission is finished, then external ping transmission is enabled back again.

- in 'slave' device, I set the CLB module to automatically send back the ping frame upon reception (as explained in the TI Examples for PWM synchronization). Similarly to what I do in the 'master' device, if the application wants to send data, then the external ping transmission is disabled and then software transmission is enabled. When the software transmission is finished, the external transmission is enabled back again.

To interpret the custom received data frame (in either master or slave device), what I do is to check the USER_DATA value, and then call a different function based on this value. 

Now I explain the problem that I am facing. Normally, handshake procedure goes smoothly, and the two boards are able to synchronize their PWMs. I am also able to successfully send data between them, but from time to time, the USER_DATA content and BUFFER content do not match what I am expecting. Let me give you an example:

When USER_DATA is 0, I expect the BUFFER content to be all 0x0000, and when USER_DATA is 1, I expect my buffer content to be all 0xAAAA. However, sometimes, I may receive USER_DATA  with value 1, and the buffer content is all zeros, and the other way around. Basically, it seems like if the RX submodule is reading old information of either the USER_DATA or the BUFFER register. But I know that it is impossible (from my application code) to have given the wrong values to these registers. So I think it has to do with the arbitration of the TX/RX modules of FSI.

Here Is a code snippet of what I do in the 'write' function:

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static int fsi__write(struct fsi_f *f)
{
/* Set software trigger mode */
FSI_setTxStartMode(FSITXA_BASE, FSI_TX_START_FRAME_CTRL);
FSI_disableRxPingWatchdog(FSIRXA_BASE);
FSI_disableTxExtPingTrigger(FSITXA_BASE);
FSI_setTxFrameType(FSITXA_BASE, FSI_FRAME_TYPE_NWORD_DATA);
/* Fill USER_DATA and BUFFER */
FSI_setTxUserDefinedData(FSITXA_BASE,f->id);
FSI_writeTxBuffer(FSITXA_BASE,f->data,16U,0U);
/* Start transmission */
FSI_clearTxEvents(FSITXA_BASE, FSI_TX_EVT_FRAME_DONE); // Clear previous FRAME_DONE flags
FSI_startTxTransmit(FSITXA_BASE);
/* Wait until the data frame is sent */
fsi__wait(FSI_TX_EVT_FRAME_DONE);
/* Enable Ping Watchdog with 1.5 seconds of timeout, assuming 100 MHz SYSCLK*/
FSI_setRxPingTimeoutMode(FSIRXA_BASE,FSI_PINGTIMEOUT_ON_HWINIT_PING_FRAME);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

And here is a code snippet of what I do in the 'read' function

Fullscreen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static int fsi__read(struct fsi_f *f)
{
uint16_t rxFlags;
uint16_t receivedWords;
/* Read RX Event flags */
rxFlags = FSI_getRxEventStatus(FSIRXA_BASE);
/* Return in case of CRC error */
if(rxFlags & (FSI_RX_EVT_CRC_ERR)){
FSI_clearRxEvents(FSITXA_BASE, FSI_RX_EVT_CRC_ERR);
return 0;
}
/* If received data frame, and there are 16 words, read its content */
if(rxFlags & (FSI_RX_EVT_DATA_FRAME | FSI_RX_EVT_FRAME_DONE) ){
receivedWords = FSI_getRxWordCount(FSIRXA_BASE);
if(receivedWords == 16){
FSI_clearRxEvents(FSITXA_BASE, (FSI_RX_EVT_DATA_FRAME | FSI_RX_EVT_FRAME_DONE));
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

 

Is there anything that I might be doing wrong? I am thinking that maybe there is some race condition somewhere because I am switching between external trigger and software trigger or something like that...

For your information, none of this code is run inside any interrupt.

Any help is appreciated and let me know if you need a better explanation of my problem.

Best regards.

  • Hi Jorge,

    I would guess that this issue is on the transmit side of things and related to how / when your 'f->data' is being filled. It's likely that old data is being used.

    Can you check where in your code 'f->data' is being defined? You'll need to make sure it's being set before you start the FSI transmission.

    Best,

    Kevin

  • Hello Kevin,

    Thank you for your answer. The f->data buffer is filled/set just before my fsi__write function is called, everything outside any interrupt. So, for sure that f->data is properly updated. 

    In fact, I have done an experiment and instead of sending the f->id in the USER_DATA register, i am sending that value as part of the standard data buffer (i put f->id in the last word). If I do it this way, i never have a discrepancy between the received f->id and f->data. The only problem with this approach is that obviously one word of the buffer is 'wasted'.

    I don't know if that gives you any hint for what I could be doing wrong.

  • Hi Jorge,

    Thank you for your answer. The f->data buffer is filled/set just before my fsi__write function is called, everything outside any interrupt. So, for sure that f->data is properly updated. 

    That should be OK. f->id is set at that the same time?

    In fact, I have done an experiment and instead of sending the f->id in the USER_DATA register, i am sending that value as part of the standard data buffer (i put f->id in the last word). If I do it this way, i never have a discrepancy between the received f->id and f->data. The only problem with this approach is that obviously one word of the buffer is 'wasted'.

    This is strange. Do you ever ever receive the wrong data in this case? Maybe reading the same received data twice in a row?

    What optimization do you have set in the project's properties? I'm wondering if you still see the original issue if you turn optimization off for both TX and RX side.

    Best,

    Kevin

  • Hi Kevin, thank you again for your support.

    That should be OK. f->id is set at that the same time?

    Correct, f->id and f->data are both set just before calling my fsi__write() function.

    Do you ever ever receive the wrong data in this case? Maybe reading the same received data twice in a row?

    With the workaround of sending f->id as the last word of the buffer, i never had a discrepancy so far between f->id and the expected f->data. In fact, this test has been running for 3 days, 24 hours, without any issue. What I have not checked is if I received the same data twice in a row (but f->id would still be consistent with f->data). I will double check if that is happening.

    What optimization do you have set in the project's properties?

    For both sides, i have been running the code with optimisation level 0, (-O0) and --opt_for_speed=2

    Best regards,

    Jorge.

  • Hi Jorge,

    What I have not checked is if I received the same data twice in a row (but f->id would still be consistent with f->data). I will double check if that is happening.

    Thanks, this would be to check if old data is transmitted / received at some point.

    For both sides, i have been running the code with optimisation level 0, (-O0) and --opt_for_speed=2

    OK, that rules out that optimization is not causing any potential weirdness like this.

    I am thinking that maybe there is some race condition somewhere because I am switching between external trigger and software trigger or something like that...

    Can you further explain how you are utilizing the triggers for starting FSI transmission? You mention switching between SW and ext trigger.

    Best,

    Kevin

  • Hello Kevin,

    Can you further explain how you are utilizing the triggers for starting FSI transmission? You mention switching between SW and ext trigger

    Sure.

    In device A (let's say, the master), I have a PWM set at a frequency of around 4.8 KHz which is the external trigger to the ping message. This master is also expecting to receive a ping message from the slave as well, so I set up the ping watchdog. Like that, both master and slave can know if there has been any interruption in the communication.

    In device B (the slave side), I have programmed the CLB as explained in Using the Fast Serial Interface (FSI) With Multiple Devices in an Application (Rev. E), (section 7.1.3). This means that every time that the slave receives a ping message, it will forward it back to the master. Slave also has the ping watchdog activated. Therefore, the CLB is configured to trip EPWM XBAR TRIP_5 when a ping frame is received, and this TRIP_5 is used as external trigger in the FSI module.

    Normally, the only thing that master and slave do is sending and receiving these ping frames to each other. But, when the application needs to send some data (either master or slave), they have to stop the process of automatic ping transmission, send the data via software trigger, and then resume the automatic ping transmission process.

    In this piece of code (called at the beginning of my FSI__write() function, I stop automatic ping transmission, stop the ping watchdog, and enable software transmission:

    Fullscreen
    1
    2
    3
    4
    FSI_setTxStartMode(FSITXA_BASE, FSI_TX_START_FRAME_CTRL);
    FSI_disableRxPingWatchdog(FSIRXA_BASE);
    FSI_disableTxExtPingTrigger(FSITXA_BASE);
    FSI_setTxFrameType(FSITXA_BASE, FSI_FRAME_TYPE_NWORD_DATA);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Then, I fill the buffer and user data fields and trigger the software transmission. When the software transmission is finished (by checking the TX_EVT_FRAME_DONE flag), then I reenable automatic ping transmission:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /* Enable Ping Watchdog with 1.5 seconds of timeout, assuming 100 MHz SYSCLK*/
    FSI_setRxPingTimeoutMode(FSIRXA_BASE,FSI_PINGTIMEOUT_ON_HWINIT_PING_FRAME);
    FSI_enableRxPingWatchdog(FSIRXA_BASE,TIMEOUT_WATCHDOG);
    /* Enable ping trigger*/
    FSI_setTxPingTag(FSITXA_BASE, FSI_FRAME_TAG1);
    FSI_setTxFrameType(FSITXA_BASE, FSI_FRAME_TYPE_PING);
    FSI_enableTxExtPingTrigger(FSITXA_BASE, priv->trg_src);
    FSI_setTxStartMode(FSITXA_BASE, FSI_TX_START_EXT_TRIG);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Those code blocks are identical in both devices (master and slave). The only difference is the external trigger source.

    I hope that clarifies a bit more the process

    Best regards,

    Jorge.

  • Hi Jorge,

    Thanks for the explanation. The process you've implemented makes sense to me.

    I had one thought, if you disable the ping frame triggering / watchdog completely and just have the data frame communications on-going does this Data Words / USER_DATA mismatch ever occur? You mentioned earlier if "switching between external trigger and software trigger" causes this somehow, this could be a test to check.

    If you test this and don't see the issue, I wonder if the SW sequence of enabling / disabling the triggered ping frames has some effect.

    Best,

    Kevin

  • Dear Kevin,

    Thank you again for your answer. 

    I have run a test in which I disabled the automatic ping transmission. So, basically, the only thing that the two devices do after the handshake is sending data frames with a software trigger. So this is my fsi__write() function after disabling automatic ping transmission:

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    static int fsi__write(struct fsi_f *f)
    {
    /* Fill USER_DATA and BUFFER */
    FSI_setTxUserDefinedData(FSITXA_BASE,f->id);
    FSI_writeTxBuffer(FSITXA_BASE,f->data,16U,0U);
    /* Start transmission */
    FSI_clearTxEvents(FSITXA_BASE, FSI_TX_EVT_FRAME_DONE); // Clear previous FRAME_DONE flags
    FSI_startTxTransmit(FSITXA_BASE);
    /* Wait until the data frame is sent */
    fsi__wait(FSI_TX_EVT_FRAME_DONE);
    return 1;
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    However, even after doing this, I still get sometimes not corresponding data between the USER_DATA and the BUFFER. So it seems like this test rules out that this is produced by switching from automatic ping transmission to software triggered data transmission.

    Do you have any other idea that might be causing this? Or point me in a direction or test that i can try?

    Thank you again and best regards,

    Jorge.

  • Hi Jorge,

    OK, I can only think of it being related to the software sequencing on the transmit or receive side. Would you be open to sharing your FSI code with me to try and reproduce it? You can share with me off forum if you prefer by adding me as a friend (i.e. request friendship first).

    Best,

    Kevin

  • Thank you Kevin,

    I added you as friend and sent you the relevant pieces of code. Please let me know if you need anything else.

    Best regards,

    Jorge.

  • Hi Jorge,

    Sorry for the delay, was traveling last week.

    I received your message and code OK. I'll update you this week and let you know if I have any questions / conclusions. Will keep the discussion offline for anything specific to your code.

    Best,

    Kevin