User avatar
OneMadGypsy
Posts: 326
Joined: Wed Apr 28, 2021 1:57 am
Location: New Orleans, Louisiana
Contact: Website

Clocks

Sun May 16, 2021 2:37 am

I need a little help with clocks. I am writing a simple clock debugger that spits out detailed info about any clock you request. I have dug around (a lot) in the source and I have figured out a bunch, but I have some gaps that I can't fill on my own.I have gathered that parsing the auxsrc and src from a clock can be done as below:

Code: Select all

clock_hw_t *clock = &clocks_hw->clk[clk_index];
int aux_ctrl = (clock->ctrl & CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS) >> CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB;
int src_ctrl = (clock->ctrl & CLOCKS_CLK_REF_CTRL_SRC_BITS) >> CLOCKS_CLK_REF_CTRL_SRC_LSB;

Then if I want to find out what those numbers refer to, I can switch over clk_index, to determine which clock I am dealing with, then create another inner switch something like the below code.

WIP

Code: Select all

        case clk_ref:
            type = "clk_ref";
            fc0  = CLOCKS_FC0_SRC_VALUE_CLK_REF;
            switch(aux_ctrl){
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
            }
            switch(src_ctrl){
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH    : src_type = "rosc_ph"; break;
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX: src_type = "ref_aux"; break;
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC       : src_type = "xosc"   ; break;
            }
            break;

Here's where my questions start.

1) What is CLKSRC_PH? (?peripheral?)
2) In the case of a constant like this: CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX
Does that mean that the clock source will be the same as whatever refs AUXSRC is?
3) In the case of a constant like this CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC (ie. a constant that has nothing following CLKSRC)
Does this mean that xosc is the source or to use whatever xosc's source is?

The answers to these questions make all the difference in the world. It's the difference between printing "some_clk" and digging into that clock to discover a different specific clock. Any knowledgeable help is appreciated
Last edited by OneMadGypsy on Sun May 16, 2021 3:56 am, edited 1 time in total.
"Focus is a matter of deciding what things you're not going to do." ~ John Carmack

User avatar
OneMadGypsy
Posts: 326
Joined: Wed Apr 28, 2021 1:57 am
Location: New Orleans, Louisiana
Contact: Website

Re: Clocks

Sun May 16, 2021 3:18 am

To broaden the way people can help me ~ below is the entire module I am building. It's mostly just one long function. Feel free to cut it up and give me an example based on what I already have.

info.c

Code: Select all

#include "py/runtime.h"
#include "py/obj.h"
#include "py/objstr.h"
#include "hardware/clocks.h"
#include "hardware/structs/clocks.h"

