12810|18

167

帖子

0

TA的资源

纯净的硅(高级)

楼主
 

LM3S库函数解析之SysCtlClockSet [复制链接]

SysCtlClockSet函数负责设置LM3S处理器的时钟,大家都知道,现在的ARM芯片越来越强大,时钟系统也越来越复杂。到底它的时钟设置会有多复杂呢,还是深入SysCtlClockSet函数来一探究竟吧。

SysCtlClockSet函数只有一个参数,所有的时钟设置都在这一个数据中表达,但是时钟控制寄存器却有两个,也就是说要通过这一个长整型变量来设置两个寄存器的值。这时候我们不禁要问一句,LM3S所有的芯片都有两个时钟寄存器吗?还有那些低端的101102也是这样的吗?那TI也真够下本钱的。

事实上财大气粗的TI也还是比较节俭的,并非所有的芯片都有两个时钟寄存器。这就牵扯出了一个问题,LM3S的库函数是给整个系列通用的,如果我们在没有RCC2寄存器的芯片上设置RCC2会有什么反应呢?这个函数的第一句就给了我们答案。

    if(DEVICE_IS_SANDSTORM && (ulConfig & SYSCTL_RCC2_USERCC2))

    {

        return;

    }

DEVICE_IS_SANDSTORM是一个宏,定义在库文件Hw_sysctl.h中。它的作用就是检测当前芯片有没有RCC2寄存器,从这个宏中我推测LM3S芯片至少分为两个版本,Ver0版和Ver1版,其中Ver1版又分为两个系列,Sandstorm系列和Fury系列。其中只有Ver1版的Fury系列有寄存器RCC2。这个宏会根据DID0寄存器来判断当前芯片是否是Fury系列芯片,如果不是则返回true

ulConfig & SYSCTL_RCC2_USERCC2则是判断当前设置中有没有设计RCC2寄存器。ulConfig是函数SysCtlClockSet的参数,其最高位决定是否使用RCC21表示使用RCC20表示不使用RCC2SYSCTL_RCC2_USERCC2的值为0x80000000,最高位是1两者按位与之后,如果ulConfig最高位为1,则结果不为0,与DEVICE_IS_SANDSTORM逻辑与的结果为真,就会执行return语句结束函数。这样,当我们在没有RCC2寄存器的器件上设置RCC2 的时候,函数不会执行任何操作,避免出现错误。

由于时钟对于处理器的重要性,使得时钟设置不能像其它寄存器那样直接将新的值写入即可,这中间涉及到时钟切换等操作,要不我们一下子把所有时钟都给关闭了,处理器也就不能执行后面的语句了,新的时钟也就出不来了。因此在设置时钟之前有必要先了解一下当前时钟状况。如下:

    ulRCC = HWREG(SYSCTL_RCC);

    ulRCC2 = HWREG(SYSCTL_RCC2);

    读出当前系统中RCCRCC2寄存器的值在变量ulRCCulRCC2中暂存,前面我们说过了,有些器件吗没有RCC2寄存器,对于没有RCC2寄存器的器件,在RCC2位置读出的数据将为0,而写该操作将被忽略,不会对系统产生影响,因为其RCC2所在地址(偏移量0x70)没有被使用。

锁相环输出依赖其它时钟源,因此,不论怎样更改时钟设置,锁相环都会有一段时间停止工作,为了抱着处理器的时钟连续,在配置时钟之前需要先把系统时钟切换到不依赖锁相环的时钟源,外部时钟或者内部时钟。

    ulRCC |= SYSCTL_RCC_BYPASS;

    ulRCC &= ~(SYSCTL_RCC_USESYSDIV);

    ulRCC2 |= SYSCTL_RCC2_BYPASS2;

 

    HWREG(SYSCTL_RCC) = ulRCC;

    HWREG(SYSCTL_RCC2) = ulRCC2;

 

最新回复

再顶!  详情 回复 发表于 2012-8-3 14:42

赞赏

1

