前言

收到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实际显示效果:

总结

既然精确延时函数实现了,那么各种协议的传感器、显示模块、通信模块的驱动都可以轻松实现了,希望分享的本篇帖子能给社区的朋友一些帮助,也希望大家能多多发帖,互相交流学习。

参考资料

历史精选


欢迎关注我的个人博客www.wangchaochao.top

或微信扫码关注我的公众号

织女星开发板RISC-V内核实现微秒级精确延时的更多相关文章

  1. 织女星开发板使用RISC-V核驱动GPIO

    前言 织女星开发板是OPEN-ISA社区为中国大陆地区定制的一款体积小.功耗超低和功能丰富的 RISC-V评估开发板,基于NXP半导体四核异构RV32M1主控芯片. 两个RISC-V核:RI5CY + ...

  2. 真正的RISC-V开发板——VEGA织女星开发板开箱评测

    前言 由于最近ARM公司要求员工"停止所有与华为及其子公司正在生效的合约.支持及未决约定",即暂停与华为的相关合作,大家纷纷把注意力投向了另一个的处理器架构RISC-V,它是基于精 ...

  3. 手把手教你搭建织女星开发板RISC-V开发环境

    前言 Windows环境下搭建基于Eclipse + RISC-V gcc编译器的RISC-V开发环境,配合openocd调试软件,可以实现RISC-V内核程序的编译.下载和调试. 准备工作 工欲善其 ...

  4. NXP恩智浦VEGA织女星开发板免费申请!

    前言 大概两周前申请了一块NXP恩智浦的开发板,今天终于收到了!在这里推荐给大家,官方网站刚上线一个月左右,目前申请的人还不算多,感兴趣的朋友可以申请一个,体验一下这个四核性能怪兽.大厂就是大气,包装 ...

  5. 织女星开发板启动模式修改——从ARM M4核启动

    前言 刚开始玩织女星开发板的时候,想先从熟悉的ARM核入手,连上Jlink,打开MDK版本的Demo程序,编译OK,却检测不到芯片,仔细看了一下文档,原来RV32M1芯片默认从RISC-V核启动,如果 ...

  6. 织女星开发板调试器升级为Jlink固件

    前言 为了能使用板载的FreeLink调试器来调试RISC-V内核,我们需要把默认的CMSIC-DAP固件,升级为JLink固件,固件升级之后,通过选择使用不同的驱动程序,来支持ARM内核还是RISC ...

  7. windows下实现微秒级的延时

    windowsintegeriostream汇编嵌入式任务 最近正在做一个嵌入式系统,是基于windows ce的,外接硬件的时序要微秒级的延时.1.微秒级的延时肯定不能基于消息(SetTimer函数 ...

  8. 荣品RP4412开发板烧写内核cannot load出错的原因

    问:荣品RP4412开发板烧写必须要配置Xmanager吗? 现在我烧写内核出现这个错误是什么原因呢? 答:4412文件夹下没有zImage这个文件, 你打开4412这个文件夹. 你都拼写错了, zI ...

  9. 小白自制Linux开发板 三. Linux内核与文件系统移植

    上一篇完成了uboot的移植,但是想要愉快的在开发板上玩耍还需要移植Linux内核和文件系统. 1.Linux内核 事实上对于F1C100S/F1C200S,Linux官方源码已经对licheepi ...

随机推荐

  1. .net access config 相对路径

    <configuration> <connectionStrings> <add name="ConStr" connectionString=&qu ...

  2. angular实现draggable拖拽

    前言:最近项目要实现一个拖拽功能,我在网上开始了各类搜寻,虽然后面因为数据原因舍弃了拖拽的这一需求,但是为了不辜负最近的研究,还是来记录一下. 场景需求:面试预约选时间节点,候选人之间是可以相互交换的 ...

  3. Kubernetes服务发现入门:如何高效管理服务?

    愈发复杂的应用程序正在依靠微服务来保持可扩展性和提升效率.Kubernetes为微服务提供了完美的环境,并能够让其与Kubernetes的工具组件和功能兼容.当应用程序的每个部分放置在一个容器中,整个 ...

  4. Java 判断密码是否是大小写字母、数字、特殊字符中的至少三种

    public class CheckPassword { //数字 public static final String REG_NUMBER = ".*\\d+.*"; //小写 ...

  5. 《Java练习题》习题集五

    编程合集: https://www.cnblogs.com/jssj/p/12002760.html Java总结:https://www.cnblogs.com/jssj/p/11146205.ht ...

  6. HA Joker Vulnhub Walkthrough

    下载地址: https://www.vulnhub.com/entry/ha-joker,379/ 主机扫描: ╰─ nmap -p- -sV -oA scan 10.10.202.132Starti ...

  7. Android 项目优化(五):应用启动优化

    介绍了前面的优化的方案后,这里我们在针对应用的启动优化做一下讲解和说明. 一.App启动概述 一个应用App的启动速度能够影响用户的首次体验,启动速度较慢(感官上)的应用可能导致用户再次开启App的意 ...

  8. git版本控制入门--码云

    1.下载git:https://git-scm.com/download   2.安装过程一直点下一步即可.   3.进入刚创建的文件夹     4.在此时登录码云,创建项目.项目名称最好与文件夹名称 ...

  9. Shell—详解$( )、$(( ))、``与${ }的区别

    https://www.jianshu.com/p/2237f029c385 https://www.cnblogs.com/chenpython123/p/11052276.html https:/ ...

  10. Windows下安装和破解redis desktopmanager 2019.4

    redis可视化客户端工具:redis desktop manager 破解版链接:https://www.52pojie.cn/thread-1042770-1-1.html redis deskt ...