| パソコン制御をもっと気軽に 電子制御をもっと気楽に |
低速CPUクロックによる省電力化
Arduino RP2040 2026/01/10
#include "PowerSaveHelper.hpp"
void cShowClkRegs::ShowAll( Print * aPrint )
{
ShowClockFrequency( aPrint );
ShowPllRegs( aPrint ) ;
ShowClkRegs( aPrint ) ;
ShowXoscRegs( aPrint ) ;
ShowRoscRegs( aPrint ) ;
}
void cShowClkRegs::ShowClockFrequency( Print * aPrint )
{
/*
RP2040
#define CLOCKS_FC0_SRC_VALUE_NULL _u(0x00)
#define CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY _u(0x01)
#define CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY _u(0x02)
#define CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC _u(0x03)
#define CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC_PH _u(0x04)
#define CLOCKS_FC0_SRC_VALUE_XOSC_CLKSRC _u(0x05)
#define CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN0 _u(0x06)
#define CLOCKS_FC0_SRC_VALUE_CLKSRC_GPIN1 _u(0x07)
#define CLOCKS_FC0_SRC_VALUE_CLK_REF _u(0x08)
#define CLOCKS_FC0_SRC_VALUE_CLK_SYS _u(0x09)
#define CLOCKS_FC0_SRC_VALUE_CLK_PERI _u(0x0a)
#define CLOCKS_FC0_SRC_VALUE_CLK_USB _u(0x0b)
#define CLOCKS_FC0_SRC_VALUE_CLK_ADC _u(0x0c)
#define CLOCKS_FC0_SRC_VALUE_CLK_RTC _u(0x0d)
RP2350
0x01 → PLL_SYS_CLKSRC_PRIMARY
0x02 → PLL_USB_CLKSRC_PRIMARY
0x03 → ROSC_CLKSRC
0x04 → ROSC_CLKSRC_PH
0x05 → XOSC_CLKSRC
0x06 → CLKSRC_GPIN0
0x07 → CLKSRC_GPIN1
0x08 → CLK_REF
0x09 → CLK_SYS
0x0a → CLK_PERI
0x0b → CLK_USB
0x0c → CLK_ADC
0x0d → CLK_HSTX
0x0e → LPOSC_CLKSRC
0x0f → OTP_CLK2FC
0x10 → PLL_USB_CLKSRC_PRIMARY_DFT
*/
uint fc0_src[]={ 1,2,3,5, 8,9, 10,11,12,13} ;
const char * src_name[]={"PLL_SYS","PLL_USB","ROSC","XOSC",
"CLK_REF","CLK_SYS",
"CLK_PERI","CLK_USB","CLK_ADC","CLK_RTC" } ;
// scr_nameにあるPLL_SYSからCLK_ADCまでを表示します
// RP2350で追加されたclkはここでは表示していません
for ( int n=0;n<9;n++ ){
uint32_t Frq = frequency_count_khz( fc0_src[n] ) ;
aPrint->printf("%-8s:%6dKHz\n",src_name[n],Frq);
}
#if defined( PICO_RP2040 )
// RP2350にRTCは無い
uint32_t Frq = frequency_count_hz( fc0_src[9] ) ;
aPrint->printf("%-8s:%6dHz\n",src_name[9],Frq);
#endif
}
void cShowClkRegs::ShowPllRegs( Print * aPrint)
{
const char * PllName[]={"PLL_SYS","PLL_USB"};
pll_hw_t * pll_hw[]={pll_sys,pll_usb};
int PreDiv;
int FBDiv;
int PostDiv1;
int PostDiv2;
double CLK = 12.0 ; /* MHz*/
for(int rr=0;rr<2;rr++)
{
uint32_t cs = pll_hw[rr]->cs;
uint32_t pwr = pll_hw[rr]->pwr;
uint32_t fdiv= pll_hw[rr]->fbdiv_int;
uint32_t prim= pll_hw[rr]->prim;
aPrint->printf("%-10s cs=%8X pwr=%8X fdiv=%8X prim=%8X \n",PllName[rr], cs, pwr, fdiv, prim );
PreDiv = cs & PLL_CS_REFDIV_BITS;
FBDiv = fdiv & PLL_FBDIV_INT_BITS ;
PostDiv2 = (prim>>PLL_PRIM_POSTDIV2_LSB) & PLL_PRIM_POSTDIV2_RESET ;
PostDiv1 = (prim>>PLL_PRIM_POSTDIV1_LSB) & PLL_PRIM_POSTDIV1_RESET ;
aPrint->printf(" F = 12Mhz / %2d * %4d / %d /%d = %5.1f Mhz\n",PreDiv,FBDiv,PostDiv1,PostDiv2,
CLK/PreDiv*FBDiv/PostDiv1/PostDiv2 );
}
}
void cShowClkRegs::ShowClkRegs( Print * aPrint )
{
#if 0
typedef enum clock_num_rp2040 {
clk_gpout0 = 0, ///< Select CLK_GPOUT0 as clock source
clk_gpout1 = 1, ///< Select CLK_GPOUT1 as clock source
clk_gpout2 = 2, ///< Select CLK_GPOUT2 as clock source
clk_gpout3 = 3, ///< Select CLK_GPOUT3 as clock source
clk_ref = 4, ///< Select CLK_REF as clock source
clk_sys = 5, ///< Select CLK_SYS as clock source
clk_peri = 6, ///< Select CLK_PERI as clock source
clk_usb = 7, ///< Select CLK_USB as clock source
clk_adc = 8, ///< Select CLK_ADC as clock source
clk_rtc = 9, ///< Select CLK_RTC as clock source
CLK_COUNT
} clock_num_t;
typedef enum clock_num_rp2350 {
clk_gpout0 = 0, ///< Select CLK_GPOUT0 as clock source
clk_gpout1 = 1, ///< Select CLK_GPOUT1 as clock source
clk_gpout2 = 2, ///< Select CLK_GPOUT2 as clock source
clk_gpout3 = 3, ///< Select CLK_GPOUT3 as clock source
clk_ref = 4, ///< Select CLK_REF as clock source
clk_sys = 5, ///< Select CLK_SYS as clock source
clk_peri = 6, ///< Select CLK_PERI as clock source
clk_hstx = 7, ///< Select CLK_HSTX as clock source
clk_usb = 8, ///< Select CLK_USB as clock source
clk_adc = 9, ///< Select CLK_ADC as clock source
CLK_COUNT
} clock_num_t;
#endif
#if defined( PICO_RP2040 )
int CLK_NO[10] = {0,1,2,3,4,5,6,7,8,9} ;
const char * RegName[10]={"CLK_GPOUT0","CLK_GPOUT1","CLK_GPOUT2","CLK_GPOUT3",
"CLK_REF","CLK_SYS","CLK_PERI","CLK_USB","CLK_ADC","CLK_RTC"};
const char * AuxSrcName0[16]={"PLL_SYS","GPIN0","GPIN1","PLL_USB","ROSC","XOSC", // 0..5
"CLK_SYS","CLK_USB","CLK_ADC","CLK_RTC","CLK_REF", // 6..10
"SRC11","SRC12","SRC13","SRC14","SRC15"}; // 11..15
const char * AuxSrcName4[4]={"PLL_USB","GPIN0","GPIN1","SRC3"}; // for clk_ref
const char * SrcName4 [4]={"ROSC","AuxSrc","XOSC","SRC3"};
#else
int CLK_NO[10] = {0,1,2,3,4,5,6,8,9,7} ;
const char * RegName[10]={"CLK_GPOUT0","CLK_GPOUT1","CLK_GPOUT2","CLK_GPOUT3",
"CLK_REF","CLK_SYS","CLK_PERI","CLK_USB","CLK_ADC","CLK_HSTX"};
const char * AuxSrcName0[16]={"PLL_SYS","GPIN0","GPIN1","PLL_USB","PLL_USB_PRIM","ROSC","XOSC", // 0..6
"LPOSC","CLK_SYS","CLK_USB","CLK_ADC","CLK_REF","CLK_PERI", // 7..12
"CLK_HSTX","OPT_CLK2","SRC15" }; // 13..15
const char * AuxSrcName4[4]={"PLL_USB","GPIN0","GPIN1","PLL_USB_PRIM"}; // for clk_ref
const char * SrcName4 [4]={"ROSC","AuxSrc","XOSC","LPOSC"};
#endif
const char * AuxSrcName5[8]={"PLL_SYS","PLL_USB","ROSC","XOSC" ,"GPIN0","GPIN1","SRC6" ,"SRC7"}; // for clk_sys
const char * SrcName5 [8]={"CLK_REF","AuxSrc"};
const char * AuxSrcName6[8]={"CLK_SYS","PLL_SYS","PLL_USB","ROSC","XOSC" ,"GPIN0","GPIN1","SRC7"}; // for clk_peri
const char * AuxSrcName7[8]={"PLL_USB","PLL_SYS","ROSC" ,"XOSC","GPIN0","GPIN1","SRC6" ,"SRC7"}; // for clk_usb, clk_adc
int Auxsrc ;
int Src ;
int Int ;
int Frac ;
String Kill="" ;
String Enable="" ;
for(int rr=0;rr<10;rr++)
{
uint32_t ctrl=clocks_hw->clk[ CLK_NO[rr] ].ctrl;
uint32_t div =clocks_hw->clk[ CLK_NO[rr] ].div ;
aPrint->printf("%-10s ctrl=%8X div=%8X \n",RegName[rr],ctrl,div );
switch(rr){
case 0:
case 1:
case 2:
case 3:
Enable = (ctrl & 0x0800)==0 ? "Disable" : "Enable" ;
Kill = (ctrl & 0x0400)==0 ? "" : "Kill" ;
Auxsrc = ( ctrl>>5 ) & 0xF;
Int = ( div >>8 ) & 0xFFFFFF ;
Frac = div & 0xFF ;
aPrint->printf(" ExtSrc=%-10s int=%8d frac=%3d %s %s \n",AuxSrcName0[Auxsrc],Int,Frac,Enable.c_str(),Kill.c_str() );
break;
case 4: // ref
Auxsrc = ( ctrl>>5 ) & 0x3;
Src = ctrl & 0x3;
Int = ( div >>8 ) & 0x3 ;
aPrint->printf(" ExtSrc=%-10s Src=%-10s int=%8d \n",AuxSrcName4[Auxsrc],SrcName4[Src],Int );
break;
case 5: // sys
Auxsrc = ( ctrl>>5 ) & 0x7 ;
Src = ctrl & 0x01;
Int = ( div >>8 ) & 0xFFFFFF ;
Frac = div & 0xFF ;
aPrint->printf(" ExtSrc=%-10s Src=%-10s int=%8d frac=%3d\n",AuxSrcName5[Auxsrc],SrcName5[Src],Int,Frac );
break;
case 6: // Peri
Enable = (ctrl & 0x0800)==0 ? "Disable" : "Enable" ;
Kill = (ctrl & 0x0400)==0 ? "" : "Kill" ;
Auxsrc = ( ctrl>>5 ) & 0x7 ;
aPrint->printf(" ExtSrc=%-10s %s %s \n",AuxSrcName6[Auxsrc],Enable.c_str(),Kill.c_str() );
break;
case 7: // USB rp2040:[7] rp2350:[8]
case 8: // ADC rp2040:[8] rp2350:[9]
Enable = (ctrl & 0x0800)==0 ? "Disable" : "Enable" ;
Kill = (ctrl & 0x0400)==0 ? "" : "Kill" ;
Auxsrc = ( ctrl>>5 ) & 0x7 ;
Int = ( div >>8 ) & 0x3 ;
aPrint->printf(" ExtSrc=%-10s int=%8d %s %s \n",AuxSrcName7[Auxsrc],Int,Enable.c_str(),Kill.c_str() );
break;
#if defined( PICO_RP2040 )
// for RP2040 RP2350にRTCは無い
case 9: // RTC
Enable = (ctrl & 0x0800)==0 ? "Disable" : "Enable" ;
Kill = (ctrl & 0x0400)==0 ? "" : "Kill" ;
Auxsrc = ( ctrl>>5 ) & 0x7 ;
Int = ( div >>8 ) & 0xFFFFFF ;
Frac = div & 0xFF ;
aPrint->printf(" ExtSrc=%-10s int=%8d frac=%3d %s %s\n",AuxSrcName7[Auxsrc],Int,Frac,Enable.c_str(),Kill.c_str() );
break;
#else
// for RP2350 HSTX
#endif
}
}
}
void cShowClkRegs::ShowXoscRegs( Print * aPrint )
{
uint32_t ctrl = xosc_hw->ctrl;
uint32_t status = xosc_hw->status;
aPrint->printf("XOSC ctrl=%8X status=%8X \n",ctrl,status );
}
void cShowClkRegs::ShowRoscRegs( Print * aPrint )
{
uint32_t ctrl = rosc_hw->ctrl;
uint32_t freqa = rosc_hw->freqa;
uint32_t freqb = rosc_hw->freqb;
uint32_t div = rosc_hw->div;
uint32_t status = rosc_hw->status;
aPrint->printf("ROSC ctrl=%8X freqa=%8X freqb=%8X div=%8X status=%8X \n",ctrl,freqa,freqb,div,status );
}
#if defined( PICO_RP2350 )
void cShowClkRegs::ShowTickRegs(Print * aPrint )
{
/*
typedef enum tick_gen_num_rp2350 {
TICK_PROC0 = 0,
TICK_PROC1 = 1,
TICK_TIMER0 = 2,
TICK_TIMER1 = 3,
TICK_WATCHDOG = 4,
TICK_RISCV = 5,
TICK_COUNT
} tick_gen_num_t;
*/
const char * TickName[] = {"TIMER0","TIMER1","WATCHDOG"} ;
tick_gen_num_t Num[] = {tick_gen_num_t::TICK_TIMER0,tick_gen_num_t::TICK_TIMER1,tick_gen_num_t::TICK_WATCHDOG };
//
aPrint->printf("Tick regs\n");
for( int n=0;n<3;n++){
ticks_slice_hw_t * slice = & ticks_hw->ticks[ Num[n] ] ;
aPrint->printf(" %-10s ctrl=%8X cycle=%8X \n" ,TickName[n], slice->ctrl, slice->cycles );
}
}
#endif
uint32_t cShowClkRegs::frequency_count_hz(uint src) {
// frequency_count_khzをマイナーチェンジしました
fc_hw_t *fc = &clocks_hw->fc0;
// If frequency counter is running need to wait for it. It runs even if the source is NULL
while(fc->status & CLOCKS_FC0_STATUS_RUNNING_BITS) {
tight_loop_contents();
}
// Set reference freq
fc->ref_khz = clock_get_hz(clk_ref) / 1000;
// FIXME: Don't pick random interval. Use best interval
fc->interval = 15;
// No min or max
fc->min_khz = 0;
fc->max_khz = 0xffffffff;
// Set SRC which automatically starts the measurement
fc->src = src;
while(!(fc->status & CLOCKS_FC0_STATUS_DONE_BITS)) {
tight_loop_contents();
}
// Return the result
return fc->result * 1000 / ( 1 << CLOCKS_FC0_RESULT_KHZ_LSB );
}
CPU is RP2040 group
CPU is RP2040
Setup done
CPU 12MHz Cu= 1
PLL_SYS : 0KHz
PLL_USB : 0KHz
ROSC : 0KHz
XOSC : 12000KHz
CLK_REF : 12002KHz
CLK_SYS : 12000KHz <-- 12MHz
CLK_PERI: 12002KHz
CLK_USB : 0KHz
CLK_ADC : 0KHz
CLK_RTC : 0Hz
CPU 40MHz Cu= 2
PLL_SYS : 40000KHz <-- PLL_SYSが動作している
PLL_USB : 0KHz
ROSC : 0KHz
XOSC : 12000KHz
CLK_REF : 12002KHz
CLK_SYS : 40000KHz <-- 40MHz
CLK_PERI: 12002KHz
CLK_USB : 0KHz
CLK_ADC : 0KHz
CLK_RTC : 0Hz
CPU 2MHz Cu= 3
PLL_SYS : 0KHz
PLL_USB : 0KHz
ROSC : 0KHz
XOSC : 12000KHz
CLK_REF : 4002KHz
CLK_SYS : 2000KHz <-- 2MHz
CLK_PERI: 12000KHz
CLK_USB : 0KHz
CLK_ADC : 0KHz
CLK_RTC : 0Hz
| シーブイデブ e-mail:mnakatani@cvdev-jp.com |