【RISC-V MCU CH32V103测评】--前进的维子--第一篇-嘀嗒定时器
[复制链接]
本帖最后由 wintonson 于 2021-1-19 18:15 编辑
【RISC-V MCU CH32V103测评】 ---前进的维子--滴答
嘀嗒
前进的维子
2021年1月19日
目录
1、目的
2:系统定时器(嘀嗒)
2.1:什么是系统定时器。
2.2:系统定时器是谁的外设呢?
2.3:系统定时器在时钟树里是什么样的。
2.4:系统定时器的寄存器介绍 。
2.5:依靠上面的内容分析一下 例程中的代码 。
2.5.1:Delay_Ms 实现细节 。
2.5.2:*(__IO uint32_t*)0xE000F004) 啥意思?
2.5.3:系统时钟 SystemCoreClock 变量的来龙去脉?
3、杂谈:
3.1:芯片手册很重要。
3.2:别人的代码看到什么程度。
3.3:关于延时
4、 文章总结
“我们希望把RISC-V支持成为未来世界三大体系之一,尤其希望RISC-V能成为中国有足够话语权的体系架构。RISC-V完全开源免费,也非常适合中国超大规模的市场需求。中国有世界上最多的芯片设计企业,中国的CPU应用数量也是世界上最大的。”
---倪光南
1、目的
大家好,我是“维子”。本文以官方范例代码中 GPIO_Toggle 项目为例。讲解一下项目中设及到的:时钟树、系统定时器、和程序特点。
官方教程是基于库函数包的。我这篇文章所涉及的代码并没用到库。
本文主要目的是:尝试把“维子”看手册、分析代码的一些习惯和大家分享。
2、系统定时器(嘀嗒)
2.1:什么是系统定时器。
用自己话讲:就是一个有很高优先级的定时器。在使用操作系统的时候,它一般被操作系统设置为作为时间片轮转用的定时器(系统心跳,嘀嗒)。就是周期性的干一些事的东西。这么理解吧,以前的单片机没这个定时器的时候呢,程序员们就用普通定时器做这个事儿。后来开发芯片的人看到了,那就给你们加一个定时器吧。于是在他们设计内核的时候,就加进来了。( Cortex m0 m3 内核好像都有这个。)
这个例子里,大家把他当成普通定时器就好。
2.2:系统定时器是谁的外设呢?
它是RIS-V3内核的外设。 下面两幅图是存储器地址映射图,和寄存器地址。
刚好滴答寄存器的地址区间,就在内核私有外设空间内。
2.3:系统定时器在时钟树里是什么样的。
关于时钟树的比喻: 汽车要运转,需要发动机把“旋转”带到变速箱再传递到轮子上吧。单片机呢,也需要把外部晶振或者内部晶振的“频率”传递到内部各个外设去。这个频率就是时钟,传过去的路径。就是时钟树。
这棵树,树根是时钟源(这里看到4个时钟源,HSE MSI LSE LSI),树干就是PLL 和各个选择控制。树枝就是各个内部外设(实际属于内核的外设)。比如图中画圈的SysTick(系统定时器)。从图里看到,系统定时器,的时钟源主要来源于对于sysclk的分频出来的hclk。然后再8分频。
2.4:系统定时器的寄存器介绍
应用手册68页 9.5.3 STK 寄存器描述 开始讲解他的控制寄存器。
寄存器数目很少,一共才五个。 这五个有分三个:1控制、2计数、3比较。然后我们看到,它有64位计数值!真的是64位。
继续看,其实CTLR寄存器中只有第0位,是有效的控制位。如下图:
2.5:依靠上面的内容分析一下 例程中的代码
void Delay_Ms (uint32_t n)
{
uint32_t i;
SysTick->CTLR = 0;
i = (uint32_t)n*p_ms;
SysTick->CNTL0 = 0;
SysTick->CNTL1 = 0;
SysTick->CNTL2 = 0;
SysTick->CNTL3 = 0;
SysTick->CTLR = 1;
while((*(__IO uint32_t*)0xE000F004) <= i);
}
其中 p_ms 是全局变量 在 延时初始化过程中给出。
void Delay_Init(void)
{
p_us=SystemCoreClock/8000000;
p_ms=(uint16_t)p_us*1000;
}
在这段代码里我们应该能看到什么呢?
2.5.1:Delay_Ms 实现细节
Delay_Ms函数 是“死等”函数。 先关systick;再清理为初值;再开始计数;然后不停的判断定时器的计数值是不是超出范围,超出范围之后,while的条件不成立,跳出代码继续执行;于是实现了延时。
2.5.2:*(__IO uint32_t*)0xE000F004) 啥意思?
有些人这里看不懂 *(__IO uint32_t*)0xE000F004) 这个就是取某个地址的值。 相当于读寄存器。其实是固定套路。我记得iar好像就是这么定义的寄存器。
2.5.3:系统时钟 SystemCoreClock 变量的来龙去脉?
系统从startup.s 开始执行,执行到最后的时候,执行了 jal SystemInit 这条汇编命令,跳转到了system_ch32v10x.c 文件中的SystemInit 函数初始系统时钟。
3、杂谈:
3.1:芯片手册很重要。
要认真阅读。 必要的时候要打印出来,来回的翻看。
接触过很多手册变态到几千页,但是到关键部分我也是打印出来看。
3.2:别人的代码看到什么程度。
接到别人的代码,必须要像我看这部分代码一样,一直看到寄存器。可能有很多小伙伴看不懂汇编。其实汇编并不难。翻来覆去也就那么几个东西。少留点神就行了。一定要知道来龙去脉。 自用了std库 后面有用了hal库以后,我也很少接触底层的寄存器。但是呢,我们要懂怎么去读。在手册的那个地方去找。
3.3:关于延时
在真正的工作中,我们是不允许使用这种例程代码里的延时的。白白的消耗了单片机的时间什么也不做。有这个时间去让单片机休眠不香吗? 或者让其他需要执行的代码执行不就好了嘛。所以一般都是用中断方式驱动定时器。我用单片机,一般会留两个定时器,一个是ms级延时,一个是s级延时。然后短延时用ms长延时用s。具体的延时时间各个项目的实际不同也不一样。如果用freertos啥的,相对于单片机其实更简单一些。因为操作系统已经把这些弄好了。你用就可以了。
4、文章总结
本文,作为测评的第二篇文章。
* 简单的介绍了一下系统定时器。
* 分析了例程中延时函数的实现细节。
* 捎带讲解了系统时钟启动的一些过程。
* 列出了“维子”自己对于手册的态度和对于看代码的态度。
本文所讲解的内容也是基础中的基础。其实我想通过这篇文章和大家交流的仅仅是研发的习惯而已。
最后我讲一个我亲身经历的故事。有一个月薪小两万(在我这个伪二线城市绝对是高工资中的高工资了)的软件工程师,连0x0F是什么都不知道(如果真有读者也不知道,请看大学c语言教材第二章)。他怯生生的问我:“0xFF是不是四个字符”。“维子”还得悄悄的给他讲“码制”。因为我怕别人听到了会笑话他。
希望本文,对同学们有所启发。
|