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.

[参考译文] TMDSCNCD28388D:具有 DMA 传输的 ePWM 触发 ADC 仅在调试模式下与断点一起工作

Guru**** 2390755 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1071430/tmdscncd28388d-epwm-triggered-adc-with-dma-transfer-works-only-with-a-breakpoint-in-debug-mode

部件号:TMDSCNCD28388D

您好,Forum,

以下是 我的问题摘要:

  1. 以示例代码开头:ADC_EX11_MULTIPLE_SOC_ePWM。
  2. 已修改代码,从 ADCA,ADCB 和 ADCC 各读取3个通道
  3. 增加了 ADC 数据到内存的 DMA 传输
  4. 增加了 FSI 导线,可通过两个 FSI 适配器板将数据传输到另一个控制板

只有在调试模式下有 Estop 或中断点时,代码才能正常工作。

当我在没有断点的情况下运行代码时,所有 ADC 通道的读数都为零。

请查看下面的代码,让我知道它有什么问题。

注:FSI 部件工作正常。 它确实会传输在 Tx 缓冲区中获得的内容。

//#############################################################################
//
// TITLE:  ADC ePWM Triggering Multiple SOC
//
//!
//! This software sets up ePWM3 to periodically trigger a set of conversions on
//! ADCA, ADCB and ADCC. Multiple ADCs work together to process a batch of conversions
//! using the available parallelism across the ADCs.
//!
//! ADCA Interrupt ISRs are used to read results of ADCA, ADCB and ADCC.
//!
//! \b External \b Connections \n
//!  - A0, A4, A5, B0, B2, B3, C2 and C4 pins should be connected to signals to be
//!    converted.
//!
//!
//! \b External \b Connections \n
//! - A0, A4, A5, B0, B2, B3, C2 and C4 should be connected to signals to convert
//! \b Watch \b Variables \n
//! - \b adcAResult0 - Digital representation of the voltage on pin A0 (pin-43)
//! - \b adcAResult1 - Digital representation of the voltage on pin A4 (pin-39) 
//! - \b adcAResult2 - Digital representation of the voltage on pin A5 (pin-38) 
//! - \b adcBResult0 - Digital representation of the voltage on pin B0 (pin-46)
//! - \b adcBResult1 - Digital representation of the voltage on pin B2 (pin-48)
//! - \b adcBResult2 - Digital representation of the voltage on pin B3 (pin-49)
//! - \b adcCResult0 - Digital representation of the voltage on pin C2 (pin-31)
//! - \b adcCResult1 - Digital representation of the voltage on pin C4 (pin-29)
//
//#############################################################################
// $TI Release: F2838x Support Library v3.04.00.00 $
// $Release Date: Fri Feb 12 19:08:49 IST 2021 $
// $Copyright:
// Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
//#############################################################################
//
//
// Included Files
//
#include "driverlib.h"
#include "device.h"
#include "fsi_app.h"
//
// Defines
//
#define RESULTS_BUFFER_SIZE      3
//buffer for storing conversion results
// 1024 x 16-bit words
#define EX_ADC_RESOLUTION       12
// 12 for 12-bit conversion resolution, which supports single-ended signaling
// Or 16 for 16-bit conversion resolution, which supports single-ended or
// differential signaling
#define EX_ADC_SIGNALMODE       "SINGLE-ENDED"
//"SINGLE-ENDED" for ADC_MODE_SINGLE_ENDED:
// Sample on single pin (VREFLO is the low reference)
// Or "Differential" for ADC_MODE_DIFFERENTIAL:
// Sample on pair of pins (difference between pins is converted, subject to
// common mode voltage requirements; see the device data manual)

#define PRESCALER_VAL    FSI_PRESCALE_50MHZ

//
// Globals
//

