【龙芯1c库】封装时钟接口和使用示例
2017-05-08 18:21
330 查看
龙芯1c库是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库。Git地址:http://git.oschina.NET/caogos/OpenLoongsonLib1c
本文通过“龙芯1c库”中提供的时钟相关接口,获取了PLL,CPU,DDR和APB的时钟,并将其打印出来,然后再详细讲解是如何封装这几个接口的。
pll的接口为clk_get_pll_rate(),
cpu的是clk_get_cpu_rate()。
apb的是clk_get_apb_rate()。
由测试结果可知,PLL频率为504Mhz,cpu为252Mhz,APB为126Mhz。
是不是可以修改一下让PLL=252Mhz,而cpu不用分频,直接等于PLL频率呢?这个问题留给大家了,呵呵。
由上图可知,所有时钟都来自晶振。
晶振频率经过PLL后,得到一个频率,然后分频后送到了CPU;再(对CPU频率)分频后得到一个频率,送给SDRAM,APB等。
注意它们的父子关系;linux代码中也可以看出他们的父子关系,如下
目前需要关注的几个时钟是:晶振,PLL,CPU,SDRAM,APB。其中晶振的频率为24Mhz,由原理图可以知道,如下
除了晶振为外部硬件之外,其它的PLL,CPU,SDRAM和APB频率都可以通过寄存器配置。
相关寄存器
主要有两个寄存器——START_FREQ和CLK_DIV_PARAM。
PLL/SDRAM频率配置寄存器
这样,代码结合手册中的寄存器描述是不是很好懂啊。
Linux中如何查看CPU频率
APB频率=DDR频率从前面的时钟结构图中也可以看出来。
clock.h
本文通过“龙芯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; #define myprintf (*callvec->printf) #define mygets (*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
相关文章推荐
- 【龙芯1c库】封装模拟I2C接口和使用示例
- 【龙芯1c库】封装硬件I2C接口和使用示例
- 【龙芯1c库】封装硬件pwm接口和使用示例
- 【龙芯1c库】封装gpio接口和使用示例
- 【龙芯1c库】封装引脚复用接口和使用示例
- 【龙芯1c库】封装硬件定时器接口和使用示例
- 【龙芯1c库】封装软件延时接口和使用示例
- 【龙芯1c库】封装systick系统滴答定时器接口和使用示例
- 【龙芯1c库】封装硬件SPI接口和使用示例
- 《GOF设计模式》—单件(Singleton)—Delphi源码示例:单件接口(使用全局变量)
- 封装的注册表操作接口(目前使用在WINCE上)
- 天气预报接口使用及示例
- JavaWeb -- Struts1 使用示例: 表单校验 防表单重复提交 表单数据封装到实体
- JavaWeb -- Struts1 使用示例: 表单校验 防表单重复提交 表单数据封装到实体
- JAVA中常用接口的介绍及使用示例:java.lang.Comparable
- php快递单号查询接口使用示例
- 项目过程中如何使用面向对象的特征:继承,封装,多态,接口
- Java 中 ListIterator 接口的使用示例
- php接口和抽象类使用示例详解
- vxworks下辅助时钟aux clk的使用示例