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.

F28377D-SEP: SPI DMA intialization issue

Part Number: F28377D-SEP
Other Parts Discussed in Thread: ADS7028, C2000WARE, SYSCONFIG

I wanted to read the 4 channels of ADS7028 though SPI and and store this data in DMA at every 10KHz PWM ISR. However, the SPI is not getting triggered as well as DMA. The CLK and CS are always low. 

here is my code snippet - DMA bugffer in GSRAM
#pragma DATA_SECTION(sData, "ramgs0");
#pragma DATA_SECTION(rData, "ramgs0");
uint16_t sData[NUM_ADC_CHANNELS];
uint16_t rData[NUM_ADC_CHANNELS];

the main loop --

void main(void)
{
    uint16_t i;

    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_DMA);

    DINT;

    for(i=0; i<NUM_ADC_CHANNELS; i++) {
        sData[i] = 0xAAAA;
        rData[i] = 0x0000;
    }

    InitSystem();
    InitSPI_and_ADS7028();
    InitDMA();

    Interrupt_register(INT_EPWM1, &INT_EPWM1_ISR);
    Interrupt_register(INT_DMA_CH1, &INT_DMA_CH1_ISR);

    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    InitEPWM_Trigger();
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    Interrupt_enable(INT_EPWM1);
    Interrupt_enable(INT_DMA_CH1);
    EINT;
    ERTM;

    while(1)
    {
        // Debug Loop
    }
}
SPI and ADS7028 intialization --

void InitSPI_and_ADS7028(void)
{
    SPI_disableModule(ADS_SPI_BASE);
    SPI_setConfig(ADS_SPI_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1, SPI_MODE_MASTER, 1000000, 8);
    SPI_enableModule(ADS_SPI_BASE);
    SPI_disableFIFO(ADS_SPI_BASE);

    ADS_Write(0x01, 0x01); // Reset Device
    DEVICE_DELAY_US(10000);

    // Register 0x12 (Sequence Select)
    // To select Ch 1, 2, 3, 4:
    // Binary: 0001 1110 = 0x1E
    ADS_Write(0x12, 0x1E);

    // Enable Auto Sequence Mode (Register 0x10 = 0x11)
    ADS_Write(0x10, 0x11);

    SPI_disableModule(ADS_SPI_BASE);
    SPI_setConfig(ADS_SPI_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1, SPI_MODE_MASTER, ADS_SPI_SPEED, 16);
    SPI_enableFIFO(ADS_SPI_BASE);
    SPI_resetTxFIFO(ADS_SPI_BASE);
    SPI_resetRxFIFO(ADS_SPI_BASE);

    SPI_setFIFOInterruptLevel(ADS_SPI_BASE, SPI_FIFO_TX0, SPI_FIFO_RX1);
    SPI_enableInterrupt(ADS_SPI_BASE, SPI_INT_TXFF | SPI_INT_RXFF);
    SPI_enableModule(ADS_SPI_BASE);
}
DMA initialization --

void InitDMA(void)
{
    DMA_initController();

  // --- RX Channel (Ch1) ---
    DMA_configAddresses(DMA_CH1_BASE, (const void *)rData, (const void *)(ADS_SPI_BASE + SPI_O_RXBUF));
    DMA_configBurst(DMA_CH1_BASE, 1, 0, 1);
    DMA_configTransfer(DMA_CH1_BASE, NUM_ADC_CHANNELS, 0, 0);
    DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SPICRX, DMA_CFG_ONESHOT_DISABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT);
    DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_END);
    DMA_enableInterrupt(DMA_CH1_BASE);
    DMA_enableTrigger(DMA_CH1_BASE);

    // --- TX Channel (Ch2) ---
    DMA_configAddresses(DMA_CH2_BASE, (const void *)(ADS_SPI_BASE + SPI_O_TXBUF), (const void *)sData);
    DMA_configBurst(DMA_CH2_BASE, 1, 1, 0);
    DMA_configTransfer(DMA_CH2_BASE, NUM_ADC_CHANNELS, 0, 0);    DMA_configMode(DMA_CH2_BASE, DMA_TRIGGER_SPICTX, DMA_CFG_ONESHOT_ENABLE | DMA_CFG_CONTINUOUS_DISABLE | DMA_CFG_SIZE_16BIT);
    DMA_enableTrigger(DMA_CH2_BASE);
}

Interrupt --