#pragma DATA_SECTION(adcADataBuffer, "ramgs0");
#pragma DATA_SECTION(adcBDataBuffer, "ramgs0");
#pragma DATA_SECTION(adcCDataBuffer, "ramgs0");
#pragma DATA_SECTION(adcResults, "ramgs0");
uint16_t adcADataBuffer[RESULTS_BUFFER_SIZE];
uint16_t adcBDataBuffer[RESULTS_BUFFER_SIZE];
uint16_t adcCDataBuffer[RESULTS_BUFFER_SIZE];
uint16_t adcResults[8];
volatile uint16_t done;
//
// Function Prototypes
//
void configureADC(uint32_t adcBase);
void initEPWM();
void initADCSOC(void);
void initializeDMA(void);
void configureDMAChannels(void);
__interrupt void adcA1ISR(void);
__interrupt void dmach1ISR(void);
//
// Main
//
void main(void)
{
    uint16_t resultsIndex;
    //
    // Initialize device clock and peripherals
    //
    Device_init();

    //
    // Disable pin locks and enable internal pullups.
    //
    Device_initGPIO();
    //
    // Initialize basic settings for FSI
    //
    initFSI();

    //
    // Initialize PIE and clear PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();

    //
    // Initialize the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();

    //
    // Interrupts that are re-mapped to ISR functions
    //
    // ISR for ADCA INT1 - occurs after first conversion
    // ISR for DMA ch1 - occurs when DMA transfer is complete
    //
    Interrupt_register(INT_ADCA1, &adcA1ISR);
    Interrupt_register(INT_DMA_CH1, &dmach1ISR);
    //
    // ISR for FSI Tx/Rx :: INT1/INT2
    //
    Interrupt_register(INT_FSITXA1, &fsiTxInt1ISR);
    Interrupt_register(INT_FSITXA2, &fsiTxInt2ISR);
    Interrupt_register(INT_FSIRXA1, &fsiRxInt1ISR);
    Interrupt_register(INT_FSIRXA2, &fsiRxInt2ISR);
    //
    // Enable specific PIE & CPU interrupts:
    // ADCA INT1 - Group 1, interrupt 1
    // DMA interrupt - Group 7, interrupt 1
    //
    Interrupt_enable(INT_ADCA1);
    Interrupt_enable(INT_DMA_CH1);
    //
    // Enable FSI Tx/Rx interrupts
    //
    Interrupt_enable(INT_FSITXA1);
    Interrupt_enable(INT_FSITXA2);
    Interrupt_enable(INT_FSIRXA1);
    Interrupt_enable(INT_FSIRXA2);

    //
    // Initialize basic settings for FSI
    //
    //initFSI();
    //
    // Set up the ADC and the ePWM and initialize the SOC
    //
    configureADC(ADCA_BASE);
    configureADC(ADCB_BASE);
    configureADC(ADCC_BASE);
    initEPWM();

    initADCSOC();

    //
    // Initialize the DMA & configure DMA channels 1, 2 & 3
    //
    initializeDMA();
    configureDMAChannels();

    //
    // Initialize results buffer
    //
    for(resultsIndex = 0; resultsIndex < RESULTS_BUFFER_SIZE; resultsIndex++)
    {
        adcADataBuffer[resultsIndex] = 0;
        adcBDataBuffer[resultsIndex] = 0;
        adcCDataBuffer[resultsIndex] = 0;
    }
    //
    // Clearing all pending interrupt flags
    //
    DMA_clearTriggerFlag(DMA_CH1_BASE);   // DMA channel 1
    DMA_clearTriggerFlag(DMA_CH2_BASE);   // DMA channel 2
    DMA_clearTriggerFlag(DMA_CH3_BASE);   // DMA channel 3
    HWREGH(ADCA_BASE + ADC_O_INTFLGCLR) = 0x3U; // ADCA
    HWREGH(ADCB_BASE + ADC_O_INTFLGCLR) = 0x3U; // ADCB
    HWREGH(ADCC_BASE + ADC_O_INTFLGCLR) = 0x3U; // ADCC
    EPWM_forceADCTriggerEventCountInit(EPWM3_BASE, EPWM_SOC_A); // EPWM3 SOCA
    EPWM_clearADCTriggerFlag(EPWM3_BASE, EPWM_SOC_A); // EPWM3 SOCA

    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    fsi_SetupTransfer();

    //
    // Start DMA
    //
    done = 0;
    DMA_startChannel(DMA_CH1_BASE);
    DMA_startChannel(DMA_CH2_BASE);
    DMA_startChannel(DMA_CH3_BASE);

    //
    // Start ePWM3, enabling SOCA and putting the counter in up-count mode
    //
    EPWM_enableADCTrigger(EPWM3_BASE, EPWM_SOC_A);
    EPWM_setTimeBaseCounterMode(EPWM3_BASE, EPWM_COUNTER_MODE_UP);

    //
    // Loop until the ISR signals the transfer is complete
    //

   while(1)
   {
       if(done == 0)
       {
           __asm(" NOP");
       }
    }
}

