USB Communication Breaks When Enabling DMA Channel

jdotson8

New member
I am building a device using the Teensy 4.1 that continuously reads data over USB from a client program on another device, does some processing, and then outputs that data to an OLED display. I previously had a version of this working that used direct writes to the GPIO registers to send data to the display. It didn't leave enough processor time for all of the incoming data so I have been trying to adopt DMA. I got DMA working with the display using sample data stored in memory, but when I try to send data to the Teensy, my client hangs trying to connect to the port. It seems this only happens as soon as I call dmaChannel.enable().

The client program is currently a very basic sketch in Processing using the Serial library.

My DMA configuration borrows heavily from miciwan's DMA output example here.

Code:
// Configure DMA channel
    dmaChannel.begin();
    dmaChannel.sourceBuffer(dmaBuffer, WIDTH * HEIGHT * sizeof(unsigned int));
    dmaChannel.destination(GPIO1_DR);
  dmaChannel.interruptAtHalf();
    dmaChannel.interruptAtCompletion();
    dmaChannel.attachInterrupt(loadDMABuffer);

  // set the IOMUX mode to 3, to route it to FlexPWM
    IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_06 = 1;

    // setup flexPWM to generate clock signal on pin 4
    FLEXPWM2_MCTRL        |= FLEXPWM_MCTRL_CLDOK(1);

    FLEXPWM2_SM0CTRL     = FLEXPWM_SMCTRL_FULL | FLEXPWM_SMCTRL_PRSC(0);
    FLEXPWM2_SM0CTRL2     = FLEXPWM_SMCTRL2_INDEP | FLEXPWM_SMCTRL2_CLK_SEL(0);            // wait enable? debug enable?
    FLEXPWM2_SM0INIT     = 0;
    FLEXPWM2_SM0VAL0     = 0;                                    // midrange value to position the signale
    FLEXPWM2_SM0VAL1     = 16;                                    // max value
    FLEXPWM2_SM0VAL2     = 0;                                    // start A
    FLEXPWM2_SM0VAL3     = 8;                                // end A
    FLEXPWM2_OUTEN        |= FLEXPWM_OUTEN_PWMA_EN(1);

    FLEXPWM2_SM0TCTRL     = FLEXPWM_SMTCTRL_PWAOT0;

    FLEXPWM2_MCTRL        |= FLEXPWM_MCTRL_LDOK(1);
    FLEXPWM2_MCTRL        |= FLEXPWM_MCTRL_RUN(1);

    // clock XBAR
    CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
   
    // Tell XBAR to dDMA on Falling edge
    // DMA will output next data piece on falling edge
    // so the client can receive it on rising
    XBARA1_CTRL0 = XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(2) | XBARA_CTRL_DEN0;
   
    // connect the clock signal to DMA_CH_MUX_REQ30
    xbarConnect(XBARA1_IN_FLEXPWM2_PWM1_OUT_TRIG0, XBARA1_OUT_DMA_CH_MUX_REQ30);
   
    // trigger our DMA channel at the request from XBAR
    dmaChannel.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_0);

  dmaChannel.enable();

How can I get USB Serial and output DMA to work at the same time?
 
Some further reading seems to indicate that all DMA channels share a bus and cannot be run concurrently. I’m not sure if I’m understanding this correctly since that would seem to limit the usefulness of having multiple DMA channels. Since Serial is also using DMA, I suppose this could be the reason it is blocked? If that is the case, are there any other ways I can read data over USB without using DMA or anything else that would cause bus contention? I need about 4 MB/s.
 
Last edited:
It's more likely to be a case of one interrupt blocking others - what is the loadDMABuffer function doing? You really need to post a complete sample if you expect people to offer insight.
 
Ah, pretty big oof on my part. Looks like I was forgetting to clear the interrupt on the DMA channel from that interrupt handler. Thanks for quickly pointing me in the right direction!

Code:
dmaChannel.clearInterrupt();    // tell system we processed it.
asm("DSB");                        // this is a memory barrier
 
Back
Top