Shop OBEX P1 Docs P2 Docs Learn Events
Clock Speed change from external xtal to internal RC and back again to external xtal — Parallax Forums

Clock Speed change from external xtal to internal RC and back again to external xtal

JohnR2010JohnR2010 Posts: 431
edited 2014-10-01 08:41 in General Discussion
The Propeller manual talks about a three step process when changing clock speed from the internal RC to an external crystal. It says you need to set the PLLENA, OSCENA, and OSCM registers wait 10ms and then set the CLK register. Does anyone have a good example of this process? I was looking at the clock speed code for the DefCon Badge and I cant see they are doing any type of 3 step process. I have tried setting the clock speeds as laid out in the DefCon and I cant change the speed from external crystal to internal RC.

I'm sure this has been asked and answered and before someone jumps on me I searched and read through a ton of posts and haven't come up with a clean solution this cant be more than 4 or 5 lines of code. Little frustrated I have to ask this question going to walk away and come back. Arrrgggg I should be able to figure it out on my own!!

Thanks

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-09-30 13:10
    There's a "Clock" object in the Propeller Tool Library. The "SetClock" method does what you want. I'm looking for an example.

    Edit: I see before using "SetClock" you have to use the "Init" method to let the object know what crystal you're using.
  • JohnR2010JohnR2010 Posts: 431
    edited 2014-09-30 13:15
    Duane Degn wrote: »
    There's a "Clock" object in the Propeller Tool Library. The "SetClock" method does what you want. I'm looking for an example.

    Yep that is what Im using. I can go from fast to slow. The problem I'm having is going from slow back to fast (external crystal).

    Here is how I go from Fast to Slow:
    clkset(0_0_0_00_001, 20_000) ' Set Clock speed slow

    Here is what I'm trying to get to work to get me back to fast speed.
    clkset(%0_1_1_01_001, 20_000) ' Turn on external crystal
    waitcnt(cnt + (clkfreq / 100)) ' wait ~10ms
    clkset(%0_1_1_01_111, 80_000_000) ' Set Clock back to high speed

    I have also just tried the last clkset line without the two steps before it.

    I know Im missing something.

    Edit Sorry I thought you were talking about the Clkset command. I hate to have an object to change the clock speed. I will take a look at how they do it. Thanks.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2014-09-30 13:30
    It's been a while since I've done this (over three years by the date stamp on my code) but this is what I did.

    I used these constants.
    CON
    
      _Fast = xtal1 + pll16x
      _Slow = RCSLOW
      _CurrentCrystal = 5_000_000
    

    I used what looks like a modified clock object.
    OBJ   
    
      Speed : "Clock110716a"
    

    I think I just added the minimum wait amount (381) to the pause method(s). I'm just about positive the code below would work with the original version of the object.

    I called Init.
    Speed.Init(_CurrentCrystal)
    

    To put the Prop in what I called "sleep" mode I used:
    Speed.SetClock(_Slow)
    

    This is my "WakeUp" method.
    PUB WakeUp'' Start debug cog and Nordic cog
    '' Change clock settings to 80MHz
    
    
      Speed.SetClock(_Fast)
    

    It also contained additional housekeeping items.

    I also shut down all but one cog in sleep mode and would start these cogs back up with the "WakeUp" method.

    I didn't feel the need to understand how the method "SetClock" works but it looks like it's pretty well commented.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2014-09-30 14:35
    Have a look at the DEFCON 22 badge code -- it has constants and methods that support clock speed switching.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-09-30 17:16
    Here's a demo program. LEDR and LEDG here are pins for a two-pin led as an indicator of activity, fast flash when operating at 80MHz and slow when at 20kHz. You will see that I make the transition from RCslow to 80MHz via RCfast. The transition can happen using RCslow there, but in that case it will lock up unless the waitcnt delay is increased from 10ms to 20ms. Maybe you were having a problem with insufficient delay? When dealing with RCslow, you have to be careful to avoid extra program overhead in Spin. Avoid nested method calls and complicated expressions. The interpreter is really poking along at 20kHz!
    [SIZE=1][FONT=courier new]CON
      _clkmode = xtal1 + pll16x                '
      _xinfreq = 5_000_000
    
      XMHZ = _xinfreq/1000000
    
      LEDR = 21
      LEDG = 22
    
    PUB ClockModeTest
             dira[LEDR..LEDG]~~
             outa[LEDR..LEDG] := %10
            repeat
                   repeat 10                  ' a few fast flashes at 80MHz
                         waitcnt(clkfreq/5+cnt)
                         !outa[LEDR..LEDG]
                   Clk_RCslow
                   repeat 10                   ' a few slow flashes at 20kHz
                         waitcnt(clkfreq/2+cnt)
                         !outa[LEDR..LEDG]
                   Clk_RCfast_Xtal_On        ' if RCslow here, have to increase waitcnt delay
                   waitcnt(clkfreq/100+cnt)
                   Clk_xtal(80)              ' back to 80MHz and do it again
    
    PRI Clk_RCslow
            clkset(%0_00_00_001, 20_000)    ' drop to RCSLOW at  ~20 KHz
    
    PRI Clk_RCfast
             clkset(0_00_00_000, 12_000_000)   ' xtal osc off,  operating RCfast at ~12MHz
    
    PRI Clk_RCslow_Xtal_On
            clkset(%0_11_01_001, 20_000)   ' xtal1 osc & pll on, operating on RCslow
    
    PRI Clk_RCfast_Xtal_On
            clkset(%0_11_01_000, 12_000_000)   ' xtal1 osc & pll on, operating on RCfast
    
    PRI Clk_xtal(fMHz)   ' enter with desired clock frequency, must be 1,2,4,8,16 * XMHZ
            if fMHz == XMHZ    ' XMHZ is _xinfreq/1000000
                  clkset(%0_01_01_010, _xinfreq)   ' xtal operation at xtal frequency, no pll
            else                     ' use the pll to multiply frequency
                  clkset(%0_11_01_000 | >|(fMHz/XMHZ)+2, fMHz*1_000_000)  ' xtal+pll,
    [SIZE=2][FONT=arial]
    
    [/FONT][/SIZE]
    [/FONT][/SIZE]
  • JohnR2010JohnR2010 Posts: 431
    edited 2014-10-01 05:52
    Maybe you were having a problem with insufficient delay? When dealing with RCslow, you have to be careful to avoid extra program overhead in Spin. Avoid nested method calls and complicated expressions. The interpreter is really poking along at 20kHz!
    Thanks Tracy! The time delay is what was getting me. Everything worked when I followed your trick of switching on the external crystall via RCfast instead of RCslow.

    Is there a way I can give you a vote up in this forum? I'm used to a forum (http://stackoverflow.com) where you can give people points for helping! You and others have helped me several times and I cant see where I can do that with this forum.
  • JohnR2010JohnR2010 Posts: 431
    edited 2014-10-01 06:49
    JonnyMac wrote: »
    Have a look at the DEFCON 22 badge code -- it has constants and methods that support clock speed switching.

    Thanks Jon I looked at your code just before I posted this question on the forum. My program needs to switch clock speeds several times, I go from 80MHz to the slow internal clock (20kHz) for sleep mode and then wake up and switch back to 80Mhz. I think your 10ms delay needs to be increased when you are switching from 20kHz back out to the external crystal and oscillator circuit. My delay was also 10ms and it didn't work. Tracy gave me sample code in where it switches to RCFast 12MHz to turn on the external crystal circuit, waits 10ms and then jumps out to the Crystal for the 5MHz * 16 = 80MHz. I couldn't do this with the 10ms delay at 20kHZ but I could at 12MHz.

    So to recap:
    To go from fast (80MHz) external clock to internal slow (20kHz) I made this call:
      clkset(%0_00_00_001, 20_000)  
    

    To go back to 80MHz I had to follow this process:
      clkset(%0_11_01_000, 12_000_000)                      ' Turn on external crystal circuit to warm it up, set clock to internal RCFAST 12Mhz.
      waitcnt(cnt + (clkfreq / 100))                        ' wait ~10ms
      clkset(%0_11_01_111, 80_000_000)                      ' Set Clock to exteranal 5MHz crystal * 16
    

    Have you tried using your method to go from 20kHZ to 80MHz?
    Thanks for posting your code!!
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2014-10-01 08:41
    Thanks John, I'm glad that helped.

    Useful code execution can happen during the RCfast phase while waiting for the xtal to spin up. Anything involving spi or i2c such as reading a clock chip. In some cases I have RCfast inside the low power loop, and code executed there informs the decision of whether or not to go to higher speeds and timing accuracy.

    I know you use the serial port a lot for your zigbee and other things. Be sure to clear all the transmit buffers (txflush(port)+one character delay) before dropping the clock speed.
Sign In or Register to comment.