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.

EK-TM4C123GXL: TIVA uDMA Implementation

Part Number: EK-TM4C123GXL

Hi,

I am currently using the TIVA device for an audio playback functionality, using a PWM signal, where the audio files are stored in external flash on a booster pack. Up to this point I have configured the SSI module to read data from flash and play it back successfully. However, moving forward I would like to utilize the uDMA to handle the transfer of data from flash to the buffer and then to the timer for PWM output.

The question that this is raising relates to the CS signal. It must be low for the duration of data transfer and on the tm4c123 device this can only be done manually by toggling the GPIO pin. I have included the two files being used below. Again, I am hoping to get some insight, or potentially an example, of how to implement the uDMA for this function.

Thanks,

Garrett

*timers.c*

#define SSI_CLK GPIO_PIN_4
#define SSI_CS GPIO_PIN_5
#define SSI_RX GPIO_PIN_6
#define SSI_TX GPIO_PIN_7
#define endAddr 208065

int d=0, c=10, b=0;
int strAddr = 100;

uint8_t Buffer[10];
unsigned long dutyCycle;

unsigned short sine[32] = { 0x0000, 0x7D39, 0x7FD8, 0x5964, 0x4073, 0x7FFD, 0x0647, 0xBA33, 0x0000, 0x45CD, 0xF9B9,
                           0x8003, 0xBF8D, 0xA69C, 0x8028, 0x82C7, 0x0000, 0x7D39, 0x7FD8, 0x5964, 0x4073, 0x7FFD,
                           0x0647, 0xBA33, 0x0000, 0x45CD, 0xF9B9, 0x8003, 0xBF8D, 0xA69C, 0x8028, 0x82C7};

unsigned short sine1[32] = { 0x0000, 0x007A, 0x007D, 0x0057, 0x003F, 0x007D, 0x06, 0x00B6, 0x0000, 0x0044, 0x00F4,
                             0x007D, 0x00BB, 0x00A3, 0x007D, 0x0080, 0x0000, 0x007A, 0x007D, 0x0057, 0x003F, 0x007D,
                             0x0006, 0x00B6, 0x0000, 0x0044, 0x00F4, 0x007D, 0x00BB, 0x00A3, 0x007D, 0x0080};
//*****************************************************************************
//
//! \addtogroup example_list
//! <h1>Timer (timers)</h1>
//!
//! This example application demonstrates the use of the timers to generate
//! periodic interrupts.  One timer is set up to interrupt once per second and
//! the other to interrupt twice per second; each interrupt handler will toggle
//! its own indicator on the display.
//
//*****************************************************************************

//uint32_t g_ui32Flags;

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

//*****************************************************************************
//
// The interrupt handler for Timer 3 & SSI
//
//*****************************************************************************

void
Timer3IntHandler(void)
{



    ROM_TimerIntClear(TIMER3_BASE, TIMER_CAPB_EVENT);
    if(c==10){


    SPIFlashRead(SSI2_BASE, strAddr, &Buffer, 10);

    if (strAddr >= endAddr)
        strAddr = 100;
    else
    strAddr=strAddr+10;
    c=0;
    }
    ROM_TimerMatchSet(TIMER3_BASE, TIMER_A, Buffer[c]);
    c++;


/*
    ROM_TimerIntClear(TIMER3_BASE, TIMER_CAPB_EVENT);

    ROM_TimerMatchSet(TIMER3_BASE, TIMER_A, sine1[d]);
    d++;
    if(d == 32)
        d = 0;

*/

}


//*****************************************************************************
//
// This example application demonstrates the use of the timers to generate
// periodic interrupts.
//
//*****************************************************************************
int
main(void)
{

    unsigned long ulPeriodA;
    unsigned long ulPeriodB;
    unsigned long sysClock;
    uint8_t manID = 0;
    uint16_t devID = 0;


    ulPeriodA = 255; //max 65535 with 16-bit timer      sets to 16kHz (80MHz/5000)
    dutyCycle = 1; //50% duty cycle
    ulPeriodB = 4080;   // (66.66M / 16k)

    //Enable Peripherals used
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI2);

///////////////////////////////// Pin Configurations //////////////////////////////////////

    //Timer 3A
    ROM_GPIOPinConfigure(GPIO_PB2_T3CCP0);                  //configure function of GPIO Pin  (_P#_fucntion)
    ROM_GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_2);      //configures pin for use by timer
    //Audio Amp
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTB_BASE, GPIO_PIN_3); //Using AMP CTL* on board
    ROM_GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, 0);       //Must move resistor to use AMP CTL (PA4)
    //SSI
    ROM_GPIOPinTypeSSI(GPIO_PORTB_BASE, SSI_CLK | SSI_RX | SSI_TX);  //configures pins for SSI
    ROM_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3); //manual CS
    ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, 255); // manual Chip Select
    ROM_GPIOPinConfigure(GPIO_PB4_SSI2CLK);
//    ROM_GPIOPinConfigure(GPIO_PB5_SSI2FSS);
    ROM_GPIOPinConfigure(GPIO_PB6_SSI2RX);
    ROM_GPIOPinConfigure(GPIO_PB7_SSI2TX);


