@@ -132,10 +132,24 @@ namespace klib::core::lpc178x::io::system {
132132
133133 template <
134134 source Source, uint32_t Freq,
135- uint16_t Multiplier, pre_divider PreDivider,
136- uint8_t Div
135+ uint16_t Multiplier = 1 , pre_divider PreDivider = pre_divider::div_1 ,
136+ uint8_t Div = 1
137137 >
138138 static void set_main () {
139+ // calculate the fcco frequency using the oscilator and multiplier
140+ constexpr static uint32_t partial_freq = (Freq * 2 * Multiplier) / klib::exp2 (static_cast <uint32_t >(PreDivider));
141+
142+ // make sure the pll inputs are valid
143+ static_assert (Multiplier > 0 , " Invalid multiplier" );
144+ static_assert (Div > 0 , " Invalid divider" );
145+ static_assert (
146+ (Multiplier == 1 ) || (partial_freq >= 156'000'000 && partial_freq <= 320'000'000 ),
147+ " Invalid Fcco output. PLL frequency needs to be between 156 and 320mhz"
148+ );
149+
150+ // calculate the final frequency
151+ constexpr static uint32_t freq = (partial_freq / Div);
152+
139153 // enable the crystal if we are changing to that
140154 if constexpr (Source == source::main) {
141155 crystal::enable<true >();
@@ -148,10 +162,10 @@ namespace klib::core::lpc178x::io::system {
148162
149163 // enable/disable the boost based on the frequency
150164 // (> 100 Mhz = on)
151- SYSCON->PBOOST = (Freq > 100'000'000 ) ? 0b11 : 0b00 ;
165+ SYSCON->PBOOST = (freq > 100'000'000 ) ? 0b11 : 0b00 ;
152166
153167 // check if we need to enable the pll
154- if constexpr (Multiplier) {
168+ if constexpr (Multiplier > 1 ) {
155169 // disconnect the main pll if it is connected.
156170 if (SYSCON->CCLKSEL & (0x1 << 8 )) {
157171 SYSCON->CCLKSEL &= ~(0x1 << 8 );
@@ -173,7 +187,7 @@ namespace klib::core::lpc178x::io::system {
173187 SYSCON->CLKSRCSEL = static_cast <uint32_t >(Source);
174188
175189 // setup the main pll
176- setup<pll::main>(Multiplier, PreDivider);
190+ setup<pll::main>(( Multiplier - 1 ) , PreDivider);
177191
178192 // enable the pll
179193 enable<pll::main, true >();
@@ -189,20 +203,26 @@ namespace klib::core::lpc178x::io::system {
189203 }
190204
191205 // setup the cpu clock divider
192- SYSCON->CCLKSEL = Div & 0x1f | ((Multiplier > 0 ) << 8 );
206+ SYSCON->CCLKSEL = ( Div - 1 ) & 0x1f | ((Multiplier > 1 ) << 8 );
193207
194208 // notify klib what freqency we are running
195- klib::io::clock::set (Freq );
209+ klib::io::clock::set (freq );
196210 }
197211
198212 template <
199213 uint32_t Freq, uint16_t Multiplier,
200214 pre_divider PreDivider
201215 >
202216 static void set_usb () {
203- static_assert ((Freq % 48'000'000 ) == 0 , " Pll frequency needs to be 48, 96 or 144Mhz" );
204- static_assert (Freq <= 144'000'000 , " Maximum USB pll frequency supported is 144Mhz" );
205- static_assert (Freq >= 48'000'000 , " Minumim USB pll frequency supported is 48Mhz" );
217+ static_assert ((48'000'000 % Freq) == 0 , " Invalid crystal frequency" );
218+
219+ // calculate the frequency
220+ constexpr static uint32_t freq = ((Freq * Multiplier) / klib::exp2 (static_cast <uint32_t >(PreDivider)));
221+
222+ static_assert ((freq % 48'000'000 ) == 0 , " Pll frequency needs to be 48, 96 or 144Mhz" );
223+ static_assert (freq <= 144'000'000 , " Maximum USB pll frequency supported is 144Mhz" );
224+ static_assert (freq >= 48'000'000 , " Minumim USB pll frequency supported is 48Mhz" );
225+ static_assert (Multiplier > 0 , " Invalid multiplier" );
206226
207227 // check if the crystal is stable and enabled
208228 if (!crystal::status ()) {
@@ -221,7 +241,7 @@ namespace klib::core::lpc178x::io::system {
221241 }
222242
223243 // setup the second pll
224- setup<pll::alternate>(Multiplier, PreDivider);
244+ setup<pll::alternate>(Multiplier - 1 , PreDivider);
225245
226246 // enable the pll
227247 enable<pll::alternate, true >();
@@ -233,7 +253,7 @@ namespace klib::core::lpc178x::io::system {
233253
234254 // setup the correct divider for the usb and
235255 // change to the alternate pll
236- SYSCON->USBCLKSEL = (Freq / 48'000'000 ) | (0x2 << 8 );
256+ SYSCON->USBCLKSEL = (freq / 48'000'000 ) | (0x2 << 8 );
237257 }
238258 };
239259
0 commit comments