lpcware

Pin-Interrupt triggered DMA needs Flag-Reset

Discussion created by lpcware Employee on Jun 15, 2016
Content originally posted in LPCWare by TheBird on Thu Jan 07 03:42:05 MST 2016
Dear all

I'm new on this Forum and on ARM-Microcontrollers. So far I have programmed PIC-Microcontrollers. I hope that someone can help me =)

project description
I have to akquire data from an external ADC via SPI. I have the LPCXpresso824-MAX eval-board. The ADC sample-rate is up to 1MSPs at 16Bit Data-with.
This ADC start the Analog-digital-conversion after a digital signal, generated by PWM. After the Confersion the ADC offers a rising edge on a different digital line (called ADC_INT) to signal that data is available. After this signal i have to initiate a 16bit SPI conversion.

approach
I want to use the ADC_INT signal to trigger an DMA-Channel who will initiate a SPI-Write. After that, another DMA-Channel have to store the SPI-Data to the RAM

implementation
For the first step i wanted to send a 'X' by USART over a PININT-Triggered DMA.
This works by the attached code below.

My problem is that i need to clear the LPC_PININT->IST Interrupt flag after each external interrupt.

So i tryed to disable the PinInterrupt by outcomment "Chip_PININT_SetPinModeEdge(LPC_PININT, PININTCH0);" and
"Chip_PININT_EnableIntLow(LPC_PININT, PININTCH0);" . After that the DMA-trigger will not be fired.

If i enable the interrupt, but dont clear the Interrupt-Flag the DMA-trigger will be fired once.

I hope that anyone can explain me how to use the DMA-Controller without clearing the LPC_PININT->IST Interrupt-Flag.

With best regards
TheBird


#include <string.h>
#include "board.h"

/*****************************************************************************
* Private types/enumerations/variables
****************************************************************************/
#ifdef __ICCARM__
#define ALIGNSTR(x) # x
#define ALIGN(x) _Pragma(ALIGNSTR(data_alignment = ## x))
#else
#define ALIGN(x) __attribute__ ((aligned(x)))
#endif


/* DMA descriptors must be aligned to 16 bytes */
ALIGN(16) static DMA_CHDESC_T dmaTXDesc[8];

#define UART_TX_PIN 6
#define UART_RX_PIN 0

char DMASEN = 'X';

/*****************************************************************************
* Public types/enumerations/variables
****************************************************************************/

/*****************************************************************************
* Private functions
****************************************************************************/

/* Clear an error on a DMA channel */
static void dmaClearChannel(DMA_CHID_T ch) {
    Chip_DMA_DisableChannel(LPC_DMA, ch);
    while ((Chip_DMA_GetBusyChannels(LPC_DMA) & (1 << ch)) != 0) {
    }

    Chip_DMA_AbortChannel(LPC_DMA, ch);
    Chip_DMA_ClearErrorIntChannel(LPC_DMA, ch);
}

/*****************************************************************************
* Public functions
****************************************************************************/

/**
* @brief   DMA Interrupt Handler
* @return  None
*/
void DMA_IRQHandler(void) {
    uint32_t errors, pending;

    /* Get DMA error and interrupt channels */
    errors = Chip_DMA_GetErrorIntChannels(LPC_DMA);
    pending = Chip_DMA_GetActiveIntAChannels(LPC_DMA);

    /* Check DMA interrupts of UART 0 TX channel */
    if ((errors | pending) & (1 << DMAREQ_USART0_TX)) {
        /* Clear DMA interrupt for the channel */
        Chip_DMA_ClearActiveIntAChannel(LPC_DMA, DMAREQ_USART0_TX);

        /* Handle errors if needed */
        if (errors & (1 << DMAREQ_USART0_TX)) {
            /* DMA error, channel needs to be reset */
            dmaClearChannel(DMAREQ_USART0_TX);
        }
    }

    Board_LED_Toggle(2); //Visualize DMA-Interrupt
}

///**
// * @brief Handle interrupt from PININT0
// * @return    Nothing
// */
void PIN_INT0_IRQHandler(void) {
    Chip_PININT_ClearIntStatus(LPC_PININT, PININTCH0); //Clear Pin-Interrupt-Status-Flag
    Board_LED_Toggle(0);    //Visualize PinInterrupt
}

