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.

Setting clock by directly accessing registers

Genius 3300 points


I am learning how to set clock by directly accessing the system registers rather than using library.

I have written code for it. I have verified the frequency by toggling the pins. 

Can someone verify that steps I have done are ok & should be in this sequence.

Case1 : 16Mhz external oscialltor as system clock

If I call  library function then value after library function are , RCC = 0x078C3D40 & RCC2 = 0x07C06800

But if I call my function , RCC = 0x078E3D50 , RCC2 = 0x80406800 

void system_clock_init(void)
{
    volatile uint32_t u32_dummy;

/* library function bypassed */    
//    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ );  /* External 16Mhz crystal as system clock */

/* override RCC2 register settings */
    SYSCTL->RCC2 |= RB_SYSCTL_RCC2_USERCC2;
    
/* bypass pll while clock init */    
    SYSCTL->RCC2 |= RB_SYSCTL_RCC2_BYPASS;
    
/* select crystal value  */
    SYSCTL->RCC &= (uint32_t)(~RB_SYSCTL_RCC_XTAL_MASK);       /* clear xtal filed value */
    SYSCTL->RCC |= RB_SYSCTL_RCC_XTAL_16MHZ;                   /* select 16Mhz crystal */
    
/* dont use sysdivider, system clock is undivided  */    
    SYSCTL->RCC &= (uint32_t)(~RB_SYSCTL_RCC_USESYSDIV);                   

/* select oscilaltor source */
    SYSCTL->RCC2 &= (uint32_t)(~RB_SYSCTL_RCC2_OSCSRC_MASK);       /* clear oscsrc mask */    
    SYSCTL->RCC2 |= RB_SYSCTL_RCC2_MOSC;
    
/* power down PLL */    
    SYSCTL->RCC2 |= RB_SYSCTL_RCC2_PWRDN2;
    
/* clear sysdiv bits & set divider */    
    SYSCTL->RCC2 &= (uint32_t)(~RB_SYSCTL_RCC2_SYSDIV_MASK);   /* divide by 1 i.e sys clock freq */
    
/* sys clock is osc src */    
    SYSCTL->RCC2 |= (RB_SYSCTL_RCC2_BYPASS);      
	
/* give some dummy delay */    
    for(u32_dummy = 0U ; u32_dummy < 100U ; u32_dummy++);
      
} /* function ends here */   

Case2 : 80Mhz using  external oscialltor 16Mhz

If I call  library function then value after library function are , RCC = 0x014E1540 & RCC2 = 0XC1004000

But if I call my function , RCC = 0x07CE3D50 , RCC2 = 0XC1004000

