AnsweredAssumed Answered

DMA on M4 causing USB and Ethernet to Hang On Linux (A5)

Question asked by James Seelbach on Oct 12, 2017
Latest reply on Nov 6, 2017 by James Seelbach

Hi everyone,

 

I am facing an issue where the M4 (Running MQX) is running a DMA operation that appears to stop the USB and Ethernet peripherals from working correctly in the Linux environment on the A5.  While this particular DMA is running, these devices seem to 'hang' and don't indicate to Linux that they have received data even through they have.

 

The DMA operation that appears to cause the issue is running on the M4.  The operation is sending a table of 512 values to a Port Toggle Output Register in order to toggle GPIO values over a period of time.  The DMA is set up using DMA1 channel 31.  The request source is selected as 24 (Flex Timer Module 0 Channel 0).  This timer is configured to 'pace' the DMA of these 512 bytes within a window of time that these GPIO signals should occur in.  Once the DMA is complete, it will be manually initiated again repeatedly (about 600-2000 times).

 

The DMA is set up using the following code:

 

...

static DMA_CHANNEL_HANDLE transferChannel;

...

void dmaInit(void){
   uint32_t ret;

 

   ret = dma_channel_claim(&transferChannel, 31);

 

 

   ret = dma_channel_setup(transferChannel, 1, 0);

 

 

   ret = dma_request_source(transferChannel, 24);

}

 

 

The DMA process is started using the following function:

...

static DMA_TCD transferDescriptor;

...

void startPrintingDMA(){
   transferDescriptor.DST_ADDR = (uint32_t) address_of_Port_Toggle_Output_Register;
   transferDescriptor.SRC_WIDTH = 1;
   transferDescriptor.SRC_MODULO = 0;
   transferDescriptor.SRC_OFFSET = 1;
   transferDescriptor.DST_MODULO = 0;
   transferDescriptor.DST_OFFSET = 0;
   transferDescriptor.DST_WIDTH = 1;
   transferDescriptor.LOOP_BYTES = 1;
   transferDescriptor.LOOP_COUNT = 512;
   transferDescriptor.LOOP_SRC_OFFSET = 0;
   transferDescriptor.LOOP_DST_OFFSET = 0;

   dma_transfer_submit(transferChannel, &transferDescriptor, NULL);

   dmaEnable();
}

 

Then it is repeated over and over by calling dmaEnable() repeatedly.

 

void dmaEnable(){
   DMA_SADDR_REG(DMA1_BASE_PTR, 31) = (uint32_t)((uint32_t *)address_of_source_table);
   DMA_DADDR_REG(DMA1_BASE_PTR, 31) = (uint32_t) address_of_Port_Toggle_Output_Register;
   DMA_SERQ_REG(DMA1_BASE_PTR) = 31;
}

 

The flexTimer module 0 channel 0 is configured to tick about every 0.50 ms or slower.

This DMA transfer is performed about 600-2000 times back to back.  

 

During this DMA on the M4, a hang issue is seen on Linux running on the A5.  The USB and Ethernet interfaces do not respond on a poll() system call event until the DMA completes (All of the DMA cycles since it is restarted about 600-2000 times as mentioned earlier).  Enabling debug messages for the gadget driver being used on the USB, this 'hang' time during the DMA is apparent at a driver level as well.

 

The M4 has another DMA operation (For the SPI using request source 15) that does not appear to cause this issue when run under similar circumstances.  This DMA is much faster since it is using "SPI1 Transmit" as the request source).  This DMA is executed about every 0.25 ms or slower and is intended to write data to the SPI interface.

 

Please let me know what further information I could provide that would help with this issue.

 

Thanks,

 

James

Outcomes