_clkmode and _clkfreq

in Propeller 1
Does anyone remember how one goes about setting the clock mode in PropGCC? I know you can set it at runtime by using a macro in propeller.h but I want to set the initial clock settings in the binary file header. I know there is a way to do it but I haven't been able to find the documentation. Does anyone remember? Should this work?
#include <propeller.h>
#define RCFAST 0x00
#define RCSLOW 0x01
#define XINPUT 0x22
#define XTAL1 0x2a
#define XTAL2 0x32
#define XTAL3 0x3a
#define PLL1X 0x41
#define PLL2X 0x42
#define PLL4X 0x43
#define PLL8X 0x44
#define PLL16X 0x45
unsigned char _clkmode = XTAL1+PLL8X;
Comments
__asm__ ( " .global __clkmodeval\n" ); __asm__ ( " __clkmodeval = 0x6e\n" );
Seems like it would be good to wrap this in a macro in propeller.h!#define INITIAL_CLKMODE(x) \ __asm__ ( " .global __clkmodeval\n" ); \ __asm__ ( " __clkmodeval = " #x "\n" );
That works with this code:INITIAL_CLKMODE(0x6e)
but not with this code:#define RCFAST 0x00 #define RCSLOW 0x01 #define XINPUT 0x22 #define XTAL1 0x2a #define XTAL2 0x32 #define XTAL3 0x3a #define PLL1X 0x41 #define PLL2X 0x42 #define PLL4X 0x43 #define PLL8X 0x44 #define PLL16X 0x45 INITIAL_CLKMODE(XTAL1+PLL8X)
I guess C macro substitution is not done inside of __asm__ blocks?The table is a bit misleading though.
Scroll down to the bottom of this code
RCFAST 0_0_0_00_000 RCSLOW 0_0_0_00_001 XINPUT (no PLL) 0_0_1_00_010 XINPUT PLL1X 0_1_1_00_011 XINPUT PLL2X 0_1_1_00_100 XINPUT PLL4X 0_1_1_00_101 XINPUT PLL8X 0_1_1_00_110 XINPUT PLL16X 0_1_1_00_111 XTAL1 PLL1X 0_1_1_01_011 XTAL1 PLL2X 0_1_1_01_100 XTAL1 PLL4X 0_1_1_01_101 XTAL1 PLL8X 0_1_1_01_110 XTAL1 PLL16X 0_1_1_01_111 XTAL2 PLL1X 0_1_1_10_011 XTAL2 PLL2X 0_1_1_10_100 XTAL2 PLL4X 0_1_1_10_101 XTAL2 PLL8X 0_1_1_10_110 XTAL2 PLL16X 0_1_1_10_111 XTAL3 PLL1X 0_1_1_11_011 XTAL3 PLL2X 0_1_1_11_100 XTAL3 PLL4X 0_1_1_11_101 XTAL3 PLL8X 0_1_1_11_110 XTAL3 PLL16X 0_1_1_11_111 ^---------------0 = always 0 (1 resets the chip) ^-------------0 = pll disabled 1 = pll enabled ^-----------0 = rcfast/rcslow (internal) 1 = oscillator/xtal (external) ^^-------00 = rcfast/rcslow/xinput 01 = xtal1 2Kohm 36pF 4-16MHz xtal 10 = xtal2 1Kohm 26pF 8-32MHz xtal 11 = xtal3 500ohm 16pF 20-60MHz xtal ^^^--000 = rcfast 001 = rcslow 010 = xinput (no pll) (oscillator input) 011 = pllx1 100 = pllx2 101 = pllx4 110 = pllx8 111 = pllx16
macros inside assembler...
Getting strings out of the C macro preprocessor is always a challenge. The C preprocessor is very dumb, and it just literally does string substitution, whereas most of us (even seasoned programmers) think in terms of semantic replacement.
Here's a sample program that shows (I think) how to do it. Try1 is the naive approach, which only does one level of expansion. Try2 does a deeper substitution:
#include <stdio.h> #define stringize_(x) #x #define string_(x) stringize_(x) #define RCSLOW 0x01 #define CLOCKMODE1(x) "__clkmodeval = " #x ";" #define CLOCKMODE2(x) "__clkmodeval = " string_(x) ";" int main() { printf("try 1: %s\n", CLOCKMODE1(RCSLOW)); printf("try 2: %s\n", CLOCKMODE2(RCSLOW)); return 0; }
The output is:
try 1: __clkmodeval = RCSLOW; try 2: __clkmodeval = 0x01;
Note that the macro replacement, if done, is recursive, e.g. if you replace the #define RCSLOW with:
#define RCSLOW_ORIG 0x01 #define RCSLOW RCSLOW_ORIG
the output is still the same. The trick is just getting past that first level of indirection.You'll get a string something like "0x08+0x0400" substituted (remember, the preprocessor doesn't understand any syntax, it just blindly replaces strings). I think the assembler will probably be OK with that, it should be able to evaluate the expression.
What happens when there are multiple clock settings, one of them has a typo, or there is nothing?
#define RCFAST 0x00 #define RCSLOW 0x01 #define XINPUT 0x22 #define XTAL1 0x2a #define XTAL2 0x32 #define XTAL3 0x3a #define PLL1X 0x41 #define PLL2X 0x42 #define PLL4X 0x43 #define PLL8X 0x44 #define PLL16X 0x45 #define stringize_(x) #x #define string_(x) stringize_(x) #define INITIAL_CLKMODE(x) \ __asm__ ( ".global __clkmodeval\n\t" \ "__clkmodeval = " string_(x) ";"); INITIAL_CLKMODE(XTAL1+PLL8X)
I think so. The only concern I have is polluting the preprocessor macro space. I can't think of any reason off the top of my head why someone would complain about `stringize_` and `string_`.... but maybe something a little more cryptic to be sure? Maybe `__propgcc_stringize_` and `__propgcc_string_` to be sure?
I've used changes in clock settings in SimpleIDE to reduce battery power and for long wait times. For example with a set up that measures temperature, bar pressure, and humidity every 10 minutes and stores them to an SD card for later evaluation.
I have cog 0 enter a wait state after saving the data, setting pin 0 to 0, which causes two other cogs to sleep (waitpeq), but I can't sleep the SimpleIDE SD and ADC cogs, so I rely on lowering the clock to reduce power. After 10 minutes, cog 0 wakes, sets the clock back to 80 Meg, and sets P0 = 1, waking the waitpeq cogs.
Would your method allow this?
Tom
What David was showing was a way to set the initial clock mode and frequency. To change this at run time, use the clkset(mode, frequency) macro from propeller.h.