__interrupt void INT_EPWM1_ISR(void)
{
    if(SPI_isBusy(ADS_SPI_BASE)) {
        spi_error_count++;
        EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
        return;
    }
    epwm_isr_count++;
    // Reset FIFOs
    SPI_resetRxFIFO(ADS_SPI_BASE);
    SPI_resetTxFIFO(ADS_SPI_BASE);
    // Assert CS
    GPIO_writePin(ADS_CS_GPIO, 0);
    // Start DMA
    DMA_startChannel(DMA_CH1_BASE);
    DMA_startChannel(DMA_CH2_BASE);
    // Force Trigger (Kickstart)
    DMA_forceTrigger(DMA_CH2_BASE);
    EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

__interrupt void INT_DMA_CH1_ISR(void)
{
    int i;
    uint16_t raw_data;
    while(SPI_isBusy(ADS_SPI_BASE));
    GPIO_writePin(ADS_CS_GPIO, 1);
    dma_isr_count++;
    for(i = 0; i < NUM_ADC_CHANNELS; i++) {
        raw_data = rData[i];
        adc_volts[i] = (float)((raw_data >> 4) & 0x0FFF) * (3.3f / 4096.0f);
    }
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
}

Kindly check if there is any timing issue or wrong initialization of the DMA using SPICTX.

  • Hi Souradeep,

    Can you try running the SPI+DMA example from C2000ware called spi_ex5_loopback_dma? We don't provide this example for F2837xD, but it is available in C2000ware for other devices - for example F28004x (path: [C2000ware install]/driverlib/f28004x/examples/spi/), and the SPI and DMA implementation would be the same. Can you try porting the example to F2837xD and testing it out on your setup? If you can get the example working, it will be better to use as a starting point for your code.

    Best Regards,

    Delaney

  • Hi I have gone through that file, somehow the porting is not working properly. 
    I have the following working code, which config the ADS7028 properly, and I am able to read and write correct data. However, I want add DMA for SPI to offload the CPU. If you could help me with proper initialization and guidelines to follow, it would be helpful.   

    #include "driverlib.h"
    #include "device.h"

    #define ADS_SPI_BASE SPIC_BASE
    #define ADS_CS_GPIO 53
    #define ADS_CS_PIN_CONFIG GPIO_53_GPIO53
    #define NUM_ADC_CHANNELS 4
    // ADS7028 Opcodes
    #define OPCODE_WRITE 0x08
    #define OPCODE_READ 0x10
    #define OPCODE_NOP 0x00

    volatile uint32_t isr_count = 0;
    uint16_t adc_raw[8], channel_id[4];

    float adc_volts[8];
    // Function Prototypes
    void InitSystem(void);
    void InitSPI_and_ADS7028(void);
    void InitEPWM_Trigger(void);
    void ADS_Write(uint8_t addr, uint8_t d);
    uint16_t ADS7028_ReadData(void);
    __interrupt void INT_EPWM1_ISR(void);

    void main(void)
    {
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    InitSystem();
    InitSPI_and_ADS7028();

    Interrupt_register(INT_EPWM1, &INT_EPWM1_ISR);

    InitEPWM_Trigger();

    Interrupt_enable(INT_EPWM1);
    EINT;
    ERTM;

    while(1)
    {

    }
    }

    void InitSystem(void)
    {
    // SPI-C GPIOs
    GPIO_setPinConfig(GPIO_50_SPISIMOC);
    GPIO_setPadConfig(50, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(50, GPIO_QUAL_ASYNC);

    GPIO_setPinConfig(GPIO_51_SPISOMIC);
    GPIO_setPadConfig(51, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(51, GPIO_QUAL_ASYNC);

    GPIO_setPinConfig(GPIO_52_SPICLKC);
    GPIO_setPadConfig(52, GPIO_PIN_TYPE_PULLUP);
    GPIO_setQualificationMode(52, GPIO_QUAL_ASYNC);

    // Chip Select
    GPIO_setPinConfig(ADS_CS_PIN_CONFIG);
    GPIO_setPadConfig(ADS_CS_GPIO, GPIO_PIN_TYPE_STD);
    GPIO_setDirectionMode(ADS_CS_GPIO, GPIO_DIR_MODE_OUT);
    GPIO_writePin(ADS_CS_GPIO, 1);
    }

    void InitSPI_and_ADS7028(void)
    {
    SPI_disableModule(ADS_SPI_BASE);
    SPI_setConfig(ADS_SPI_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1, SPI_MODE_MASTER, 1000000, 8);
    SPI_enableModule(ADS_SPI_BASE);
    SPI_disableFIFO(ADS_SPI_BASE);

    ADS_Write(0x01, 0x01); // Reset
    DEVICE_DELAY_US(10000);
    ADS_Write(0x05, 0x00);
    DEVICE_DELAY_US(1);
    ADS_Write(0x02, 0x10); // Enable 4-bit Channel ID
    // Select Ch 1, 2, 3, 4 (Mask 0x1E: 0000 1111)
    ADS_Write(0x12, 0x0F);
    // Start Auto Seq
    ADS_Write(0x10, 0x11);

    SPI_disableModule(ADS_SPI_BASE);
    SPI_setConfig(ADS_SPI_BASE, DEVICE_LSPCLK_FREQ, SPI_PROT_POL0PHA1, SPI_MODE_MASTER, 1000000, 16);
    SPI_enableFIFO(ADS_SPI_BASE);
    SPI_resetTxFIFO(ADS_SPI_BASE);
    SPI_resetRxFIFO(ADS_SPI_BASE);
    SPI_enableModule(ADS_SPI_BASE);

    ADS7028_ReadData();
    }

    void ADS_Write(uint8_t addr, uint8_t d)
    {
    GPIO_writePin(ADS_CS_GPIO, 0); DEVICE_DELAY_US(1);
    SPI_writeDataBlockingNonFIFO(ADS_SPI_BASE, (uint16_t)(OPCODE_WRITE << 8));
    SPI_readDataBlockingNonFIFO(ADS_SPI_BASE);
    SPI_writeDataBlockingNonFIFO(ADS_SPI_BASE, (uint16_t)(addr << 8));
    SPI_readDataBlockingNonFIFO(ADS_SPI_BASE);
    SPI_writeDataBlockingNonFIFO(ADS_SPI_BASE, (uint16_t)(d << 8));
    SPI_readDataBlockingNonFIFO(ADS_SPI_BASE);
    DEVICE_DELAY_US(1); GPIO_writePin(ADS_CS_GPIO, 1);
    }
    uint16_t ADS7028_ReadData(void)
    {
    uint16_t rawResult;

    GPIO_writePin(ADS_CS_GPIO, 0);
    DEVICE_DELAY_US(1); // Setup time if needed

    SPI_writeDataNonBlocking(ADS_SPI_BASE, 0x0000);

    while(SPI_getRxFIFOStatus(ADS_SPI_BASE) == SPI_FIFO_RX0) {
    // Wait for data
    }

    rawResult = SPI_readDataNonBlocking(ADS_SPI_BASE);

    DEVICE_DELAY_US(1); // Hold time if needed
    GPIO_writePin(ADS_CS_GPIO, 1);

    return rawResult;
    }

    void InitEPWM_Trigger(void) // 10kHz Trigger
    {
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    GPIO_setPinConfig(GPIO_0_EPWM1A);
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
    EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
    EPWM_setTimeBasePeriod(EPWM1_BASE, 10000);
    EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO);
    EPWM_setInterruptEventCount(EPWM1_BASE, 1);
    EPWM_enableInterrupt(EPWM1_BASE);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    }

    __interrupt void INT_EPWM1_ISR(void)
    {
    uint16_t temp_raw; // Temporary variable to hold the 16-bit packet

    isr_count++;

    // --- Channel 1 ---
    temp_raw = ADS7028_ReadData(); // Read [Data][ID]
    channel_id[0] = temp_raw & 0x000F; // Extract ID (Lower 4 bits)
    adc_raw[0] = (temp_raw >> 4) & 0x0FFF; // Shift & Mask to get 12-bit Data
    adc_volts[0] = (float)adc_raw[0] * (3.3f / 4096.0f);

    // --- Channel 2 ---
    temp_raw = ADS7028_ReadData();
    channel_id[1] = temp_raw & 0x000F;
    adc_raw[1] = (temp_raw >> 4) & 0x0FFF;
    adc_volts[1] = (float)adc_raw[1] * (3.3f / 4096.0f);

    // --- Channel 3 ---
    temp_raw = ADS7028_ReadData();
    channel_id[2] = temp_raw & 0x000F;
    adc_raw[2] = (temp_raw >> 4) & 0x0FFF;
    adc_volts[2] = (float)adc_raw[2] * (3.3f / 4096.0f);

    // --- Channel 4 ---
    temp_raw = ADS7028_ReadData();
    channel_id[3] = temp_raw & 0x000F;
    adc_raw[3] = (temp_raw >> 4) & 0x0FFF;
    adc_volts[3] = (float)adc_raw[3] * (3.3f / 4096.0f);

    EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    }

    thanks,
    Souradeep

  • Hi Souradeep,

    In order to port the example, I would suggest importing the empty_project for F2837xD, then copying over the contents of the main.c and the .syscfg files. Do you get any errors in Sysconfig if you do this? I believe the only thing that would need to change beyond that is the GPIO settings. Can you try this and send me any errors you get?

    Best Regards,

    Delaney