Hello,
I need to know how to setup SPI DMA. I have setup plain SPI with interrupts successfully but I am not able to do that with DMA. I am not sure what mistake I am doing. Below is the source if you can help I would really appreciate it.
I am trying to trigger DMA channel 1 for Tx of SPIA Tx which is master. I am not sure what am I missing. My goal is to go into DMA_ISR. Just some dummy data Tx, not loopback though. I would do receive Rx later.
Thanks in Advance!
Regards
Varun
#ifndef DMA_INIT_C
#define DMA_INIT_C
/* Header Files includes */
#include "driverlib.h"
#include "device.h"
#include "dma_init.h"
#include "dma.h"
//
// Defines
//
#define BURST (FIFO_LVL-1) // burst size should be less than 8
#define TRANSFER 15 // [(MEM_BUFFER_SIZE/FIFO_LVL)-1]
#define FIFO_LVL 8 // FIFO Interrupt Level
//
// Globals
//
#pragma DATA_SECTION(sdata, "ramgs0"); // map the TX data to memory
#pragma DATA_SECTION(rdata, "ramgs1"); // map the RX data to memory
uint16_t sdata[128]; // Send data buffer
uint16_t rdata[128]; // Receive data buffer
uint16_t rdata_point; // Keep track of where we are
// in the data stream to check received data
volatile uint16_t *DMADest;
volatile uint16_t *DMASource;
volatile uint16_t done;
void Init_DMA()
{
uint16_t i;
// Interrupts that are used in this example are re-mapped to
// ISR functions found within this file.
Interrupt_register(INT_DMA_CH1, &DMACh1ISR);
Interrupt_register(INT_DMA_CH2, &DMACh2ISR);
//! Initializes the DMA controller to a known state.
DMA_initController();
//Sets DMA emulation mode.
DMA_setEmulationMode(DMA_EMULATION_FREE_RUN);
//Configure DMA settings for SPITX.
Set_DMA_Config_TX();
//Configure DMA settings for SPITX.
Set_DMA_Config_RX();
//
// Initialize the data buffers
//
for(i=0; i<128; i++)
{
sdata[i] = i;
rdata[i]= 0;
}
rdata_point = 0;
Interrupt_enable(INT_DMA_CH1); // Enable PIE Group 7, INT 1 (DMA CH1)
Interrupt_enable(INT_DMA_CH2); // Enable PIE Group 7, INT 2 (DMA CH2)
Interrupt_enableInCPU(INTERRUPT_CPU_INT6); // Enable CPU INT6
//! Starts a DMA channel.
DMA_startChannel(DMA_CH2_BASE); // Start SPI RX DMA channel
DMA_startChannel(DMA_CH1_BASE); // Start SPI TX DMA channel
done = 0; // Test is not done yet
//while(!done); // wait until the DMA transfer is complete
}
void Set_DMA_Config_TX()
{
DMASource = (volatile uint16_t *)sdata;
// configure DMACH1 for TX
//! Configures the DMA channel
DMA_configAddresses(DMA_CH1_BASE, (SPIA_BASE+SPI_O_TXBUF), DMASource);
//! Configures the DMA channel's burst settings.
DMA_configBurst(DMA_CH1_BASE, BURST, 0x0001, 0x0000);
//! Configures the DMA channel's transfer settings.
DMA_configTransfer(DMA_CH1_BASE, TRANSFER, 0x0001, 0x0000);
//! Disables the DMA channel overrun interrupt.
DMA_disableOverrunInterrupt(DMA_CH1_BASE);
//! Configures the DMA channel trigger and mode.
DMA_configMode(DMA_CH1_BASE, DMA_TRIGGER_SPIATX, DMA_CFG_SIZE_16BIT);
//! Enables a DMA channel interrupt source.
DMA_enableInterrupt(DMA_CH1_BASE);
//! Sets the interrupt generation mode of a DMA channel interrupt.
DMA_setInterruptMode(DMA_CH1_BASE, DMA_INT_AT_BEGINNING); /* DMA interrupt is generated at the end of a transfer */
//! Clears a DMA channel's peripheral trigger flag.
DMA_clearTriggerFlag(DMA_CH1_BASE);
//! Clears the DMA channel error flags.
DMA_clearErrorFlag(DMA_CH1_BASE);
}
void Set_DMA_Config_RX()
{
DMADest = (volatile uint16_t *)rdata;
// configure DMACH2 for RX
//! Configures the DMA channel
DMA_configAddresses(DMA_CH2_BASE, DMADest, (SPIA_BASE+SPI_O_RXBUF));
//! Configures the DMA channel's burst settings.
DMA_configBurst(DMA_CH2_BASE, BURST, 0x0000, 0x0001);
//! Configures the DMA channel's transfer settings.
DMA_configTransfer(DMA_CH2_BASE, TRANSFER, 0x0000, 0x0001);
//! Disables the DMA channel overrun interrupt.
DMA_disableOverrunInterrupt(DMA_CH2_BASE);
//! Configures the DMA channel trigger and mode.
DMA_configMode(DMA_CH2_BASE, DMA_TRIGGER_SPIARX, DMA_CFG_SIZE_16BIT);
//! Enables a DMA channel interrupt source.
DMA_enableInterrupt(DMA_CH2_BASE);
//! Sets the interrupt generation mode of a DMA channel interrupt.
DMA_setInterruptMode(DMA_CH2_BASE, DMA_INT_AT_BEGINNING); /* DMA interrupt is generated at the end of a transfer */
//! Clears a DMA channel's peripheral trigger flag.
DMA_clearTriggerFlag(DMA_CH2_BASE);
//! Clears the DMA channel error flags.
DMA_clearErrorFlag(DMA_CH2_BASE);
}
//
// INTCH1_ISR - DMA Channel 1 ISR
//
__interrupt void DMACh1ISR(void)
{
//! Halts a DMA channel.
DMA_stopChannel(DMA_CH1_BASE);
//! Acknowledges PIE Interrupt Group
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
}
//
// INTCH2_ISR - DMA Channel 2 ISR
//
__interrupt void DMACh2ISR(void)
{
uint16_t i;
//! Halts a DMA channel.
DMA_stopChannel(DMA_CH2_BASE);
//! Acknowledges PIE Interrupt Group
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP7);
for( i = 0; i<128; i++ )
{
//
// check for data integrity
//
if(rdata[i] != i)
{
error();
}
}
done = 1; // test done.
return;
}
//
// error - Halt debugger when error received
//
void error(void)
{
asm(" ESTOP0"); //Test failed!! Stop!
for (;;);
}
#endif /* #ifndef DMA_INIT_C */
#ifndef SPI_INIT_C
#define SPI_INIT_C
//
// Included Files
//
#include "spi_init.h"
#include "driverlib.h"
#include "device.h"
volatile uint16_t sData[8]; // Send data buffer
volatile uint16_t rData[8]; // Receive data buffer
volatile uint16_t rDataPoint = 0; // To keep track of where we are in the
// data stream to check received data
uint16_t TG1_TX_DATA[8] = {0x0F00, 0x0F01, 0x0F02, 0x0F03, 0x0F04, 0x0F05, 0x0F06, 0x0F07};
spi_config config_spi_channelA={ SPIA_BASE,
DEVICE_LSPCLK_FREQ,
SPI_PROT_POL0PHA0,
SPI_MODE_MASTER,
500000,
16,
SPI_FIFO_TX8,
SPI_FIFO_RX8,
SPI_EMULATION_FREE_RUN,
};
spi_config config_spi_channelB={ SPIB_BASE,
DEVICE_LSPCLK_FREQ,
SPI_PROT_POL0PHA0,
SPI_MODE_SLAVE,
500000,
16,
SPI_FIFO_TX2,
SPI_FIFO_RX2,
SPI_EMULATION_FREE_RUN,
};
void setup_spi()
{
//
// Must put SPI into reset before configuring it
//
uint16_t i;
for(i = 0; i < 8; i++)
{
sData[i] = 0xAB;
rData[i]= 0;
}
//SPIA Module Init Master//
// SPI configuration. Use a 500kHz SPICLK and 16-bit word size.
SPI_disableModule(SPIA_BASE);
SPI_setConfig(config_spi_channelA.base, config_spi_channelA.lspclkHz, config_spi_channelA.protocol,config_spi_channelA.mode, config_spi_channelA.bitRate, config_spi_channelA.dataWidth);
SPI_disableLoopback(SPIA_BASE);
SPI_setEmulationMode(config_spi_channelA.base, config_spi_channelA.EmulationMode);
//
// FIFO and interrupt configuration
//
SPI_enableFIFO(config_spi_channelA.base);
SPI_clearInterruptStatus(config_spi_channelA.base, SPI_INT_RXFF | SPI_INT_TXFF);
SPI_setFIFOInterruptLevel(config_spi_channelA.base, config_spi_channelA.TxLevel, config_spi_channelA.RxLevel);
SPI_disableInterrupt(config_spi_channelA.base, SPI_INT_RXFF);
SPI_enableModule(config_spi_channelA.base); // Configuration complete. Enable the module.
//SPI Module B as slave.
//
// SPI configuration. Use a 500kHz SPICLK and 16-bit word size.
Interrupt_enable(INT_SPIB_TX);
Interrupt_enable(INT_SPIB_RX);
Interrupt_register(INT_SPIB_TX, &spiTxBFIFOISR);//todo
Interrupt_register(INT_SPIB_RX, &spiRxBFIFOISR);//todo
SPI_disableModule(config_spi_channelB.base);
SPI_setConfig(config_spi_channelB.base, config_spi_channelB.lspclkHz, config_spi_channelB.protocol,config_spi_channelB.mode, config_spi_channelB.bitRate, config_spi_channelB.dataWidth);
SPI_disableLoopback(SPIB_BASE);
SPI_setEmulationMode(config_spi_channelB.base, config_spi_channelB.EmulationMode);
//
// FIFO and interrupt configuration
//
SPI_enableFIFO(config_spi_channelB.base);
SPI_clearInterruptStatus(config_spi_channelB.base, SPI_INT_RXFF | SPI_INT_TXFF);
SPI_setFIFOInterruptLevel(config_spi_channelB.base, config_spi_channelB.TxLevel, config_spi_channelB.RxLevel);
SPI_disableInterrupt(config_spi_channelB.base, SPI_INT_RXFF);
// Configuration complete. Enable the module.
SPI_enableModule(config_spi_channelB.base);
}
// SPI A Transmit FIFO ISR
//
__interrupt void spiTxAFIFOISR(void)
{
uint16_t i;
//debug only #todo
GPIO_writePin(31u,0); /* temp debug only */
DEVICE_DELAY_US(10000); /* temp debug only */
GPIO_writePin(31u,1); /* temp debug only */
DEVICE_DELAY_US(50000); /* temp debug only */
//
// Send data
//
for(i = 0; i < 8; i++)
{
SPI_writeDataNonBlocking(SPIA_BASE, sData[i]);
}
//
// Increment data for next cycle
//
// for(i = 0; i < 2; i++)
// {
// sData[i] = sData[i]<<1;
// }
//
// Clear interrupt flag and issue ACK
//
SPI_clearInterruptStatus(SPIA_BASE, SPI_INT_TXFF);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);
}
//
// SPI A Receive FIFO ISR
//
__interrupt void spiRxAFIFOISR(void)
{
uint16_t i;
//
// Read data
//
for(i = 0; i < 2; i++)
{
rData[i] = SPI_readDataNonBlocking(SPIA_BASE);
}
//
// Check received data
//
for(i = 0; i < 2; i++)
{
if(rData[i] != (rDataPoint + i))
{
// Something went wrong. rData doesn't contain expected data.
//ESTOP0;
}
}
rDataPoint++;
//
// Clear interrupt flag and issue ACK
//
SPI_clearInterruptStatus(SPIA_BASE, SPI_INT_RXFF);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);
}
// SPI B Transmit FIFO ISR
//
__interrupt void spiTxBFIFOISR(void)
{
uint16_t i;
//debug only #todo
GPIO_writePin(31u,0); /* temp debug only */
DEVICE_DELAY_US(10000); /* temp debug only */
GPIO_writePin(31u,1); /* temp debug only */
DEVICE_DELAY_US(50000); /* temp debug only */
//
// Send data
//
for(i = 0; i < 8; i++)
{
SPI_writeDataNonBlocking(SPIB_BASE, sData[0]);
}
//
// Increment data for next cycle
//
// for(i = 0; i < 2; i++)
// {
// sData[i] = sData[i]<<1;
// }
//
// Clear interrupt flag and issue ACK
//
SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_TXFF);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);
}
//
// SPI B Receive FIFO ISR
//
__interrupt void spiRxBFIFOISR(void)
{
uint16_t i;
//
// Read data
//
for(i = 0; i < 2; i++)
{
rData[i] = SPI_readDataNonBlocking(SPIB_BASE);
}
//
// Check received data
//
for(i = 0; i < 2; i++)
{
if(rData[i] != (rDataPoint + i))
{
// Something went wrong. rData doesn't contain expected data.
//ESTOP0;
}
}
rDataPoint++;
//
// Clear interrupt flag and issue ACK
//
SPI_clearInterruptStatus(SPIB_BASE, SPI_INT_RXFF);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP6);
}
#endif