【龙芯1c库】封装时钟接口和使用示例

来源:互联网 发布:阿里巴巴程序员工资待遇 编辑:程序博客网 时间:2024/06/17 09:31
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库。Git地址:http://git.oschina.NET/caogos/OpenLoongsonLib1c

本文通过“龙芯1c库”中提供的时钟相关接口,获取了PLL,CPU,DDR和APB的时钟,并将其打印出来,然后再详细讲解是如何封装这几个接口的。

龙芯1c库中时钟接口使用示例

时钟接口简介

提供几个clk_get_xxx_rate()的接口,用于获取相应的频率。比如
pll的接口为clk_get_pll_rate(),
cpu的是clk_get_cpu_rate()。
apb的是clk_get_apb_rate()。

测试思路

在main()函数中获取pll,cpu,ddr,apb的频率,并打印出来。

代码清单

#include "../lib/gpio.h"#include "../lib/clock.h"#include "../lib/pwm_timer.h"#include "../lib/ls1c_regs.h"#include "led.h"typedef long long off_t;struct callvectors {int     (*open) (char *, int, int);int     (*close) (int);int     (*read) (int, void *, int);int     (*write) (int, void *, int);off_t   (*lseek) (int, off_t, int);int     (*printf) (const char *, ...);void    (*cacheflush) (void);char    *(*gets) (char *);};struct callvectors *callvec;#definemyprintf (*callvec->printf)#definemygets   (*callvec->gets)int main(int argc, char **argv, char **env, struct callvectors *cv){callvec = cv;    unsigned long pll_rate, cpu_rate, ddr_rate, apb_rate, dc_rate;    unsigned int ctrl;    volatile unsigned int *clk_div_param = (volatile unsigned int *)LS1C_CLK_DIV_PARAM;    ctrl = *clk_div_param;    myprintf("[%s] ctrl=0x%x\n", __FUNCTION__, ctrl);    pll_rate = clk_get_pll_rate();    cpu_rate = clk_get_cpu_rate();    ddr_rate = clk_get_ddr_rate();    apb_rate = clk_get_apb_rate();    dc_rate  = clk_get_dc_rate();    myprintf("[%s] pll_rate=%luHz, cpu_rate=%luHz, ddr_rate=%luHz, apb_rate=%luHz, dc_rate=%luHz\n",               __FUNCTION__, pll_rate, cpu_rate, ddr_rate, apb_rate, dc_rate);//    test_pwm();    return(0);}

运行结果


由测试结果可知,PLL频率为504Mhz,cpu为252Mhz,APB为126Mhz。
是不是可以修改一下让PLL=252Mhz,而cpu不用分频,直接等于PLL频率呢?这个问题留给大家了,呵呵。


龙芯1c的时钟简介

时钟结构

由上图可知,所有时钟都来自晶振。
晶振频率经过PLL后,得到一个频率,然后分频后送到了CPU;再(对CPU频率)分频后得到一个频率,送给SDRAM,APB等
注意它们的父子关系;linux代码中也可以看出他们的父子关系,如下

目前需要关注的几个时钟是:晶振,PLL,CPU,SDRAM,APB。其中晶振的频率为24Mhz,由原理图可以知道,如下

除了晶振为外部硬件之外,其它的PLL,CPU,SDRAM和APB频率都可以通过寄存器配置。

相关寄存器

主要有两个寄存器——START_FREQ和CLK_DIV_PARAM。

PLL/SDRAM频率配置寄存器

Linux中是如何查看PLL频率的

Linux中是如何查看SDRAM频率的

这样,代码结合手册中的寄存器描述是不是很好懂啊。

CPU/CAMERA/DC频率配置寄存器

Linux中如何查看CPU频率

Linux中如何查看APB频率

APB是外设总线。比如pwm时钟源于APB。


APB频率=DDR频率从前面的时钟结构图中也可以看出来。

封装接口

接口要点

弄清楚各个时钟间的父子关系——晶振频率经过PLL后,得到一个频率,然后分频后送到了CPU;再(对CPU频率)分频后得到一个频率,送给SDRAM,APB等。

代码清单

clock.c