//
// configureADC - Write ADC configurations and power up the ADC for the
// selected ADC
//
void configureADC(uint32_t adcBase)
{
    //
    // Set ADCCLK divider to /4 (This is 50 MHz)
    //
    ADC_setPrescaler(adcBase, ADC_CLK_DIV_4_0);
    //
    // Set resolution and signal mode (see #defines above) and load
    // corresponding trims.
    //
    ADC_setMode(adcBase, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
    //
    // Set pulse positions to late (end of conversion)
    //
    ADC_setInterruptPulseMode(adcBase, ADC_PULSE_END_OF_CONV);
    //
    // Power up the ADCs and then delay for 1 ms
    //
    ADC_enableConverter(adcBase);
    //
    // Delay for 1ms to allow ADC time to power up
    //
    DEVICE_DELAY_US(1000);
}

//
// Function to configure ePWM3 to generate the SOC.
//
void initEPWM(void)
{
    //
    // Disable SOCA
    //
    EPWM_disableADCTrigger(EPWM3_BASE, EPWM_SOC_A);

    //
    // Configure the SOC to occur on the first up-count event
    //
    EPWM_setADCTriggerSource(EPWM3_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_U_CMPA);
    EPWM_setADCTriggerEventPrescale(EPWM3_BASE, EPWM_SOC_A, 1);
    //
    // Set the compare A value to 1250 and the period to 2499
    // Assuming ePWM clock is 100MHz, this would give 40kHz sampling
    // 50MHz ePWM clock would give 25kHz sampling, etc. 
    // The sample rate can also be modulated by changing the ePWM period
    // directly (ensure that the compare A value is less than the period). 
    // Tpwm = (TBPRD+1) x TBCLK // Tpwm = 2500 * 1/100E+6 = 25 Us
    // Fpwm = 1/Tpwm = 1/25E-6 = 40kHz
    //
    EPWM_setCounterCompareValue(EPWM3_BASE, EPWM_COUNTER_COMPARE_A, 1250);//1250/2500 = 50% duty cycle
    EPWM_setTimeBasePeriod(EPWM3_BASE, 2499);//2499
    //EPWM_disablePhaseShiftLoad(EPWM3_BASE);// Clear PHSEN bit
    //EPWM_setPeriodLoadMode(EPWM3_BASE, EPWM_PERIOD_SHADOW_LOAD);
    //EPWM_enableSyncOutPulseSource(EPWM3_BASE, EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO);
    //
    // Set the local ePWM module clock divider to /1
    //
    EPWM_setClockPrescaler(EPWM3_BASE,
                           EPWM_CLOCK_DIVIDER_1,
                           EPWM_HSCLOCK_DIVIDER_1);

    //
    // Freeze the counter
    //
    EPWM_setTimeBaseCounterMode(EPWM3_BASE, EPWM_COUNTER_MODE_STOP_FREEZE);
}

//
// Function to configure SOCs on ADCA, ADCB and ADCC to be triggered by ePWM3.
//
void initADCSOC(void)
{
    uint16_t acqps;
    //
    // Minimum acquisition window (in SYSCLKS) based on 12-bit resolution
    //
    acqps = 14;// 15 is 80ns
    //
    // - NOTE: A longer sampling window will be required if the ADC driving
    //   source is less than ideal (an ideal source would be a high bandwidth
    //   op-amp with a small series resistance). See TI application report
    //   SPRACT6 for guidance on ADC driver design.
    // - NOTE: SOCs need not use the same S+H window duration, but SOCs 
    //   occurring in parallel (SOC0 on ADCA, ADCB, ADCC occur in
    //   parallel, as do the SOC1s on the 3 ADCs, etc.) should usually
    //   use the same value to ensure simultaneous samples and synchronous 
    //   operation.  

    //
    // Select the channels to convert and configure the ePWM trigger
    //
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN0, acqps);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN4, acqps);
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN5, acqps);
    ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN0, acqps);
    ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN2, acqps);
    ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN3, acqps);
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN2, acqps);
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN4, acqps);
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM3_SOCA,
                 ADC_CH_ADCIN5, acqps);

    //
    // Select SOC2 on ADCA as the interrupt source.
    //
    ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER2);
    ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
    ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER2);
    ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER3);
    ADC_disableInterrupt(ADCA_BASE, ADC_INT_NUMBER4);
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
}

