【裸机开发笔记】6410的系统时钟设置(下)---几个常用函数的C源码。

来源:互联网 发布:js base64转换为pdf 编辑:程序博客网 时间:2024/04/29 04:09

好了,贴源码!

 

//common.h

#ifndef COMMON_H#define COMMON_Htypedef unsigned long uint32;#define MASK_CODE(LSB_LOCATION,FIELD_LEN)                ((((uint32)1<<FIELD_LEN)-1)<<LSB_LOCATION)#define FILL_BITS(MEM_ADDR,LSB_LOCATION,FIELD_LEN,VALUE)(*(volatile uint32 *)(MEM_ADDR)) = ( (*(volatile uint32 *)(MEM_ADDR)) & ~MASK_CODE((LSB_LOCATION),(FIELD_LEN)) ) | ( ((uint32)(VALUE)<<(LSB_LOCATION)) & MASK_CODE((LSB_LOCATION),(FIELD_LEN)) )//注:FILL_BITS(MEM_ADDR,LSB_LOCATION,FIELD_LEN,VALUE)这个宏,它执行的操作是,//用VALUE这个数填充MEM_ADDR地址处从第LSB_LOCATION位开始的FIELD_LEN个位.#define SET_REG(REG_ADDR,LSB_LOCATION,FIELD_LEN,VALUE)        FILL_BITS(REG_ADDR,LSB_LOCATION,FIELD_LEN,VALUE)#endif

 

 

 
//clock.h

#ifndef CLOCK_H#define CLOCK_H#include"common.h"#define CONFIG_SYS_CLK_FREQ 12000000 void set_sys_clk(uint32 mode);uint32 get_ARMCLK(void);uint32 get_FCLK(void);//即APLLuint32 get_HCLK(void);uint32 get_PCLK(void);void change_freq(uint32 arm_ratio,uint32 hclkx2_ratio,uint32 hclk_ratio,uint32 pclk_ratio);//0-150-7                0-1         0-15//这四个参数加1后才是实际分频。#define rAPLL_LOCK      (*(volatile uint32 *)(0x7e00f000))#define rMPLL_LOCK      (*(volatile uint32 *)(0x7e00f004))#define rEPLL_LOCK      (*(volatile uint32 *)(0x7e00f008))#define rAPLL_CON(*(volatile uint32 *)(0x7E00F00C))#define rMPLL_CON(*(volatile uint32 *)(0x7E00F010))#define rEPLL_CON0  (*(volatile uint32 *)(0x7E00F014))#define rEPLL_CON1  (*(volatile uint32 *)(0x7E00F018))#define rCLK_SRC(*(volatile uint32 *)(0x7E00F01C))#define rOTHERS        (*(volatile uint32 *)(0x7E00F900))#define rMISC_CON(*(volatile uint32 *)(0x7E00F838))#define rCLK_DIV0(*(volatile uint32 *)(0x7E00F020))//--------#define _APLL_MDIV1000//reset: 0x190,10bits#define _APLL_PDIV10//reset: 0x3,6bits#define _APLL_SDIV1//reset: 0x2,3bits#define _MPLL_MDIV1000//reset: 0x214,10bits#define _MPLL_PDIV10//reset: 0x6,6bits#define _MPLL_SDIV1//reset: 0x3,3bits#define _ARM_RATIO2//0-15#define _HCLKX2_RATIO 3//0-7#define _HCLK_RATIO0//0-1#define _PCLK_RATIO3//0-15/*PLL_FOUT:FOUT = MDIV X FIN / (PDIV X 2^SDIV)MDIV: 64 ≤ MDIV ≤ 1023PDIV: 1 ≤ PDIV ≤ 63SDIV: 0 ≤ SDIV ≤ 5FVCO (=MDIV X FIN / PDIV): 800MHz ≤ FVCO ≤ 1600MHzFOUT: 40MHz ≤ FVCO ≤ 1600MHzFIN : 10MHz ≤ FIN ≤ 20MHzDon't set the value P and M to all zeros.CLK:ARM_CLK=APLLOUT / (_ARM_RATIO+1)HCLKX2=MPLLOUT / (_HCLKX2_RATIO+1)HCLK=HCLKX2  / (_HCLK_RATIO+1)PCLK=HCLKX2  / (_PCLK_RATIO+1)设置时还需注意HCLK必须是PCLK的整偶倍数*/#endif

 


需要修改频率时,只需修改clock.h文件中的下列宏的值即可:

//--------#define _APLL_MDIV1000//reset: 0x190,10bits#define _APLL_PDIV10//reset: 0x3,6bits#define _APLL_SDIV1//reset: 0x2,3bits#define _MPLL_MDIV1000//reset: 0x214,10bits#define _MPLL_PDIV10//reset: 0x6,6bits#define _MPLL_SDIV1//reset: 0x3,3bits#define _ARM_RATIO2//0-15#define _HCLKX2_RATIO 3//0-7#define _HCLK_RATIO0//0-1#define _PCLK_RATIO3//0-15



 

 

 

 

//clock.c

