Skip to content

Commit 60e330f

Browse files
rootroot
authored andcommitted
Added Settable Clock for MIMXRT BOARDS
1 parent 7be66a5 commit 60e330f

File tree

9 files changed

+300
-3
lines changed

9 files changed

+300
-3
lines changed

ports/mimxrt10xx/boards/sparkfun_teensy_micromod/mpconfigboard.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@
1919

2020
#define CIRCUITPY_USB_DEVICE_INSTANCE 0
2121
#define CIRCUITPY_USB_HOST_INSTANCE 1
22+
23+
#define HAS_SETTABLE_CLOCK 1

ports/mimxrt10xx/boards/teensy40/mpconfigboard.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@
1616

1717
#define DEFAULT_UART_BUS_RX (&pin_GPIO_AD_B0_03)
1818
#define DEFAULT_UART_BUS_TX (&pin_GPIO_AD_B0_02)
19+
20+
#define HAS_SETTABLE_CLOCK 1

ports/mimxrt10xx/boards/teensy41/mpconfigboard.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@
1919

2020
#define CIRCUITPY_USB_DEVICE_INSTANCE 0
2121
#define CIRCUITPY_USB_HOST_INSTANCE 1
22+
23+
#define HAS_SETTABLE_CLOCK 1

ports/mimxrt10xx/common-hal/microcontroller/Processor.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
* THE SOFTWARE.
2626
*/
2727

28+
//https://raw.githubusercontent.com/adafruit/circuitpython/main/ports/mimxrt10xx/common-hal/microcontroller/Processor.c
29+
2830
#include <math.h>
2931

3032
#include "common-hal/microcontroller/Processor.h"
@@ -50,6 +52,13 @@ float common_hal_mcu_processor_get_temperature(void) {
5052
return temp;
5153
}
5254

55+
uint32_t common_hal_mcu_processor_set_sys_clock(mcu_processor_obj_t *self,
56+
uint32_t frequency) {
57+
SystemCoreClock = setarmclock(frequency);
58+
return SystemCoreClock;
59+
}
60+
61+
5362
float common_hal_mcu_processor_get_voltage(void) {
5463
return NAN;
5564
}
@@ -75,4 +84,4 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) {
7584

7685
mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) {
7786
return RESET_REASON_UNKNOWN;
78-
}
87+
}

ports/mimxrt10xx/common-hal/microcontroller/Processor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@
3131
#define COMMON_HAL_MCU_PROCESSOR_UID_LENGTH 16
3232

3333
#include "py/obj.h"
34+
#include "clocks.h"
3435

3536
typedef struct {
3637
mp_obj_base_t base;
3738
// Stores no state currently.
39+
uint32_t frequency;
3840
} mcu_processor_obj_t;
3941

4042
#endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_MICROCONTROLLER_PROCESSOR_H

ports/mimxrt10xx/peripherals/mimxrt10xx/MIMXRT1062/clocks.c

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
#include "fsl_clock.h"
3636
#include "fsl_iomuxc.h"
37+
#include "fsl_device_registers.h"
3738

3839
#include "clocks.h"
3940

