【龙芯1c库】封装systick系统滴答定时器接口和使用示例

本文首先介绍“龙芯1c库”中封装的systick系统滴答定时器相关的几个函数,然后通过读取tick数来测试相关接口函数是否正常工作,然后是systick滴答定时器的一些介绍知识,最后才讲解如何封装这几个接口函数的。

“龙芯1c库”是把龙芯1c的常用外设的常用功能封装为一个库,类似于STM32库,完整源码请移步到https://gitee.com/caogos/OpenLoongsonLib1c

接口简介

滴答定时器初始化——sys_tick_init()

函数原型

// 滴答定时器初始化
void sys_tick_init(unsigned int tick)

入参为每秒钟的中断次数

使用示例

// 每秒的产生的tick数
#define TICK_PER_SECOND                 (1000)
unsigned int tick_per_second = TICK_PER_SECOND;
sys_tick_init(tick_per_second);     // 每秒产生1000个tick

获取tick值——sys_tick_get()

函数原型

// 获取tick值
unsigned long sys_tick_get(void)

使用示例

unsigned long tick = 0;
tick = sys_tick_get();

禁止滴答定时器——sys_tick_disable()

函数原型

// 禁止滴答定时器
void sys_tick_disable(void)

使用示例

直接调用即可,如下

sys_tick_disable();

使能滴答定时器——sys_tick_enable()

函数原型

// 使能滴答定时器
void sys_tick_enable(void)

使用示例

直接调用即可,如下

sys_tick_enable();

在函数sys_tick_init()中,已经调用了sys_tick_enable(),这里再单独提出来的目的是为了和sys_tick_disable()配套。

滴答定时器中断处理函数——sys_tick_handler()

因为滴答定时器比较特殊,默认已经把该中断处理函数注册了,中断发生后会自动调用该函数进行处理。这里提一下的目的是为了一些高级用户,他们可能需要修改中断处理函数中的内容。

默认的中断程序中,会维护一个计数器,每次中断就加一。

测试示例

一般情况下,滴答定时器被用于产生一个固定的时钟节拍。比如每1ms触发一次中断,产生一个节拍。对应一些要求不太高的延时,可以读取系统的当前tick值来实现延时,实际上操作系统就是这样做的。

这里的测试思路是,在初始化后,观察禁止和使能后,当前tick值是否发生变化;观察当改变定时时间后,当前tick值变化的快慢。测试源码如下

// 测试滴答定时器的源文件


#include "../lib/ls1c_public.h"
#include "../lib/ls1c_sys_tick.h"
#include "../lib/ls1c_delay.h"


// 每秒的产生的tick数
#define TICK_PER_SECOND                 (1000)


/*
 * 测试滴答定时器
 */
void test_sys_tick(void)
{
    int i;
    unsigned int tick_per_second = TICK_PER_SECOND;
    
    // 滴答定时器初始化
    // 每次滴答定时器中断就会将tick加一,这里只需要读取tick值,并打印出来即可
    sys_tick_init(tick_per_second);     // 每秒产生1000个tick    
    printf("sys tick init ok! tick = %u\r\n", tick_per_second);
    for (i=0; i<5; i++)
    {
        printf("[%s] tick=%d\r\n", __FUNCTION__, sys_tick_get());
        delay_s(1);
    }

    // 禁止滴答定时器后,看看tick值是否变化
    sys_tick_disable();
    printf("sys tick disable\r\n");
    for (i=0; i<5; i++)
    {
        printf("[%s] tick=%d\r\n", __FUNCTION__, sys_tick_get());
        delay_s(1);
    }


    // 重新使能滴答定时器后,再看看tick是否变化
    sys_tick_enable();
    printf("sys tick enable\r\n");
    for (i=0; i<5; i++)
    {
        printf("[%s] tick=%d\r\n", __FUNCTION__, sys_tick_get());
        delay_s(1);
    }


    // 修改tick
    tick_per_second = TICK_PER_SECOND/2;
    sys_tick_disable();
    sys_tick_init(tick_per_second);
    printf("modify tick = %u\r\n", tick_per_second);
    for (i=0; i<5; i++)
    {
        printf("[%s] tick=%d\r\n", __FUNCTION__, sys_tick_get());
        delay_s(1);
    }

    while (1)
        ;
}


龙芯1c的systick系统滴答定时器简介

滴答定时器是通用的,每个操作系统都需要的功能。操作系统中的任务切换就是依靠滴答定时器来实现的。简单来说就是滴答定时器定时(比如1ms)产生中断,操作系统在滴答定时器的中断处理函数中判断是否需要切换任务,切换到那个任务,如果需要切换则执行切换。

正因为这个功能这么通用,不是龙芯CPU特有的,所以在目前的龙芯1c芯片手册中也没有相关介绍。那我是怎么知道这些细节的呢?我是在移植中断那部分代码时发现的,后面又在《see mips run》中发现了相关介绍,如下

滴答定时器是由寄存器Count和寄存器Compare组成的。并且位于协处理器0上。
正因为滴答定时器是位于协处理器0上,并且所有MIPS CPU通用的,所以滴答定时器的中断也是MIPS CPU通用的,并且定好了——协处理器0的状态寄存器(SR)中的IM7用于屏蔽或使能滴答定时器,协处理器0的原因寄存器(CAUSE)中的IP7用于判断是否发生了滴答定时器中断。也就是说,滴答定时器中断的使能又协处理器0的状态寄存器(SR)中的IM7和IE两个位来控制。其中IE为全局使能位,正常启动后,IE会被使能,所以通常使用IM7来使能或禁止滴答定时器中断。

封装systick系统滴答定时器接口

滴答定时器的原理和源码都很简单,这里直接把源码贴出来

ls1c_sys_tick.h

// 系统滴答定时器相关接口


#ifndef __OPENLOONGSON_SYS_TICK_H
#define __OPENLOONGSON_SYS_TICK_H



// 滴答定时器初始化
void sys_tick_init(unsigned int tick);

// 禁止滴答定时器
void sys_tick_disable(void);

// 使能滴答定时器
void sys_tick_enable(void);


// 时钟中断处理函数
void sys_tick_handler(void);

// 获取tick值
unsigned long sys_tick_get(void);



#endif



ls1c_sys_tick.c

// 系统滴答定时器相关接口


#include "ls1c_mipsregs.h"


#define CPU_HZ			                (252 * 1000000)


static volatile unsigned long system_tick;


// 禁止滴答定时器
void sys_tick_disable(void)
{
    unsigned int status = 0;

    status = read_c0_status();
    status &= (~STATUSF_IP7);
    write_c0_status(status);

    return ;
}


// 使能滴答定时器
void sys_tick_enable(void)
{

    unsigned int status = 0;

    status = read_c0_status();
    status |= STATUSF_IP7;
    write_c0_status(status);

    return ;
}


// 滴答定时器初始化
void sys_tick_init(unsigned int tick)
{
    // 设置定时时间
    write_c0_compare(CPU_HZ/2/tick);
    write_c0_count(0);

    // 使能
    sys_tick_enable();

    return ;
}


void sys_tick_increase(void)
{
    ++system_tick;
}


// 滴答定时器中断处理函数
void sys_tick_handler(void)
{
    unsigned int count;

    count = read_c0_compare();
    write_c0_compare(count);
    write_c0_count(0);

    sys_tick_increase();

    return ;
}


// 获取tick值
unsigned long sys_tick_get(void)
{
    return system_tick;
}


感谢阅读!


猜你喜欢

转载自blog.csdn.net/caogos/article/details/79187901
今日推荐