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.

PWM Code on TM4C123BH6PM

Other Parts Discussed in Thread: TM4C123BH6PM

Hi, I'm trying to make a code about making a PWM without using the Tivaware libraries.

However, there were no PWM detected when I tested with my oscilloscope.

Here's the code below. Can somebody tell what is wrong and what needs to be added?

#include <stdbool.h>
#include <stdint.h>
#include "My_headers\tm4c123bh6pm.h"

#include "My_headers\hw_types.h"

#define BIT0                      (0x0001u)
#define BIT1                      (0x0002u)
#define BIT2                      (0x0004u)
#define BIT3                      (0x0008u)
#define BIT4                      (0x0010u)
#define BIT5                      (0x0020u)
#define BIT6                      (0x0040u)
#define BIT7                      (0x0080u)
#define BIT8                      (0x0100u)
#define BIT9                      (0x0200u)
#define BITA                      (0x0400u)
#define BITB                      (0x0800u)
#define BITC                      (0x1000u)
#define BITD                      (0x2000u)
#define BITE                      (0x4000u)
#define BITF                      (0x8000u)

void SW_Delay(volatile unsigned long Delay_t){
 Delay_t *= 1000;
 while(Delay_t--);
}

void RCC_CLK_SET(int RCC_BIT){

 uint32_t ui32Delay, ui32RCC, ui32RCC2;

     //
     // Get the current value of the RCC and RCC2 registers.
     //
     ui32RCC = SYSCTL_RCC_R;
     ui32RCC2 = SYSCTL_RCC2_R;

     //
     // Bypass the PLL and system clock dividers for now.
     //
     ui32RCC |= SYSCTL_RCC_BYPASS;
     ui32RCC &= ~(SYSCTL_RCC_USESYSDIV);
     ui32RCC2 |= SYSCTL_RCC2_BYPASS2;

     //
     // Write the new RCC value.
     //
     SYSCTL_RCC_R = ui32RCC;
     SYSCTL_RCC2_R = ui32RCC2;

     //
     // See if the oscillator needs to be enabled.
     //
     if((ui32RCC & SYSCTL_RCC_MOSCDIS) && !(RCC_BIT & SYSCTL_RCC_MOSCDIS))
     {
         //
         // Make sure that the required oscillators are enabled.  For now, the
         // previously enabled oscillators must be enabled along with the newly
         // requested oscillators.
         //
         ui32RCC &= (~SYSCTL_RCC_MOSCDIS | (RCC_BIT & SYSCTL_RCC_MOSCDIS));

         //
         // Write the new RCC value.
         //
         SYSCTL_RCC_R = ui32RCC;

         //
         // Wait for a bit, giving the oscillator time to stabilize.  The number
         // of iterations is adjusted based on the current clock source; a
         // smaller number of iterations is required for slower clock rates.
         //
         if(((ui32RCC2 & SYSCTL_RCC2_USERCC2) &&
             (((ui32RCC2 & SYSCTL_RCC2_OSCSRC2_M) == SYSCTL_RCC2_OSCSRC2_30) ||
              ((ui32RCC2 & SYSCTL_RCC2_OSCSRC2_M) ==
               SYSCTL_RCC2_OSCSRC2_32))) ||
            (!(ui32RCC2 & SYSCTL_RCC2_USERCC2) &&
             ((ui32RCC & SYSCTL_RCC_OSCSRC_M) == SYSCTL_RCC_OSCSRC_30)))
         {
             //
             // Delay for 4096 iterations.
             //
             SW_Delay(4096);
         }
         else
         {
             //
             // Delay for 524,288 iterations.
             //
             SW_Delay(524288);
         }
     }

     //
     // Set the new crystal value and oscillator source.  Because the OSCSRC2
     // field in RCC2 overlaps the XTAL field in RCC, the OSCSRC field has a
     // special encoding within RCC_BIT to avoid the overlap.
     //
     ui32RCC &= ~(SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M);
     ui32RCC |= RCC_BIT & (SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M);
     ui32RCC2 &= ~(SYSCTL_RCC2_USERCC2 | SYSCTL_RCC2_OSCSRC2_M);
     ui32RCC2 |= RCC_BIT & (SYSCTL_RCC2_USERCC2 | SYSCTL_RCC_OSCSRC_M);
     ui32RCC2 |= (RCC_BIT & 0x00000008) << 3;

     //
     // Write the new RCC value.
     //
     SYSCTL_RCC_R = ui32RCC;
     SYSCTL_RCC2_R = ui32RCC2;

     //
     // Wait for a bit so that new crystal value and oscillator source can take
     // effect.
     //
     SW_Delay(16);

     //
     // Set the PLL configuration.
     //
     ui32RCC &= ~SYSCTL_RCC_PWRDN;
     ui32RCC |= RCC_BIT & SYSCTL_RCC_PWRDN;
     ui32RCC2 &= ~SYSCTL_RCC2_PWRDN2;
     ui32RCC2 |= RCC_BIT & SYSCTL_RCC2_PWRDN2;

     //
     // Clear the PLL lock interrupt.
     //
     SYSCTL_MISC_R = SYSCTL_IMC_PLLLIM;// 0x040 problem

     //
     // Write the new RCC value.
     //
     if(ui32RCC2 & SYSCTL_RCC2_USERCC2)
     {
         SYSCTL_RCC2_R = ui32RCC2;
         SYSCTL_RCC_R = ui32RCC;
     }
     else
     {
         SYSCTL_RCC_R = ui32RCC;
         SYSCTL_RCC2_R = ui32RCC2;
     }

     //
     // Set the requested system divider and disable the appropriate
     // oscillators.  This value is not written immediately.
     //
     ui32RCC &= ~(SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV |
                  SYSCTL_RCC_MOSCDIS);
     ui32RCC |= RCC_BIT & (SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV |
                              SYSCTL_RCC_MOSCDIS);
     ui32RCC2 &= ~(SYSCTL_RCC2_SYSDIV2_M);
     ui32RCC2 |= RCC_BIT & SYSCTL_RCC2_SYSDIV2_M;
     if(RCC_BIT & SYSCTL_RCC2_DIV400)
     {
         ui32RCC |= SYSCTL_RCC_USESYSDIV;
         ui32RCC2 &= ~(SYSCTL_RCC_USESYSDIV);
         ui32RCC2 |= RCC_BIT & (SYSCTL_RCC2_DIV400 | SYSCTL_RCC2_SYSDIV2LSB);
     }
     else
     {
         ui32RCC2 &= ~(SYSCTL_RCC2_DIV400);
     }

     //
     // See if the PLL output is being used to clock the system.
     //
     if(!(RCC_BIT & SYSCTL_RCC_BYPASS))
     {
         //
         // Wait until the PLL has locked.
         //
         for(ui32Delay = 32768; ui32Delay > 0; ui32Delay--)
         {
             if(SYSCTL_RIS_R & SYSCTL_IMC_PLLLIM)
             {
                 break;
             }
         }

         //
         // Enable use of the PLL.
         //
         ui32RCC &= ~(SYSCTL_RCC_BYPASS);
         ui32RCC2 &= ~(SYSCTL_RCC2_BYPASS2);
     }

     //
     // Write the final RCC value.
     //
     SYSCTL_RCC_R = ui32RCC;
     SYSCTL_RCC2_R = ui32RCC2;

     //
     // Delay for a little bit so that the system divider takes effect.
     //
     SW_Delay(16);
}