查看全部赞赏

 
点赞 关注

回复
举报

167

帖子

0

TA的资源

纯净的硅(高级)

沙发
 

LM3S有众多的时钟源,要知道,每一个时钟源都要耗电,为了实现低功耗,允许用户将不用的时钟源关闭,但这又会带来一个问题,如果我们把时钟切换到了一个时钟源,但是我一不小心刚刚把这个时钟源给关掉了,这该怎么办呢?所以,在切换时钟之前先要看看我们使用的时钟源是否正在运行,方法是检测ulRCCulConfig中相应位是否一致。这里的SYSCTL_RCC_IOSCDISSYSCTL_RCC_MOSCDIS起到的其实是一个屏蔽字的作用,屏蔽掉其他的位,留下相应的位来运算。检测及设置时钟源代码如下:

    if(((ulRCC & SYSCTL_RCC_IOSCDIS) && !(ulConfig & SYSCTL_RCC_IOSCDIS)) ||

       ((ulRCC & SYSCTL_RCC_MOSCDIS) && !(ulConfig & SYSCTL_RCC_MOSCDIS)))

    {

        ulRCC &= (~(SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS) |

                  (ulConfig & (SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS)));

 

        //如果新的时钟配置字中关于时钟源使能的部分与原来的不一致,则先将原来的清零,然后再将新的写入

        HWREG(SYSCTL_RCC) = ulRCC;

 

        if((ulRCC2 & SYSCTL_RCC2_USERCC2) &&

           (((ulRCC2 & SYSCTL_RCC2_OSCSRC2_M) == SYSCTL_RCC2_OSCSRC2_30) ||

            ((ulRCC2 & SYSCTL_RCC2_OSCSRC2_M) == SYSCTL_RCC2_OSCSRC2_32)))

        {

            //如果使用了RCC2并且系统采用的是低速时钟,则等待4096个时钟周期,反之则等待524288个时钟周期。

            SysCtlDelay(4096);

        }

        else

        {

            SysCtlDelay(524288);

        }

    }

 
 

回复

167

帖子

0

TA的资源

纯净的硅(高级)

板凳
 

好了,解决了时钟连续的问题了,下面该大刀阔斧的干了,将所设置的时钟标志字写入RCC,如下:

    ulRCC &= ~(SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M |

               SYSCTL_RCC_PWRDN | SYSCTL_RCC_OEN);

清除原来寄存器里的相关位,包括用于指定晶振频率的9:6位,用于指定振荡源的5:4位,用于控制锁相环供电的PWRDN位与锁相环使能的OEN位,不管原来是什么值,统统清除设置新的值。这里需要提及一下的就是这个OEN位,在Datasheet上没有提及这一位,其所在的位置(12位)被标为保留位,应该是Datasheet的一处错误!

设置新的值:

    ulRCC |= ulConfig & (SYSCTL_RCC_XTAL_M | SYSCTL_RCC_OSCSRC_M |

                         SYSCTL_RCC_PWRDN | SYSCTL_RCC_OEN);

跟前面一样,这里的SYSCTL_RCC_XTAL_M等是作为屏蔽字的。

RCC2如法炮制:

    ulRCC2 &= ~(SYSCTL_RCC2_USERCC2 | SYSCTL_RCC2_OSCSRC2_M |

                SYSCTL_RCC2_PWRDN2);

    ulRCC2 |= ulConfig & (SYSCTL_RCC2_USERCC2 | SYSCTL_RCC_OSCSRC_M |

                          SYSCTL_RCC2_PWRDN2);

后面还有一个赋值语句:

    ulRCC2 |= (ulConfig & 0x00000008) << 3;

这个是干什么的呢?

这是用来设置使用低频振荡器的。在RCC2中,设置振荡源的位比RCC中多出一位,同时RCC中有一个保留字11,用此保留字再加上前面多出的一位就可以用来指定两个振荡源了,分别是内部30KHz和外部32KHz。由于与RCC相同的两位已经在前面设置了,这里只需要设置最高位就可以了。

