织女星开发板RISC-V内核实现微秒级精确延时
前言
收到VEGA织女星开发板也有一段时间了,好久没玩了,想驱动个OLED屏,但是首先要实现IIC协议,而实现IIC协议,最基本的就是需要一个精确的延时函数,所以研究了一下如何来写一个精确的延时函数。众所周知,ARM Cortex-M内核都有一个24位的SysTick系统节拍定时器,它是一个简易的周期定时器,用于提供时基,多为操作系统所使用。RV32M1的RISC-V内核也有一个SysTick定时器,只不过它不属于内核,而是使用的一个外部通用定时器,即LPIT0( low power periodic interval timer)定时器的通道0来实现的,我们可以从system_RV32M1_ri5cy.c文件中获得一些信息:
/* Use LIPT0 channel 0 for systick. */
#define SYSTICK_LPIT LPIT0
#define SYSTICK_LPIT_CH 0
#define SYSTICK_LPIT_IRQn LPIT0_IRQn
/* Leverage LPIT0 to provide Systick */
void SystemSetupSystick(uint32_t tickRateHz, uint32_t intPriority)
{
/* Init pit module */
CLOCK_EnableClock(kCLOCK_Lpit0);
/* Reset the timer channels and registers except the MCR register */
SYSTICK_LPIT->MCR |= LPIT_MCR_SW_RST_MASK;
SYSTICK_LPIT->MCR &= ~LPIT_MCR_SW_RST_MASK;
/* Setup timer operation in debug and doze modes and enable the module */
SYSTICK_LPIT->MCR = LPIT_MCR_DBG_EN_MASK | LPIT_MCR_DOZE_EN_MASK | LPIT_MCR_M_CEN_MASK;
/* Set timer period for channel 0 */
SYSTICK_LPIT->CHANNEL[SYSTICK_LPIT_CH].TVAL = (CLOCK_GetIpFreq(kCLOCK_Lpit0) / tickRateHz) - 1;
/* Enable timer interrupts for channel 0 */
SYSTICK_LPIT->MIER |= (1U << SYSTICK_LPIT_CH);
/* Set interrupt priority. */
EVENT_SetIRQPriority(SYSTICK_LPIT_IRQn, intPriority);
/* Enable interrupt at the EVENT unit */
EnableIRQ(SYSTICK_LPIT_IRQn);
/* Start channel 0 */
SYSTICK_LPIT->SETTEN |= (LPIT_SETTEN_SET_T_EN_0_MASK << SYSTICK_LPIT_CH);
}
void SystemClearSystickFlag(void)
{
/* Channel 0. */
SYSTICK_LPIT->MSR = (1U << SYSTICK_LPIT_CH);
}
system_RV32M1_ri5cy.h文件中的SysTick中断服务函数:
#define SysTick_Handler LPIT0_IRQHandler
关于LPIT0
LPIT0的每个通道都包含一个32位的计数器,加载计数值之后开始倒数,当倒数到0时,中断标志位被置1,通过向中断标志位写1来清除中断。为了尽量减少执行函数所消耗的时间,delay延时函数的采用了直接操作寄存器的方式来实现。通过阅读RV32M1参考手册【Chapter 50 Low Power Interrupt Timer (LPIT)】章节,和fsl_lpit.h库函数的实现,我们可以了解到以下几个寄存器的功能:
寄存器名称 | 全称 | 读/写 | 含义 |
---|---|---|---|
TVAL | Timer Value Register | 读/写 | 设置定时器初值 |
CVAL | Current Timer Value | 只读 | 获取当前计数值 |
SETEN | Set Timer Enable Register | 读写 | 定时器使能控制 |
CLRTEN | Clear Timer Enable Register | 只写 | 清除计数值 |
MCR | Module Control Register | 读写 | 定时器时钟使能控制 |
MSR | Module Status Register | 读写 | 溢出中断标志,写1清除中断 |
通过上面参考手册相关寄存器的介绍,我们有两种方式来获取定时器是否溢出:
- 获取当前计数值是否为0,即CVAL寄存器的值
- 获取寄存器状态是否溢出,即MSR寄存器的值。
这几个寄存器都是32位的,具体每一位的含义,可以查阅RV32M1参考手册
delay.c文件
#include "delay.h"
static uint8_t fac_us=0; //us延时倍乘数
static uint16_t fac_ms=0; //ms延时倍乘数,在ucos下,代表每个节拍的ms数
void Delay_Init(void)
{
CLOCK_SetIpSrc(kCLOCK_Lpit0, kCLOCK_IpSrcFircAsync); //设置定时器时钟48MHz
LOG("LPIT0: %ld \r\n", CLOCK_GetIpFreq(kCLOCK_Lpit0)); //输出LPIT0时钟
CLOCK_EnableClock(kCLOCK_Lpit0); //使能时钟
LPIT_Reset(LPIT0); //复位定时器
LPIT0->MCR = LPIT_MCR_M_CEN_MASK; //使能定时器
fac_us = CLOCK_GetIpFreq(kCLOCK_Lpit0)/1000000;
fac_ms = fac_us*1000;
}
//基于SysTick即LPIT0实现的延时微秒函数
void Delay_us(uint32_t Nus)
{
LPIT0->CHANNEL[kLPIT_Chnl_0].TVAL = 48 * Nus - 1; //加载时间
LPIT0->SETTEN |= (LPIT_SETTEN_SET_T_EN_0_MASK << kLPIT_Chnl_0); //启动定时器
while(LPIT0->CHANNEL[kLPIT_Chnl_0].CVAL); //等待计数值到0
// while((LPIT0->MSR & 0x0001) != 0x01); //等待溢出
// LPIT0->MSR |= (1U << kLPIT_Chnl_0); //写1,清除中断
LPIT0->CLRTEN |= (LPIT_CLRTEN_CLR_T_EN_0_MASK << kLPIT_Chnl_0); //清除计数器
}
//基于SysTick即LPIT0实现的延时毫秒函数
void Delay_ms(uint32_t Nms)
{
LPIT0->CHANNEL[kLPIT_Chnl_0].TVAL = Nms * fac_ms - 1; //加载时间
LPIT0->SETTEN |= (LPIT_SETTEN_SET_T_EN_0_MASK << kLPIT_Chnl_0); //启动定时器
while(LPIT0->CHANNEL[kLPIT_Chnl_0].CVAL); //等待计数到0
// while((LPIT0->MSR & 0x0001) != 0x0001); //等待产生中断
// LPIT0->MSR |= (1U << kLPIT_Chnl_0); //向中断标志位写1,清除中断
LPIT0->CLRTEN |= (LPIT_CLRTEN_CLR_T_EN_0_MASK << kLPIT_Chnl_0); //清除计数器
}
delay.h文件
#ifndef __DELAY_H__
#define __DELAY_H__
#include "fsl_lpit.h"
#include "fsl_lpit.h"
#include "fsl_debug_console.h"
#include "sys.h"
void Delay_Init(void); //SysTick定时器,即LPIT0,时钟可设置
void Delay_ms(uint32_t Nms);
void Delay_us(uint32_t Nus);
#endif
实际验证
...
#include "delay.h"
...
int main(void)
{
...
Delay_Init();
...
while(1)
{
GPIOA->PTOR = 1 << 24; //寄存器方式操作,减小误差
Delay_ms(100); //延时微秒函数验证
// Delay_us(5); //延时微秒函数验证
}
}
通过实际示波器测试,发现Delay_us微秒级延时函数,无论延时多少时间都有2us左右的误差,不知道是这为什么,不过实现IIC协议驱动OLED屏并没有什么影响。
驱动IIC接口OLED
- 社区首页的LOGO图片
- OLED实际显示效果:
总结
既然精确延时函数实现了,那么各种协议的传感器、显示模块、通信模块的驱动都可以轻松实现了,希望分享的本篇帖子能给社区的朋友一些帮助,也希望大家能多多发帖,互相交流学习。
参考资料
历史精选
- 真正的RISC-V开发板——VEGA织女星开发板开箱评测
- 手把手教你搭建织女星开发板RISC-V开发环境
- 织女星开发板启动模式修改——从ARM M4核启动
- 织女星开发板调试器升级为Jlink固件
- NXP恩智浦VEGA织女星开发板免费申请!
- 国产处理器的逆袭机会——RISC-V
欢迎关注我的个人博客:www.wangchaochao.top
或微信扫码关注我的公众号
织女星开发板RISC-V内核实现微秒级精确延时的更多相关文章
- 织女星开发板使用RISC-V核驱动GPIO
前言 织女星开发板是OPEN-ISA社区为中国大陆地区定制的一款体积小.功耗超低和功能丰富的 RISC-V评估开发板,基于NXP半导体四核异构RV32M1主控芯片. 两个RISC-V核:RI5CY + ...
- 真正的RISC-V开发板——VEGA织女星开发板开箱评测
前言 由于最近ARM公司要求员工"停止所有与华为及其子公司正在生效的合约.支持及未决约定",即暂停与华为的相关合作,大家纷纷把注意力投向了另一个的处理器架构RISC-V,它是基于精 ...
- 手把手教你搭建织女星开发板RISC-V开发环境
前言 Windows环境下搭建基于Eclipse + RISC-V gcc编译器的RISC-V开发环境,配合openocd调试软件,可以实现RISC-V内核程序的编译.下载和调试. 准备工作 工欲善其 ...
- NXP恩智浦VEGA织女星开发板免费申请!
前言 大概两周前申请了一块NXP恩智浦的开发板,今天终于收到了!在这里推荐给大家,官方网站刚上线一个月左右,目前申请的人还不算多,感兴趣的朋友可以申请一个,体验一下这个四核性能怪兽.大厂就是大气,包装 ...
- 织女星开发板启动模式修改——从ARM M4核启动
前言 刚开始玩织女星开发板的时候,想先从熟悉的ARM核入手,连上Jlink,打开MDK版本的Demo程序,编译OK,却检测不到芯片,仔细看了一下文档,原来RV32M1芯片默认从RISC-V核启动,如果 ...
- 织女星开发板调试器升级为Jlink固件
前言 为了能使用板载的FreeLink调试器来调试RISC-V内核,我们需要把默认的CMSIC-DAP固件,升级为JLink固件,固件升级之后,通过选择使用不同的驱动程序,来支持ARM内核还是RISC ...
- windows下实现微秒级的延时
windowsintegeriostream汇编嵌入式任务 最近正在做一个嵌入式系统,是基于windows ce的,外接硬件的时序要微秒级的延时.1.微秒级的延时肯定不能基于消息(SetTimer函数 ...
- 荣品RP4412开发板烧写内核cannot load出错的原因
问:荣品RP4412开发板烧写必须要配置Xmanager吗? 现在我烧写内核出现这个错误是什么原因呢? 答:4412文件夹下没有zImage这个文件, 你打开4412这个文件夹. 你都拼写错了, zI ...
- 小白自制Linux开发板 三. Linux内核与文件系统移植
上一篇完成了uboot的移植,但是想要愉快的在开发板上玩耍还需要移植Linux内核和文件系统. 1.Linux内核 事实上对于F1C100S/F1C200S,Linux官方源码已经对licheepi ...
随机推荐
- django基础之day08,分页器从无到有,动态思路解析全过程
*********分页器从无到有的全过程,动态思路解析如下:******** 1.通过book_queryset = models.Book.objects.all()[start_num:end_n ...
- Redis Cluster 的数据分片机制
上一篇<分布式数据缓存中的一致性哈希算法> 文章中讲述了一致性哈希算法的基本原理和实现,今天就以 Redis Cluster 为例,详细讲解一下分布式数据缓存中的数据分片,上线下线时数据迁 ...
- 在 .NET Core 中使用 Diagnostics (Diagnostic Source) 记录跟踪信息
前言 最新一直在忙着项目上的事情,很久没有写博客了,在这里对关注我的粉丝们说声抱歉,后面我可能更多的分享我们在微服务落地的过程中的一些经验.那么今天给大家讲一下在 .NET Core 2 中引入的全新 ...
- 约数之和(POJ1845 Sumdiv)
最近应老延的要求再刷<算法进阶指南>(不得不说这本书不错)...这道题花费了较长时间~(当然也因为我太弱了)所以就写个比较易懂的题解啦~ 原题链接:POJ1845 翻译版题目(其实是AcW ...
- 【nginx+keepalived】nginx+keepalived搭建高可用
一.结构及环境 1.1 环境介绍 操作系统:centos7 nginx+keepalived:106.53.73.200 master nginx+keepalived:182.254.184.102 ...
- [ASP.NET Core 3框架揭秘] 文件系统[3]:物理文件系统
ASP.NET Core应用中使用得最多的还是具体的物理文件,比如配置文件.View文件以及作为Web资源的静态文件.物理文件系统由定义在NuGet包"Microsoft.Extension ...
- vue-practice
vue-完整代码 这是一个完整的vue案例,但是接口似乎都失效了,单是代码本身还是很有参考价值的呦!~ 里面包含了:vue,vue-router,....,还是直接看json文件吧 { "n ...
- javaWeb实现验证码--代码超简单
1.前端显示 HTML: <h3>验证码:</h3> <input type="text" name="validationCode&quo ...
- Git submodule update 命令执行
git submodule update操作可能导致执行.gitmodules文件中定义的任意shell命令. 受影响的产品 Git版本2.20.0至2.24.0 修复版本 Git v2.24.1,v ...
- 如何从Mac删除恶意广告软件,摆脱那些通过弹出广告或工具栏入侵Mac的恶意软件
厌倦了那些利用弹出式广告和工具栏之类入侵Mac的恶意软件?该如何摆脱Mac上的恶意软件呢?今天小编为大家带来两种方法从Mac 删除广告软件,甚至阻止它到达您的Mac,感兴趣的朋友一起来看看吧! 方法一 ...