void PWMCLKSet(int PWM_BIT){ //Set the PWM clock to the system clock.

    //
    // Check that there is a PWM block on this part.
    //
    ASSERT(SYSCTL_DC1_R & (SYSCTL_DC1_PWM0 | SYSCTL_DC1_PWM1));

    //
    // Set the PWM clock configuration into the run-mode clock configuration
    // register.
    //
    SYSCTL_RCC_R = (SYSCTL_RCC_R &
                          ~(SYSCTL_RCC_USEPWMDIV | SYSCTL_RCC_PWMDIV_M) | PWM_BIT);

    //Clear SYSCTL_RCC_R [20:17] bit (USEPWMDIV, PWMDIV)
    //Then OR PWM_BIT to fill [20:17] bit(USEPWMDIV, PWMDIV)
}

void PWM_Module_Enable(int Enable){

 SYSCTL_RCGCPWM_R |= Enable;

 //PWM Run Mode Clock Gating Control Register

}

void GPIO_Gate_Control(int GPIO_BIT){

 SYSCTL_RCGCGPIO_R |= GPIO_BIT;
 SYSCTL_RCGC2_R |= GPIO_BIT;

}

void GPIO_B_PWM_SET(int PWM_BIT){

        SW_Delay(5);

        // Enable the GPIO pin for the LED (PF3).  Set the direction as output, and
        // enable the GPIO pin for digital function.
        //
        GPIO_PORTB_DIR_R |= PWM_BIT | BIT7; // Select as Output
        GPIO_PORTB_AFSEL_R |= PWM_BIT; //Alternative Function Select
        GPIO_PORTB_DEN_R |= PWM_BIT | BIT7; // Enable the GPIO pin for digital function.
        GPIO_PORTB_ODR_R &= 0; //clear GPIOODR, ODR Disable

        GPIO_PORTB_PCTL_R |= 0x4000000; //GPIO Port Control Register PCM6 => M0PWM0

        GPIO_PORTB_DATA_R &= ~(BIT7); //Set PB7 to GND


}

