This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

USB Integrated DMA Controller on EK-TM4C129XL

Other Parts Discussed in Thread: TM4C1294NCPDT

Hey all,

I have made some modifications to the usbdcdc.c example code from the Tivaware USB Library to add bulk DMA transfer functionality. The transfers are working correctly and all is well.

My only problem currently is that I cannot figure out which interrupt service routine is being called for when the DMA transfer is complete. I set up the DMA transfer according to section 21.3.6.3 of the TM4C1294NCPDT datasheet where it talks about using DMA transfers with bulk endpoints.

From the datasheet:

"

The DMA controller should be programmed to perform a burst DMA read of the maximum size

of packet for the endpoint (512 bytes for high speed, 64 bytes for full speed) when the DMA

request line for the endpoint transitions from low to high. The controller should keep performing

these burst reads on each DMA request until the entire data block has been transferred. (The

last burst may however be of less than the maximum packet size). It should then interrupt the

CPU.

"

I have been looking everywhere and it is unclear where/when the DMA peripheral interrupts the CPU. If someone could point me in the right direction that would be great!


Cheers,

Bryan

 

 

  • Update,

    I have actually worked out what seems to be sort of a hack. It might work but it doesn't seem like it is the right thing to do. In usbhandler.c in USB Library I modified the code as such:

    void USB0DeviceIntHandler(void) {
    	uint32_t ui32Status;
    	uint32_t ui32DMAChIntStatus = 0;
    	//
    	// Get the controller interrupt status.
    	//
    	ui32Status = MAP_USBIntStatusControl(USB0_BASE);
    	ui32DMAChIntStatus = USBDMAChannelIntStatus(USB0_BASE);
    	if (ui32DMAChIntStatus) {
    		SysTickDisable();
    	}
    
    	//
    	// Call the internal handler.
    	//
    	USBDeviceIntHandlerInternal(0, ui32Status);
    }

    The systickdisable call is to stop a timer I have that I am using to time the data transfer. I am using DMA Channel 3 and for some reason if I use the condition USB_DMA_INT_CH3 I do not enter the if statement. For some reason I am also unable to put a watch expression on ui32DMAChIntStatus, which is quite frustrating. Right now my timer is telling me it takes around 400uS to transmit 8192 bytes of data over USB HS, which is believable but I need to know for sure.

  • Hello Bryan,

    Are there multiple DMA channels being enabled?

    Regards
    Amit
  • Hello Amit,

    I am only enabling DMA Channel 3. Is there a chance I am using the wrong token to check for DMA Channel 3 Interrupt? I looked at the define and it is 0x04

    Regards,
    Bryan
  • Hi again Amit,

    I was able to fix my issue with adding a watch expression for the status of the register. It looks to be the case that there is a discrepancy in the way the USB_DMAINTR register is indexed and the way that the tokens for determining the interrupt that was triggered. I have attached some screenshots below showing the issue.

    Regards,

    Bryan

  • Hello Bryan,

    The interrupt is cleared on read, hence the watchpoint may not be returning any status as the USBDMAInterruptStatus would have already cleared the register. You may want to check the interrupt status read before it or the variable value as well.

    Regards
    Amit
  • Hello Amit,

    Good suggestions, but the problem with the watchpoint was not that it was reporting zero. It seems there is an issue related to CCS that doesn't allow the setting of watchpoint's for certain expressions. It said that it was unable to recognize the expression so I moved the variable to be a global variable within usbhandler.c and I was able to see the variable and confirm the issue.

    It would be nice to have a breakpoint on the line of code right before USBDMAInterruptStatus, but the USB handler actually gets called quite often during the setup of the device and it causes strange issues with passing descriptors to windows when I spend too much time stepping through and waiting for the interrupt to be related to DMA.

    Cheers,

    Bryan

  • Hello Bryan

    So the issue was with the variable reading 0x0?

    Regards
    Amit
  • Hello Amit,

    Here is a screenshot of the issue with assigning a watchpoint to the value of the DMA Interrupt register:

    Cheers,

    Bryan

  • Hello Bryan,

    Can you check the Variables Tab?

    Regards
    Amit
  • Hello Amit,

    Only the variable ui32Status shows up in the variables tab. I have already "resolved" the issue by putting the declaration of ui32DMAChIntStatus to a larger scope than just the usbhandler function.

    Regards,
    Bryan
  • Hello Bryan

    But I sill do not see the value of the ui32DMAChIntStatus in the CCS snapshot

    Regards
    Amit
  • Hello Amit,

    I am sorry I think we have a misunderstanding. I already noted that I am able to see the value of ui32DMAChIntStatus at this point. I thought you wanted to see the issue I was having with setting a watchpoint for the variable. I just took away the modifications I made to my code to reproduce the error and show it to you.

    The issue I was having earlier was solved because I was trying to stop the timer when the DMA Interrupt status was "USB_DMA_INT_CH3" when I should have been using "USB_DMA_INT_CH4". For some reason as per the first screenshot I posted, the Tivaware library defines the interrupt status tokens with a 1-based index so it goes from DMA channel 1 to DMA channel 8. The actual case is that there are DMA channels 0 through 7.

    Because of this, it is required to use the token "USB_DMA_INT_CH4" to check for the DMA interrupt for DMA channel 3. I was able to confirm this by fixing the watchpoint and observing that the hex code on the interrupt was 0x08 which corresponds to the token USB_DMA_INT_CH4.

    Regards,
    Bryan
  • Hello Bryan,

    OK, yes there was a confusion and that you are right that the DMA channels 0 to 7 have been defined as 1 to 8 in the define.

    Regards
    Amit
  • Hello All,

    I have revisited this code because it seems to have stopped behaving reliably. Sometimes when I initiate USB DMA Transfers, I am not ever interrupted when the DMA Transfer has completed. It might be the case that the interrupt status register for DMA transfers is getting cleared by a function that I am not aware of.

    Is there a way to register an interrupt handler to specifically deal with USB DMA Interrupts?

    Right now my interrupt handling for USB DMA Interrupts is handled within the following function below:

    void USB0DeviceIntHandler(void) {
    	uint32_t ui32Status;
    	uint32_t ui32DMAChIntStatus = 0;
    
    	//
    	// Get the controller interrupt status.
    	//
    	ui32Status = MAP_USBIntStatusControl(USB0_BASE);
    
    	// Set pending transmission as complete
    	ui32DMAChIntStatus = USBDMAChannelIntStatus(USB0_BASE);
    	if (ui32DMAChIntStatus)
    	{
    		usbDMADisable();
    	}
    
    	//
    	// Call the internal handler.
    	//
    	USBDeviceIntHandlerInternal(0, ui32Status);
    }

    Any help is greatly appreciated!

    Thanks,

    Bryan

  • Hello Bryan,

    I am tracking the following two forum posts for USB and DMA operations

    e2e.ti.com/.../489701
    e2e.ti.com/.../491095

    and it looks like the USB DMA SW integration may have a bug.

    Regards
    Amit
  • Hello Amit,

    Do you know if there is a way to check the device's registers to see if the DMA Transfer has completed? That is all I really need to know. Really I would like to know whether there is any other way besides using the USBDMAChannelIntStatus function to check if a configured DMA transfer is complete.

    Cheers,

    Bryan

  • Hello Bryan,

    I don't think so that there is any other way of getting the interrupt status.

    Regards
    Amit
  • Hey Amit,

    I was able to make my code more robust by editing usbdenum.c. I edited the function USBDeviceIntHandlerInternal to handle the call to USBDMAChannelIntStatus according to how I set up my DMA transfer. Before, the call to check the interrupt status was being called in the internal ISR for the USB and it was clearing it when I was not looking.

    Kindest Regards,

    Bryan

  • When a DMA channel completes, XFERMODE  (bits 0,1 & 2) of the associated DMA channel control word go to zero. This is a direct indication that the DMA channel has stopped. In document number spms433b this is detailed on page 708.

    Is that any use to you Bryan?

  • Hello Pete,

    Not on the TM4C129x device. The DMA controller is embedded in the USB and uses the USB Master port to access the buffers.

    Regards
    Amit
  • Oops.... I read TM4C1294.