AnsweredAssumed Answered

LPC11U6x - DMA and SSP

Question asked by Chris Pflieger on Jun 2, 2020
Latest reply on Jul 1, 2020 by Chris Pflieger

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)

What am I doing wrong?

 

#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);
}

Outcomes