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.

TM4C123GH6PM: TM4C123G DMA+PWM

Part Number: TM4C123GH6PM

I need to generate PWM signal with timer and modulate it by my signal so I decided to use DMA. Unfortunately I found out that DMA transaction doesn't occur by PWM event. I made an example project which shows a problem. In this project DMA controls GPIO pin (just for example) and it only works if I use TIMER_CFG_PERIODIC mode of the timer. If I choose TIMER_CFG_A_PWM DMA transactions never happend (interrupt never occurs). Could you tell me is there any problem in my code or it's just a feature of the processor?

#include <stdint.h>
#include <stdbool.h>
#include "stdlib.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_uart.h"
#include "inc/hw_gpio.h"
#include "inc/hw_types.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/udma.h"
#include "driverlib/timer.h"
#include "driverlib/gpio.h"
#include <string.h>


#define GPIO_BASE_OUTPUT1 GPIO_PORTF_BASE
#define GPIO_PERIPH_OUTPUT1 SYSCTL_PERIPH_GPIOF

void InituDMA(void);
void InitGPIO(void);
void InitTimer(void);
void setup();
void loop(void);
void TimerInt(void);


//Saves the system clk
volatile uint32_t g_ui32SysClock;

//Array to save the GPIO states
static uint32_t OutputState[4] = {0x00000002, 0x00000000, 0x00000000, 0x00000002};
static uint32_t OutputState2[4] = {0x00000002, 0x00000000, 0x00000002, 0x00000000};



//*****************************************************************************
//
// The control table used by the uDMA controller.  This table must be aligned
// to a 1024 byte boundary.
//
//*****************************************************************************

#pragma data_alignment=1024
uint8_t DMAcontroltable[1024];

/*
  After 4 transfers the DMA is done and calls this interrupt
  This is to reset the DMA and re-enable it
*/
void TimerInt(void)
{
    TimerIntClear(TIMER3_BASE, TIMER_TIMA_DMA);
    
	if(uDMAChannelModeGet(UDMA_CH2_TIMER3A | UDMA_PRI_SELECT) == UDMA_MODE_STOP)
	{
		//Set again the same source address and destination
		uDMAChannelTransferSet(UDMA_CH2_TIMER3A | UDMA_PRI_SELECT,
			UDMA_MODE_PINGPONG,
			OutputState, (void *)(GPIO_BASE_OUTPUT1 + 0x03FC),
			4);
	}
	if(uDMAChannelModeGet(UDMA_CH2_TIMER3A | UDMA_ALT_SELECT) == UDMA_MODE_STOP)
	{
		uDMAChannelTransferSet(UDMA_CH2_TIMER3A | UDMA_ALT_SELECT,
			UDMA_MODE_PINGPONG,
			OutputState2, (void *)(GPIO_BASE_OUTPUT1 + 0x03FC),
			4);
	}
  
    //Always needed since after it's done the DMA is disabled
	uDMAChannelEnable(UDMA_CH2_TIMER3A);
}

/*
  Function to setup the DMA
*/
void InituDMA()
{

  //Just disable to be able to reset the peripheral state
  SysCtlPeripheralDisable(SYSCTL_PERIPH_UDMA);
  SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA);
  SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);

  SysCtlDelay(10);

  uDMAEnable();

  uDMAControlBaseSet(DMAcontroltable);
  
/*
 * This is for seting up the GPIO_BASE_OUTPUT1 with CH2 TimerA
 */
  
  //Set the channel trigger to be Timer3A
  uDMAChannelAssign(UDMA_CH2_TIMER3A);

  //Disable all the atributes in case any was set
  uDMAChannelAttributeDisable(UDMA_CH2_TIMER3A,
  //UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
	UDMA_ATTR_USEBURST |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK);

  /*
    This sets up the item size to 8bits, source increment to 8bits
    and destination increment to none and arbitration size to 1
  */
  uDMAChannelControlSet(UDMA_CH2_TIMER3A | UDMA_PRI_SELECT,
  UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_NONE |
    UDMA_ARB_1);
  
  uDMAChannelControlSet(UDMA_CH2_TIMER3A | UDMA_ALT_SELECT,
  UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_NONE |
    UDMA_ARB_1);

  /*
    This will setup the transfer mode to basic, source address to the array we want
    and destination address to the GPIO state we chosed. It also sets the total transfer
    size to 2.
  */
  uDMAChannelTransferSet(UDMA_CH2_TIMER3A | UDMA_PRI_SELECT,
    UDMA_MODE_PINGPONG,
    OutputState, (void *)(GPIO_BASE_OUTPUT1 + 0x03FC),
    4);
  
  uDMAChannelTransferSet(UDMA_CH2_TIMER3A | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG,
    OutputState2, (void *)(GPIO_BASE_OUTPUT1 + 0x03FC),
    4);


  //Enable the DMA chanel
  uDMAChannelEnable(UDMA_CH2_TIMER3A);
}

/*
  This is to set all the pins of the GPIO chosen to output
*/
void InitGPIO()
{
    SysCtlPeripheralDisable(GPIO_PERIPH_OUTPUT1);
    SysCtlPeripheralReset(GPIO_PERIPH_OUTPUT1);
    SysCtlPeripheralEnable(GPIO_PERIPH_OUTPUT1);
    SysCtlDelay(10);

    GPIOPinTypeGPIOOutput(GPIO_BASE_OUTPUT1, GPIO_PIN_1);
	GPIOPinWrite(GPIO_BASE_OUTPUT1, GPIO_PIN_1, 0);
}

/*
  Function to setup the timer to count down periodic with 1 second period.
  It also enables the DMA trigger and the event to timeout (counter reach 0)
*/
void InitTimer()
{
	SysCtlPeripheralDisable(SYSCTL_PERIPH_TIMER3); 
	SysCtlPeripheralReset(SYSCTL_PERIPH_TIMER3);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER3);    
	SysCtlDelay(10);
	
	
	TimerConfigure(TIMER3_BASE, TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PWM);//TIMER_CFG_PERIODIC); // Periodic works fine
	TimerLoadSet(TIMER3_BASE, TIMER_A, 2499);
	TimerMatchSet(TIMER3_BASE, TIMER_A, 800);

	TimerIntClear(TIMER3_BASE, TIMER_TIMA_DMA);
	TimerIntRegister(TIMER3_BASE, TIMER_A, TimerInt);
	TimerIntEnable(TIMER3_BASE, TIMER_TIMA_DMA);

	TimerDMAEventSet(TIMER3_BASE, TIMER_DMA_TIMEOUT_A);
}

void main()
{
	//Set CLK to ~80Mhz
	g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_20MHZ |
    	SYSCTL_OSC_MAIN | 
		SYSCTL_USE_PLL |
    	SYSCTL_CFG_VCO_480), 80000000);

	InitTimer();
	InitGPIO();
	InituDMA();
  
	//Enable the timer to start counting
	TimerEnable(TIMER3_BASE, TIMER_A); 

	//Infinite loop and just watch the pins toggle
	while(true)
	{

	}
}