STATIC mp_obj_t info_clock_data(mp_obj_t clkid_obj) {
    enum clock_index clk_index = mp_obj_get_int(clkid_obj);
    clock_hw_t *clock = &clocks_hw->clk[clk_index];
    
    int aux_ctrl = (clock->ctrl & CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS) >> CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB;
    int src_ctrl = (clock->ctrl & CLOCKS_CLK_REF_CTRL_SRC_BITS) >> CLOCKS_CLK_REF_CTRL_SRC_LSB;
    
    int fc0 = -1;
    const char *clk_type;
    const char *aux_type;
    const char *src_type;
     
    switch(clk_index){
        case clk_ref:
            clk_type = "clk_ref";
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_REF;
            switch(aux_ctrl){
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            switch(src_ctrl){
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH    : src_type = "rosc_ph"; break;
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX: src_type = "ref_aux"; break;
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC       : src_type = "xosc"   ; break;
                default: src_type = "bad src_type";
            }
            break;
        case clk_sys:
            clk_type = "clk_sys";
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_SYS;
            switch(aux_ctrl){
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ROSC_CLKSRC   : aux_type = "rosc_ph"; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            switch(src_ctrl){
                case CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF           : src_type = "ref"    ; break;
                case CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX: src_type = "sys_aux"; break;
                default: src_type = "bad src_type";
            }
            break; 
        case clk_peri:
            clk_type = "clk_peri";
            src_type = "0";
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_PERI;
            switch(aux_ctrl){
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS       : aux_type = "clk_sys"; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH: aux_type = "rosc"   ; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            break;
        case clk_usb:
            clk_type = "clk_usb";
            src_type = "0";
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_USB;
            switch(aux_ctrl){
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH: aux_type = "rosc_ph"; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
            }
            break; 
        case clk_adc:
            clk_type = "clk_adc";
            src_type = "0";
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_ADC;
            switch(aux_ctrl){
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH: aux_type = "rosc_ph"; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            break; 
        case clk_rtc:
            clk_type = "clk_rtc";
            src_type = "0";
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_RTC;
            switch(aux_ctrl){
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH: aux_type = "rosc_ph"; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            break; 
        default :
            clk_type = "bad clk_type";
            aux_type = "bad aux_type";
            src_type = "bad src_type";
    } 
    
    if (fc0 > -1) {
        mp_printf(MP_PYTHON_PRINTER, "%s:\ncfg:\t\t%dkhz\nfreq:\t\t%dkhz\ndiv:\t\t%d\n", clk_type, clock_get_hz(clk_index)/1000, frequency_count_khz(fc0), clock->div);
        mp_printf(MP_PYTHON_PRINTER, "control:\nperi ctrl\t%s\nsrc ctrl:\t%s\n\n", aux_type, src_type);
        //mp_printf(MP_PYTHON_PRINTER, "indexes:\nfc0:\t\t%d\nperi ctrl:\t%d\nsys ctrl:\t%d\n\n", fc0, aux_ctrl, sys_ctrl);
    }
    else mp_printf(MP_PYTHON_PRINTER, "bad clock data");
    
    return mp_const_none;
}

MP_DEFINE_CONST_FUN_OBJ_1(info_clock_data_obj, info_clock_data);

STATIC mp_obj_t info_clock_data_all(void) {
    for(int i=clk_ref; i <= clk_rtc; ++i)
        info_clock_data(mp_obj_new_int(i));
    return mp_const_none;
}

MP_DEFINE_CONST_FUN_OBJ_0(info_clock_data_all_obj, info_clock_data_all);


//__> MODULE

STATIC const mp_map_elem_t info_globals_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_info) },
    { MP_OBJ_NEW_QSTR(MP_QSTR_clock_data_all), (mp_obj_t)&info_clock_data_all_obj},
    { MP_OBJ_NEW_QSTR(MP_QSTR_clock_data)    , (mp_obj_t)&info_clock_data_obj    },
    
    //{ MP_ROM_QSTR(MP_QSTR_clk_gpout0), MP_ROM_INT(clk_gpout0) },
    //{ MP_ROM_QSTR(MP_QSTR_clk_gpout1), MP_ROM_INT(clk_gpout1) },
    //{ MP_ROM_QSTR(MP_QSTR_clk_gpout2), MP_ROM_INT(clk_gpout2) },
    //{ MP_ROM_QSTR(MP_QSTR_clk_gpout3), MP_ROM_INT(clk_gpout3) },
    { MP_ROM_QSTR(MP_QSTR_clk_ref)   , MP_ROM_INT(clk_ref)    },
    { MP_ROM_QSTR(MP_QSTR_clk_sys)   , MP_ROM_INT(clk_sys)    },
    { MP_ROM_QSTR(MP_QSTR_clk_peri)  , MP_ROM_INT(clk_peri)   },
    { MP_ROM_QSTR(MP_QSTR_clk_usb)   , MP_ROM_INT(clk_usb)    },
    { MP_ROM_QSTR(MP_QSTR_clk_adc)   , MP_ROM_INT(clk_adc)    },
    { MP_ROM_QSTR(MP_QSTR_clk_rtc)   , MP_ROM_INT(clk_rtc)    },
};

STATIC MP_DEFINE_CONST_DICT (mp_module_info_globals, info_globals_table);

const mp_obj_module_t info_user_cmodule = {
    .base    = { &mp_type_module },
    .globals = (mp_obj_dict_t*)&mp_module_info_globals,
};

MP_REGISTER_MODULE(MP_QSTR_info, info_user_cmodule, MODULE_INFO_ENABLED);


supporting files in case you want to build it

micropython.cmake

Code: Select all

add_library(usermod_info INTERFACE)

target_sources(usermod_info INTERFACE
    ${CMAKE_CURRENT_LIST_DIR}/info.c
)

target_include_directories(usermod_info INTERFACE
    ${CMAKE_CURRENT_LIST_DIR}
)

target_compile_definitions(usermod_info INTERFACE
    -DMODULE_INFO_ENABLED=1
)

target_link_libraries(usermod INTERFACE usermod_info)
"Focus is a matter of deciding what things you're not going to do." ~ John Carmack

User avatar
OneMadGypsy
Posts: 326
Joined: Wed Apr 28, 2021 1:57 am
Location: New Orleans, Louisiana
Contact: Website

Re: Clocks

Mon May 17, 2021 3:37 am

I realized that the way I was getting the src/aux bits was not specific enough, and has to be done specially for every clock. Here is the correct version. I still don't have answer to any of the questions I asked, so if some of these flags mean "dig deeper" I'm still not doing that in this script. This script still doesn't handle gpout0 to 3. It's not that I'm having any trouble with that, though. It's actually that they are handled differently, and I haven't spent any time trying to think of a good way to incorporate them into what I already have. Speaking of not spending any time on gpout clocks ~ I'm trying to fix threading ~ properly and for good. I spent almost the entire day reverse engineering threading. I am currently nowhere on the level of actually fixing it, but I have scope.I'll start applying that scope to the code tomorrow. Right now I'm about to update my sdcard script to include an LED and a detect pin. Then I'm going to fix my firmware so people can load either Pimoroni's Pico Explorer/Pico Display ST7789 script or mine. I wrote a graphics library that is way better than theirs. It's actually more of a game utils library. I have fast collision detection, RLE images with numerous options (flip, rotate, etc), and a bunch of other stuff. When I get this other core working the way it's supposed to it's gonna be game on.

Code: Select all

#include "py/runtime.h"
#include "py/obj.h"
#include "py/objstr.h"
#include "hardware/clocks.h"
#include "hardware/structs/clocks.h"

STATIC mp_obj_t info_clock_data(mp_obj_t clkid_obj) {
    enum clock_index clk_index = mp_obj_get_int(clkid_obj);
    clock_hw_t *clock = &clocks_hw->clk[clk_index];
    
    int fc0      = -1;
    const char *clk_type;
    int aux_ctrl = -1;
    const char *aux_type;
    int src_ctrl = -1;
    const char *src_type;
     
    switch(clk_index){
        case clk_ref:
            clk_type = "clk_ref";
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_REF;
            aux_ctrl = (clock->ctrl & CLOCKS_CLK_REF_CTRL_AUXSRC_BITS) >> CLOCKS_CLK_REF_CTRL_AUXSRC_LSB;
            src_ctrl = (clock->ctrl & CLOCKS_CLK_REF_CTRL_SRC_BITS)    >> CLOCKS_CLK_REF_CTRL_SRC_LSB;
            switch(aux_ctrl){
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_REF_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            switch(src_ctrl){
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH    : src_type = "rosc_ph"; break;
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX: src_type = "ref_aux"; break;
                case CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC       : src_type = "xosc"   ; break;
                default: src_type = "bad src_type";
            }
            break;
        case clk_sys:
            clk_type = "clk_sys";
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_SYS;
            aux_ctrl = (clock->ctrl & CLOCKS_CLK_SYS_CTRL_AUXSRC_BITS) >> CLOCKS_CLK_SYS_CTRL_AUXSRC_LSB;
            src_ctrl = (clock->ctrl & CLOCKS_CLK_SYS_CTRL_SRC_BITS)    >> CLOCKS_CLK_SYS_CTRL_SRC_LSB;
            switch(aux_ctrl){
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_ROSC_CLKSRC   : aux_type = "rosc_ph"; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_SYS_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            switch(src_ctrl){
                case CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLK_REF           : src_type = "ref"    ; break;
                case CLOCKS_CLK_SYS_CTRL_SRC_VALUE_CLKSRC_CLK_SYS_AUX: src_type = "sys_aux"; break;
                default: src_type = "bad src_type";
            }
            break; 
        case clk_peri:
            clk_type = "clk_peri";
            src_type = "0";
            aux_ctrl = (clock->ctrl & CLOCKS_CLK_PERI_CTRL_AUXSRC_BITS) >> CLOCKS_CLK_PERI_CTRL_AUXSRC_LSB;
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_PERI;
            switch(aux_ctrl){
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLK_SYS       : aux_type = "clk_sys"; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH: aux_type = "rosc"   ; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_PERI_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            break;
        case clk_usb:
            clk_type = "clk_usb";
            src_type = "0";
            aux_ctrl = (clock->ctrl & CLOCKS_CLK_USB_CTRL_AUXSRC_BITS) >> CLOCKS_CLK_USB_CTRL_AUXSRC_LSB;
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_USB;
            switch(aux_ctrl){
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH: aux_type = "rosc_ph"; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
            }
            break; 
        case clk_adc:
            clk_type = "clk_adc";
            src_type = "0";
            aux_ctrl = (clock->ctrl & CLOCKS_CLK_ADC_CTRL_AUXSRC_BITS) >> CLOCKS_CLK_ADC_CTRL_AUXSRC_LSB;
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_ADC;
            switch(aux_ctrl){
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH: aux_type = "rosc_ph"; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_ADC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            break; 
        case clk_rtc:
            clk_type = "clk_rtc";
            src_type = "0";
            aux_ctrl = (clock->ctrl & CLOCKS_CLK_RTC_CTRL_AUXSRC_BITS) >> CLOCKS_CLK_RTC_CTRL_AUXSRC_LSB;
            fc0      = CLOCKS_FC0_SRC_VALUE_CLK_RTC;
            switch(aux_ctrl){
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_SYS: aux_type = "pll_sys"; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB: aux_type = "pll_usb"; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_ROSC_CLKSRC_PH: aux_type = "rosc_ph"; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_XOSC_CLKSRC   : aux_type = "xosc"   ; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN0  : aux_type = "gpin0"  ; break;
                case CLOCKS_CLK_RTC_CTRL_AUXSRC_VALUE_CLKSRC_GPIN1  : aux_type = "gpin1"  ; break;
                default: src_type = "bad aux_type";
            }
            break; 
        default :
            clk_type = "bad clk_type";
            aux_type = "bad aux_type";
            src_type = "bad src_type";
    } 
    
    if (fc0 > -1) {
        mp_printf(MP_PYTHON_PRINTER, "%s:\ncfg:\t\t%dkhz\nfreq:\t\t%dkhz\ndiv:\t\t%d\n", clk_type, clock_get_hz(clk_index)/1000, frequency_count_khz(fc0), clock->div);
        mp_printf(MP_PYTHON_PRINTER, "control:\nperi ctrl\t%s\nsrc ctrl:\t%s\n\n", aux_type, src_type);
        //mp_printf(MP_PYTHON_PRINTER, "indexes:\nfc0:\t\t%d\nperi ctrl:\t%d\nsys ctrl:\t%d\n\n", fc0, aux_ctrl, sys_ctrl);
    }
    else mp_printf(MP_PYTHON_PRINTER, "bad clock data");
    
    return mp_const_none;
}

MP_DEFINE_CONST_FUN_OBJ_1(info_clock_data_obj, info_clock_data);


STATIC mp_obj_t info_clock_data_all(void) {
    for(int i=clk_ref; i <= clk_rtc; ++i)
        info_clock_data(mp_obj_new_int(i));
    return mp_const_none;
}

MP_DEFINE_CONST_FUN_OBJ_0(info_clock_data_all_obj, info_clock_data_all);


//__> MODULE
STATIC const mp_map_elem_t info_globals_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_info) },
    { MP_OBJ_NEW_QSTR(MP_QSTR_clock_data_all), (mp_obj_t)&info_clock_data_all_obj},
    { MP_OBJ_NEW_QSTR(MP_QSTR_clock_data)    , (mp_obj_t)&info_clock_data_obj    },
    
    //{ MP_ROM_QSTR(MP_QSTR_clk_gpout0), MP_ROM_INT(clk_gpout0) },
    //{ MP_ROM_QSTR(MP_QSTR_clk_gpout1), MP_ROM_INT(clk_gpout1) },
    //{ MP_ROM_QSTR(MP_QSTR_clk_gpout2), MP_ROM_INT(clk_gpout2) },
    //{ MP_ROM_QSTR(MP_QSTR_clk_gpout3), MP_ROM_INT(clk_gpout3) },
    { MP_ROM_QSTR(MP_QSTR_clk_ref)   , MP_ROM_INT(clk_ref)    },
    { MP_ROM_QSTR(MP_QSTR_clk_sys)   , MP_ROM_INT(clk_sys)    },
    { MP_ROM_QSTR(MP_QSTR_clk_peri)  , MP_ROM_INT(clk_peri)   },
    { MP_ROM_QSTR(MP_QSTR_clk_usb)   , MP_ROM_INT(clk_usb)    },
    { MP_ROM_QSTR(MP_QSTR_clk_adc)   , MP_ROM_INT(clk_adc)    },
    { MP_ROM_QSTR(MP_QSTR_clk_rtc)   , MP_ROM_INT(clk_rtc)    },
};

STATIC MP_DEFINE_CONST_DICT (mp_module_info_globals, info_globals_table);

const mp_obj_module_t info_user_cmodule = {
    .base    = { &mp_type_module },
    .globals = (mp_obj_dict_t*)&mp_module_info_globals,
};

MP_REGISTER_MODULE(MP_QSTR_info, info_user_cmodule, MODULE_INFO_ENABLED);
"Focus is a matter of deciding what things you're not going to do." ~ John Carmack

User avatar
jbeale
Posts: 3884
Joined: Tue Nov 22, 2011 11:51 pm
Contact: Website

Re: Clocks

Mon May 17, 2021 5:54 am

As a non-useful reply, this is beyond my experience level with the Pico board, but I hope someone can help.

User avatar
OneMadGypsy
Posts: 326
Joined: Wed Apr 28, 2021 1:57 am
Location: New Orleans, Louisiana
Contact: Website

Re: Clocks

Mon May 17, 2021 6:25 am

@jbeale

It would be nice, but if not, it's not a huge deal. I just wanted to be able to do a deep audit of clocks, and allow others to do the same. It was a lesser form of this that helped me fix SPI baudrate on over-clocked Picos. What I have so far gives a decent amount of info, albeit maybe incomplete.

re: non-useful reply

On the contrary, well wishes are always welcomed, friend.

re: beyond your experience level

Me too! I've been programming in this language for a month (sort of, it's complicated), and I certainly don't have deep knowledge of the pico-sdk. It's a lot of work reverse engineering these things. Most of the stuff you find in ports/rp2 is entirely useless if you want to actually fix something. It's just a bunch of wrappers with some last-minute touches. You have to dig through the pico-sdk if you really want to do some work. The problem is, the pico-sdk is massive, and sprawled out. There are 3 or 4 entirely different paths just for clocks. That's just defining clocks and basic usage. It gets even more sprawled out if we are going to consider all the places that do something with a clock. Even if you find all the most important information on clocks, determining what things actually do is a whole nother fiasco. There is one spot in clocks that sets the div, does a buttload of other stuff after that, and then sets the div again with a comment claiming that now it's safe to do it. :D As dumb as that sounds, I just know if you get rid of that first set it will probably break everything ... and therein lies an example of the confusion in figuring out what the H is going on.

However, I don't care how hard it is. I will figure out everything eventually. I have like 17 pages of flowcharts mapping out how stuff connects together, and I keep making it more specific. Given enough time, I could probably make the sdk perfect, and I probably will.

If you want to upgrade your skills go into lib/pico-sdk/src, pick a folder (rp2_common is a good one), pick some file and start reading. Use find in files with some decent editor to find the functions that are being called in whatever you are reading, and then go read those, too. You could discover the entire sdk with this method.
"Focus is a matter of deciding what things you're not going to do." ~ John Carmack

hippy
Posts: 10270
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Clocks

Mon May 17, 2021 11:07 am

OneMadGypsy wrote:
Sun May 16, 2021 2:37 am
1) What is CLKSRC_PH? (?peripheral?)
I would guess -
2.17.4. ROSC divider

The divider has 2 outputs, rosc_clksrc and rosc_clksrc_ph, the second being a phase shifted version of the first. This is primarily intended for use during product development and the outputs will be identical if the PHASE register is left in its default state.
The registers are defining where some thing will be getting its clock from, the bits going to a 1 of N input selector to select which clock source is routed to that thing.

Registers for various things will have differing number of select bits, different sized selectors, and differing clocks it can select.

So each register definition would be something like 'Register XYZZY has 2 bits [5,4] which select [SYS_CLK, XOSC_CLK, ROSC_CLK, ROSC_CLK_PH]".

Which, in actual hardware, would be ...

Code: Select all

                    .--------.
    SYS_CLK  ------>| 0      |
    XOSC_CLK ------>| 1      |
    ROSC_CLK ------>| 2  OUT |---> XYZZY_CLK   
    ROSC_CLK_PH --->| 3      |
                    `---..---'
                        ||
            .--- - ----.--.----.
XYZZY_REG : |31       6|54|3210|
            `--- - ----^--^----'

Code: Select all

mem = {}
inf = {}

inf[0x30001234] = [ "XYZZY_REG", [5,4], ["SYS_CLK","XOSC_CLK","ROSC_CLK","ROSC_CLK_PH"] ]

def ShowClock(address):
  val = mem[address]
  reg, bits, src = inf[address]
  sel = 0
  for n in range(len(bits)):
    if (val & (1 << bits[n])):
      sel = sel | (1 << (len(bits)-n-1))
  clk = src[sel]
  print("{} {} has selected {} clock ({})".format(hex(address), reg, clk, sel))

mem[0x30001234] = 0x00000020
ShowClock(0x30001234)

Code: Select all

0x30001234 XYZZY_REG has selected ROSC_CLK clock (2)
I am not clear what you need beyond that.

Part of any difficulty in mapping things out may be due to coming at it with a top-down approach of figuring out what the SDK is using or doing. For me this is a bottom-up issue, figuring out what the hardware does. From that it should be easier to see why the SDK is setting things how it has to get the clock configured and routed to be used by something.

User avatar
OneMadGypsy
Posts: 326
Joined: Wed Apr 28, 2021 1:57 am
Location: New Orleans, Louisiana
Contact: Website

Re: Clocks

Mon May 17, 2021 8:28 pm

Thank you! This is excellent information. Thank you for taking the time to share this with me.

_________________________________________________________________________________________________________________________________

Observation:
hippy wrote:
Mon May 17, 2021 11:07 am
OneMadGypsy wrote:
Sun May 16, 2021 2:37 am
1) What is CLKSRC_PH? (?peripheral?)
I would guess -