void system_clock_init(void)
{
    volatile uint32_t u32_dummy;

/* library function bypassed */    
//    SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ );

/* override RCC2 register settings */
    SYSCTL->RCC2 |= RB_SYSCTL_RCC2_USERCC2;
    
/* bypass pll while clock init */    
    SYSCTL->RCC2 |= RB_SYSCTL_RCC2_BYPASS;
    
/* select crystal value  */
    SYSCTL->RCC &= (uint32_t)(~RB_SYSCTL_RCC_XTAL_MASK);       /* clear xtal filed value */
    SYSCTL->RCC |= RB_SYSCTL_RCC_XTAL_16MHZ;                   /* select 16Mhz crystal */
    
/* use sysdivider  */    
    SYSCTL->RCC |= RB_SYSCTL_RCC_USESYSDIV;                   

/* select oscilaltor source */
    SYSCTL->RCC2 &= (uint32_t)(~RB_SYSCTL_RCC2_OSCSRC_MASK);       /* clear oscsrc mask */    
    SYSCTL->RCC2 |= RB_SYSCTL_RCC2_MOSC;
    
/* activate PLL */    
    SYSCTL->RCC2 &= (uint32_t)(~RB_SYSCTL_RCC2_PWRDN2);
    
/* use 400Mhz PLL */    
    SYSCTL->RCC2 |= RB_SYSCTL_RCC2_DIV400;
    
/* clear sysdiv bits & set divider */    
    SYSCTL->RCC2 &= (uint32_t)(~RB_SYSCTL_RCC2_SYSDIV_MASK);   
    SYSCTL->RCC2 |= REG32_BIT_24;           /* setting for 80Mhz */
    
/* wait for PLL to lock */    
    while( 0U == (SYSCTL->RIS & RB_SYSCTL_RIS_PLLLRIS) );
    
/* sys clock is PLL out */    
    SYSCTL->RCC2 &= (uint32_t)(~RB_SYSCTL_RCC2_BYPASS);     
	
/* give some dummy delay */    
    for(u32_dummy = 0U ; u32_dummy < 100U ; u32_dummy++);
      
} /* function ends here */   

  • Hello Vindhyachal,

    Why don't you reuse the existing function? If still you want to continue with the custom approach then you can cross refer to the SysCtlClockSet API.

    Regards
    Amit
  • Hi Amit,

    To be honest, I found TM4C API bit hard to understand. (Hard for me may be easier to someone else :) ) .

    I can use SysCtlClockSet API because this is called only once at startup. But not other library except initialization once, because they have to be called again & again in code. IMHO for best speed/size performance it is better to write own code.
    Since I am learning TM4C so I prefer to understand each peripheral & write own code.

    Just for feedback, don't take it otherwise:
    I found library written by ST for their 8-bit & 32-bit extremely organized, documented & well written. Along with that they have many examples with them. But again easy for me may be harder for someone else :).
  • Weirdly enough I like the Tiva better than the ST one (maybe it's because it wasn't the one I started with).

    Like any driver C library, it's less efficient than direct register programming.
    I do believe support for Direct Register programming will be kinda lost. Kinda because instead Tivaware macros will be used like HWREG. So maybe it's something you should look into. It's still register programming though so don't worry.

    The thing about ARM is that for most applications the C drivers work just fine! So it's easier to find support for the libraries instead of direct register programming. It has advantages like being harder to get a value wrong or accessing the wrong register. Other advantages are faster code develop and better portability (the HWREG and such use I said before eases that portability too).
    Of course if needed either for speed or lack of support from the library, you can later develop code in direct register access (and some functions).
    Just my opinion,of course you can use what you chose. It's always a matter of trade-offs.
  • Like I said, things easier for me may be difficult for others & vice versa.

    I started ARM with NXP where I did direct register programming. So always a fan of it.

    IMHO Even if Tivaware use HWREG but still be very inefficient compared to direct accessing. Although direct accessing has its own drawback like error while accessing & portabaility across same architecture MCU's.

    Even in most of industry project near by me I have rearly seen use of libraries except for initialization purpose which is far more common as they are called one time only during program initialization.

    Of-course it can again depend upon industry to industry.

  • Hello Vindhyachal,

    After you enable the Main Oscillator you would need to delay for the startup time of the Main Oscillator crystal as given in the data sheet. Other than that it looks correct.

    Regards
    Amit
  • Would the, "forum response" slow to a crawl if many/most "demanded" direct accessing code solutions, only?   Should such be considered?

    You note that, "Industry projects nearby... rarely employ library code...but for most basic and/or singular calls."   Our tech group works with a wide range of clients (embedded now with 9B (USD) firm) - and we find exactly the opposite!

    Is not "most" of the new product's profit generated by those, "First to market?"   Following your lead (direct accessing only) do we not prolong & complicate product development?   And for what?   (critical code sections can be "hand coded" - if your group has the skill, focused expertise, & time - AND if the product and/or client really does benefit from that extra time/cost/effort...)

    Code libraries are here to stay - for good reason - and your "industry projects" which avoid such ease/effort/time-saving are unlikely to compete well on the world-stage...

  • Vindhyachal ,

    Thanks for this note. I've been thinking about this in the last couple days. I spent 4 hours trying to get the clocks set up using coded from scratch register writes. I never did get it to work correctly. I switched to the SysCtl API to see how that would work. I got the clock to the exact frequency and source I wanted in 5 minutes. Of course the API could have a subtle bug that wasn't caught. But I think it is even more likely to introduce a bug by hand-coding this sort of routine. At least the API has customer support and if others run into bugs it will get fixed.

    You are correct, commercial success critically depends on time to market. If there are custom routines that will actually improve the customer value of the product, then spend effort here "gold plating" your code.