@@ -335,3 +336,247 @@ void clocks_init(void) {
335336

336337
CLOCK_EnableClock(kCLOCK_Iomuxc);
337338
}
339+
340+
/* clockspeed.c
341+
* http://www.pjrc.com/teensy/
342+
* Copyright (c) 2017 PJRC.COM, LLC
343+
*
344+
* Permission is hereby granted, free of charge, to any person obtaining a copy
345+
* of this software and associated documentation files (the "Software"), to deal
346+
* in the Software without restriction, including without limitation the rights
347+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
348+
* copies of the Software, and to permit persons to whom the Software is
349+
* furnished to do so, subject to the following conditions:
350+
*
351+
* The above copyright notice and this permission notice shall be included in
352+
* all copies or substantial portions of the Software.
353+
*
354+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
355+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
356+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
357+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
358+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
359+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
360+
* THE SOFTWARE.
361+
*/
362+
//Note setarmclock is a port from Teensyduino for the Teensy 4.x written by Paul Stroffgren,
363+
// A brief explanation of F_CPU_ACTUAL vs F_CPU
364+
// https://forum.pjrc.com/threads/57236?p=212642&viewfull=1#post212642
365+
volatile uint32_t F_CPU_ACTUAL = 396000000;
366+
volatile uint32_t F_BUS_ACTUAL = 132000000;
367+
368+
// Define these to increase the voltage when attempting overclocking
369+
// The frequency step is how quickly to increase voltage per frequency
370+
// The datasheet says 1600 is the absolute maximum voltage. The hardware
371+
// can actually create up to 1575. But 1300 is the recommended limit.
372+
// (earlier versions of the datasheet said 1300 was the absolute max)
373+
#define OVERCLOCK_STEPSIZE 28000000
374+
#define OVERCLOCK_MAX_VOLT 1575
375+
376+
#define DCDC_REG3 0x40080012
377+
#define DCDC_REG0 0x40080000
378+
#define DCDC_REG0_STS_DC_OK_L ((uint32_t)(1<<31))
379+
#define CCM_ANALOG_PLL_USB1_ENABLE_L ((uint32_t)(1<<13))
380+
#define CCM_ANALOG_PLL_USB1_POWER_L ((uint32_t)(1<<12))
381+
#define CCM_ANALOG_PLL_USB1_EN_USB_CLKS_L ((uint32_t)(1<<6))
382+
#define CCM_ANALOG_PLL_USB1_LOCK_L ((uint32_t)(1<<31))
383+
#define CCM_CCGR6_DCDC(n) ((uint32_t)(((n) & 0x03) << 6))
384+
#define CCM_ANALOG_PLL_ARM_LOCK_L ((uint32_t)(1<<31))
385+
#define CCM_ANALOG_PLL_ARM_BYPASS_L ((uint32_t)(1<<16))
386+
#define CCM_ANALOG_PLL_ARM_ENABLE_L ((uint32_t)(1<<13))
387+
#define CCM_ANALOG_PLL_ARM_POWERDOWN_L ((uint32_t)(1<<12))
388+
#define CCM_CDHIPR_ARM_PODF_BUSY_L ((uint32_t)(1<<16))
389+
#define CCM_CDHIPR_AHB_PODF_BUSY_L ((uint32_t)(1<<1))
390+
#define CCM_CDHIPR_PERIPH_CLK_SEL_BUSY_L ((uint32_t)(1<<5))
391+
#define CCM_CBCDR_PERIPH_CLK_SEL_L ((uint32_t)(1<<25))
392+
#define CCM_CCGR_OFF 0
393+
#define CCM_CCGR_ON_RUNONLY 1
394+
#define CCM_CCGR_ON 3
395+
396+
/* Teensyduino Core Library - clockspeed.c
397+
* http://www.pjrc.com/teensy/
398+
* Copyright (c) 2017 PJRC.COM, LLC.
399+
*
400+
* Permission is hereby granted, free of charge, to any person obtaining
401+
* a copy of this software and associated documentation files (the
402+
* "Software"), to deal in the Software without restriction, including
403+
* without limitation the rights to use, copy, modify, merge, publish,
404+
* distribute, sublicense, and/or sell copies of the Software, and to
405+
* permit persons to whom the Software is furnished to do so, subject to
406+
* the following conditions:
407+
*
408+
* 1. The above copyright notice and this permission notice shall be
409+
* included in all copies or substantial portions of the Software.
410+
*
411+
* 2. If the Software is incorporated into a build system that allows
412+
* selection among a list of target devices, then similar target
413+
* devices manufactured by PJRC.COM must be included in the list of
414+
* target devices and selectable in the same manner.
415+
*
416+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
417+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
418+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
419+
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
420+
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
421+
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
422+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
423+
* SOFTWARE.
424+
*/
425+
426+
//uint32_t set_arm_clock(uint32_t frequency);
427+
428+
// stuff needing wait handshake:
429+
// CCM_CACRR ARM_PODF
430+
// CCM_CBCDR PERIPH_CLK_SEL
431+
// CCM_CBCMR PERIPH2_CLK_SEL
432+
// CCM_CBCDR AHB_PODF
433+
// CCM_CBCDR SEMC_PODF
434+
435+
uint32_t setarmclock(uint32_t frequency)
436+
{
437+
uint32_t cbcdr = CCM->CBCDR; // pg 1021
438+
uint32_t cbcmr = CCM->CBCMR; // pg 1023
439+
uint32_t dcdc = DCDC->REG3;
440+
441+
// compute required voltage
442+
uint32_t voltage = 1150; // default = 1.15V
443+
if (frequency > 528000000) {
444+
voltage = 1250; // 1.25V
445+
#if defined(OVERCLOCK_STEPSIZE) && defined(OVERCLOCK_MAX_VOLT)
446+
if (frequency > 600000000) {
447+
voltage += ((frequency - 600000000) / OVERCLOCK_STEPSIZE) * 25;
448+
if (voltage > OVERCLOCK_MAX_VOLT) voltage = OVERCLOCK_MAX_VOLT;
449+
}
450+
#endif
451+
} else if (frequency <= 24000000) {
452+
voltage = 950; // 0.95
453+
}
454+
455+
// if voltage needs to increase, do it before switch clock speed
456+
CCM->CCGR6 |= CCM_CCGR6_DCDC(CCM_CCGR_ON);
457+
if ((dcdc & ((uint32_t)(0x1F << 0))) < ((uint32_t)(((voltage - 800) / 25) & 0x1F) << 0)) {
458+
//printf("Increasing voltage to %u mV\n", voltage);
459+
dcdc &= ~((uint32_t)(0x1F << 0));
460+
dcdc |= ((uint32_t)(((voltage - 800) / 25) & 0x1F) << 0);
461+
DCDC->REG3 = dcdc;
462+
while (!(DCDC->REG0 & DCDC_REG0_STS_DC_OK_L)) ; // wait voltage settling
463+
}
464+
465+
if (!(cbcdr & CCM_CBCDR_PERIPH_CLK_SEL_L)) {
466+
//printf("need to switch to alternate clock during reconfigure of ARM PLL\n");
467+
const uint32_t need1s = CCM_ANALOG_PLL_USB1_ENABLE_L | CCM_ANALOG_PLL_USB1_POWER_L |
468+
CCM_ANALOG_PLL_USB1_LOCK_L | CCM_ANALOG_PLL_USB1_EN_USB_CLKS_L;
469+
uint32_t sel, div;
470+
if ((CCM_ANALOG->PLL_USB1 & need1s) == need1s) {
471+
//printf("USB PLL is running, so we can use 120 MHz\n");
472+
sel = 0;
473+
div = 3; // divide down to 120 MHz, so IPG is ok even if IPG_PODF=0
474+
} else {
475+
//printf("USB PLL is off, use 24 MHz crystal\n");
476+
sel = 1;
477+
div = 0;
478+
}
479+
if ((cbcdr & ((uint32_t)(0x07 << 27))) != CCM_CBCDR_PERIPH_CLK2_PODF(div)) {
480+
// PERIPH_CLK2 divider needs to be changed
481+
cbcdr &= ~((uint32_t)(0x07 << 27));
482+
cbcdr |= CCM_CBCDR_PERIPH_CLK2_PODF(div);
483+
CCM->CBCDR = cbcdr;
484+
}
485+
if ((cbcmr & ((uint32_t)(0x03 << 12))) != CCM_CBCMR_PERIPH_CLK2_SEL(sel)) {
486+
// PERIPH_CLK2 source select needs to be changed
487+
cbcmr &= ~((uint32_t)(0x03 << 12));
488+
cbcmr |= CCM_CBCMR_PERIPH_CLK2_SEL(sel);
489+
CCM->CBCMR = cbcmr;
490+
while (CCM->CDHIPR & ((uint32_t)(1<<3))) ; // wait
491+
}
492+
// switch over to PERIPH_CLK2
493+
cbcdr |= ((uint32_t)(1<<25));
494+
CCM->CBCDR = cbcdr;
495+
while (CCM->CDHIPR & ((uint32_t)(1<<5))) ; // wait
496+
} else {
497+
//printf("already running from PERIPH_CLK2, safe to mess with ARM PLL\n");
498+
}
499+
500+
// TODO: check if PLL2 running, can 352, 396 or 528 can work? (no need for ARM PLL)
501+
502+
// DIV_SELECT: 54-108 = official range 648 to 1296 in 12 MHz steps
503+
uint32_t div_arm = 1;
504+
uint32_t div_ahb = 1;
505+
while (frequency * div_arm * div_ahb < 648000000) {
506+
if (div_arm < 8) {
507+
div_arm = div_arm + 1;
508+
} else {
509+
if (div_ahb < 5) {
510+
div_ahb = div_ahb + 1;
511+
div_arm = 1;
512+
} else {
513+
break;
514+
}
515+
}
516+
}
517+
uint32_t mult = (frequency * div_arm * div_ahb + 6000000) / 12000000;
518+
if (mult > 108) mult = 108;
519+
if (mult < 54) mult = 54;
520+
//printf("Freq: 12 MHz * %u / %u / %u\n", mult, div_arm, div_ahb);
521+
frequency = mult * 12000000 / div_arm / div_ahb;
522+
523+
//printf("ARM PLL=%x\n", CCM_ANALOG->PLL_ARM);
524+
const uint32_t arm_pll_mask = CCM_ANALOG_PLL_ARM_LOCK_L | CCM_ANALOG_PLL_ARM_BYPASS_L |
525+
CCM_ANALOG_PLL_ARM_ENABLE_L | CCM_ANALOG_PLL_ARM_POWERDOWN_L |
526+
CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK;
527+
if ((CCM_ANALOG->PLL_ARM & arm_pll_mask) != (CCM_ANALOG_PLL_ARM_LOCK_L
528+
| CCM_ANALOG_PLL_ARM_ENABLE_L | CCM_ANALOG_PLL_ARM_DIV_SELECT(mult))) {
529+
//printf("ARM PLL needs reconfigure\n");
530+
CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_L;
531+
// TODO: delay needed?
532+
CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_ENABLE_L
533+
| CCM_ANALOG_PLL_ARM_DIV_SELECT(mult);
534+
while (!(CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_L)) ; // wait for lock
535+
//printf("ARM PLL=%x\n", CCM_ANALOG->PLL_ARM);
536+
} else {
537+
//printf("ARM PLL already running at required frequency\n");
538+
}
539+
540+
if ((CCM->CACRR & ((uint32_t)(0x07 << 0))) != (div_arm - 1)) {
541+
CCM->CACRR = CCM_CACRR_ARM_PODF(div_arm - 1);
542+
while (CCM->CDHIPR & CCM_CDHIPR_ARM_PODF_BUSY_L) ; // wait
543+
}
544+
545+
if ((cbcdr & ((uint32_t)(0x07 << 10))) != CCM_CBCDR_AHB_PODF(div_ahb - 1)) {
546+
cbcdr &= ~((uint32_t)(0x07 << 10));
547+
cbcdr |= CCM_CBCDR_AHB_PODF(div_ahb - 1);
548+
CCM->CBCDR = cbcdr;
549+
while (CCM->CDHIPR & CCM_CDHIPR_AHB_PODF_BUSY_L); // wait
550+
}
551+
552+
uint32_t div_ipg = (frequency + 149999999) / 150000000;
553+
if (div_ipg > 4) div_ipg = 4;
554+
if ((cbcdr & ((uint32_t)(0x03 << 8))) != (CCM_CBCDR_IPG_PODF(div_ipg - 1))) {
555+
cbcdr &= ~((uint32_t)(0x03 << 8));
556+
cbcdr |= CCM_CBCDR_IPG_PODF(div_ipg - 1);
557+
// TODO: how to safely change IPG_PODF ??
558+
CCM->CBCDR = cbcdr;
559+
}
560+
561+
//cbcdr &= ~CCM_CBCDR_PERIPH_CLK_SEL;
562+
//CCM_CBCDR = cbcdr; // why does this not work at 24 MHz?
563+
CCM->CBCDR &= ~((uint32_t)(1<<25));
564+
while (CCM->CDHIPR & CCM_CDHIPR_PERIPH_CLK_SEL_BUSY_L) ; // wait
565+
566+
F_CPU_ACTUAL = frequency;
567+
F_BUS_ACTUAL = frequency / div_ipg;
568+
//scale_cpu_cycles_to_microseconds = 0xFFFFFFFFu / (uint32_t)(frequency / 1000000u);
569+
570+
//printf("New Frequency: ARM=%u, IPG=%u\n", frequency, frequency / div_ipg);
571+
572+
// if voltage needs to decrease, do it after switch clock speed
573+
if ((dcdc & ((uint32_t)(0x1F << 0))) > ((uint32_t)(((voltage - 800) / 25) & 0x1F) << 0)) {
574+
//printf("Decreasing voltage to %u mV\n", voltage);
575+
dcdc &= ~((uint32_t)(0x1F << 0));
576+
dcdc |= ((uint32_t)(0x1F << 0));
577+
DCDC->REG3 = dcdc;
578+
while (!(DCDC->REG0 & DCDC_REG0_STS_DC_OK_L)) ; // wait voltage settling
579+
}
580+
581+
return frequency;
582+
}