ulConfig取值中,代表30KHz的是0x80000030,代表32KHz的是0x80000038。与屏蔽字0x00000008运算后左移三位,就可以将决定位移动到所需要的位置第“6”位(从0开始)。

那么从刚才这个运算来看,起作用的其实只有第四位一位,我们把30KHz32KHz代表的值取0x800000000x80000008就可以了,前面的那个3根本没参加运算,如果设置成0x00000040的话连移位都不需要了,事实是这样的吗?我们前面说了,RCC2中与RCC相同位置的位已经在前面设置了,同时,要想使用低频晶振,RCC2中的5:4位必须设置成11,但是11RCC是保留字,所以,不可以通过可以与RCC共享的值来设置,必须单独指定。我们再来看一下这两个值的二进制代码(最后8位):

30KHz00110000

32KHz00111000

如果把32KHz中位置3处的1移动到位置6,大家会发现什么,这不就是30KHz32KHzRCC2中编码的原码吗?

所以设置是这样的:5:4中的两位因为作用一样,只是在RCC中没意义,但是RCC2起作用的时候RCC中相应位不起作用,所以,完全可以由这两位来覆盖,但是第6位就不一样了,在RCC寄存器中有别的用处,RCC2中的值不能覆盖,所以将这一位挪到了另外两位的后面,形成了这样一种编码,再赋值的时候先赋第5:4位(可以同时赋给RCCRCC2,然后屏蔽掉这两位,再左移三位,将最后一位移动到需要的位置,再单独赋给RCC2

 
 
 

回复

167

帖子

0

TA的资源

纯净的硅(高级)

4
 

接下来清除锁相环锁定中断,因为待会等待锁相环锁定时还需要判断这一中断。

    HWREG(SYSCTL_MISC) = SYSCTL_INT_PLL_LOCK;

把变量中暂存的值写入实际寄存器:

    if(ulRCC2 & SYSCTL_RCC2_USERCC2)

    {

        HWREG(SYSCTL_RCC2) = ulRCC2;

        HWREG(SYSCTL_RCC) = ulRCC;

    }

    else

    {

        HWREG(SYSCTL_RCC) = ulRCC;

        HWREG(SYSCTL_RCC2) = ulRCC2;

    }

    SysCtlDelay(16);

这里有个顺序,如果使用了RCC2,则需要先写RCC2再写RCC,否则先写RCC再写RCC2,我想估计是RCC2中的USERRCC2位需要抢先控制系统吧,目前还不很确定为什么这么做。

写入寄存器之后需要等待一段时间等待新的设定生效。

最后是有关锁相环分频系数和振荡源使能及其它一些的设置,由于前面新的时钟源已经运行起来了,所以这里不需要再注意顺序了,全部设置完成后一次性写入。

下面是关于锁相环分频系数及振荡源使能的设置,目前操作是在临时变量中进行的。

    ulRCC &= ~(SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV |

               SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS);

    ulRCC |= ulConfig & (SYSCTL_RCC_SYSDIV_M | SYSCTL_RCC_USESYSDIV |

                         SYSCTL_RCC_IOSCDIS | SYSCTL_RCC_MOSCDIS);

    ulRCC2 &= ~(SYSCTL_RCC2_SYSDIV2_M);

    ulRCC2 |= ulConfig & SYSCTL_RCC2_SYSDIV2_M;

如果使用了锁相环,则需要等待锁相环锁定后才能进行后面的操作:

    if(!(ulConfig & SYSCTL_RCC_BYPASS))

    {

        for(ulDelay = 32768; ulDelay > 0; ulDelay--)

        {

            if(HWREG(SYSCTL_RIS) & SYSCTL_INT_PLL_LOCK)

            {

                break;//等待锁相环锁定

            }

        }

 

        // 如果使用了锁相环,则需要将锁相环旁路位清零

        ulRCC &= ~(SYSCTL_RCC_BYPASS);

        ulRCC2 &= ~(SYSCTL_RCC2_BYPASS2);

}

 

    HWREG(SYSCTL_RCC) = ulRCC;

    HWREG(SYSCTL_RCC2) = ulRCC2;

    SysCtlDelay(16);

最后将暂存变量中的值写入寄存器,短暂延时等待新设置生效,时钟设置就完成了!

注:程序中用到的宏DEVICE_IS_SANDSTORMHWREG(x)hw_types.h中定义。函数SysCtlDelayx)就在文件sysctl.c中定义。

 
 
 

