本实验利用Plus1 7021自带的定时计数器介绍基本编程方法,涉及到中断使用, Plus17021系统提供4个通用的16位计数定时器timer0到timer3; 每个计数定时器都支持计数到预设值时产生相应的中断信号。
对应系统分配的中断号如下表所示
| 中断号 |
Timer0 | 151 |
Timer1 | 152 |
Timer2 | 153 |
Timer3 | 154 |
对应的32位寄存器详细介绍,请参考我们提供的文档QAC628_regfile.pdf, 如下
...
这里简单介绍相关寄存器的含义,如下表所示:
...
...
控制寄存器
...
计数预值控制器
...
计数时钟预处理控制器
...
计数值控制器
This experiment uses the HDMI display and timer counter function of the Plus1 7021 platform to introduce the basic programming method, which involves interrupt use. The Plus1 7021 system provides four general-purpose 16-bit count timers, timer0 to timer3. When the preset value is reached, the corresponding interrupt signal is generated by each timer。
The interrupt numbers assigned by the corresponding system are shown in the table below
| Interrupt Number |
Timer0 | 151 |
Timer1 | 152 |
Timer2 | 153 |
Timer3 | 154 |
The corresponding 32-bit registers are described in detail, please refer to the online technical documentation provided as follows:
Here is a brief introduction to the meaning of related registers, as shown in the following table:
| Control Register | Counting controller | Counting clock preprocessing controller | Counting value controller | ||||||
Timer0 | timer0_ctrl bit[31:16] :Reserved bit[15:14] :Timer clock selection 0: System clock (default) 1: STC 90KHZ clock bit13 :Operation method 0:Single operation (default) 1:Repeat the operation bit12 : Reserved bit11 :Switch control 0:Turn off the counter 1:Start counter bit[10:0] :Reserved | timer0_reload bit[31:16] :Reserved bit[15:0] : 16-bit count preset value setting
|
| timer0_cnt bit[31:16] :Reserved bit[15:0] : 16-bit count value
| ||||||
Timer0timer1 | timer0timer1_ctrl bit[31:16] :保留Reserved bit[15:14] :计数时钟选择 :Timer clock selection 0: 系统时钟System clock (default) 1: STC 90KHZ 时钟clock bit13 :操作方式 :Operation method 0:单次操作0:Single operation (default) 1:重复操作1:Repeat the operation bit12 : 保留Reserved bit11 :开关控制 0:关闭计数器 1:启动计数器 :Switch control 0:Turn off the counter 1:Start counter bit[10:0] :保留timer0_reload :Reserved | timer1_reload bit[31:16] :Reserved bit[15:0] : 16-bit count preset value setting
|
| timer1_cnt bit[31:16] :保留Reserved bit[15:0] :16位计数预值设置 16-bit count value
| ||||||
timer2 | timer0timer2_cntctrl bit[31:166] :保留Reserved bit[155:02] : 16位计数值
|
timer1 | timer1_ctrl :Timer clock selection 0: System clock (default) 1: STC 90KHZ clock bit1 :Operation method 0:Single operation (default) 1:Repeat the operation bit1 : Reserved bit0 :Switch control 0:Turn off the counter 1:Start counter | timer2_reload bit[31:16] :保留Reserved bit[15:14] :计数时钟选择 0: 系统时钟(default) 1: STC 90KHZ 时钟 bit13 :操作方式 0:单次操作(default) 1:重复操作 bit12 : 保留 bit11 :开关控制 0:关闭计数器 1:启动计数器 bit[10:0] :保留 timer1_reload0] : 16-bit count preset value setting
| timer2_pres_val bit[31:16] :保留Reserved bit[15:0] :16位计数预值设置 16-bit count clock preset value setting
|
| timer1timer2_cnt bit[31:16] :保留Reserved bit[15:0] : 16位计数值16-bit count value
| |||
timer2timer3 | timer2timer3_ctrl bit[31:6] :保留Reserved bit[5:2] :计数时钟选择 :Timer clock selection 0: 系统时钟System clock (default) 1: STC 90KHZ 时钟clock bit1 :操作方式 :Operation method 0:单次操作0:Single operation (default) 1:重复操作1:Repeat the operation bit1 : 保留Reserved bit0 :开关控制 0:关闭计数器 1:启动计数器 timer2 :Switch control 0:Turn off the counter 1:Start counter | timer3_reload bit[31:16] :保留Reserved bit[15:0] : 16位计数预值设置16-bit count preset value setting
|
timer3 | timer2timer3_pres_val bit[31:16] :保留Reserved bit[15:0] : 16位计数时钟预值设置
| timer2_cnt bit[31:16] :保留 bit[15:0] : 16位计数值
| timer3_ctrl16-bit count clock preset value setting
| timer3_cnt bit[31:616] :保留Reserved bit[515:2] :计数时钟选择 0: 系统时钟(default) 1: STC 90KHZ 时钟 bit1 :操作方式 0:单次操作(default) 1:重复操作 bit1 : 保留 bit0 :开关控制 0:关闭计数器 1:启动计数器 | timer3_reload bit[31:16] :保留 bit[15:0] : 16位计数预值设置
| timer3_pres_val bit[31:16] :保留 bit[15:0] : 16位计数时钟预值设置
| timer3_cnt bit[31:16] :保留 bit[15:0] : 16位计数值
|
安装目录 \SP7021\workspace\sp7021\include 文件夹下的regmap_q628.h定义了这四个寄存器,如下图红色:
regmap_q628.h
struct stc_regs {
unsigned int stc_15_0; // 12.0
unsigned int stc_31_16; // 12.1
unsigned int stc_64; // 12.2
unsigned int stc_divisor; // 12.3
unsigned int rtc_15_0; // 12.4
unsigned int rtc_23_16; // 12.5
unsigned int rtc_divisor; // 12.6
unsigned int stc_config; // 12.7
...
unsigned int timerw_ctrl; // 12.12
unsigned int timerw_cnt; // 12.13
unsigned int stc_47_32; // 12.14
unsigned int stc_63_48; // 12.15
...
unsigned int stcl_0; // 12.24
unsigned int stcl_1; // 12.25
unsigned int stcl_2; // 12.26
unsigned int atc_0; // 12.27
unsigned int atc_1; // 12.28
unsigned int atc_2; // 12.29
...
};
#define STC_REG ((volatile struct stc_regs *)RF_GRP(12, 0))
定时器控制实验需要如下3个文件,如下:
1) 安装目录 \SP7021\workspace\sp7021\ 文件夹下的main.c
2) 安装目录 \SP7021\workspace\sp7021\testapi\util 文件夹下的timer.c
3) 安装目录 \SP7021\workspace\sp7021\ include\util文件夹下的timer.h
main.c
int main(void)
{
printf("Build @%s, %s\n", __DATE__, __TIME__);
hw_init();
sys_init();
timer_test_init();/*interrupt test api */
sp_interrupt_setup(); /* interrupt manager module init */
while(1);
}
首先时系统及硬件初始化:hw_init();sys_init();
然后时调用timer.c中定义的计数定时器初始化函数timer_test_init();
最后调用系统中断管理函数sp_interrupt_setup();
上面的4个函数只有timer_test_init()是由用户根据应用需求编写,其它都是系统提供。
...
0] : 16-bit count value
|
The regmap_q628.h under the installation directory \SP7021\workspace\sp7021\ include folder defines these four registers, as marked in red below:
regmap_q628.h
struct stc_regs {
unsigned int stc_15_0; // 12.0
unsigned int stc_31_16; // 12.1
unsigned int stc_64; // 12.2
unsigned int stc_divisor; // 12.3
unsigned int rtc_15_0; // 12.4
unsigned int rtc_23_16; // 12.5
unsigned int rtc_divisor; // 12.6
unsigned int stc_config; // 12.7
unsigned int timer0_ctrl; // 12.8
Timer Register
unsigned int timer0_cnt; // 12.9
Timer Register
unsigned int timer1_ctrl; // 12.10
Timer Register
unsigned int timer1_cnt; // 12.11
Timer Register
unsigned int timerw_ctrl; // 12.12
unsigned int timerw_cnt; // 12.13
unsigned int stc_47_32; // 12.14
unsigned int stc_63_48; // 12.15
unsigned int timer2_ctl; // 12.16
Timer Register
unsigned int timer2_pres_val;// 12.17
Timer Register
unsigned int timer2_reload; // 12.18
Timer Register
unsigned int timer2_cnt; // 12.19
Timer Register
unsigned int timer3_ctl; // 12.20
Timer Register
unsigned int timer3_pres_val;// 12.21
Timer Register
unsigned int timer3_reload; // 12.22
Timer Register
unsigned int timer3_cnt; // 12.23
Timer Register
unsigned int stcl_0; // 12.24
unsigned int stcl_1; // 12.25
unsigned int stcl_2; // 12.26
unsigned int atc_0; // 12.27
unsigned int atc_1; // 12.28
unsigned int atc_2; // 12.29
unsigned int timer0_reload; // 12.30
Timer Register
unsigned int timer1_reload; // 12.31
Timer Register
};
#define STC_REG ((volatile struct stc_regs *)RF_GRP(12, 0))
The HDMI display and timer interrupt control experiment require the following 3 files, as follows:
1) Install directory \SP7021\workspace\sp7021\main.c
2) Install directory \SP7021\workspace\sp7021\testapi\util \timer.c
3) Install directory \SP7021\workspace\sp7021\include\util\timer.h
main.c
int main(void)
{
printf("Build @%s, %s\n", __DATE__, __TIME__);
hw_init();
sys_init();
disp_hdmi_init();
timer_test_init();/*interrupt test api */
sp_interrupt_setup(); /* interrupt manager module init */
while(1);
}
Step1: First, system and hardware initialization: hw_init (); sys_init ();
Step2: HDMI display initialization setting disp_hdmi_init (), as follows:
void disp_hdmi_init()
{
sp_disp_init();
sp_enable_log_to_osd();
sp_osd_draw_string("Display and Timer test...",240,50,20,113);
}
The function of sp_enable_log_to_osd () realizes sending serial debugging information printf () to HDMI display interface;
The function of sp_osd_draw_string () realizes the display of ASCII characters at the specified coordinate position of the HDMI display screen
Step3: Then call the count timer initialization function timer_test_init () defined in timer.c;
Step4: Finally call the system interrupt management function sp_interrupt_setup ();
Of the above four functions, only timer_test_init () is written by the user according to the application requirements, and the others are provided by the system.
The function body of timer_test_init () is implemented in timer.c, which is responsible for the initialization of counting timer timer3, including the selection of counting clock, setting of timer value, timer interrupt configuration and corresponding interrupt processing function operation.
timer.c
#include "common_all.h"
#include "cache.h"
#include "sp_interrupt.h"
#define TIMER3_TICKS (90 - 1) /* 1s */
#define TIMER3_CONFIG_STC (1 << 2) /* src: stc */
#define TIMER3_RELOAD (1 << 1) /* timer3 auto reload */
#define TIMER3_RUN (1 << 0) /* timer3 run */
#define TIMER3_STOP (0 << 0) /* timer3 stop */
#define TIMER3_INT (154)
static unsigned int g_repeat_cnt = 0;
void timer3_interrupt_control_mask(int enable)
static void timer3_isr_cfg()
void timer3_callback(void)
void timer_test_init()
timer.c提供实现定时器控制实验的4个方法函数及宏定义,分别讲解如下:c provides 4 method functions and macro definitions for implementing timer control experiments, which are explained as follows:
void timer3_interrupt_control_mask(int enable)
{
if (enable != 0) {
/* enable timer3 interrupt */
hal_interrupt_unmask(TIMER3_INT);
} else {
hal_interrupt_mask(TIMER3_INT);
}
}
用来控制计数定时器3中断的开与关;enable为0时关闭中断,为1时开启中断}
}
Used to control the opening and closing of the count timer 3 interrupt; when the enable is 0, the interrupt is turned off, and when it is 1, the interrupt is turned on
static void timer3_isr_cfg()
{
printf("[CFG] Timer3\n");
STC_REG->timer3_ctl = TIMER3_CONFIG_STC | TIMER3_RELOAD;
STC_REG->timer3_pres_val = 999;
STC_REG->timer3_reload = TIMER3_TICKS;
STC_REG->timer3_cnt = TIMER3_TICKS;
hal_interrupt_configure(TIMER3_INT, 0, 1);
timer3_interrupt_control_mask(1);
STC_REG->timer3_ctl |= TIMER3_RUN;
}
实现计数定时器每1秒产生1次中断,相关配置工作如下:
Realize that the count timer generates an interrupt every 1 second. The related configuration work is as follows:
1) STC_REG->timer3_ctl = TIMER3_CONFIG_STC | TIMER3_RELOAD;
计时钟选择STC 90KHZ 时钟;操作方式为重复操作Select clock as STC 90KHZ clock; operation mode is repeated operation
2) STC_REG->timer3_pres_val
= 999; 计数时钟预处理设置为999,表示每收到1000个STC 90KHZ时钟,timer3 才计数1次;= 999;
Counting clock preprocessing is set to 999, which means that timer3 only counts once every 1000 STC 90KHZ clocks are received;
3) STC_REG->timer3_reload = TIMER3_TICKS;
计数预值设置为89, 表示timer3 计数90次后,重新开始计数The pre-count value is set to 89, which means that timer3 starts counting again after 90 times
4) STC_REG->timer3_cnt = TIMER3_TICKS;
计数初值设置为89,因为计数器是 UP to DOWN 的方式,即从初值计数到0完成1次操作;The initial count value is set to 89, because the counter is UP to DOWN, that is, from the initial value count to 0 to complete 1 operation;
5) hal_interrupt_configure(TIMER3_INT, 0, 1);
这是系统提供的中断设置函数,共有3个参数需要设置,如下:
This is the interrupt setting function provided by the system. There are 3 parameters to be set, as follows:
void hal_interrupt_configure(int vector, int level, int up)
int vector :中断号,系统分配指定,每个定时器都有自己专门的中断号:
time0的中断号是151
time1的中断号是152
time2的中断号是153
time3的中断号是154:Interrupt number, assigned by the system, each timer has its own dedicated interrupt number:
The interrupt number of time0 is 151
The interrupt number of time1 is 152
The interrupt number of time2 is 153
The interrupt number of time3 is 154
int level :中断信号触发方式
0:边沿触发
1:电平触发:Interrupt signal trigger mode
0:Edge trigger
1:Level trigger
int up :中断信号极性方式
0:负极性(负边沿或负电平)
1:正极性(正边沿或正电平:Interrupt signal polarity
0:Negative polarity (negative edge or negative level)
1:Positive polarity (positive edge or positive level)
6) timer3_interrupt_control_mask(1);
开启计数定时器3中断
Turn on count timer 3 interrupt
7) STC_REG->timer3_ctl |= TIMER3_RUN;
启动计数定时器3,计数开始 Start counting timer 3, counting starts
void timer3_callback(void)
{
printf("@Timer3[%d]\n", ++g_repeat_cnt);
}
是对应的中断处理函数操作,将中断的次数显示在IDE 环境的Terminal窗口,如图所示。
It is the corresponding interrupt processing function operation, which displays the number of interrupts in the Terminal window of the IDE environment, and also sends them to the HDMI terminal for display.
void timer_test_init()
{
static interrupt_operation timer3_opt;
memcpy(timer3_opt.dev_name, "Timer3", strlen("Timer3"));
timer3_opt.vector = TIMER3_INT;
timer3_opt.device_config = timer3_isr_cfg;
timer3_opt.interrupt_handler = timer3_callback;
interrupt_register(&timer3_opt
);
}
是中断初始化操作,完成中断函数的注册,包含上面定义的3个函数的调用);
}
It is an interrupt initialization operation to complete the registration of the interrupt function, including the call of the three functions defined above
timer.h
#ifndef __TIMER_H__
#define __TIMER_H__
void timer_test_init();
#endif // __TIMER_H__
When a function in timer.c 中的函数被其它文件中的函数调用时,需要在timer.h中申明
在Plus1 IDE环境中compile后,下载到平台运行,在terminal窗口看到如下信息
...
is called by a function in another file, it needs to be declared in timer.h
After compile in the Plus1 IDE environment, download to the platform to run, and see the following information in the terminal window
...