//
// ADC A Interrupt 1 ISR
//
#pragma CODE_SECTION(adcA1ISR, ".TI.ramfunc");
__interrupt void adcA1ISR(void)
{
    //
    // Clear the interrupt flag
    //
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);

    //
    // Check if overflow has occurred
    //
    if(true == ADC_getInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1))
    {
        ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
        ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
    }
    //
    // Acknowledge interrupt
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}
//
// dmach1ISR - This is called at the end of the DMA transfer, the conversions
//
#pragma CODE_SECTION(dmach1ISR, ".TI.ramfunc");
__interrupt void dmach1ISR(void)
{
    //
    done = 1;
    fsi_DataTransfer();

    // Acknowledge interrupt
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
    //ESTOP0;
    done = 0;
}
//
// initializeDMA - Initialize DMA through hard reset
//
void initializeDMA(void)
{
    //
    // Perform a hard reset on DMA
    //
    DMA_initController();
    //
    // Allow DMA to run free on emulation suspend
    //
    DMA_setEmulationMode(DMA_EMULATION_FREE_RUN);
}
//
// configureDMAChannels - Initialize DMA ch 1 to transfer ADCA results
//                        , DMA ch 2 to transfer ADCB results
//                        and ch 3 to transfer ADCC results
//
void configureDMAChannels(void)
{
    //
    // DMA channel 1 set up for ADCA
    //
    DMA_configAddresses(DMA_CH1_BASE, (uint16_t *)&adcADataBuffer,
                        (uint16_t *)ADCARESULT_BASE);

    //
    // Perform enough 3-word burst to fill the results buffer. Data will be
    // transferred 16 bits at a time hence the address steps below.
    //
    DMA_configBurst(DMA_CH1_BASE, 3, 1, 1);
    DMA_configTransfer(DMA_CH1_BASE, 1, 0, 0);
    DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_ADCA1,
                   (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_ENABLE |
                    DMA_CFG_SIZE_16BIT));

    DMA_enableTrigger(DMA_CH1_BASE);
    DMA_disableOverrunInterrupt(DMA_CH1_BASE);
    DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_END);
    DMA_enableInterrupt(DMA_CH1_BASE);


    //
    // DMA channel 2 set up for ADCB
    //
    DMA_configAddresses(DMA_CH2_BASE, (uint16_t *)&adcBDataBuffer,
                        (uint16_t *)ADCBRESULT_BASE);

    //
    // Perform enough 3-word burst to fill the results buffer. Data will be
    // transferred 32 bits at a time hence the address steps below.
    //
    DMA_configBurst(DMA_CH2_BASE, 3, 1, 1);
    DMA_configTransfer(DMA_CH2_BASE, 1, 0, 0);
    DMA_configMode(DMA_CH2_BASE, DMA_TRIGGER_ADCA1,
                   (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_ENABLE |
                           DMA_CFG_SIZE_16BIT));

    DMA_enableTrigger(DMA_CH2_BASE);
    DMA_disableOverrunInterrupt(DMA_CH2_BASE);
    DMA_setInterruptMode(DMA_CH2_BASE, DMA_INT_AT_END);
    DMA_enableInterrupt(DMA_CH2_BASE);

    //
    // DMA channel 3 set up for ADCC
    //
    DMA_configAddresses(DMA_CH3_BASE, (uint16_t *)&adcCDataBuffer,
                        (uint16_t *)ADCCRESULT_BASE);

    //
    // Perform enough 3-word burst to fill the results buffer. Data will be
    // transferred 16 bits at a time hence the address steps below.
    //
    DMA_configBurst(DMA_CH3_BASE, 3, 1, 1);
    DMA_configTransfer(DMA_CH3_BASE, 1, 0, 0);
    DMA_configMode(DMA_CH3_BASE, DMA_TRIGGER_ADCA1,
                   (DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_ENABLE |
                    DMA_CFG_SIZE_16BIT));

    DMA_enableTrigger(DMA_CH3_BASE);
    DMA_disableOverrunInterrupt(DMA_CH3_BASE);
    DMA_setInterruptMode(DMA_CH3_BASE, DMA_INT_AT_END);
    DMA_enableInterrupt(DMA_CH3_BASE);
}

