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.

TM4C123GXL (Tiva C ceries launchpad) PWM configuration problem

Hi,

I'am trying to configure PWM output to PD0 and PD1 ports, but nothing happens.

Any advices are appreciated (I am NOT using tivaware as this is an educational project)

Below is the code with my comments (mostly based on datasheet example; Keil IDE):

void WaitForInterrupt(void);  // low power mode

void PWM_Init(void){  
	SYSCTL_RCGCPWM_R |= 0x00000001; // activate PWM0 clock
	SYSCTL_RCGCGPIO_R |= 0x00000008; // activate port D clock  (PD0, PD1)
	while((SYSCTL_PRGPIO_R&0x00000008) == 0){}; // wait until port D is ready
	GPIO_PORTD_AFSEL_R |= 0x00000003;  // enable PD0 and PD1 pin alternative functionality
	GPIO_PORTD_PCTL_R &= ~0x000000FF;
	GPIO_PORTD_PCTL_R |= 0x00000044; // configure PD0 and PD1 as PWM0 (PWM6, PWM7)
	GPIO_PORTD_AMSEL_R &= ~0x00000003; // disable aternative functionality PD0 and PD1
	GPIO_PORTD_DEN_R |= 0x00000003; // enable i/o on PD0 and PD1
	SYSCTL_RCC_R |=0x00140000; // use USEPWMDIV and set divider PWMDIV to divide by 8 
//(alternatively: SYSCTL_RCC_R|=SYSCTL_RCC_USEPWMDIV; SYSCTL_RCC_R|=SYSCTL_RCC_PWMDIV_8;)

// Configuring of PWM generator for countdown mode with immediate updates to the parameters
	PWM0_3_CTL_R &= ~0x00000002; // count down mode (cleared second bit)
	PWM0_3_GENA_R |= 0x0000008C; // CMPA down, if counter=CMPA drive PWMA low, high if counter=LOAD
	PWM0_3_GENB_R |= 0x0000080C; // CMPB down, if counter=CMPB drive PWMB low, high if counter=LOAD
// 
	PWM0_3_LOAD_R |= 0x00008234; // period minus one i.e.  frequency 300Hz (3333.3uS), System clock divided by 8 (10MHz, 0.1uS), period=3333.3/0.1-1 
	PWM0_3_CMPA_R |= 0x0000014A; // ~1% duty cycle
	PWM0_3_CMPB_R |= 0x0000014A; // ~1% duty cycle
	PWM0_3_CTL_R |= 0x00000001; // start PWM Generator 3 timers
	PWM0_ENABLE_R |= 0x000000C0; // enable PWM output
}
	
int main(void){
	PLL_Init();           // bus clock at 80 MHz
	PWM_Init();           // activate PWM0 (PD0 and PD1)
  while(1){ 
    WaitForInterrupt(); // low power mode
  }
}

  • Hi Stanislav,

    I usualy just program in tivaware but i think you have missing the register to enable the PWM clock, equivalente to SysPeripheralEnable, altough you use other register to do that.

    Quoting from the datasheet:

    1. Enable the PWM clock by writing a value of 0x0010.0000 to the RCGC0 register in the System
    Control module (see page 456).
    2. Enable the clock to the appropriate GPIO module via the RCGC2 register in the System Control
    module (see page 464).

    Also take into considerantion that after enabling the clock, with RCGCx, or RCGCGPIO or RCGCPWM, you need to wait 3 system clocks before you acess any register from that module

    Hope it helped

  • Thanks for answer, however:

    1. RCG0 is used for legacy software support so RCGCPWM register is used instead.

    (Datasheet: This register should be used to control the clocking for the PWM modules. To support
    legacy software, the RCGC0 register is available.)

    Same with RCGCGPIO

    (Datasheet: This register should be used to control the clocking for the GPIO modules. To support
    legacy software, the RCGC2 register is available.)

    2. Delay is performed with while loop by polling PRGPIO register (if = 1 then ready for access)

    and enough time pass till I access PWM (I also checked this by polling SYSCTL_PRPWM_R0 bit, just to confirm my words; i.e. if=1 then ready)

    So the problem is definetely not in the things you mentioned above ...

  • Hello Stainslav,

    Since I did not have the PLL_Init function, I commented the same out and ran the same with the default PIOSC as system clock and it gives a PWM output on PD0 and PD1 of 7.42Hz and 99% DC

    The frequency is correct as the default clock is 16MHz for which you are dividing by 33332 and the PWMDIV which is being OR-ed will result in div of 64.

    Regards

    Amit

  • Hi Amit,

    Thanks, so it seems I have some wrong preferences in Keil logic analyzer in debugging mode as I see no current... so I will look for harware logic analyzer and check Keil preferences and/or will cry at their forum:)

    Below is PLL_Init() however it works fine (as I checked it before in other applications):

    #define SYSDIV2 4
    
    void PLL_Init(void){
      // 0) configure the system to use RCC2 for advanced features
      //    such as 400 MHz PLL and non-integer System Clock Divisor
      SYSCTL_RCC2_R |= SYSCTL_RCC2_USERCC2;
      // 1) bypass PLL while initializing
      SYSCTL_RCC2_R |= SYSCTL_RCC2_BYPASS2;
      // 2) select the crystal value and oscillator source
      SYSCTL_RCC_R &= ~SYSCTL_RCC_XTAL_M;   // clear XTAL field
      SYSCTL_RCC_R += SYSCTL_RCC_XTAL_16MHZ;// configure for 16 MHz crystal
      SYSCTL_RCC2_R &= ~SYSCTL_RCC2_OSCSRC2_M;// clear oscillator source field
      SYSCTL_RCC2_R += SYSCTL_RCC2_OSCSRC2_MO;// configure for main oscillator source
      // 3) activate PLL by clearing PWRDN
      SYSCTL_RCC2_R &= ~SYSCTL_RCC2_PWRDN2;
      // 4) set the desired system divider and the system divider least significant bit
      SYSCTL_RCC2_R |= SYSCTL_RCC2_DIV400;  // use 400 MHz PLL
      SYSCTL_RCC2_R = (SYSCTL_RCC2_R&~0x1FC00000) // clear system clock divider field
                      + (SYSDIV2<<22);      // configure for 80 MHz clock
      // 5) wait for the PLL to lock by polling PLLLRIS
      while((SYSCTL_RIS_R&SYSCTL_RIS_PLLLRIS)==0){};
      // 6) enable use of PLL by clearing BYPASS
      SYSCTL_RCC2_R &= ~SYSCTL_RCC2_BYPASS2;
    }