/**
* @brief   Main UART/DMA program body
* @return  Does not exit
*/int main(void) {
    int i = 0;
    char tmp[64];
    SystemCoreClockUpdate();
    Board_Init();

    sprintf(tmp, "%c[2J", 27);   //Clear Screen
    Board_UARTPutSTR(tmp);

    sprintf(tmp, "Board Initialized\r\n");
    Board_UARTPutSTR(tmp);

    //========= Initialize UART for DMA ==============================

    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM); //Enable the clock to the Switch Matrix

    /* Disable the fixed pins assigned to 0 and 6 */
    Chip_SWM_DisableFixedPin(SWM_FIXED_ACMP_I1);
    Chip_SWM_DisableFixedPin(SWM_FIXED_ADC1);

    /* Connect the U0_TXD_O and U0_RXD_I signals to port pins (see define above) */
    Chip_SWM_MovablePinAssign(SWM_U0_TXD_O, UART_TX_PIN);
    Chip_SWM_MovablePinAssign(SWM_U0_RXD_I, UART_RX_PIN);

    /* Disable the clock to the Switch Matrix to save power */
    Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_SWM);

    /* Configure UART-Module */
    Chip_UART_Init(LPC_USART0);
    Chip_UART_ConfigData(LPC_USART0, UART_CFG_DATALEN_8 | UART_CFG_PARITY_NONE | UART_CFG_STOPLEN_1);
    Chip_UART_SetBaud(LPC_USART0, 115200);
    Chip_UART_Enable(LPC_USART0);
    Chip_UART_TXEnable(LPC_USART0);

    //========= GPIO-Interrupt for Wake-Up-Switch (PIO0_4) =====================
    Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_SWM);
    Chip_SWM_DisableFixedPin(SWM_FIXED_ADC11);
    Chip_GPIO_SetPinDIRInput(LPC_GPIO_PORT, 0, 4); //!< Configure GPIO pin as input pin
    Chip_SYSCTL_SetPinInterrupt(0, 4); //!< Configure interrupt channel 0 for the GPIO pin in SysCon block
    Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_SWM);

    /* Configure channel 1 interrupt as edge sensitive and falling edge interrupt */
    Chip_PININT_SetPinModeEdge(LPC_PININT, PININTCH0);
    Chip_PININT_EnableIntLow(LPC_PININT, PININTCH0);

    NVIC_EnableIRQ(PIN_INT0_IRQn);  //Enable PIN-Interrupt

    //========= Configure DMA Support for UART-TX ==============================
    Chip_DMA_Init(LPC_DMA);

    /* Map PINT0 to DMA_USART0_TX */
    Chip_DMATRIGMUX_SetInputTrig(LPC_DMATRIGMUX, DMAREQ_USART0_TX, DMATRIG_PINT0);

    /* Enable DMA controller and use driver provided DMA table for current descriptors */
    Chip_DMA_Enable(LPC_DMA);
    Chip_DMA_SetSRAMBase(LPC_DMA, DMA_ADDR(Chip_DMA_Table));

    /* Create a descriptor for the data */
    dmaTXDesc[0].source = DMA_ADDR(&DMASEN);            // Write DMASEN
    dmaTXDesc[0].dest = DMA_ADDR(&LPC_USART0->TXDATA);  // To USART0_TX
    dmaTXDesc[0].xfercfg = DMA_XFERCFG_CFGVALID | DMA_XFERCFG_RELOAD | DMA_XFERCFG_CLRTRIG | DMA_XFERCFG_WIDTH_8 | DMA_XFERCFG_SRCINC_0 | DMA_XFERCFG_DSTINC_0 | DMA_XFERCFG_XFERCOUNT(1); // Just 1 value
    dmaTXDesc[0].next = DMA_ADDR(&(dmaTXDesc[0]));

    /* Setup transfer descriptor and validate it */
    Chip_DMA_SetupTranChannel(LPC_DMA, DMAREQ_USART0_TX, &dmaTXDesc[0]);

    /* Setup data transfer */
    Chip_DMA_SetupChannelTransfer(LPC_DMA, DMAREQ_USART0_TX, dmaTXDesc[0].xfercfg);

    /* Setup DMA UART TX support*/
    Chip_DMA_EnableChannel(LPC_DMA, DMAREQ_USART0_TX);    //Enable Channel 1
    Chip_DMA_EnableIntChannel(LPC_DMA, DMAREQ_USART0_TX); //Enable DMA Interrupt for Channel 1
    Chip_DMA_SetupChannelConfig(LPC_DMA, DMAREQ_USART0_TX, DMA_CFG_HWTRIGEN | DMA_CFG_TRIGPOL_HIGH | DMA_CFG_TRIGTYPE_EDGE | DMA_CFG_TRIGBURST_SNGL | DMA_CFG_CHPRIORITY(2));

    Chip_DMA_SetChannelValid(LPC_DMA, DMAREQ_USART0_TX);

    NVIC_EnableIRQ(DMA_IRQn);   //Enable DMA-Interrupt

    //========= Print Debug-Informations ==============================
    sprintf(tmp, "Application started\r\n");
    Board_UARTPutSTR(tmp);

    sprintf(tmp, "System Clock: %uMHz\r\n", (uint) (SystemCoreClock / 1000000));
    Board_UARTPutSTR(tmp);

    sprintf(tmp, "Main Clock: %uMHz\r\n", (uint) (Chip_Clock_GetMainClockRate() / 1000000));
    Board_UARTPutSTR(tmp);

    sprintf(tmp, "Device ID: 0x%04X\r\n", (uint) Chip_SYSCTL_GetDeviceID());
    Board_UARTPutSTR(tmp);


    while (1) {
        //Blink a LED to visualise th
            if (i++ > 1000000) {
            Board_LED_Toggle(1);
            i = 0;
        }
        //Chip_PININT_ClearIntStatus(LPC_PININT, PININTCH0);
        asm("NOP");

    }
}

Outcomes