And we are both wrong, but you still provided the answer in the very next sentence
2.17.4. ROSC divider

The divider has 2 outputs, rosc_clksrc and rosc_clksrc_ph, the second being a PHase shifted version of the first. This is primarily intended for use during product development and the outputs will be identical if the PHASE register is left in its default state.

PH is phase.

__________________________________________________________________________________________________________________________________
Part of any difficulty in mapping things out may be due to coming at it with a top-down approach of figuring out what the SDK is using or doing. For me this is a bottom-up issue...
I'll meet you at PICO_DEFAULT_LED_PIN and we'll call it even. :D
"Focus is a matter of deciding what things you're not going to do." ~ John Carmack

User avatar
bensimmo
Posts: 5367
Joined: Sun Dec 28, 2014 3:02 pm
Location: East Yorkshire

Re: Clocks

Tue May 18, 2021 6:51 am

I think the I guess - was meaning read the following, not I guess it means peripherals :-)

All very Interesting.

User avatar
OneMadGypsy
Posts: 326
Joined: Wed Apr 28, 2021 1:57 am
Location: New Orleans, Louisiana
Contact: Website

Re: Clocks

Tue May 18, 2021 7:13 am

@bensimmo

Heh, yeah I think you are right. I just noticed the "-" after the statement. Meh, small mistake. I'm sure hippy can forgive me.
"Focus is a matter of deciding what things you're not going to do." ~ John Carmack