ports/mimxrt10xx/peripherals/mimxrt10xx/clocks.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@
2727
extern uint32_t SystemCoreClock;
2828

2929
void clocks_init(void);
30+
uint32_t setarmclock(uint32_t frequency);

shared-bindings/microcontroller/Processor.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,20 @@
3030
#include <math.h>
3131
#include <stdint.h>
3232

33-
#include "py/objproperty.h"
33+
//#include "py/objproperty.h"
34+
35+
//#include "py/runtime.h"
36+
37+
#include "shared-bindings/util.h"
3438

39+
#include "shared/runtime/buffer_helper.h"
40+
#include "shared/runtime/context_manager_helpers.h"
41+
#include "py/mperrno.h"
42+
#include "py/objtype.h"
43+
#include "py/objproperty.h"
3544
#include "py/runtime.h"
45+
#include "supervisor/shared/translate.h"
46+
3647

3748
//| class Processor:
3849
//| """Microcontroller CPU information and control
@@ -61,6 +72,27 @@
6172
//| frequency: int
6273
//| """The CPU operating frequency in Hertz. (read-only)"""
6374
//|
75+
76+
STATIC mp_obj_t mcu_processor_set_sys_clock(mp_obj_t self_in, mp_obj_t freq) {
77+
mcu_processor_obj_t *self = MP_OBJ_TO_PTR(self_in);
78+
#if defined(HAS_SETTABLE_CLOCK)
79+
uint32_t value_of_freq = MP_OBJ_SMALL_INT_VALUE(freq);
80+
common_hal_mcu_processor_set_sys_clock(self, value_of_freq);
81+
#else
82+
mp_raise_msg(&mp_type_NotImplementedError,translate("Settable Clock Not Implemented for Your Board"));
83+
#endif
84+
return mp_const_none;
85+
}
86+
87+
MP_DEFINE_CONST_FUN_OBJ_2(mcu_processor_set_sys_clock_obj, mcu_processor_set_sys_clock);
88+
89+
const mp_obj_property_t mcu_processor_freq_obj = {
90+
.base.type = &mp_type_property,
91+
.proxy = {(mp_obj_t)&mcu_processor_set_sys_clock_obj,
92+
MP_ROM_NONE,
93+
MP_ROM_NONE},
94+
};
95+
6496
STATIC mp_obj_t mcu_processor_get_frequency(mp_obj_t self) {
6597
return mp_obj_new_int_from_uint(common_hal_mcu_processor_get_frequency());
6698
}
@@ -157,6 +189,7 @@ STATIC const mp_rom_map_elem_t mcu_processor_locals_dict_table[] = {
157189
{ MP_ROM_QSTR(MP_QSTR_temperature), MP_ROM_PTR(&mcu_processor_temperature_obj) },
158190
{ MP_ROM_QSTR(MP_QSTR_uid), MP_ROM_PTR(&mcu_processor_uid_obj) },
159191
{ MP_ROM_QSTR(MP_QSTR_voltage), MP_ROM_PTR(&mcu_processor_voltage_obj) },
192+
{ MP_ROM_QSTR(MP_QSTR_setfrequency), MP_ROM_PTR(&mcu_processor_set_sys_clock_obj) },
160193
};
161194

162195
STATIC MP_DEFINE_CONST_DICT(mcu_processor_locals_dict, mcu_processor_locals_dict_table);

shared-bindings/microcontroller/Processor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ uint32_t common_hal_mcu_processor_get_frequency(void);
3838
mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void);
3939
float common_hal_mcu_processor_get_temperature(void);
4040
void common_hal_mcu_processor_get_uid(uint8_t raw_id[]);
41-
float common_hal_mcu_processor_get_voltage(void);
41+
float common_hal_mcu_processor_get_voltage(void);
42+
uint32_t common_hal_mcu_processor_set_sys_clock(mcu_processor_obj_t *self, uint32_t frequency);
4243

4344
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_MICROCONTROLLER_PROCESSOR_H

0 commit comments

Comments
 (0)