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.

fsi_ex3_loopback_dmacontrol doubts about this FSI code

Other Parts Discussed in Thread: TMS320F28388D

Good afternoon,

I would like to make a query of the example fsi_ex3_loopback_dmacontrol of loopback control with FSI using DMA.
I think I understand almost in full all the code. The only doubt I have is in the while loop in these lines that I have marked in red. I don't know why the pointer goes to the address (GSx+1). I also don't understand the double pointer at the end for the GS0 data frame transmission.

  • Hi Pedro,

    Please expect a response for this query tomorrow.

    Best Regards,

    Delaney

  • Hi Pedro,

    I apologize for the delay. These lines in the example are added in for debugging purposes and aren't necessary to the FSI/DMA functionality.

    The last lines you marked will increment the first value in the GS0 memory after all the DMA channels complete a transfer. This can be used to keep track of which transfer the data you see in the Memory browser belongs to. The (uint16_t *) is used to first cast the GS0_START_ADDR define to a pointer, which contains the value 0x10000, meaning that it will point to that location in memory. The outer * is used to dereference this pointer, which will allow the = operation to write to the value at its memory address. The incremented variable countDMAtransfers gets written to this location in memory, the first value in GS0, with every run of the outermost while loop.

    In the first two lines you marked in the example, the GSx+1 is done to exclude the first value from the validation check because there will be a mismatch for every transfer except the first. This mismatch is due to the fact that the DMA channels are running in continuous mode. Here is what would happen if the first value was incremented but wasn't excluded from the validation check:

    Each step corresponds to the lines of code in gray below it.

    1. The C code initially waits in the first while loop until CH2 completes its first full transfer. If CH2 has finished transferring, that means CH1 is also finished transferring since they both get triggered on the same event (the FSI TX transmission) and CH1 has priority since it has a lower numeric value.

    while(dmaIntr1 == 0U);

    2. The C code then waits in the second while loop until the RX CH4 DMA completes its first full transfer. At this point however, the CH1 and CH2 DMAs are still enabled because they are in continuous mode, and they are both triggered again immediately after the FSI transmit completes. So, the TX DMAs begin their 2nd transfers of data, which still contains a 0 in the first spot. Then, the RX DMA channels will be serviced after. Eventually when CH4 has finished transferring, the CH3 DMA is also finished transferring for the same reason mentioned in 1).

    while(dmaIntr2 == 0U);

    3. The C code then begins validating the data contained in both GS0 and GS2. There will be no errors raised during this check since the first GS0 value is still 0 and the full initial data has been received into GS2 (where the first value is 0).

    for(i = 1; i < TOTAL_WORDS_IN_TRANSFER; i++)
    {
         compare16(*txTempData16,*rxTempData16);
         txTempData16++;
         rxTempData16++;
    }

    4. The C code will then increment the first value in GS0. However, since CH1 and CH2 have already started (and likely finished) doing their second transfers, this value isn't updated in the 2nd FSI transmit.

    countDMAtransfers++;
    *(uint16_t *)GS0_START_ADDR = (uint16_t )countDMAtransfers;

    5. The C code will then move back to the top of the main loop and wait for the CH2 to complete its second transfer.

    while(dmaIntr1 == 0U);

    6. Afterwards, the C code will wait for the CH4 to complete its transfer as well. The data received on the RX side will still contain a 0 at the first spot.

    while(dmaIntr2 == 0U);

    7. When the C code then validates the data, there will be a 1 in the first spot of the GS0 data and a 0 in the first spot of the GS2 data, which will increment the error count. This issue will persist for the first value of each remaining validation check where the first GS2 value will always be one behind the first GS0 value. So, the check for this value was excluded in the example in order to only log actual FSI transmission errors with the error variable.

    for(i = 1; i < TOTAL_WORDS_IN_TRANSFER; i++)
    {
         compare16(*txTempData16,*rxTempData16);
         txTempData16++;
         rxTempData16++;
    }

    Let me know if you have any more questions.

    Best Regards,

    Delaney

  • Good morning Delaney,

    Thank you very much for taking your time to reply to me, I appreciate it very much. It was very clear to me the answer you gave me. Basically the first address of GS0 is reserved to keep the count of DMA transfers and since since it is continuous when it reaches "*(uint16_t *)GS0_START_ADDR = (uint16_t )countDMAtransfers;" it has already triggered the transfer without this change and therefore the first address cannot be compared. I think this is how you explained it to me.
    Thank you very much for the good answer Delaney, have a nice day.

    Best regards,
    Pedro.

  • Hi Delaney, I wanted to ask you another question. Do you know if the field for the number of words sent by FSI can be changed at any time? I mean, if I want to change nWords in different points of the program with the line "FSI_setTxSoftwareFrameSize(FSITXA_BASE, nWords);" without having to perform a Reset in the FSI. I would like to develop a program for Master and Slave in which the Master and Slave would have the possibility to send 1, 2 and 16 frames depending on the content of the frame received from the Master/Slave without having to reset the peripheral, with DMA in TX and RX in both Master&Slave. 

    BR,

    Pedro

  • Hi Pedro,

    I don't see anything in the TRM mentioning this so I would have to test it out.

    This set up may be difficult to do using the DMA however since the varying frame lengths would need to be accounted for in the DMA settings. Would the change in frame length always happen in the same order (ex. 1, 2, 16, 1, 2, 16, 1...)? The calling of FSI_setTxSoftwareFrameSize() and FSI_setRxSoftwareFrameSize(); would also have to be done by the CPU which runs independent of the DMA. The only way to synchronize this function call with the DMA would be to do it in a DMA interrupt, which means at the very least each full transfer would have to use the same frame length.

    Best Regards,

    Delaney

  • Okey, thank you Delaney. I will investigate about it. 

    I have another question Delaney, how in the loopback execises like this with DMA or ex1 with CPU, does the PING frame is sent automatically?

    In the exercise of STAR of daisy_nose, the ping frames are sent as following:

    FSI_setTxFrameTag(FSITXA_BASE, FSI_FRAME_TAG0); 
    FSI_setTxFrameType(FSITXA_BASE, FSI_FRAME_TYPE_PING);
    FSI_startTxTransmit(FSITXA_BASE);

    I have seen in the oscilloscope when I debug loopback exercises that sometimes in the screen appears PING frames but I don't know in which part of the code it's implemented this (maybe when you set the reference value of timer and watchdog????)

    Thank you very much for your help.

    BR,

    Pedro

  • Hi Pedro,

    For FSITX there are 3 different ways ping frames can be sent: automatically, software triggered, and externally triggered. See the the Ping Frame Generation section of the TRM for more details.

    For automatic ping generation, the ping timer is used. It is set up with the function FSI_enableTxPingTimer() and the passed in ping timer reference value decides how often each ping frame is automatically sent. On the FSIRX side, you can also use the ping watchdog to monitor for ping frame reception. This is set up with the FSI_enableRxPingWatchdog() function and the passed in value specifies how long it should wait between ping frames received until the error flag is raised (an interrupt can also be configured to fire in this case.) A lot of the examples use this type of ping frame generation, including fsi_ex3_loopback_dmacontrol.

    In the exercise of STAR of daisy_nose, the ping frames are sent as following:

    The code you have included here is an example of a software triggered ping frame. These are sent the same as regular data frames but with the frame type set as 0b0000 (FSI_FRAME_TYPE_PING). 

    I don't believe any of the examples use externally triggered ping frames, however the function FSI_enableTxExtPingTrigger() can be used to set up this up. The value passed in chooses the external source (usually being an event from another peripheral) that will trigger a ping frame transmission.

    Best Regards,

    Delaney

  • Thank you very much Delaney, I have read this part of the TRM and it's how you said in your reply Slight smile

    I appreciate how you helped me. Have a nice week.

    BR,

    Pedro

  • Good morning Delaney,

    I wanted to ask you one more question. In the fsi_ex3_loopback_dmacontrol, all the loopback is done with DMA. My question is about the trigger of the DMA. As the ping frames are sent periodically with the counter from the TX, when the RX receives this frames does it triggers the DMA although it is not a data frame?? I don't see in the code where it's configured it so I guess that when the RX receives a DAT frame or PING frame, it triggers the DMA and it saves in RAM the data from the RX_BUF_BASE, bit it should be only with data frames.

    Another question I have related with the DMA control of FSI is the following:

    I want the slave when it receives a DATA frame from the Master, to have a DMA channel that:
    - First, check the TAG of the frame that has arrived.
    - Second, if the TAG is correct, that the DMA is in charge of sending the Words of the RX_BUF to the GS memory address that I have chosen. If it does not match, discard the message and do not store it in memory.
    I thought of doing it with 2 DMA channels as they do the communication in some example, one for the UDATA_TAG and one for DATAFRAME. The problem is that both have the trigger when the RX_FRAME event arrives so the DATAFRAME channel would put in memory the frame data even if the tag is not correct. I would like to know how to coordinate both DMA to avoid this problem.

    I will wait for your answer. Have a nice day,

    BR,

    Pedro.

  • Hi Pedro,

    I will look into this and get back to you tomorrow.

    Best Regards,

    Delaney

  • Good morning Delaney,

    As I told you, I am looking at FSI possibilities for a Master-Slave application I want to implement. I want to realize a star architecture (not daisy-chain) at first with 4-5 slaves.
    I have seen the Star Broadcast example 9 "fsi_ex9_star_broadcast.c" but there is one thing I want to implement:
    - I want to eliminate waiting in while loops of the Slaves reception. Para ello, he pensado en realizar interrupciones por FSI y DMA (interrupciones DMA que sean disparadas en las interrupciones FSI).
    - I want the messages I send by Tx to go with a TAGx (x=1 to 5) and receive response only from the Slave TAGx. So I want to make a communication with a single slave at any time and each of the slaves respond to the message from the master if they match the tag assigned to each of them fixed. 

    In the example fsi_ex3_loopback_dmacontrol.c dedicates 2 DMA channels for each RX channel. For me this would be impossible because CPU1 has 6 DMA channels and if I want 5 slaves, I should dedicate only 1 DMA channel for each TX or RX in the Master. In the slave, since it only receives FSI communication from the master I could implement 2 DMA channels per TX or RX. However, I wanted to program the Master and the Slave with the same criteria, therefore, I want the slave to have only one DMA channel per RX or TX.

    I will tell you how I have it implemented in the Slave:

    •  I configure the Tx to trigger when writing to UDATA-TAG register (or force it with starttx) with:

    FSI_setTxStartMode(FSITXA_BASE, FSI_TX_START_FRAME_CTRL_OR_UDATA_TAG);

    • I configure Rx in such a way that I allow RxA interrupts with the following lines, so the INTERRUPTION appears when the RX receives a FSI frame with TAG=txDataFrameTag (pls confirm me if this works as I think)

    FSI_setRxFrameTagRef(FSIRXA_BASE, txDataFrameTag);
    FSI_setRxFrameTagMask(FSIRXA_BASE, 0000);
    Interrupt_register(INT_FSIRXA1, &fsiRxInt1ISR_DATAFRAMES); //interrupciones de FSI RX INT1 para el handshake
    Interrupt_enable(INT_FSIRXA1);
    FSI_enableRxInterrupt(FSIRXA_BASE, FSI_INT1, FSI_RX_EVT_DATA_FRAME_TAG_MATCH);

    • I configure the DMA channels and I start the DMA channels with the following code. The most important is the config dma functions where I choose to trigger the DMA with SOFTWARE. In case you want to know, the DMA_TRANSFER_SIZE_IN_BURSTS is 1 and nWords is 16. So the purpose is to receive 16 words of data from FSI and store it in the first 16 directions of GS2 (the same in Tx but taking the first 16 directions from GS0 to transmit it throught the TX buffer). 

    fsirx_dma_config();
    fsitx_dma_config();
    FSI_enableRxDMAEvent(FSIRXA_BASE); //FUNCION DE FSI PARA QUE DEJE QUE DMA ACCEDA A SUS DATOS
    FSI_enableTxDMAEvent(FSITXA_BASE);
    DMA_startChannel(DMA_CH1_BASE);
    DMA_startChannel(DMA_CH2_BASE);
    //IN "fsitx_dma_config()" I CONFIGURE THE FOLLOWING
    void fsitx_dma_config() //COPIADA DE EX3 LOOPBACK. CONFIGURAR BIEN
    {
        //
        // CANAL 1 PARA DATA-FRAME (DISPARADO POR SW, EN ESTE CASO POR CANAL 2 DMA RXTAG)
        //
        DMA_configAddresses(DMA_CH1_BASE, txBufAddr, (uint16_t *)GS0_START_ADDR); //A DIFERENCIA DE RX AQUÍ SE CAMBIA DIRECCION DESTINO Y DIRECCION SRC
        DMA_configBurst(DMA_CH1_BASE, nWords, 1, 1);
        DMA_configTransfer(DMA_CH1_BASE, DMA_TRANSFER_SIZE_IN_BURSTS, 0, 0);
        DMA_configWrap(DMA_CH1_BASE, DMA_TRANSFER_SIZE_IN_BURSTS, 0, nWords, 0);//CAMBIO DE FUENTE Y DESTINO
        DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SOFTWARE, DMA_CFG_ONESHOT_DISABLE|
                       DMA_CFG_CONTINUOUS_ENABLE | DMA_CFG_SIZE_16BIT); //IGUAL QUE EN RX PERO CAMBIO EN EL Nº TRIGGER DEL DMA
        DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_END);
        DMA_enableInterrupt(DMA_CH1_BASE);
        DMA_enableTrigger(DMA_CH1_BASE);
    
    }
    //IN "fsirx_dma_config()" I CONFIGURE THE FOLLOWING
    void fsirx_dma_config()
    {
        //
        // CANAL 3 DMA PARA DATA (DISPARADO POR SW, EN ESTE CASO POR CANAL 2 DMA RXTAG)
        //
        DMA_configAddresses(DMA_CH2_BASE, (uint16_t *)GS2_START_ADDR, rxBufAddr); //copia el contenido del buffer rx en GS2
        DMA_configBurst(DMA_CH2_BASE, nWords, 1, 1);
        DMA_configTransfer(DMA_CH2_BASE, DMA_TRANSFER_SIZE_IN_BURSTS, 0, 0);
        DMA_configWrap(DMA_CH2_BASE, DMA_TRANSFER_SIZE_IN_BURSTS, 0,
                       DMA_TRANSFER_SIZE_IN_BURSTS, 0);
    
        DMA_configMode(DMA_CH2_BASE, DMA_TRIGGER_SOFTWARE, DMA_CFG_ONESHOT_DISABLE|
                       DMA_CFG_CONTINUOUS_ENABLE|DMA_CFG_SIZE_16BIT);
        //DMA_setInterruptMode(DMA_CH2_BASE, DMA_INT_AT_END);
        DMA_disableInterrupt(DMA_CH2_BASE);
        DMA_enableTrigger(DMA_CH2_BASE);
    }

    Therefore the idea is as follows in the Slave:
    - RX FSI interrupt because it has received a data frame with a TAG corresponding to that Slave.
    - In the ISR the received TAG is stored in position 17 of GS2 and performs a FORCE TRIGGER of the RX DMA channel that writes the 16 dataframes in GS2 from position 1 to 16 and of the TX DMA channel that writes the 16 dataframes from GS0 to position 1 to 16 of TX BUFFER. After finishing this a TX DMA interrupt appears that the only important thing it does in its ISR is to write the GS0 TAG position 17 to the UDATA-TAG register of the FSI that as I have put in the line "FSI_setTxStartMode(FSITXA_BASE, FSI_TX_START_FRAME_CTRL_OR_UDATA_TAG);" causes the TX FSI transmission to be triggered.

    I would like to know your opinion about this architecture, if you see any problem in using FSI with DMA in this different way. I also make in the middle of the code a change in the ISR of RX because for the handshake I configured these lines,

    Interrupt_register(INT_FSIRXA1, &fsiRxInt1ISR_HANDSHAKE); //interrupciones de FSI RX INT1 para el handshake
    Interrupt_enable(INT_FSIRXA1);

    but then for the normal operation of the master-slave communication I change the ISR:

    Interrupt_register(INT_FSIRXA1, &fsiRxInt1ISR_DATAFRAMES); //interrupciones de FSI RX INT1 para el handshake
        Interrupt_enable(INT_FSIRXA1);

    I also clarify that the fact of using the RX DMA by SOFTWARE TRIGGER is because I think that if I put it as DMA_TRIGGER_FSIRXA, I understand that the DMA would be activated when it receives a frame by FSI, even if it is from a different TAG than the slave. While if I activate it by SOFTWARE in the ISR of the RX I make sure that it will implement the DMA only when the TAG of the slave arrives, which is the one through which the interrupt appears by the line "FSI_enableRxInterrupt(FSIRXA_BASE, FSI_INT1, FSI_RX_EVT_DATA_FRAME_TAG_MATCH);". 

    I expect you could help me with this plan. If you think that it could be implemented in a more optimal way, please say to me. 

    Have a nice week Delaney.

    Best regards,

    Pedro

  • Hi Pedro,

    I'm sorry for the delayed response. 

    To answer your previous question, the DMA trigger will only occur on the event of a received data frame, so received ping frames will not trigger the DMA with the FSIRX DMA trigger. This is due to the fact that ping frames are used to verify proper connection between the two devices communicating, rather than to send any data for the receiving device to store in memory.

    Yes, using a software DMA trigger and tag matching interrupts would be my recommendation if you want to use tags for differentiating which slave device the master is sending to. You are correct in that the FSIRX DMA trigger will happen upon the reception of any data frame in the RX buffer, regardless of if the tag matches.

    Normally I would suggest using user data matching instead for the slaves, since in this case the frames themselves wouldn't be placed in the FSI RX buffer unless the UDATA matches. This would mean the regular FSIRX DMA trigger could be used and would only transfer valid data on the RX line for each slave. However, you are using the F2838x correct? Unfortunately, UDATA matching is only available on devices F28003x and F28P65x as this feature was added into the Type 2 design of the FSI peripheral. If you wanted to switch to one of these devices, the implementation could be simplified significantly. Just putting that option out there. Assuming you want to use tag matching though, the following are my notes about your planned implementation. 

    On the slave(s) side:

    Is there a reason why the received tag needs to be stored in memory? The tag matching scheme looks good. For the handshake mechanism, these would be triggered on the same interrupt flag condition, correct? If this is the case, I would recommend keeping them in the same ISR and using a global variable to keep track of which operation the slave is currently doing.

    On the master side:

    I would suggest using one DMA channel for transmitting (that would be connected to all slave RX lines) and five channels for receiving from each slave device. You could set up the master receive DMA's the same as the slave receiver DMA's using the tag matching interrupt and a software DMA trigger. For the one transmit DMA, I would suggest adding an end of transmission DMA interrupt that inside its ISR will write to the UDATA and TAG register and initiate the master transmission. This way the DMA will first transfer the TX data to the FSI TX buffer, then the UDATA and TAG will be written after its finished and send the frame.

    Using the continuous mode of the DMAs in this case shouldn't be an issue since you are using software triggering. Keep in mind that if you use the FSI triggers for any DMA channels, continuous mode could cause some issues like we saw had to be accounted for in the example. If you end up using the FSI triggers for any DMA channels, I would instead disable continuous mode and use the end of transfer interrupts to reenable the DMA channel for further transfers.

    Overall, your setup sounds good. Let me know if you have any more questions.

    Best Regards,

    Delaney

  • Good morning Delaney,

    Thank you very much for your answer :). I think you got well what I am doing and I really appreciate your reply, it has been very useful.

    I have some questions about some things you said:

    1st: Normally I would suggest using user data matching instead for the slaves, since in this case the frames themselves wouldn't be placed in the FSI RX buffer unless the UDATA matches. This would mean the regular FSIRX DMA trigger could be used and would only transfer valid data on the RX line for each slave. However, you are using the F2838x correct? Unfortunately, UDATA matching is only available on devices F28003x and F28P65x as this feature was added into the Type 2 design of the FSI peripheral. If you wanted to switch to one of these devices, the implementation could be simplified significantly. Just putting that option out there. Assuming you want to use tag matching though, the following are my notes about your planned implementation.

    I dont understand very well the development use of the user_data, for me it's like another field as the tag in a message from FSI. I planned to use the TAG in order to make an order that the slaves store information from master and send their slave information to master. Nevertheless, the TAG and the USER-DATA comes from the same register and they use the same interruption "FSI_RX_EVT_DATA_FRAME_TAG_MATCH". But as you said this implementation only can be done with F28003x and F28P65x. Unfortunately, I am able only to develop this in TMS320F28388D because is the uP that we are going to develop the project. But I get that feedback as an important reason in order to select the proper microprocessor. 

    2nd: Is there a reason why the received tag needs to be stored in memory? The tag matching scheme looks good. For the handshake mechanism, these would be triggered on the same interrupt flag condition, correct? If this is the case, I would recommend keeping them in the same ISR and using a global variable to keep track of which operation the slave is currently doing.

    No, there is not a reson for that, sincerely. If the TAG matches in the FSI INT and then it triggers the RX DMA to store the info, the important data is the nWords transmitted in the dataframe. About the handshake mechanism, I used different ISR for RX handshake and RX normal frames and I changed the ISR aftr the handshake. However, I am going to take your advice to use the same ISR and use a global variable flag to differentiate between Handshake reception and normal transmission reception, thus saving me an ISR and various problems that may arise. 

    3rd: I would suggest using one DMA channel for transmitting (that would be connected to all slave RX lines) and five channels for receiving from each slave device. You could set up the master receive DMA's the same as the slave receiver DMA's using the tag matching interrupt and a software DMA trigger. For the one transmit DMA, I would suggest adding an end of transmission DMA interrupt that inside its ISR will write to the UDATA and TAG register and initiate the master transmission. This way the DMA will first transfer the TX data to the FSI TX buffer, then the UDATA and TAG will be written after its finished and send the frame.

    Yes, that's what I had in mind, to use one DMA channel for TXA and one DMA channel for each RX receiver. As there are 6 DMA channels per CPU, I had in mind 1 for TXA and 1 for RXA, 1 for RXB, etc.... I have not yet done the master code completely but I have an idea of how to do it. I will also evaluate later if I will use CPU2 for the 3 remaining RX channels (RXF, RXG, RXH) to use it with DMA and so I can expand the number of slaves up to 8. But first I want to develop it on CPU1 for 5 slaves max. Regarding the use that would be made of the channels, what you tell me is very similar to how I have it implemented in the slave so it seems that there is not much complication, between today and tomorrow I will try to implement it well and if I fall into any problem I will consult you, thank you very much Delaney. 

    4th: Using the continuous mode of the DMAs in this case shouldn't be an issue since you are using software triggering. Keep in mind that if you use the FSI triggers for any DMA channels, continuous mode could cause some issues like we saw had to be accounted for in the example. If you end up using the FSI triggers for any DMA channels, I would instead disable continuous mode and use the end of transfer interrupts to reenable the DMA channel for further transfers.

    My intention is to use the DMA as in the slave with Software Trigger to first ensure that the TAG received is the right one, but I will let you know as I develop the code. Regarding DMA's OneShot mode, it is my understanding that it only fires one burst. The truth is that my idea is to use only one burst of 16 words, so in principle I am indifferent to use OneShot and Continuous mode because as I only transmit 1 burst of 16 words... How do you see this?

    Thank you very much for taking your time and answering everything perfectly. Have a nice day Delaney.

    Best regards,
    Pedro

  • Hi Pedro,

    1st: I see, if you are using the F2838x there's no extra purpose for the user data field. It is simply there for use if needed by the application. For your application on the F2838x, it's best to use tag matching as you have planned.

    2nd: Yes, using the same ISR and a global flag should avoid any issues.

    3rd: Sounds good, let me know if you have any issues.

    4th: Enabling one-shot mode would mean one trigger is needed for each transfer rather than each burst. Since your transfer size is only 1 burst, enabling one-shot mode would make no difference in your case. Enabling continuous mode means that the DMA channels will remain enabled after each transfer, meaning that after each 16 bytes are transferred, the DMA doesn't need to be reenabled to receive another trigger. Since you will be using software triggers for each DMA transfer, you'll have control over when they happen so keeping the DMA channels enabled at all times shouldn't be a problem. If you want to disable continuous mode, just make sure to do as I explained earlier. Overall, one-shot and continuous mode could be used but aren't necessary for your application, so it's your choice whether or not to enable them.

    Best Regards,

    Delaney

  • Good morning Delaney,

    Thank you very much for your help. I will let you know if I have any difficulties or any aspect of the FSI that I am not clear with the documentation. Have a good week.

    Best regards,
    Pedro