void PWM0CTL(int LOAD, int CMPA, int CMPB){

 PWM0_CTL_R = 0x6; //Count Down Mode,
 PWM0_0_CTL_R = 0x06;
 //Debug Mode : counter always run
 //Disable PWM block

 PWM0_0_GENA_R = 0x8C; //PWM0GENA Register,
 //Comparator B Down and Up do nothing
 //Comparator A Down Drive pwmA low
 //Comparator A Up drive do nothing
 //Counter = LOAD Drive pwmA High
 //Counter = 0 Do nothing


 PWM0_0_GENB_R = 0x80C;//PWM0GENB Register,
 //Comparator B Down Drive pwmB Low.
 //Comparator B Up Drive do nothing
 //Comparator A Down and Up do nothing
 //Counter = LOAD Drive pwmB High
 //Counter = 0 Do nothing

 PWM0_0_LOAD_R = LOAD; //LOAD Setting

 PWM0_0_CMPA_R = CMPA;//Compare A

 PWM0_0_CMPB_R = CMPB;//Compare B

 SW_Delay(10);

 PWM0_CTL_R |= 0x1; //Now enable PWM block
 PWM0_0_CTL_R |= 0x1;
 //Start the timers in PWM generator 0
}

void PWM0ENABLE(int PWM_EN){

 PWM0_ENABLE_R |= 0x1;
 //pwmA' , pwmB' output enable to MnPWMn
}