hippy
Posts: 10270
Joined: Fri Sep 09, 2011 10:34 pm
Location: UK

Re: Clocks

Tue May 18, 2021 3:04 pm

All forgiven :D

And regarding "CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX"

Line 507 : ./src/rp2040/hardware_regs/include/hardware/regs/clocks.h

Code: Select all

// Field       : CLOCKS_CLK_REF_CTRL_SRC
// Description : Selects the clock source glitchlessly, can be changed
//               on-the-fly
//               0x0 -> rosc_clksrc_ph
//               0x1 -> clksrc_clk_ref_aux
//               0x2 -> xosc_clksrc
#define CLOCKS_CLK_REF_CTRL_SRC_RESET                    "-"
#define CLOCKS_CLK_REF_CTRL_SRC_BITS                     _u(0x00000003)
#define CLOCKS_CLK_REF_CTRL_SRC_MSB                      _u(1)
#define CLOCKS_CLK_REF_CTRL_SRC_LSB                      _u(0)
#define CLOCKS_CLK_REF_CTRL_SRC_ACCESS                   "RW"
#define CLOCKS_CLK_REF_CTRL_SRC_VALUE_ROSC_CLKSRC_PH     _u(0x0)
#define CLOCKS_CLK_REF_CTRL_SRC_VALUE_CLKSRC_CLK_REF_AUX _u(0x1)
#define CLOCKS_CLK_REF_CTRL_SRC_VALUE_XOSC_CLKSRC        _u(0x2)
My take on that is -

The BITS, MSB and LSB define how large and where the clock source select ("SRC") bit field is within the "CLOCKS_CLK_REF_CTRL" register. The three "SRC_VALUE" items are the values which can be written to those bits in that register to select a particular clock. Using my previous terminology ...

Register CLOCKS_CLK_REF_CTRL has 2 bits [1,0] which select [ROSC_CLKSRC_PH, CLKSRC_CLK_REF_AUX, XOSC_CLKSRC, unused].

Code: Select all

                                   .--------.
            ROSC_CLKSRC_PH  ------>| 0      |
            CLKSRC_CLK_REF_AUX --->| 1      |
            XOSC_CLKSRC ---------->| 2  OUT |---> CLOCKS_CLK_REF_CLK   
                              N/C -| 3      |
                                   `---..---'
                                       ||
                      .--- - ---------.--.
CLOCKS_CLK_REF_CTRL : |31            2|10|
                      `--- - ---------^--'

Return to “MicroPython”