I've been banging my head on this for a couple weeks now...
I've followed Jeremy's Ping Pong ADC code, and that's what I want - just read in all the words from the MISO and store into to buffers. I don't care what is transmitted, it just needs to be continuous.
I actually got it transmitting from the buffers, but after the first eight words, it goes off the rails and transmits out of order (which is fine).
I can't get it to receive - if I call the SW trigger on the receiver, it transmits nine words, then seems to get stuck in the ISR with a IRQ's that won't clear. It fills buffer B with "6101" (tracer of the second word transmitted)
#define I2S_BUFFER_SIZE 16U
#define DMA_PDM_TX DMAREQ_SSP0_TX
#define DMA_PDM_RX SSP0_RX_DMA
#define PDM_SPI LPC_SSP0
/*
* Local Data
*/
static uint16_t incoming_buffer_a[I2S_BUFFER_SIZE];
static uint16_t incoming_buffer_b[I2S_BUFFER_SIZE];
// we're going to set them both up to ping-pong.
static DMA_CHDESC_T dmaTXDesc[2] __attribute__ ((aligned(16)));
static DMA_CHDESC_T dmaRXDesc[2] __attribute__ ((aligned(16)));
callback_pointer_t callback_ptr;
/*
* Global Function Definitions
*/
void DMA_IRQHandler(void)
{
Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_PDM_TX);
Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_PDM_RX);
if (callback_ptr)
{
callback_ptr(incoming_buffer_a);
}
/* Rrror interrupt on channel 0? */
if ((Chip_DMA_GetIntStatus(LPC_DMA) & DMA_INTSTAT_ACTIVEERRINT) != 0)
{
/* This shouldn't happen for this simple DMA example, so set the LED
to indicate an error occurred. This is the correct method to clear
an abort. */
Chip_DMA_DisableChannel(LPC_DMA, DMA_PDM_TX);
Chip_DMA_AbortChannel(LPC_DMA, DMA_PDM_TX);
Chip_DMA_ClearErrorIntChannel(LPC_DMA, DMA_PDM_TX);
Chip_DMA_EnableChannel(LPC_DMA, DMA_PDM_TX);
}
}
void i2s_init(callback_pointer_t callback)
{
DMA_CHDESC_T Initial_DMA_RX_Descriptor;
DMA_CHDESC_T Initial_DMA_TX_Descriptor;
unsigned int i;
callback_ptr = callback;
// we have no select line
Chip_IOCON_PinMuxSet(LPC_IOCON, SPI_SCK_PORT, SPI_SCK_PIN, SPI_SCK_FUNCT | IOCON_MODE_INACT | IOCON_DIGMODE_EN);
Chip_IOCON_PinMuxSet(LPC_IOCON, SPI_MOSI_PORT, SPI_MOSI_PIN, SPI_MOSI_FUNCT | IOCON_MODE_INACT | IOCON_DIGMODE_EN);
Chip_IOCON_PinMuxSet(LPC_IOCON, SPI_MISO_PORT, SPI_MISO_PIN, SPI_MISO_FUNCT | IOCON_MODE_INACT | IOCON_DIGMODE_EN);
// setup some markers to see what gets transmitted, and if anything is received.
for (i = 0; i < I2S_BUFFER_SIZE; i++)
{
incoming_buffer_a[i] = 0x6000 + 0x100 * i + i;
incoming_buffer_b[i] = 0xB000 + 0x100 * i + i;
}
// setup SPI
Chip_SSP_Init(PDM_SPI);
Chip_SSP_SetFormat(PDM_SPI, SSP_BITS_16, SSP_FRAMEFORMAT_SPI, SSP_CLOCK_MODE0);
Chip_SSP_Set_Mode(PDM_SPI, SSP_MODE_MASTER);
Chip_SSP_SetBitRate(PDM_SPI, PDM_BITRATE);
PDM_SPI->CR1 = 3; // added to set some mysterious bits that are
// in the manual, but not in the driver code.
// it didn't help. (or hurt)
Chip_SSP_Enable(PDM_SPI);
// turn on the DMA
Chip_DMA_Init(LPC_DMA);
Chip_DMA_Enable(LPC_DMA);
Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));
NVIC_SetPriority(DMA_IRQ_NUM, DMA_INTERRUPT_PRIORITY);
Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_PDM_TX);
Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMA_PDM_RX);
// first the receiver
dmaRXDesc[0].source = DMA_ADDR(&PDM_SPI->DR);
dmaRXDesc[0].dest = DMA_ADDR(incoming_buffer_a + sizeof(incoming_buffer_a) - 1);
dmaRXDesc[0].next = DMA_ADDR(&dmaRXDesc[1]);
dmaRXDesc[0].xfercfg = DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTA |
DMA_XFERCFG_SRCINC_0 | DMA_XFERCFG_DSTINC_1 |
DMA_XFERCFG_WIDTH_16 | DMA_XFERCFG_RELOAD |
DMA_CFG_CHPRIORITY(2) | DMA_XFERCFG_XFERCOUNT(I2S_BUFFER_SIZE);
dmaRXDesc[1].source = DMA_ADDR(&PDM_SPI->DR);
dmaRXDesc[1].dest = DMA_ADDR(incoming_buffer_b + sizeof(incoming_buffer_b) - 1);
dmaRXDesc[1].next = DMA_ADDR(&dmaRXDesc[0]);
dmaRXDesc[1].xfercfg = dmaRXDesc[0].xfercfg;
// I honestly don't understand the point of this, but I'm following the example.
Initial_DMA_RX_Descriptor.source = dmaRXDesc[0].source;
Initial_DMA_RX_Descriptor.dest = dmaRXDesc[0].dest;
Initial_DMA_RX_Descriptor.next = dmaRXDesc[0].next;
Initial_DMA_RX_Descriptor.xfercfg = dmaRXDesc[0].xfercfg;
Chip_DMA_EnableChannel(LPC_DMA, DMA_PDM_RX);
Chip_DMA_EnableIntChannel(LPC_DMA, DMA_PDM_RX);
/* Chip_DMA_SetupChannelConfig() seems to either do nothing, or in some cases break the process */
//Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_PDM_RX, DMA_CFG_HWTRIGEN | DMA_CFG_TRIGBURST_BURST |
// DMA_CFG_TRIGTYPE_EDGE | DMA_CFG_TRIGPOL_LOW |
// DMA_CFG_BURSTPOWER_1 | DMA_CFG_CHPRIORITY(0));
Chip_DMA_SetupTranChannel(LPC_DMA, DMA_PDM_RX, &Initial_DMA_RX_Descriptor);
Chip_DMA_SetupChannelTransfer(LPC_DMA, DMA_PDM_RX, dmaRXDesc[0].xfercfg);
Chip_DMA_SetValidChannel(LPC_DMA, DMA_PDM_RX);
// now the transmitter
dmaTXDesc[0].source = DMA_ADDR(incoming_buffer_a + I2S_BUFFER_SIZE - 1);
dmaTXDesc[0].dest = DMA_ADDR(&PDM_SPI->DR);
dmaTXDesc[0].next = DMA_ADDR(&dmaTXDesc[1]);
dmaTXDesc[0].xfercfg = DMA_XFERCFG_CFGVALID | DMA_XFERCFG_SETINTA |
DMA_XFERCFG_SRCINC_1 | DMA_XFERCFG_DSTINC_0 |
DMA_XFERCFG_WIDTH_16 | DMA_XFERCFG_RELOAD |
DMA_CFG_CHPRIORITY(1) | DMA_XFERCFG_XFERCOUNT(I2S_BUFFER_SIZE);
dmaTXDesc[1].source = DMA_ADDR(incoming_buffer_a + I2S_BUFFER_SIZE - 1);
dmaTXDesc[1].dest = DMA_ADDR(&PDM_SPI->DR);
dmaTXDesc[1].next = DMA_ADDR(&dmaTXDesc[0]);
dmaTXDesc[1].xfercfg = dmaTXDesc[0].xfercfg;
Initial_DMA_TX_Descriptor.source = dmaTXDesc[0].source;
Initial_DMA_TX_Descriptor.dest = dmaTXDesc[0].dest;
Initial_DMA_TX_Descriptor.next = dmaTXDesc[0].next;
Initial_DMA_TX_Descriptor.xfercfg = dmaTXDesc[0].xfercfg;
Chip_DMA_EnableChannel(LPC_DMA, DMA_PDM_TX);
Chip_DMA_DisableIntChannel(LPC_DMA, DMA_PDM_TX); // We don't want a transmitter DMA interrupt.
/* Enabling either of the following lines will break the transmitter. Why ? I don't care. */
//Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_PDM_TX, (DMA_XFERCFG_CFGVALID | DMA_XFERCFG_RELOAD | DMA_XFERCFG_SETINTA | DMA_XFERCFG_WIDTH_16 | DMA_XFERCFG_SRCINC_0 | DMA_XFERCFG_DSTINC_1 | DMA_XFERCFG_XFERCOUNT(128)));
//Chip_DMA_SetupChannelConfig(LPC_DMA, DMA_PDM_TX, (DMA_CFG_PERIPHREQEN | DMA_CFG_TRIGBURST_SNGL | DMA_CFG_CHPRIORITY(3)));
Chip_DMA_SetupTranChannel(LPC_DMA, DMA_PDM_TX, &Initial_DMA_TX_Descriptor);
Chip_DMA_SetupChannelTransfer(LPC_DMA, DMA_PDM_TX, dmaTXDesc[0].xfercfg);
Chip_DMA_SetValidChannel(LPC_DMA, DMA_PDM_TX);
/* Enable the DMA IRQ */
NVIC_EnableIRQ(DMA_IRQn);
// making this call causes the tx to stop, and an endless IRQ loop.
//Chip_DMA_SWTriggerChannel(LPC_DMA, DMA_PDM_RX);
// This call is essential
Chip_DMA_SetTrigChannel(LPC_DMA, DMA_PDM_TX);
}