#include"clock.h"    //注:FILL_BITS(MEM_ADDR,LSB_LOCATION,FIELD_LEN,VALUE)这个宏,它执行的操作是,//用VALUE这个数填充MEM_ADDR地址处从第LSB_LOCATION位开始的FIELD_LEN个位.void set_sys_clk(uint32 mode){//mode:0:asyn mode异步模式        //other:syn  mode 同步模式        //两种模式的区别参考3-3页的Figure 3.2                              uint32 *p;        uint32 temp;            rAPLL_LOCK = 0xffff;        rMPLL_LOCK = 0xffff;    rMISC_CON &= ~(1u<<19);                        //SYNC6670 : Normal Moe, 1 : Sync 667MHz Mode。这里选用Normal mode          if(mode==0)      {        //设置同步模式为异步        rOTHERS &= ~0x80;                              //异步模式        while((rOTHERS & 0xf00) != 0);             //等待OTHERS的8~11位为0        rOTHERS &= ~0x40;}else  {//设置为同步模式。     rOTHERS |= 0x40;                              //同步模式        __asm{        nop;        nop;        nop;        nop;        nop;          }        rOTHERS |= 0x80;         while((rOTHERS & 0xf00) != 0xf00);             //等待OTHERS的8~11位为1111}                   //设置ARMCLK,HCLKX2,HCLK和PCLK        temp=rCLK_DIV0;        p=&temp;FILL_BITS(p,0,4,_ARM_RATIO);FILL_BITS(p,9,3,_HCLKX2_RATIO);FILL_BITS(p,8,1,_HCLK_RATIO);FILL_BITS(p,12,4,_PCLK_RATIO);        rCLK_DIV0=temp;            //设置APLL,得到APLLOUT        temp=rAPLL_CON;        p=&temp;FILL_BITS(p,16,10,_APLL_MDIV);FILL_BITS(p,8,6,_APLL_PDIV);FILL_BITS(p,0,3,_APLL_SDIV);        temp |= (1u<<31);        rAPLL_CON=temp;        //设置MPLL,得到MPLLOUT        temp=rMPLL_CON;        p=&temp;FILL_BITS(p,16,10,_MPLL_MDIV);FILL_BITS(p,8,6,_MPLL_PDIV);FILL_BITS(p,0,3,_MPLL_SDIV);temp |= (1u<<31);        rMPLL_CON=temp;//选择源        temp=rCLK_SRC;        p=&temp;FILL_BITS(p,0,1,1);//选择APLLOUTFILL_BITS(p,1,1,1);//选择MPLLOUT        rCLK_SRC=temp;               }void change_freq(uint32 arm_ratio,uint32 hclkx2_ratio,uint32 hclk_ratio,uint32 pclk_ratio){//0-150-70-10-15        uint32 *p;        uint32 temp;                temp=rCLK_DIV0;        p=&temp;FILL_BITS(p,0,4,arm_ratio);FILL_BITS(p,9,3,hclkx2_ratio);FILL_BITS(p,8,1,hclk_ratio);FILL_BITS(p,12,4,pclk_ratio);        rCLK_DIV0=temp;}#define APLL 1#define MPLL 2#define EPLL 3static uint32 get_PLLCLK(int pllreg)//返回0说明异常{uint32 r, m, p, s;if (pllreg == APLL)r = rAPLL_CON;else if (pllreg == MPLL)r = rMPLL_CON;else if (pllreg == EPLL)r = rEPLL_CON0;elsereturn 0;m = (r>>16) & 0x3ff;p = (r>>8) & 0x3f;s = r & 0x7;return (m * (CONFIG_SYS_CLK_FREQ / (p * (1 << s))));}/* return ARMCORE frequency */uint32 get_ARMCLK(void){uint32 div;div = rCLK_DIV0;return (get_PLLCLK(APLL) / ((div & 0x7) + 1));}/* return FCLK frequency */uint32 get_FCLK(void){return (get_PLLCLK(APLL));}/* return HCLK frequency */uint32 get_HCLK(void){uint32 fclk;uint32 hclkx2_div = ((rCLK_DIV0>>9) & 0x7) + 1;uint32 hclk_div = ((rCLK_DIV0>>8) & 0x1) + 1;if(rOTHERS & 0x80)fclk = get_FCLK();// SYNC Modeelsefclk = get_PLLCLK(MPLL);// ASYNC Modereturn fclk/(hclk_div * hclkx2_div);}/* return PCLK frequency */uint32 get_PCLK(void){uint32 fclk;uint32 hclkx2_div = ((rCLK_DIV0>>9) & 0x7) + 1;uint32 pre_div = ((rCLK_DIV0>>12) & 0xf) + 1;if(rOTHERS & 0x80)fclk = get_FCLK();// SYNC Modeelsefclk = get_PLLCLK(MPLL);// ASYNC Modereturn fclk/(hclkx2_div * pre_div);}


set_sys_clk(uint32 mode)函数既设置锁相环又根据已定义好的宏设置ARMCLK和HCLK等的分频。mode为0时为异步模式,为1时为同步模式。初始化时一般用这个函数。

change_freq(uint32,uint32,uint32,uint32)根据输入的参数设置ARMCLK和HCLK等的分频,但不改变PLL的设置。通过这个函数可以快捷的实现动态变频。

其他的get*****()函数就请读者自己看吧。