查看: 2714|回复: 1

[原创] 【LPC845-BRK板卡试用申请】(八)时钟系统之Clkdump

[复制链接]
  • TA的每日心情
    奋斗
    7 天前
  • 签到天数: 868 天

    连续签到: 2 天

    [LV.10]以坛为家III

    69

    主题

    3278

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    10405
    最后登录
    2025-8-27
    发表于 2023-4-26 12:26:55 | 显示全部楼层 |阅读模式
    本帖最后由 andeyqi 于 2023-4-26 12:26 编辑

    简介:

    Mcu 开发过程中调试驱动经常会遇到驱动不好用,排查问题中的一环是确认时钟状况,因时钟未打开不同的mcu现象还是不同的,我之前遇到过有的mcu会走到hardfault,有的mcu会寄存器无法写入读取的都是0x00000000,之前经常也在想如果有一个工具能dump出来当前的时钟状态及频率信息的话我们就能直接排除是否是时钟的问题,我们今天的主题就是基于 LPC845 根据内部时钟的拓扑结构输出对应外设节点的时钟路由及频率状态信息。

    1.实现方式
    我验证的板子上是无外部晶振,CPU使用的 mainclk 可以看出mainclk 时钟来源于内部Fro时钟,从图 1.1 可以看出mainclk时钟的生成的依赖关系为 fro_osc->fro->mainclk-pll_>system_clock   图中的fro_osc振荡器经过时钟选择/分频 最终给到MCU 的system clock.


    clk_dump1.png

    图 1.1

    上图的时钟路由上主要包含如下三部分内容(本实验未使用PLL如果使用PLL还包含倍频器):
    • 1代表的时钟源
    • 2代表的时钟源选择
    • 3代表的分频器


    LPC845 的SDK 库里提供了CLOCK_GetFreq 接口获取基本的时钟频率,我们只要根据对应的选择器及分频/倍频系数即可计算出对应的频率,同理对应可以递归找到对应的父节点信息直至回溯到根节点。
    1. uint32_t CLOCK_GetFreq(clock_name_t clockName)
    2. {
    3.     uint32_t freq;

    4.     switch (clockName)
    5.     {
    6.         case kCLOCK_CoreSysClk:
    7.             freq = CLOCK_GetCoreSysClkFreq();
    8.             break;
    9.         case kCLOCK_MainClk:
    10.             freq = CLOCK_GetMainClkFreq();
    11.             break;
    12.         case kCLOCK_Fro:
    13.             freq = CLOCK_GetFroFreq();
    14.             break;
    15.         case kCLOCK_FroDiv:
    16.             freq = CLOCK_GetFroFreq() >> 1U;
    17.             break;
    18.         case kCLOCK_ExtClk:
    19.             freq = CLOCK_GetExtClkFreq();
    20.             break;
    21.         case kCLOCK_WdtOsc:
    22.             freq = CLOCK_GetWdtOscFreq();
    23.             break;
    24.         case kCLOCK_PllOut:
    25.             freq = CLOCK_GetSystemPLLFreq();
    26.             break;
    27.         case kCLOCK_Frg0:
    28.             freq = CLOCK_GetFRG0ClkFreq();
    29.             break;
    30.         case kCLOCK_Frg1:
    31.             freq = CLOCK_GetFRG1ClkFreq();
    32.             break;

    33.         default:
    34.             freq = 0U;
    35.             break;
    36.     }

    37.     return freq;
    38. }
    复制代码


    2.代码对应

    按照上面的梳理我可可以将各时钟节点的的属性封装成一个结构体,然后通过链表将节点对应的父子关系链接到一起即可获取对应时钟节点的拓扑关系,按照时钟节点的属性信息定义时钟节点如下:
    1. typedef struct clock_node
    2. {
    3.     const char * name;
    4.     const char * muxhelp;
    5.     uint32_t rate;
    6.     enum clock_node_id id;
    7.     uint8_t is_update;
    8.     uint8_t parents_num;
    9.     uint8_t mux;
    10.     struct clock_node * parents[8];
    11.     /*clock node ops*/
    12.     uint32_t (*get_rate)(struct clock_node * node);
    13.     int (*set_rate)(struct clock_node * node,uint32_t rate);
    14.     uint8_t (*get_parent)(struct clock_node * node);
    15.     rt_list_t list;
    16. }clock_node_t;
    复制代码
    • name:定义节点名称,主要用于打印节点信息时方便查看
    • muxhelp:打印mux 选择器的帮助信息
    • rate:对应节点的时钟频率
    • id:对应节点id,每个节点有唯一的ID信息,结构体的op函数(get_rate/set_rate/get_parent)会根据此ID信息进行获取信息,当前只定义如下节点后续逐步添加完整
    1. enum clock_node_id
    2. {
    3.     CLK_NODE_MAIN_CLK = 0,
    4.     CLK_NODE_MAIN_CLK_PRE_PLL,
    5.     CLK_NODE_FRO,
    6.     CLK_NODE_FRO_OSC,
    7.     CLK_NODE_SYSTEM,
    8.     CLK_NODE_UART0,
    9.     CLK_NODE_UART1,
    10.     CLK_NODE_CAPT,
    11.     CLK_NODE_MAX
    12. };
    复制代码

    • is_update:对应的时钟节点结构体信息是否完成更新
    • parents_num:对应节点父节点的数量
    • mux:当前选择的mux index 数值
    • parents:父节点的指针数组,LPC 845 寄存器的mux 段最大为3bit 此处定义的最大值8
    • get_rate:获取对应节点的时钟速率方法,可以根据实际情况设置为NULL
    • set_rate:设置节点对应的时钟速率,本实验主要用于dump 当前的时钟树此函数未使用设置的NULL
    • get_parent:获取当前节点的父节点信息,并将值更新至mux成员,然后通过parents[mux]获取父节点信息
    • list:链表节点用于串联时钟path上各节点

    如下是本地定义的main_clk 初始化节点:

    static clock_node_t  main_clk =
    {
        .name = "main_clk",
        .rate = 0xffffffffu,
        .id = CLK_NODE_MAIN_CLK,
        .parents_num = 2,
        .is_update = 0,
        .mux = 0xff,
        .muxhelp = "0-main_clk_pre_pll 1-SYS PLL 2/3-none",
        .parents[0] = &main_clk_pre_pll,
        .parents[1] = NULL,
        .get_rate = lpc845_get_clock_rate,
        .set_rate = NULL,
        .get_parent = lpc845_get_parent,
    };


    我们按照上述结构对时钟系统上的各节点进行定义后更新信息后,然后通过链表串联起来后打印相关信息即可完成clock path 的时钟信息dump,本地添加clkdump 命令用于更新clock node 信息及打印输出,代码如下:
    1. #include "fsl_device_registers.h"
    2. #include "littleshell.h"
    3. #include "fsl_clock.h"
    4. #include "fsl_debug_console.h"
    5. #include "fsl_syscon.h"
    6. #include "rtlist.h"
    7. #include "utilities.h"

    8. enum clock_node_id
    9. {
    10.     CLK_NODE_MAIN_CLK = 0,
    11.     CLK_NODE_MAIN_CLK_PRE_PLL,
    12.     CLK_NODE_FRO,
    13.     CLK_NODE_FRO_OSC,
    14.     CLK_NODE_SYSTEM,
    15.     CLK_NODE_UART0,
    16.     CLK_NODE_UART1,
    17.     CLK_NODE_CAPT,
    18.     CLK_NODE_MAX
    19. };


    20. typedef struct clock_node
    21. {
    22.     const char * name;
    23.     const char * muxhelp;
    24.     uint32_t rate;
    25.     enum clock_node_id id;
    26.     uint8_t is_update;
    27.     uint8_t parents_num;
    28.     uint8_t mux;
    29.     struct clock_node * parents[8];
    30.     /*clock node ops*/
    31.     uint32_t (*get_rate)(struct clock_node * node);
    32.     int (*set_rate)(struct clock_node * node,uint32_t rate);
    33.     uint8_t (*get_parent)(struct clock_node * node);
    34.     rt_list_t list;
    35. }clock_node_t;

    36. static uint32_t lpc845_get_main_clk_pre_pll(struct clock_node * node)
    37. {
    38.     uint8_t parent = 0xffu;
    39.     uint32_t rate = 0x00;
    40.     if(node->get_parent)
    41.     {
    42.         parent = node->get_parent(node);
    43.     }

    44.     /* 0-FRO 1- External clock 2- Watchdog oscillator 3- FRO_DIV = FRO / 2 */
    45.     switch(parent)
    46.     {
    47.     case 0:
    48.         rate = CLOCK_GetFreq(kCLOCK_Fro);
    49.         break;
    50.     case 1:
    51.         rate = CLOCK_GetFreq(kCLOCK_ExtClk);
    52.         break;
    53.     case 2:
    54.         rate = CLOCK_GetFreq(kCLOCK_WdtOsc);
    55.         break;
    56.     case 3:
    57.         rate = CLOCK_GetFreq(kCLOCK_FroDiv);
    58.         break;
    59.     default:
    60.         break;
    61.     }
    62.     return rate;
    63. }

    64. static uint32_t lpc845_get_fro_clk(struct clock_node * node)
    65. {
    66.     uint8_t parent = 0xffu;
    67.     uint32_t rate = 0x00;
    68.    
    69.     if(node->get_parent)
    70.     {
    71.         parent = node->get_parent(node);
    72.     }
    73.    
    74.     /* 0-fro_oscout is divided by 2 (normal boot) or 16 (low power boot), depending on FAIM low power boot value.
    75.      * 1-FRO clock is direct from FRO oscillator
    76.     */
    77.     switch(parent)
    78.     {
    79.     case 0:
    80.         rate = CLOCK_GetFreq(kCLOCK_FroDiv);
    81.         break;
    82.     case 1:
    83.         rate = CLOCK_GetFreq(kCLOCK_Fro);
    84.         break;
    85.     default:
    86.         break;
    87.     }
    88.     return rate;

    89. }


    90. static uint32_t lpc845_get_uart_clk(struct clock_node * node)
    91. {
    92.     uint8_t parent = 0xffu;
    93.     uint32_t rate = 0x00;
    94.    
    95.     if(node->get_parent)
    96.     {
    97.         parent = node->get_parent(node);
    98.     }
    99.    
    100.     /* 0-fro_oscout is divided by 2 (normal boot) or 16 (low power boot), depending on FAIM low power boot value.
    101.      * 1-FRO clock is direct from FRO oscillator
    102.     */
    103.     switch(parent)
    104.     {
    105.     case 0:
    106.         rate = CLOCK_GetFreq(kCLOCK_Fro);
    107.         break;
    108.     case 1:
    109.         rate = CLOCK_GetFreq(kCLOCK_MainClk);
    110.         break;
    111.     case 2:
    112.         rate = CLOCK_GetFreq(kCLOCK_Frg0);
    113.         break;
    114.     case 3:
    115.         rate = CLOCK_GetFreq(kCLOCK_Frg1);
    116.         break;
    117.     case 4:
    118.         rate = CLOCK_GetFreq(kCLOCK_FroDiv);
    119.         break;   
    120.     default:
    121.         break;
    122.     }
    123.     return rate;

    124. }

    125. static uint32_t lpc845_get_capt_clk(struct clock_node * node)
    126. {
    127.     uint8_t parent = 0xffu;
    128.     uint32_t rate = 0x00;
    129.    
    130.     if(node->get_parent)
    131.     {
    132.         parent = node->get_parent(node);
    133.     }
    134.    
    135.     /* 0-fro_oscout is divided by 2 (normal boot) or 16 (low power boot), depending on FAIM low power boot value.
    136.      * 1-FRO clock is direct from FRO oscillator
    137.     */
    138.     switch(parent)
    139.     {
    140.     case 0:
    141.         rate = CLOCK_GetFreq(kCLOCK_Fro);
    142.         break;
    143.     case 1:
    144.         rate = CLOCK_GetFreq(kCLOCK_MainClk);
    145.         break;
    146.     case 2:
    147.         rate = CLOCK_GetFreq(kCLOCK_PllOut);
    148.         break;
    149.     case 3:
    150.         rate = CLOCK_GetFreq(kCLOCK_FroDiv);
    151.         break;
    152.     case 4:
    153.         rate = CLOCK_GetFreq(kCLOCK_WdtOsc);
    154.         break;   
    155.     default:
    156.         break;
    157.     }
    158.     return rate;

    159. }


    160. static uint32_t lpc845_get_clock_rate(struct clock_node * node)
    161. {
    162.     uint32_t rate = 0u;
    163.    
    164.     switch(node->id)
    165.     {
    166.     case CLK_NODE_MAIN_CLK:
    167.         rate = CLOCK_GetFreq(kCLOCK_MainClk);
    168.         break;
    169.     case CLK_NODE_MAIN_CLK_PRE_PLL:
    170.         rate = lpc845_get_main_clk_pre_pll(node);
    171.         break;
    172.     case CLK_NODE_FRO:
    173.         rate = lpc845_get_fro_clk(node);
    174.         break;
    175.     case CLK_NODE_FRO_OSC:
    176.         rate = CLOCK_GetFreq(kCLOCK_Fro);
    177.         break;
    178.     case CLK_NODE_SYSTEM:
    179.         rate = CLOCK_GetFreq(kCLOCK_CoreSysClk);
    180.         break;
    181.     case CLK_NODE_UART0:
    182.     case CLK_NODE_UART1:
    183.         rate = lpc845_get_uart_clk(node);
    184.         break;
    185.     default:
    186.         break;
    187.     }

    188.     return rate;
    189. }

    190. static uint8_t lpc845_get_parent(struct clock_node * node)
    191. {
    192.     uint8_t parent;
    193.     switch(node->id)
    194.     {
    195.     case CLK_NODE_MAIN_CLK:
    196.         parent = SYSCON->MAINCLKPLLSEL & 0x03;
    197.         break;
    198.     case CLK_NODE_MAIN_CLK_PRE_PLL:
    199.         parent = SYSCON->MAINCLKSEL & 0x03;
    200.         break;
    201.     case CLK_NODE_FRO:
    202.         parent = (SYSCON->FROOSCCTRL & SYSCON_FROOSCCTRL_FRO_DIRECT_MASK)>>SYSCON_FROOSCCTRL_FRO_DIRECT_SHIFT;
    203.         break;
    204.     case CLK_NODE_SYSTEM:
    205.         parent = 0;
    206.         break;
    207.     case CLK_NODE_UART0:
    208.         parent = SYSCON->FCLKSEL[0] & 0x07;
    209.         break;
    210.     case CLK_NODE_UART1:
    211.         parent = SYSCON->FCLKSEL[1] & 0x07;
    212.         break;
    213.     case CLK_NODE_CAPT:
    214.         parent = SYSCON->CAPTCLKSEL & 0x07;
    215.         break;        
    216.     default:
    217.         break;
    218.     }
    219.    
    220.     return parent;
    221. }

    222. static clock_node_t fro_osc =
    223. {
    224.     .name = "fro_osc",
    225.     .rate = 0xffffffffu,
    226.     .id = CLK_NODE_FRO_OSC,
    227.     .parents_num = 0,
    228.     .is_update = 0,
    229.     .mux = 0xff,
    230.     .muxhelp = NULL,
    231.     .get_rate = lpc845_get_clock_rate,
    232.     .set_rate = NULL,
    233.     .get_parent = NULL,   
    234. };



    235. static clock_node_t fro =
    236. {
    237.     .name = "fro",
    238.     .rate = 0xffffffffu,
    239.     .id = CLK_NODE_FRO,
    240.     .parents_num = 2,
    241.     .is_update = 0,
    242.     .mux = 0xff,
    243.     .muxhelp = "0:fro_oscout is divided2 1:FRO oscillator",
    244.     .parents[0] = NULL,
    245.     .parents[1] = &fro_osc,
    246.     .get_rate = lpc845_get_clock_rate,
    247.     .set_rate = NULL,
    248.     .get_parent = lpc845_get_parent,   
    249. };


    250. static clock_node_t main_clk_pre_pll =
    251. {
    252.     .name = "main_clk_pre_pll",
    253.     .rate = 0xffffffffu,
    254.     .id = CLK_NODE_MAIN_CLK_PRE_PLL,
    255.     .parents_num = 4,
    256.     .is_update = 0,
    257.     .mux = 0xff,
    258.     .muxhelp = "0-FRO 1- External clock 2- Watchdog oscillator 3- FRO_DIV = FRO / 2",
    259.     .parents[0] = &fro,
    260.     .parents[1] = NULL,
    261.     .parents[2] = NULL,
    262.     .parents[3] = NULL,
    263.     .get_rate = lpc845_get_clock_rate,
    264.     .set_rate = NULL,
    265.     .get_parent = lpc845_get_parent,
    266. };

    267. static clock_node_t  main_clk =
    268. {
    269.     .name = "main_clk",
    270.     .rate = 0xffffffffu,
    271.     .id = CLK_NODE_MAIN_CLK,
    272.     .parents_num = 2,
    273.     .is_update = 0,
    274.     .mux = 0xff,
    275.     .muxhelp = "0-main_clk_pre_pll 1-SYS PLL 2/3-none",
    276.     .parents[0] = &main_clk_pre_pll,
    277.     .parents[1] = NULL,
    278.     .get_rate = lpc845_get_clock_rate,
    279.     .set_rate = NULL,
    280.     .get_parent = lpc845_get_parent,
    281. };

    282. static clock_node_t  system_clk =
    283. {
    284.     .name = "system_clk",
    285.     .rate = 0xffffffffu,
    286.     .id = CLK_NODE_SYSTEM,
    287.     .parents_num = 1,
    288.     .is_update = 0,
    289.     .mux = 0xff,
    290.     .muxhelp = NULL,
    291.     .parents[0] = &main_clk,
    292.     .get_rate = lpc845_get_clock_rate,
    293.     .set_rate = NULL,
    294.     .get_parent = lpc845_get_parent,
    295. };


    296. static clock_node_t  uart0_clk =
    297. {
    298.     .name = "uart0_clk",
    299.     .rate = 0xffffffffu,
    300.     .id = CLK_NODE_UART0,
    301.     .parents_num = 5,
    302.     .is_update = 0,
    303.     .mux = 0xff,
    304.     .muxhelp = "0-FRO 1-Main clock 2-FRG0 clock 3-FRG1 clock 4-FRO_DIV = FRO / 2 5~7-none",
    305.     .parents[0] = &fro,
    306.     .parents[1] = &main_clk,
    307.     .parents[2] = &fro,
    308.     .parents[3] = NULL,
    309.     .parents[4] = NULL,
    310.     .parents[5] = NULL,
    311.     .parents[6] = NULL,
    312.     .parents[7] = NULL,
    313.     .get_rate = lpc845_get_uart_clk,
    314.     .set_rate = NULL,
    315.     .get_parent = lpc845_get_parent,
    316. };

    317. static clock_node_t  uart1_clk =
    318. {
    319.     .name = "uart1_clk",
    320.     .rate = 0xffffffffu,
    321.     .id = CLK_NODE_UART1,
    322.     .parents_num = 5,
    323.     .is_update = 0,
    324.     .mux = 0xff,
    325.     .muxhelp = "0-FRO 1-Main clock 2-FRG0 clock 3-FRG1 clock 4-FRO_DIV = FRO / 2 5~7-none",
    326.     .parents[0] = &fro,
    327.     .parents[1] = &main_clk,
    328.     .parents[2] = &fro,
    329.     .parents[3] = NULL,
    330.     .parents[4] = NULL,
    331.     .parents[5] = NULL,
    332.     .parents[6] = NULL,
    333.     .parents[7] = NULL,
    334.     .get_rate = lpc845_get_uart_clk,
    335.     .set_rate = NULL,
    336.     .get_parent = lpc845_get_parent,
    337. };

    338. static clock_node_t  capt_clk =
    339. {
    340.     .name = "capt_clk",
    341.     .rate = 0xffffffffu,
    342.     .id = CLK_NODE_CAPT,
    343.     .parents_num = 5,
    344.     .is_update = 0,
    345.     .mux = 0xff,
    346.     .muxhelp = "0-FRO 1-Main clock 2-SYS PLL 3-FRO_DIV = FRO/2 clock 4-Watchdog oscillator 5~7-none",
    347.     .parents[0] = &fro,
    348.     .parents[1] = &main_clk,
    349.     .parents[2] = NULL,
    350.     .parents[3] = NULL,
    351.     .parents[4] = NULL,
    352.     .parents[5] = NULL,
    353.     .parents[6] = NULL,
    354.     .parents[7] = NULL,
    355.     .get_rate = lpc845_get_capt_clk,
    356.     .set_rate = NULL,
    357.     .get_parent = lpc845_get_parent,
    358. };


    359. void update_clk_node(struct clock_node * node)
    360. {
    361.     if(!node->is_update)
    362.     {
    363.         if(node->get_rate)
    364.         {
    365.             node->rate = node->get_rate(node);
    366.         }
    367.         if(node->get_parent)
    368.         {
    369.             node->mux = node->get_parent(node);
    370.         }
    371.         rt_list_init(&node->list);
    372.         node->is_update = 1;
    373.     }
    374. }

    375. void dump_clk_node(struct clock_node * node)
    376. {
    377.     if(node->is_update)
    378.     {
    379.         PRINTF(".name = %s\r\n",node->name);
    380.         PRINTF(".rate = %d\r\n",node->rate);
    381.         PRINTF(".id = %d\r\n",node->id);
    382.         PRINTF(".parents_num = %d\r\n",node->parents_num);
    383.         if(node->parents_num != 0xff && node->parents_num != 0)
    384.             PRINTF("%s parent id is %d\r\n",node->muxhelp,node->mux);
    385.     }
    386.     else
    387.     {
    388.         PRINTF("%s node need update info.\r\n",node->name);
    389.     }
    390. }

    391. void trace_clk_node(struct clock_node * node)
    392. {
    393.     rt_list_t head = RT_LIST_OBJECT_INIT(head);
    394.     rt_list_t * pos;
    395.     struct clock_node * p_node = node;
    396.     uint8_t i_loop = 0;

    397.     const char * root_clk[10] = {
    398.         "|-- ",
    399.         "|   |-- ",
    400.         "|   |   |-- ",
    401.         "|   |   |   |-- ",
    402.         "|   |   |   |   |-- ",
    403.         "|   |   |   |   |   |-- ",
    404.         "|   |   |   |   |   |   |-- ",
    405.         "|   |   |   |   |   |   |   |-- ",
    406.         "|   |   |   |   |   |   |   |   |-- ",
    407.         "|   |   |   |   |   |   |   |   |   |-- ",
    408.     };
    409.    
    410.    
    411.     do
    412.     {
    413.         update_clk_node(p_node);
    414.         rt_list_insert_after(&head,&p_node->list);
    415.         if(p_node->parents_num)
    416.             p_node = p_node->parents[p_node->mux];
    417.     }while(p_node && p_node->parents_num);

    418.     if(p_node)
    419.     {
    420.         update_clk_node(p_node);
    421.         rt_list_insert_after(&head,&p_node->list);
    422.     }
    423.    
    424.     PRINTF("\r\n\r\n");

    425.     rt_list_for_each(pos,&head)
    426.     {
    427.         p_node = rt_list_entry(pos, clock_node_t, list);
    428.         PRINTF("%s *%s\r\n",root_clk[i_loop],p_node->name);
    429.         PRINTF("%s [rate]%d\r\n",root_clk[i_loop+1],p_node->rate);
    430.         if(p_node->muxhelp)
    431.             PRINTF("%s [%s]:[%d]\r\n",root_clk[i_loop+1],p_node->muxhelp,p_node->mux);  
    432.         i_loop++;
    433.     }
    434. }

    435. unsigned int clkdump(char argc,char ** argv)
    436. {
    437.     uint8_t index = atoi(argv[1]);

    438.     switch(index)
    439.     {
    440.     case 0:
    441.         dump_clk_node(&main_clk);
    442.         update_clk_node(&main_clk);
    443.         dump_clk_node(&main_clk);
    444.         break;
    445.     case 1:
    446.         dump_clk_node(&main_clk_pre_pll);
    447.         update_clk_node(&main_clk_pre_pll);
    448.         dump_clk_node(&main_clk_pre_pll);
    449.         break;
    450.     case 2:
    451.         dump_clk_node(&fro);
    452.         update_clk_node(&fro);
    453.         dump_clk_node(&fro);
    454.         break;
    455.     case 3:
    456.         dump_clk_node(&fro_osc);
    457.         update_clk_node(&fro_osc);
    458.         dump_clk_node(&fro_osc);
    459.         break;
    460.     case 4:
    461.         trace_clk_node(&system_clk);
    462.         break;   
    463.     case 5:
    464.         trace_clk_node(&uart0_clk);
    465.         break;
    466.     case 6:
    467.         trace_clk_node(&uart1_clk);
    468.         break;
    469.     case 7:
    470.         trace_clk_node(&capt_clk);
    471.         break;   
    472.     default:
    473.         break;
    474.     }
    475.     return 1;
    476. }
    477. LTSH_FUNCTION_EXPORT(clkdump,"dump clk info");
    复制代码

    很多芯片为了减少功耗,未使用的外设时钟是可以单独控制开关的,LPC845 的SCON模块下有两组寄存器可以用于控制时钟的enable/disable.
    clock_en.png

    图 2.1

    添加 clkgate 命令 用来输出外设时钟使能状态信息,代码如下:
    1. #define CONFIG_CLK_GATE_SHOW_ALL  1

    2. unsigned int clkgate(char argc,char ** argv)
    3. {
    4.     const char * ahbclk0[32] =
    5.     {
    6.         "SYS     ",
    7.         "ROM     ",
    8.         "RAM0_1  ",
    9.         "Reserved",
    10.         "FLASH   ",
    11.         "I2C0    ",
    12.         "GPIO0   ",
    13.         "SWM     ",
    14.         "SCT     ",
    15.         "WKT     ",
    16.         "MRT     ",
    17.         "SPI0    ",
    18.         "SPI1    ",
    19.         "CRC     ",
    20.         "URAT0   ",
    21.         "UART1   ",
    22.         "UART2   ",
    23.         "WWDT    ",
    24.         "IOCON   ",
    25.         "ACMP    ",
    26.         "GPIO1   ",
    27.         "I2C1    ",
    28.         "I2C2    ",
    29.         "I2C3    ",
    30.         "ADC     ",
    31.         "CTIMER0 ",
    32.         "MTB     ",
    33.         "DAC0    ",
    34.         "GPIO_INT",
    35.         "DMA     ",
    36.         "UART3   ",
    37.         "UART4   "
    38.     };

    39.     const char * ahbclk1[2] =
    40.     {
    41.         "CAPT    ",
    42.         "DAC1    "
    43.     };
    44.    
    45.     uint32_t tmep = SYSCON->SYSAHBCLKCTRL0;
    46.     int i;
    47.     PRINTF("\r\nSYSAHBCLKCTRL0 0x%x\r\n",tmep);
    48. #if (CONFIG_CLK_GATE_SHOW_ALL)
    49.     for(i = 0;i < 32;i++)
    50.     {
    51.         if(i != 3)
    52.         {
    53.             PRINTF("%s\t[%s] \r\n",ahbclk0[i],(tmep & (0x01 << i) ? "√" : "x"));
    54.         }
    55.     }
    56. #else
    57.     tmep &= ~(0x8);
    58.     while(tmep)
    59.     {
    60.        i = my_ffs(tmep);
    61.        PRINTF("%s\t[√] \r\n",ahbclk0[i-1]);
    62.        tmep &= ~(0x01<<(i-1));
    63.     }
    64. #endif /* end of CONFIG_CLK_GATE_SHOW_ALL */

    65.     tmep = SYSCON->SYSAHBCLKCTRL1;
    66.     tmep &= 0x03;
    67.     PRINTF("\r\nSYSAHBCLKCTRL1 0x%x\r\n",tmep);
    68. #if (CONFIG_CLK_GATE_SHOW_ALL)
    69.     for(i = 0;i < 2;i++)
    70.     {
    71.         PRINTF("%s\t[%s] \r\n",ahbclk1[i],(tmep & (0x01 << i) ? "√" : "x"));
    72.     }
    73. #else   
    74.     while(tmep)
    75.     {
    76.        i = my_ffs(tmep);
    77.        PRINTF("%s\t[√] \r\n",ahbclk1[i-1]);
    78.        tmep &= ~(0x01<<(i-1));
    79.     }
    80. #endif /* end of CONFIG_CLK_GATE_SHOW_ALL */

    81.     return 0;
    82. }

    83. LTSH_FUNCTION_EXPORT(clkgate,"clk gate status");
    复制代码


    3.代码验证

    1. unsigned int clkdump(char argc,char ** argv)
    2. {
    3.     uint8_t index = atoi(argv[1]);

    4.     switch(index)
    5.     {
    6.     case 0:
    7.         dump_clk_node(&main_clk);
    8.         update_clk_node(&main_clk);
    9.         dump_clk_node(&main_clk);
    10.         break;
    11.     case 1:
    12.         dump_clk_node(&main_clk_pre_pll);
    13.         update_clk_node(&main_clk_pre_pll);
    14.         dump_clk_node(&main_clk_pre_pll);
    15.         break;
    16.     case 2:
    17.         dump_clk_node(&fro);
    18.         update_clk_node(&fro);
    19.         dump_clk_node(&fro);
    20.         break;
    21.     case 3:
    22.         dump_clk_node(&fro_osc);
    23.         update_clk_node(&fro_osc);
    24.         dump_clk_node(&fro_osc);
    25.         break;
    26.     case 4:
    27.         trace_clk_node(&system_clk);
    28.         break;   
    29.     case 5:
    30.         trace_clk_node(&uart0_clk);
    31.         break;
    32.     case 6:
    33.         trace_clk_node(&uart1_clk);
    34.         break;
    35.     case 7:
    36.         trace_clk_node(&capt_clk);
    37.         break;   
    38.     default:
    39.         break;
    40.     }
    41.     return 1;
    42. }
    43. LTSH_FUNCTION_EXPORT(clkdump,"dump clk info");
    复制代码

    测试命令 clkdump 4 会dump 出system clock的时钟path,运行结果如图 3.1:
    clkdump_4.png

    图 3.1

    从图中看出system clock 的时钟path 为fro_osc->fro->main_clk_pre_pll->main_clk->system_clk 跟实际是吻合的而且时钟频率30M也是和实际一致。


    测试命令 clkdump 5 会dump 出uart0 clock的时钟path,运行结果如图 3.2:

    clkdump_6.png

    图 3.2

    从图中看出system clock 的时钟path 为fro_osc->fro->main_clk_pre_pll->main_clk->uart0_clk 跟实际是吻合的而且时钟频率30M也是和实际一致。


    测试命令 clkdump 6 会dump 出uart1 clock的时钟path,运行结果如图 3.3:

    clkdump_7.png

    图 3.3

    我们实际没有使用uart1 的外设时钟是未配置的,所有没有对应的path 从muxhelp 信息可知当前设置的mux 值为7 为开启时钟。


    测试命令 clkdump 7 会dump 出电容触摸外设 clock的时钟path,运行结果如图 3.4:


    clkdump_8.png

    图 3.4

    从图中看出system clock 的时钟path 为fro_osc->fro->capt_clk 跟实际是吻合的而且时钟频率30M也是和实际一致。


    测试命令clkgate 会打印时钟开启状态,运行结果如图 3.5 能够打印当前时钟使能状态。

    clkgate.png

    图 3.5


    该会员没有填写今日想说内容.
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2025-8-8 16:43
  • 签到天数: 1504 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    97

    主题

    4692

    帖子

    12

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    10093
    最后登录
    2025-8-8
    发表于 2023-4-26 14:32:45 | 显示全部楼层
    楼主 真是有想法之人。
    羡慕一下
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-8-29 19:01 , Processed in 0.084573 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表