// initFSI - Initializes FSI Tx/Rx with internal loopback and also sends FLUSH
//           sequence.
//
void initFSI(void)
{
    FSI_disableRxInternalLoopback(FSIRXA_BASE);

    GPIO_setPinConfig(DEVICE_GPIO_CFG_FSI_TXCLK);
    GPIO_setPinConfig(DEVICE_GPIO_CFG_FSI_TX0);

    GPIO_setPinConfig(DEVICE_GPIO_CFG_FSI_RXCLKA);
    GPIO_setPinConfig(DEVICE_GPIO_CFG_FSI_RX0A);
    if(nLanes == FSI_DATA_WIDTH_2_LANE)
    {
        GPIO_setPinConfig(DEVICE_GPIO_CFG_FSI_TX1);
        GPIO_setPinConfig(DEVICE_GPIO_CFG_FSI_RX1A);
    }

    //
    // Set RX GPIO to be asynchronous
    // (pass through without delay)
    // Default setting is to have 2 SYS_CLK cycles delay
    //
    GPIO_setQualificationMode(DEVICE_GPIO_PIN_FSI_RX0A, GPIO_QUAL_ASYNC);
    GPIO_setQualificationMode(DEVICE_GPIO_PIN_FSI_RXCLKA, GPIO_QUAL_ASYNC);
    if(nLanes == FSI_DATA_WIDTH_2_LANE)
    {
        GPIO_setQualificationMode(DEVICE_GPIO_PIN_FSI_RX1A, GPIO_QUAL_ASYNC);
    }

    // TODO- Add logic to calculate PRESCALER_VAL based on user input FSI CLK
    FSI_performTxInitialization(FSITXA_BASE, PRESCALER_VAL);
    FSI_performRxInitialization(FSIRXA_BASE);
    txBufAddr = (uint16_t *)FSI_getTxBufferAddress(FSITXA_BASE);
    rxBufAddr = (uint16_t *)FSI_getRxBufferAddress(FSIRXA_BASE);
}

//
// fsiTxInt1ISR - FSI Tx Interrupt on INsT1 line
//
__interrupt void fsiTxInt1ISR(void)
{
    fsiTxInt1Received = 1U;

    txEventSts = FSI_getTxEventStatus(FSITXA_BASE);

    //
    // Clear the interrupt flag and issue ACK
    //
    FSI_clearTxEvents(FSITXA_BASE, FSI_TX_EVTMASK);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4);
}