/************************************************************************* * * 时钟相关函数 * *************************************************************************/#include "ls1c_regs.h"// 晶振的频率#define AHB_CLK                 (24000000)#define APB_CLK                 (AHB_CLK)// START_FREQ寄存器bits#define M_PLL_SHIFT             (8)#define M_PLL                   (0xff << M_PLL_SHIFT)       // PLL倍频系数的整数部分#define FRAC_N_SHIFT            (16)#define FRAC_N                  (0xff << FRAC_N_SHIFT)      // PLL倍频系数的小数部分#define DIV_SDRAM_SHIFT         (0)#define DIV_SDRAM               (0x3  << DIV_SDRAM_SHIFT)// CLK_DIV_PARAM寄存器bits#define DIV_PIX_EN              (0x1  << 31)#define DIV_PIX                 (0x7f << 24)#define DIV_CAM_EN              (0x1  << 23)#define DIV_CAM                 (0x7f << 16)#define DIV_CPU_EN              (0x1  << 15)#define DIV_CPU                 (0x7f << 8)#define DIV_PIX_VALID           (0x1  << 5)#define DIV_PIX_SEL             (0x1  << 4)#define DIV_CAM_VALID           (0x1  << 3)#define DIV_CAM_SEL             (0x1  << 2)#define DIV_CPU_VALID           (0x1  << 1)#define DIV_CPU_SEL             (0x1  << 0)#define DIV_PIX_SHIFT           (24)#define DIV_CAM_SHIFT           (16)#define DIV_CPU_SHIFT           (8)/* * 获取PLL频率 * @ret PLL频率 */unsigned long clk_get_pll_rate(void){    volatile unsigned int *start_freq_reg = (volatile unsigned int *)LS1C_START_FREQ;    unsigned int ctrl;    unsigned long pll_rate = 0;    ctrl = *start_freq_reg;    pll_rate = (((ctrl & M_PLL) >> M_PLL_SHIFT) + ((ctrl & FRAC_N) >> FRAC_N_SHIFT)) * APB_CLK / 4;        return pll_rate;}/* * 获取CPU频率 * @ret CPU频率 */unsigned long clk_get_cpu_rate(void){    unsigned long pll_rate, cpu_rate;    unsigned int ctrl;    volatile unsigned int *clk_div_param = (volatile unsigned int *)LS1C_CLK_DIV_PARAM;    pll_rate = clk_get_pll_rate();    ctrl = *clk_div_param;    // 选择时钟来源    if (DIV_CPU_SEL & ctrl)     // pll分频作为时钟信号    {        if (DIV_CPU_EN & ctrl)        {            cpu_rate = pll_rate / ((ctrl & DIV_CPU) >> DIV_CPU_SHIFT);        }        else        {            cpu_rate = pll_rate / 2;        }    }    else                        // bypass模式,晶振作为时钟输入    {        cpu_rate = APB_CLK;    }    return cpu_rate;}/* * 获取DDR频率 * @ret DDR频率 */unsigned long clk_get_ddr_rate(void){    unsigned long cpu_rate, ddr_rate;    unsigned int ctrl;    volatile unsigned int *start_freq_reg = (volatile unsigned int *)LS1C_START_FREQ;    cpu_rate = clk_get_cpu_rate();    ctrl = (*start_freq_reg & DIV_SDRAM) >> DIV_SDRAM_SHIFT;    switch (ctrl)    {        case 0:            ddr_rate = cpu_rate / 2;            break;        case 1:            ddr_rate = cpu_rate / 4;            break;        case 2:        case 3:            ddr_rate = cpu_rate / 3;            break;    }    return ddr_rate;}/* * 获取APB频率 * @ret APB频率 */unsigned long clk_get_apb_rate(void){    return clk_get_ddr_rate();}/* * 获取DC频率 * @ret DC频率 */unsigned long clk_get_dc_rate(void){    unsigned long pll_rate, dc_rate;    unsigned int ctrl;    volatile unsigned int *clk_div_param = (volatile unsigned int *)LS1C_CLK_DIV_PARAM;    pll_rate = clk_get_pll_rate();    ctrl = *clk_div_param;    dc_rate = pll_rate / ((ctrl & DIV_PIX) >> DIV_PIX_SHIFT);    return dc_rate;}

clock.h

/************************************************************************* * * 时钟相关头文件 * *************************************************************************/#ifndef __OPENLOONGSON_CLOCK_H#define __OPENLOONGSON_CLOCK_H/* * 获取PLL频率 * @ret PLL频率 */unsigned long clk_get_pll_rate(void);/* * 获取CPU频率 * @ret CPU频率 */unsigned long clk_get_cpu_rate(void);/* * 获取DDR频率 * @ret DDR频率 */unsigned long clk_get_ddr_rate(void);/* * 获取APB频率 * @ret APB频率 */unsigned long clk_get_apb_rate(void);/* * 获取DC频率 * @ret DC频率 */unsigned long clk_get_dc_rate(void);#endif






0 0