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.

PMW problem on Tiva TM4C123H6GPM

Hy,

I'm trying to get a PWM signal on PF2 using the build in PWM module 1 and Generator 3.

I followed the implementation steps from the datasheet but there is no output on PF2 port.

I also tried to enable an interrupt when the PWM counter reaches 0 and CMPA comparator, and to use that interrupt to toggle PF2, but still there is no output on PF2.

The initialization function is:

void PWM6_Init(void) //Called from main.
{
	SYSCTL_RCGC0_R |= 0x00100000;		// Enable the PWM clock
	SYSCTL_RCGC2_R |= 0x00000020;		// Enable the port F clock
        GPIO_PORTF_LOCK_R = 0x4C4F434B;         // Unlock PortF PF0  
        GPIO_PORTF_CR_R |= 0x1F;                // allow changes to PF4-0 
	GPIO_PORTF_CR_R |= 0x1F;                // allow changes to PF4-0	
	GPIO_PORTF_DIR_R |= 0x04;		//PF2 output
	GPIO_PORTF_DEN_R |= 0x1F;               // Enable digital pins PF4-PF0
	GPIO_PORTF_AFSEL_R |= 0x04;             // Alternate function on bit 2
	GPIO_PORTF_PCTL_R = 0x00000500; 	// set alternate function PCTL register to PWM output signal -> M1PWM6 (to have also on port 3, set 0x00005500)
	SYSCTL_RCC_R |= 0x00100000;		// Set the Run-Mode Clock Configuration (RCC) to use PWM devider and set devider to /2
	PWM1_3_CTL_R = 0x00000000;		// PWM module 1, geerator 3 Control register
	PWM1_3_GENA_R = 0x0000008C; 		// Set up generator A
	PWM1_3_GENB_R = 0x00000000;		//disabled	// Set up generator B
	PWM1_3_LOAD_R = 0x0000013F;		// Set the load value for the PWM counter(nr of bus or PWM cycles / period, minus 1)
	PWM1_3_CMPA_R = 0x0000010F;	        // Set for comparator A 15% duty cycle (85% Low level signal).
	PWM1_3_CMPB_R	=	0x0000002F;	// Set for comparator B 85% duty cycle (15% Low level signal).
	PWM1_3_CTL_R = 0x00000001;		// Start timer for PWM module 1 Generator 3
	PWM1_ENABLE_R = 0x00000040;             // Enable PWM6 output (The generated pwm3A signal is passed to the MnPWM6 pin in this case) 
}

Then to enable interrupts on PWM I added also:

	PWM1_INTEN_R = 0x00000008;				        //Enable PWM module 1, generator 3 interrupt
	PWM1_3_INTEN_R = 0x00000009;			                //Generate an interrupt when counter = 0 and when caounter = comparator A
	SYSCTL_SRPWM_R |= 0x02;						//Reset PWM module 1
	SYSCTL_SRPWM_R &= ~0x02;					//Reset PWM module 1
	NVIC_PRI34_R = ((NVIC_PRI34_R&0xFFFF1FFF)|0x00002000);          //Priority 2 for pwm module 1, generator 3 interrupt
	NVIC_EN4_R = 0x00000200;					//enable interrupt, bit 9 in NVIC EN4

And for the Interrupt service routine:

void PWM1Generator3_Handler(void)
{
	if(PWM1_3_RIS_R&(0x01))				//If counter = 0
	{
		PWM1_3_ISC_R |= 0x01;			//Acknowledge
		GPIO_PORTF_DATA_R |= Green_LED;		//Set
	}
	else if(PWM1_3_RIS_R&(0x09))		        //If counter = comparator A
	{
		PWM1_3_ISC_R |= 0x08;			//Acknowledge
		GPIO_PORTF_DATA_R &= ~Green_LED;	//Clear
	}
}

  • Hello Gaal,

    To ease your development and support the issue you have, I would "strongly" suggest using TivaWare API for PWM with the example as given in TivaWare examples/peripherals/pwm/ directory than using DRM for register programming.

    Regards
    Amit
  • I understand.
    However I would like to write my own PWM driver (mainly for training / learning purposes).
  • Hello Gaal,

    And if you search the forum, most have started with the same intention to realize that it is not optimum.

    If you halt the debugger with the DRM code, what does it show the CPU is doing, or where is the code in execution?

    Regards
    Amit
  • Hy,

    Where can I get the TivaWare for TM4C?

    I can only find TivaWare for C Series.

  • Hello Gaal

    It is the same. TM4C is C series

    Regards
    Amit
  • I also tried with the APIs from TivaWare, unfortunatelly did't work.

    	SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);	
    	SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	
    	GPIOPinConfigure(GPIO_PF2_M1PWM6);
    	GPIOPinConfigure(GPIO_PF3_M1PWM7);
    	GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_2);
    	GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_3);
    	
    	PWMGenConfigure(PWM1_BASE, PWM_GEN_3, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);
    	PWMGenPeriodSet(PWM1_BASE, PWM_GEN_3, 64000);
    	PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6, PWMGenPeriodGet(PWM1_BASE, PWM_OUT_6) / 2);
    	PWMDeadBandEnable(PWM1_BASE, PWM_GEN_3, 160, 160);
    	PWMOutputState(PWM1_BASE, PWM_OUT_1_BIT | PWM_OUT_0_BIT, true);
            PWMGenEnable(PWM1_BASE, PWM_GEN_3);

    Somewhere I read that there is a register to enable higher current flow through pins (~20 mA mode...), could this be the couse?
    I mean is it possible that the PWM module does not output enaugh current to light on the LED on the board?

    Thanks,

    Alex

  • Gaal Alexandru said:

    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6, PWMGenPeriodGet(PWM1_BASE, PWM_OUT_6) / 2);

    PWMDeadBandEnable(PWM1_BASE, PWM_GEN_3, 160, 160);

    PWMOutputState(PWM1_BASE, PWM_OUT_1_BIT | PWM_OUT_0_BIT, true);

    Look at that last function call - note that the output bits (in highlight) FAIL to match your earlier (also in highlight) output bit... (PWM_OUT_6)   When using GEN_3 - as you know - PWM_OUT_6_BIT & PWM_OUT_7_BIT are the only 2 legal bits.

    I agree - there are "many" bit notations - this trap has claimed many...

    Your use of the embedded function w/in PWMPulseWidthSet() is risky - violates KISS (& Murphy) which states, "If anything can go wrong - it will go wrong.")   Far safer to employ a fixed value during test/verify - later you may replace...

    Re: on board Led - we've found that (any) setting of GPIO output current proves adequate...

  • Hello cb1

    I believe, you have indeed found the issue

    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6, PWMGenPeriodGet(PWM1_BASE, PWM_OUT_6) / 2);

    must be

    PWMPulseWidthSet(PWM1_BASE, PWM_OUT_6, PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3) / 2);

    Regards
    Amit
  • Hy,

    Thanks, I made the corrections you suggested. But unfortunately still no output is visible on the LED.

    The LED is working for sure, I tested it with another program. 

    I paste here my whole code. It compiles without any error or warning.

    // main.c
    #define PART_TM4C123GH6PM
    
    #include <stdbool.h>
    #include <stdint.h>
    #include <hw_memmap.h>
    #include "gpio.h"
    #include "pin_map.h"
    #include "pwm.h"
    #include "sysctl.h"
    #include "uart.h"
    #include "uartstdio.h"
    
    int main(void){
    	SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);	
    	SysCtlPWMClockSet(SYSCTL_PWMDIV_1);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM1);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    	
    	GPIOPinConfigure(GPIO_PF3_M1PWM7);
    	GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_3);
    	
    	PWMGenConfigure(PWM1_BASE, PWM_GEN_3, PWM_GEN_MODE_UP_DOWN | PWM_GEN_MODE_NO_SYNC);
    	PWMGenPeriodSet(PWM1_BASE, PWM_GEN_3, 64000);
    	PWMPulseWidthSet(PWM1_BASE, PWM_OUT_7, PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3) / 2);
    	PWMOutputState(PWM1_BASE, PWM_OUT_7_BIT, true);
      PWMGenEnable(PWM1_BASE, PWM_GEN_3);
      while(1)
    	{
      }
    }
    

  • Hello Gaal,

    And when you run the code does it show that it is executing the while(1) in the main code?

    Regards
    Amit
  • The code above is for PF3 the built in switch, but the same I have for PF2.
  • Well... if I set a breakpoint in that loop, the program does not stop the execution, so... I'm confused :)
  • I think the program stops in startup.s at:

    HardFault_Handler\
                    PROC
                    EXPORT  HardFault_Handler         [WEAK]
                    B       .
                    ENDP

  • In the startup file for the HardFault_Handler the following is stated:

    "; This is the code that gets called when the processor receives a fault

    ; interrupt.  This simply enters an infinite loop, preserving the system state

    ; for examination by a debugger."

    The file is from a course I made some time ago... I tried also with the startup file from KEIL, that is generated when a new project is created.

  • You are "consistent" in changing the PWM channel under test.   (1st post aimed @ 0_Bit, 2nd @ 6_Bit, and now 7_Bit!)   That's Krazy-Making - is it not?

    Have you (properly) re-connected to the Led from this (now) 3rd MCU PWM pin?

    At this stage - as Amit (and I) often recommend - you need to switch your (PWM "Pin du Jour") to GPIO Output mode - toggle that exact pin - and observe your Led.

  • PWM 6 Output is what I'm using... or whould like to use
    As I stated above, the code that I pasted was for PWM 7 (PF3)... I corrected this.

    Yes, I tested the PF1 , PF2, PF3 led and they all work...
    By testing I mean setting the GPIO_PORTF_DATA_R register bit 1 , 2 or 3.

    However in the debugger it seems that the program stops in the startup code (startup.s).
  • Hello Gaal

    It seems that there may be a Bus Fault occurring. If that is the case, then add a SysCtlDelay(10) after the SysCtlPeripheralEnable for GPIO.

    Regards
    Amit
  • Thanks Amit for the help.

    I finally manadged to solve the problem, which was not related to PWM  at all :)

    I had to rewrite the Reset_Handler routine from startup.s file.

            EXPORT  Reset_Handler
    Reset_Handler
            MOVW    R0, #0xED88
            MOVT    R0, #0xE000
            LDR     R1, [R0]
            ORR     R1, #0x00F00000
            STR     R1, [R0]
    
            IMPORT  __main
            B       __main

    The Reset_Handler I previously had was the one generated by KEIL, not to be used with driverlib.

  • Hello Gaal

    Glad, that you solved it. But the startup_ccs.c file should have been there in the CCS project, even when using an empty project.

    Regards
    Amit