//
// fsiTxInt2ISR - FSI Tx Interrupt on INT2 line
//
__interrupt void fsiTxInt2ISR(void)
{
    fsiTxInt2Received = 1U;

    txEventSts = FSI_getTxEventStatus(FSITXA_BASE);

    //
    // Clear the interrupt flag and issue ACK
    //
    FSI_clearTxEvents(FSITXA_BASE, FSI_TX_EVTMASK);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4);

    disableAllFSIInterrupts();

    //
    // INT2 line is set to fire for error events, stop immediately. Actual Error
    // is captured in txEventSts for debug
    //
    ESTOP0;
}

//
// fsiRxInt1ISR - FSI Rx Interrupt on INT1 line
//
__interrupt void fsiRxInt1ISR(void)
{
    rxEventSts = FSI_getRxEventStatus(FSIRXA_BASE);

    fsiRxInt1Received = 1U;

    //
    // Clear the interrupt flag and issue ACK
    //
    FSI_clearRxEvents(FSIRXA_BASE,rxEventSts);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4);
}

//
// fsiRxInt2ISR - FSI Rx Interrupt on INT2 line
//
__interrupt void fsiRxInt2ISR(void)
{
    rxEventSts = FSI_getRxEventStatus(FSIRXA_BASE);

    fsiRxInt2Received = fsiRxInt2Received + 1U;

    //
    // Clear the interrupt flag and issue ACK
    //
    FSI_clearRxEvents(FSIRXA_BASE,rxEventSts);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4);

    disableAllFSIInterrupts();

    //
    // INT2 line is set to fire for error events, stop immediately. Error
    // is captured in rxEventSts for debug
    //
    ESTOP0;
}

//
// disableAllFSIInterrupts - Disables all event interrupts in both FSI Tx/Rx,
//                           also clear them
//
void disableAllFSIInterrupts(void)
{
    FSI_disableTxInterrupt(FSITXA_BASE, FSI_INT1, FSI_TX_EVTMASK);
    FSI_disableTxInterrupt(FSITXA_BASE, FSI_INT2, FSI_TX_EVTMASK);
    FSI_disableRxInterrupt(FSIRXA_BASE, FSI_INT1, FSI_RX_EVTMASK);
    FSI_disableRxInterrupt(FSIRXA_BASE, FSI_INT2, FSI_RX_EVTMASK);

    FSI_clearTxEvents(FSITXA_BASE, FSI_TX_EVTMASK);
    FSI_clearRxEvents(FSIRXA_BASE, FSI_RX_EVTMASK);
}

//
// compare16 - Compares two 16 bit values and increments global error flag by 1
//             for mismatch
//
static inline void compare16(uint16_t val1, uint16_t val2)
{
    if(val1 != val2)
    {
        error++;
    }
}

//
// compareBufData - Compares if received data is same as transmitted ones
//                  It doesn't consider wrap-up cases, but, can be enhanced
//
void compareBufData(uint16_t txBufIndex, uint16_t rxBufIndex, uint16_t nWords)
{
    uint16_t i;
    uint16_t rxDataArray[16];

    FSI_readRxBuffer(FSIRXA_BASE, rxDataArray, nWords, rxBufIndex);

    for(i = 0; i < nWords; i++)
    {
        if(rxDataArray[i] != txBufAddr[txBufIndex])
        {
            error++;
            return;
        }

        txBufIndex++;
    }
}