int main(void) {
 
 RCC_CLK_SET(SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_XTAL_16MHZ | SYSCTL_RCC_PWRDN |
   SYSCTL_RCC_BYPASS | SYSCTL_RCC_OSCSRC_MAIN);

     // Set the PWM
 SET_PWM0_GPIO_B();

 LED();

}

  • Hello Min-Ku,

    Where is the function SET_PWM0_GPIO_B defined and how does the main function actually call the other functions for setting up PWM?

    Also is there is a bus fault or anything like that happening or is it stuck in some loop. Please note that the Bus fault have a while(1) loop so if you see a while(1) loop be sure that it is not in a Fault ISR

    Regards

    Amit

  • Hi Amit, I forgot to load that function. My bad...

    The code is below here.

    void SET_PWM0_GPIO_B(){

     PWMCLKSet(SYSCTL_RCC_PWMDIV_2); //PWM clock /2

     PWM_Module_Enable( BIT0 ); //PWM Module Enable

     GPIO_Gate_Control( BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0 ); //Enable GPIO Pins

     GPIO_B_PWM_SET( BIT6 ); //Enable PB6 / M0PWM0

     PWM0CTL(15424, 7712, 200); //Count Mode setting, LOAD setting,
     //CMPA, CMPB setting

     SW_Delay(20);

     PWM0ENABLE( BIT6 ); //Enable M0PWM0

    }

    If you see the first post, the code goes all the way to LED(); .

    Luckily, there were no stucks at while loops. I connected a LED with 330 Ohm resistor on GPIO PF3.

    The LED blinked, showing no sign of stuck.

    Is there more settings to be done?

  • Hello Min-Ku,

    The first issue is in the IO Setup. The line

    GPIO_PORTB_PCTL_R |= 0x4000000; //GPIO Port Control Register PCM6 => M0PWM0 

    has to be (It was setting PB6 Port Control bits)

    GPIO_PORTB_PCTL_R |= 0x40000000; //GPIO Port Control Register PCM6 => M0PWM0

    So as there are no stucks, it is good. I will keep on looking through the code (sorry that is is massive) for any further discrepancies. In the meantime if you can check through the debugger after making the change that the PWM counter is working that will help too.

    Regard,

    Amit

  • Thanks again Amit.

    I'm sorry to make you look at this pile of codes... T^T

    By the way, do I hvae to add some codes about oscillator flag set on function RCC_CLK_SET?

  • Min-Ku Yeo said:
    I'm sorry to make you look at this pile of codes...

    And he ain't the only one!

    You don't state "why" you've chosen this complicated path - that's always of interest (and never included).

    Now Amit is a smart & good guy - helping you "precludes/intrudes" into his efforts elsewhere - aiding others.  Is this right - is it fair?

    By rejecting the long-standing/proven code library - you force far more effort & concerns upon yourself - and others.  If a school assignment - is it proper that you, "call for help?"  If you're an independent learner - and really want to know - might there be, "a better way?"

    By a systematic review of the standard library PWM functions - as used by, "example PWM code" - you can chart the sequencing & use of most all critical PWM Registers.  (indeed that sequencing is sometimes of importance)  Armed with that mass of serious data - you are far better equipped to, "roll your own." 

    As a small tech biz owner (w/record of some success) I'd question the utility of this effort.  We'd not - ever - allow our staff to embark in this manner.  Most all of this code is register set-up & configuration - little speed or code reduction can be gained thru this effort.  (there are times/places for speed/size gains - this is not among those!)

    You've culled yourself far from the herd - presented no justification - and God help the poor person who must maintain your code downstream...  (even & especially if that person is you!)

  • Hello Min-Ku,

    I ran the test code (only modification was commenting the LED function as it was not defined). I see a 389Hz 25% Duty Cycle PWM Signal on PB6.

    Regards

    Amit

  • cb1, I was thinking the same thing. TivaWare is by no means perfect, but it makes stuff like this a whole lot less painful. I'm also small biz owner; and if my programmers want to veer off the beaten path and roll their own then they'd better have a darn good reason, because I have to pay for it.

    --Derek

  • @Derek,

    Birds of a feather - my friend...

    Culling oneself from the herd - and you/I get to pay for it - (and for unexplained reasons) - not anytime soon - this planet!

    Real horror is vendor's lack of, "rejecting such improper demand on the spot!"  Vendor (crue) has so much time, so much effort - mismanagement (like this)  should not be enabled - should be forcefully discouraged.

    And oh yes - let us repeat another 1K (or beyond) "PF0 don't work!"  Ragged outsiders have long spotted - and devised corrective action - which (seemingly) sits in valued "round file" - awaiting pick-up...

  • Hello Derek and cb1-.

    I admit too. Using the Tivaware can save a lot of times and effort for developers.

    However, I just wanted to have some time to make my own functions for my skills.

    I wanted to understand how the registers work to activate what I wanted.

    It is my first time holding a MCU datasheet for 4 months to understand the basics.

    I tried the instructions in the datasheet by myself in order to

    activate what I wanted and didn't worked as I expected.

    Thanks to you guys, the problem is solved.

    Long story short, I'm a rookie in here and I wanted to do something on my own.

    I believe that relying to other's product (like Tivaware, even though it is really well-made)

    won't make much improvement for me. Even though I made something with the Tivaware,

    I cannot answer to this simple question.

    "If the Tivaware didn't exist, could it be possible to make the same output?"

    It may sound ridiculous not to use the Tivaware but

    I just wanted to be a engineer who can solve problems by myself.

    That was the reason why I tried to make my own functions.

    Anyways, I always admire your advice. (especially cb-, your tips really motivate me)

    I hope to be smart engineers like you two.

    Wish me good luck.

    Regards, Min-Ku

  • Min-Ku Yeo said:
    I hope to be smart engineers like you two.

    Believe Derek may so qualify - I've warehouse section full of (sure to sell) parts/designs - serving as (unwelcome) reminder - my design/marketing skills...  Attention to detail is bred/learned - not born...  (this I now shout...)

    Impossible to argue now - w/the great (caring) detail you provide.  But none of that was present initially - and any dilution of Amit's time/effort must be carefully weighed - and chosen w/care/precision.

    Let me state again - a focused review of the standard StellarisWare/rebrand library functions - with the MCU manual open/ready at your side - along w/SW-DRL-UG (or rebrand reincarnation) will far more efficiently "unlock" the mystery of MCU Registers - and their care/feeding/handling...

    Suggest that you try this technique - start w/a relatively simple (say GPIO) function - and examine the "step by step" as the library achieves that functional objective.  We find that our new hires really do come to speed quickly/efficiently via this method - this madness...  (Yet still - when we've an active project - StellarisWare is always choice ONE - they can "really learn" (like you) after the quitting whistle - on their time!)  *** And I bet that's the time when the joint nearly empties - just Derek (his shop) and me (mine) bathed in the pleasant glow of our last 40W incandescents (now banned) w/only the most, "hard core" new staff doing (as Min-Ku says) "the ridiculous!" 

    I've intl. travel w/in this quarter - "correspond" w/me - perhaps we can meet/share a nice meal.  (I'll be: Taiwan, Shenzen, Seoul, Narita, Tokyo - maybe Manilla...) 

    Bon chance, mon ami.  With your desire, focused effort & having awarded a, "Verify" to a (bit) critical comment - you're clearly a, "power in the making."  

  • Hi cb1. Thanks for replying.

    This is my personal question. (I should have searched how to e-mail you... but I couldn't find it..)

    When do you come to Seoul? I live in Seoul, Korea and I really, really, really want to meet you.

    Can I get your e-mail address?

    Sincerely, Min-Ku

  • @cb1- Good point about use of vendor resources. They have enough difficult problems to solve, with silicon bugs, custom hardware issues, etc. When I saw "I'm trying to make a code about making a PWM without using the Tivaware libraries" I was a little surprised that TI answered. They should have replied "Do it with TivaWare and then unpack from there". Starting with a GPIO function is a good place to start.

    @Amit Regarding PF1, Stack Size, etc: There really should be a carefully moderated Tiva FAQs that has the answers to these common questions.


    @Min-Ku, I understand as an engineer the desire to learn. Nowadays most of us don't have that luxury unfortunately; the more time we spend on a project equals less profit.

  • @Min-Ku - Attention to detail mon ami - mouse over my id - a "correspond" flag should reveal.  You must enable such "correspondence" during your edit of this forum log-in.  (it's toward the bottom - iirc)  And I really, really want to meet someone w/your attitude & work-ethic, too.  (we buy displays/other goods from, "big S.")

    @Derek - Maddening that same/similar questions are answered repeatedly - even after we dimwits have long since proposed superior methods.  NIH alive/well (prospering?) this hallowed space.  Can you say, "burnout of tech staff" - after 100th "PF0 = NMI" (thru the motion response.)  Even the US Army had better means to manage/prevent this startling waste of manpower - both @ vendor staff and countless/hapless users!  (great case study of "what not to do" - for MBA Schools)  {Note: endeared myself (via critiques) w/Army too - "escaped fast as I could" after tour of (enforced) duty ended}.

    You impact the nail solidly w/your, "don't have that luxury!"  When's the last time you've read a non-tech book - simply for pleasure?  (and/or not felt "guilty" - as some project detail returns (front/center) to haunt...)