回复

167

帖子

0

TA的资源

纯净的硅(高级)

5
 
发表主题的字数限制也有点太少了吧,不过这样也好,发现芯币增长速度变快了
 
 
 

回复

155

帖子

0

TA的资源

一粒金砂(中级)

6
 

学习

支持..................
 
个人签名http://www.tdhj.cn
 
 

回复

978

帖子

0

TA的资源

一粒金砂(高级)

7
 

回复 4楼 柳叶舟 的帖子

你是从WORD复制过来的吧?很有很多格式修饰符占用了字符的空间
 
 
 

回复

2万

帖子

74

TA的资源

管理员

8
 

回复 5楼 柳叶舟 的帖子

哈 是从WORD复制出来的吧?
WORD和网页的语言还是有些不协调的
WORD复制到网页 经常带很多很多代码 限制的是20000字的,加上WORD代码就显得空间不足了
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
个人签名

加油!在电子行业默默贡献自己的力量!:)

 
 

回复

22

帖子

0

TA的资源

一粒金砂(初级)

9
 
感谢楼主的分享哦。。 顶顶
 
个人签名SMT贴片加工
 
 

回复

167

帖子

0

TA的资源

纯净的硅(高级)

10
 

回复 8楼 soso 的帖子

呵呵,确实如此,我是发现在Word中的排版格式在这里还可以保留,所以就用Word写了再复制到这里的,没想到它偷偷的给我增加了那么多东西
 
 
 

回复

918

帖子

0

TA的资源

纯净的硅(中级)

11
 

ulConfig & SYSCTL_RCC2_USERCC2则是判断当前设置中有没有设计RCC2寄存器。ulConfig是函数SysCtlClockSet的参数,其最高位决定是否使用RCC21表示使用RCC20表示不使用RCC2SYSCTL_RCC2_USERCC2的值为0x80000000,最高位是1两者按位与之后,如果ulConfig最高位为1,则结果不为0,与DEVICE_IS_SANDSTORM逻辑与的结果为真,就会执行return语句结束函数。这样,当我们在没有RCC2寄存器的器件上设置RCC2 的时候,函数不会执行任何操作,避免出现错误。


相与结果为1,应该是使用RCC2,那为什么还要返回呢?

 
 
 

回复

167

帖子

0

TA的资源

纯净的硅(高级)

12
 

回复 11楼 academic 的帖子

因为SANDSTORM系列器件没有RCC2,如果配置参数中包含RCC2的操作,肯定是出了问题。所以要返回
 
 
 

回复

918

帖子

0

TA的资源

纯净的硅(中级)

13
 

回复 12楼 柳叶舟 的帖子

哦,谢谢。
 
 
 

回复

349

帖子

0

TA的资源

一粒金砂(中级)

14
 
学习
支持..................
 
 
 

回复

246

帖子

0

TA的资源

纯净的硅(初级)

15
 
好帖子! 学习了
 
 
 

回复

15

帖子

0

TA的资源

一粒金砂(中级)

16
 
有没有LM3S库函数的说明啊?
 
 
 

回复

400

帖子

0

TA的资源

五彩晶圆(中级)

17
 
不错,总结得很好
 
 
 

回复

19

帖子

0

TA的资源

一粒金砂(中级)

18
 
感谢楼主的分享哦。。 顶顶
 
 
 

回复

56

帖子

0

TA的资源

一粒金砂(高级)

19
 
再顶!
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表