//
// checkReceivedFrameTypeTag - Checks received frame type/tag and updates global
//                             error flag
//
void checkReceivedFrameTypeTag(FSI_FrameType type, FSI_FrameTag tag)
{
    compare16((uint16_t)FSI_getRxFrameType(FSIRXA_BASE), (uint16_t)type);

    if(type == FSI_FRAME_TYPE_PING)
    {
        compare16(FSI_getRxPingTag(FSIRXA_BASE), (uint16_t)tag);
    }
    else
    {
        compare16(FSI_getRxFrameTag(FSIRXA_BASE), (uint16_t)tag);
    }
}
#pragma CODE_SECTION(fsi_SetupTransfer, ".TI.ramfunc")
void fsi_SetupTransfer(void)
{
    //
    // Enable normal data transfer events to be sent over INT1 line
    //
    FSI_enableTxInterrupt(FSITXA_BASE, FSI_INT1, FSI_TX_EVT_FRAME_DONE);
    FSI_enableRxInterrupt(FSIRXA_BASE, FSI_INT1, FSI_RX_EVT_PING_FRAME);

    //
    // Wait till interrupt is received on FSIRX INT1 line, verify it's for FRAME
    // DONE event for PING Frame reception
    //
    while(1)
    {
        //
        // Send the flush sequence
        //
        FSI_executeTxFlushSequence(FSITXA_BASE, PRESCALER_VAL);

        //
        // Send a ping frame with frame tag 0000b
        //
        FSI_setTxFrameTag(FSITXA_BASE, FSI_FRAME_TAG0);
        FSI_setTxFrameType(FSITXA_BASE, FSI_FRAME_TYPE_PING);
        FSI_startTxTransmit(FSITXA_BASE);

        while(fsiRxInt1Received != 1U && rxTimeOutCntr != 0U)
        {
            DEVICE_DELAY_US(1);
            rxTimeOutCntr--;
        }

        if(rxTimeOutCntr == 0)
        {
            rxTimeOutCntr = 0x100000;
            continue;
        }
        else
        {
            compare16(rxEventSts, (FSI_RX_EVT_PING_FRAME | FSI_RX_EVT_FRAME_DONE));
            checkReceivedFrameTypeTag(FSI_FRAME_TYPE_PING, FSI_FRAME_TAG1);
            //
            // If received frame type and tag matches, exit this loop and proceed
            // to next step by sending flush sequence, otherwise clear error and
            // interrupt flag and continue looping.
            //
            if(error == 0)
            {
                fsiRxInt1Received = 0;
                break;
            }

            fsiRxInt1Received = 0;
            error = 0;
        }
    }
    //
    // Send a ping frame with frame tag 0001b
    //
    FSI_setTxFrameTag(FSITXA_BASE, FSI_FRAME_TAG1);
    FSI_setTxFrameType(FSITXA_BASE, FSI_FRAME_TYPE_PING);
    FSI_startTxTransmit(FSITXA_BASE);
    DEVICE_DELAY_US(100);
    FSI_setTxSoftwareFrameSize(FSITXA_BASE, nWords);
    FSI_setTxDataWidth(FSITXA_BASE, nLanes);
    FSI_setTxUserDefinedData(FSITXA_BASE, txUserData);
    FSI_setTxFrameTag(FSITXA_BASE, txDataFrameTag);
    FSI_setTxFrameType(FSITXA_BASE, FSI_FRAME_TYPE_NWORD_DATA);
}
#pragma CODE_SECTION(fsi_DataTransfer, ".TI.ramfunc")
void fsi_DataTransfer(void)
{
    //
    // Write data into Tx buffer and set other Frame specific fields
    //
    memcpy(txBufData, &adcADataBuffer, 8);// 8 ADC channels
    FSI_writeTxBuffer(FSITXA_BASE, txBufData, nWords, 0U);
    while(fsiTxInt1Received != 1U);
    //
    // Start Transfer
    //
    FSI_startTxTransmit(FSITXA_BASE);
    while(fsiTxInt1Received != 1);
    //
    // Re-initialize flags and buffer pointer before next transmission
    //
    fsiTxInt1Received = 0U;
    dataFrameCntr++;
    FSI_setTxBufferPtr(FSITXA_BASE, 0U);
}
//
// End of file
//