//////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////// Timer Configurations ///////////////////////////////////

    //66.66MHz system clock
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_3 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);


    // Configure the 16-bit PWM Timer
    ROM_TimerConfigure(TIMER3_BASE, (TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_PWM|TIMER_CFG_B_PWM));

    //Timer 3A Load, Match, Control
    ROM_TimerLoadSet(TIMER3_BASE, TIMER_A, ulPeriodA);      //count down from 'load value' ulPeriod
    ROM_TimerMatchSet(TIMER3_BASE, TIMER_A, dutyCycle);     //PWM high until counter hits match value
    ROM_TimerControlLevel(TIMER3_BASE, TIMER_A, true);      //Controls output level ==> true = active low output

    //Timer 3B Load, Match, Control
    ROM_TimerLoadSet(TIMER3_BASE, TIMER_B, ulPeriodB);      //count down from 'load value' ulPeriod
    ROM_TimerMatchSet(TIMER3_BASE, TIMER_B, dutyCycle);     //PWM high until counter hits match value
    ROM_TimerControlLevel(TIMER3_BASE, TIMER_B, true);      //Controls output level ==> true = active low output


    //Counter Interrupt
    TimerUpdateMode(TIMER3_BASE, TIMER_B, TIMER_UP_LOAD_TIMEOUT | TIMER_UP_MATCH_TIMEOUT);
    ROM_TimerIntEnable(TIMER3_BASE, TIMER_CAPB_EVENT);

    // Enable the timers.
    ROM_TimerEnable(TIMER3_BASE, TIMER_A);
    ROM_TimerEnable(TIMER3_BASE, TIMER_B);

    // Enable processor interrupts.
    ROM_IntMasterEnable();
    // Setup the interrupts for the timer timeouts.
    ROM_IntEnable(INT_TIMER3B);

    ///////////////////////////////// SSI Configuration //////////////////////////////////////

        sysClock = ROM_SysCtlClockGet();

     //   SSIConfigSetExpClk(SSI2_BASE, sysClock, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 2000000, 8);
     //   SSIAdvModeSet(SSI2_BASE, SSI_ADV_MODE_READ_WRITE);    //mode where data is written/read from the slave
     //   SSIAdvFrameHoldEnable(SSI2_BASE);                     //enables frame hold feature
     //   SSIEnable(SSI2_BASE);                                 //enable SPI module
        SPIFlashInit(SSI2_BASE, sysClock, 4000000);

//        SPIFlashReadID(SSI2_BASE, &manID, &devID);


    /////////////////////////////////////////////////////////////////////////////////////////

    //uint32_t data[4];

    while(1)    // Loop forever while the timers run.
    {
} }

*spi_flash.c*

void
SPIFlashInit(uint32_t ui32Base, uint32_t ui32Clock, uint32_t ui32BitRate)
{
    //
    // Configure the SPI module.
    //
    MAP_SSIConfigSetExpClk(ui32Base, ui32Clock, SSI_FRF_MOTO_MODE_0,
                           SSI_MODE_MASTER, ui32BitRate, 8);

    //
    // Enable the advanced mode of operation, defaulting to read/write mode.
    //
    MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);

    //
    // Enable the frame hold feature.
    //
//    MAP_SSIAdvFrameHoldEnable(ui32Base);

    //
    // Enable the SPI module.
    //
    MAP_SSIEnable(ui32Base);
}

void
SPIFlashRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data,
             uint32_t ui32Count)
{
    uint32_t ui32Trash;
    uint8_t c=0;
    //
    // Drain any residual data from the receive FIFO.
    //
    while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0)
    {
    }
    ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, 0); // manual Chip Select//manual C
    //SysCtlDelay(10);

    // Set the SSI module into write-only mode.
    MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE);
    //
    // Send the read command.
    //
    MAP_SSIDataPut(ui32Base, CMD_READ);
    ui32Addr=ui32Addr-4;
    //
    // Send the address of the first byte to read
    //
    MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff);
    MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff);
    MAP_SSIDataPut(ui32Base, ui32Addr & 0xff);
    //
    // Set the SSI module into read/write mode.  In this mode, dummy writes are
    // required in order to make the transfer occur; the SPI flash will ignore
    // the data.
    //
    MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE);
    //
    // See if there is a single byte to be read.
    //
for(c = 0; c <= 4; c++)
{
    MAP_SSIDataPut(ui32Base, 241);
    MAP_SSIDataGet(ui32Base, &ui32Addr);
}
    if(ui32Count == 1)
    {
        //
        // Perform a single dummy write, marking it as the end of the frame.
        //
        MAP_SSIDataPut(ui32Base, 241);

    }
    else
    {
        //
        // Perform a dummy write to prime the loop.
        //
        MAP_SSIDataPut(ui32Base, 241);

        //
        // Loop while there is more than one byte left to be read.
        //
        while(--ui32Count != 1)
        {
            //
            // Perform a dummy write to keep the transmit FIFO from going
            // empty.
            //
            MAP_SSIDataPut(ui32Base, 241);

            //-
            // Read the next data byte from the receive FIFO and place it into
            // the data buffer.
            //
            MAP_SSIDataGet(ui32Base, &ui32Addr);
            *pui8Data++ = ui32Addr & 0xff;

        }

        //
        // Perform the final dummy write, marking it as the end of the frame.
        //
        MAP_SSIDataPut(ui32Base, 241);


        //
        // Read the next data byte from the receive FIFO and place it into the
        // data buffer.
        //
        MAP_SSIDataGet(ui32Base, &ui32Addr);
        *pui8Data++ = ui32Addr & 0xff;
    }

    //
    // Read the final data byte from the receive FIFO and place it into the
    // data buffer.
    //
    MAP_SSIDataGet(ui32Base, &ui32Addr);
    *pui8Data++ = ui32Addr & 0xff;

    while (SSIBusy(SSI2_BASE)){}
   ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, 255); // manual Chip Select
}