I am working on a bare metal application on a K10 processor
and must switch from reset clock configuration to using the
external oscillator with a 50 MHz crystal to clock my MCU at
100 MHz.
Are there any code samples that tackle this (or a similar)
task?
Solved! Go to Solution.
Gary
The uTasker defines are based on the part's user's maual so you can simply check the registers in the user's manual and it should be fully interpretable.
They avoid macros since they are often unclear (the field width is not obvious and also the meaning of each value is not clear, plus reading code like REG_MACRO(6) still gives no indication about what the 6 means).
You can get the uTasker source code from http://www.utasker.com/forum/index.php?topic=1721.0 in case you need to know how anything is defined.
The ones used in the clock configuration code are:
#define MCG_C1_CLKS_PLL_FLL 0x00 #define MCG_C1_FRDIV_1024 0x28 #define MCG_C1_CLKS_EXTERN_CLK 0x80 #define MCG_C2_RANGE_8M_32M 0x20 #define MCG_C2_LOCRE0 0x80 #define MCG_C5_PLLSTEN0 0x20 #define MCG_C6_PLLS 0x40 #define MCG_S_CLKST_EXTERN_CLK 0x08 #define MCG_S_CLKST_MASK 0x0c #define MCG_S_CLKST_PLL 0x0c #define MCG_S_IREFST 0x10 #define MCG_S_PLLST 0x20 #define MCG_S_LOCK 0x40
Regards
Mark
Gary
For 50MHz clock input (32 MHz is fastest crystal that can be used) the code can be taken from a K60 setup for the TWR board.
For 100MHz core/sytem clock, with 50MHz bus and 25MHz flash clocks the following (from the uTasker project) will do it:
#define CLOCK_MUL 32 #define MCG_C6_VDIV0_LOWEST depends on the K10 type used (either 24 or 16 - consult the particular data sheet) #define CLOCK_DIV 16 #define SYSTEM_CLOCK_DIVIDE 1 #define BUS_CLOCK_DIVIDE 2 #define FLEX_CLOCK_DIVIDE 16 (not important if no Flex Bus) #define FLASH_CLOCK_DIVIDE 4 MCG_C2 = (MCG_C2_RANGE_8M_32M | MCG_C2_LOCRE0); // select external clock source (with reset on clock loss) MCG_C1 = (MCG_C1_CLKS_EXTERN_CLK | MCG_C1_FRDIV_1024); // switch to external input clock (the FLL input clock is set to as close to its input range as possible, although this is not absolutely necessary since the FLL will not be used) while ((MCG_S & MCG_S_IREFST) != 0) {} // loop until the FLL source is no longer the internal reference clock while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST_EXTERN_CLK) {} // loop until the external reference clock source is valid MCG_C5 = ((CLOCK_DIV - 1) | MCG_C5_PLLSTEN0); // now move from state FEE to state PBE (or FBE) PLL remains enabled in normal stop modes MCG_C6 = ((CLOCK_MUL - MCG_C6_VDIV0_LOWEST) | MCG_C6_PLLS); while ((MCG_S & MCG_S_PLLST) == 0) {} // loop until the PLLS clock source becomes valid while ((MCG_S & MCG_S_LOCK) == 0) {} // loop until PLL locks SIM_CLKDIV1 = (((SYSTEM_CLOCK_DIVIDE - 1) << 28) | ((BUS_CLOCK_DIVIDE - 1) << 24) | ((FLEX_CLOCK_DIVIDE - 1) << 20) | ((FLASH_CLOCK_DIVIDE - 1) << 16)); // prepare bus clock divides MCG_C1 = (MCG_C1_CLKS_PLL_FLL | MCG_C1_FRDIV_1024); // finally move from PBE to PEE mode - switch to PLL clock while ((MCG_S & MCG_S_CLKST_MASK) != MCG_S_CLKST_PLL) {} // loop until the PLL clock is selected
Simulation showing the obtained speeds:
Regards
Mark
Mark,
Thanks for the tips.
1. We are feeding an external, 50 MHz oscillator to the
K10. Please forgive the oversimplification.
2. As assumed by your comments, we are not using FlexBus.
3. I can't figure out the comment:
>
> depends on the K10 type used
> (either 24 or 16 - consult the
> particular data sheet)
>
We are using a 100 MHz K10, which is indicated by a '10' at
the end of the part number. I can't find anything that maps
to 24 or 16.
4. After posting, I found code in file system_MK10D10.c, which
is auto-generated by KDS and which I presume is executed
before entry into main(). It contains 2 functions:
- SystemInit(), &
- SystemCoreClockUpdate();
both of which appear to modify the MCG (I haven't figured
out everything they do, yet). If my observation is correct,
I will have to disable this section manually to use your
code in main(), correct?
Gary
You can also generate code with PE.
The KDS code needs configuring, whereby you will also need to know the register content details since it needs raw settings configured. PE will allow you to not need to understand register settings but the generated code is pretty huge.
K10 120MHz
K10 100MHz
If using KDS you will also need to know this because you have to plug in the raw details, rather than being able to work with the actual divide and multiplications that you ultimately would like.
Therefore, for your K10 100MHz, a multiplication factor of x47 is 0x17, whereby for a K10 120MHz it is 0x1f.
#define MCG_C6_VDIV0_LOWEST 24 // when using K10 100MHz
or
#define MCG_C6_VDIV0_LOWEST 16 // when using K10 120MHz
allows the user to enter the value that is really required, eg, 47, and automates the actual register content used to match the chip.
The following article may help de-mystify the MCG and its operation http://www.utasker.com/kinetis/MCG.html
Regards
Mark
Mark,
More thanks for sorting that out.
Meanwhile I started processing the code snippet you provided. It contains 15 tokens that look like macros that aren't defined in the snippet. Of those I was able to find definitions for 4 in an MK10D10.h header inside PE:
- MCG_C2_LOCRE0()
- MCG_C5_PLLSTEN0()
- MCG_C6_PLLS()
- MCG_S()
The definitions however have parameters, while the evocations in the sample do not, so I am not sure I have the correct file and I can't find the other tokens anywhere.
Are they specific to uTasker or some other outside resource?
We don't rely much on PE because we have an internal requirement for project portability, i.e. I should be able to check a project into our version control, and another developer check it out and build it on his system without significant fine tuning. I am able to copy projects WITHIN MY WORKSPACE inside KDS, but anything copied by any other means winds up broken in ways I find very difficult to troubleshoot. If there is a way to use these tools to generate portable projects, I would love to hear about it.
Gary
The uTasker defines are based on the part's user's maual so you can simply check the registers in the user's manual and it should be fully interpretable.
They avoid macros since they are often unclear (the field width is not obvious and also the meaning of each value is not clear, plus reading code like REG_MACRO(6) still gives no indication about what the 6 means).
You can get the uTasker source code from http://www.utasker.com/forum/index.php?topic=1721.0 in case you need to know how anything is defined.
The ones used in the clock configuration code are:
#define MCG_C1_CLKS_PLL_FLL 0x00 #define MCG_C1_FRDIV_1024 0x28 #define MCG_C1_CLKS_EXTERN_CLK 0x80 #define MCG_C2_RANGE_8M_32M 0x20 #define MCG_C2_LOCRE0 0x80 #define MCG_C5_PLLSTEN0 0x20 #define MCG_C6_PLLS 0x40 #define MCG_S_CLKST_EXTERN_CLK 0x08 #define MCG_S_CLKST_MASK 0x0c #define MCG_S_CLKST_PLL 0x0c #define MCG_S_IREFST 0x10 #define MCG_S_PLLST 0x20 #define MCG_S_LOCK 0x40
Regards
Mark
Works like a hose!
Thanks, Mark!