FPGA 之 SOPC 系列(六)Nios II 程序开发 II

FPGA 之 SOPC 系列(六)Nios II 程序开发 II

今天给大侠带来今天带来FPGA 之 SOPC 系列第六篇,Nios II 程序开发 II,希望对各位大侠的学习有参考价值,话不多说,上货。

本篇接着第五篇继续介绍NIOS II的寄存器级编程方式,以该方式的定时器的编程实例应用。

以下为本篇的目录简介:

  • 6.1 项目文件的管理

  • 6.2 寄存器级编程

  • 6.3 定时器应用

 

6.1 项目文件的管理

每个C工程中,可以以功能为依据对源文件迕行文件夹分类。文件夹不可以出现空格、除英文字母、数字、下划线外的字符;更不允许出现汉字等非 ASCII码字符。例如某个工程可以划分为如下文件夹:

  • doc 说明文档

  • config 系统相关配置文件夹(系统参数配置、编译器、连接器配置文件等)

  • driver 硬件驱动文件夹(包括芯片驱动、cpu外设驱动等)

  • font 字体驱动

  • Gui 图形界面驱动

  • main 主程序

  • include 头文件

  • obj 编译后的目标文件

功能划分应以逻辑清晰、层次关系明显为目的。一旦划分好后,不可越级调用系统资源(例如只有driver内文件内直接操作硬件资源,其他文件夹代码均不可调用最底层硬件资源)。也不要互相调用而使系统资源很快耗尽

文件一旦建立,就需在文件头说明文件目的、版权及历史记录,每次修改后必须记录。工程完工或者是间歇性搁置时,需要对所有工程文件夹、文件进行只读属性设置及当前状态设置。对源代码最好做到每天一备份,以防意外篡改及丢失,以备恢复之用。

 

6.2 寄存器级编程

例:点亮LED的例子转换新的编程方式

第一步,按照上述的文件管理方式,建立一个放置头文件的文件夹,命名为inc, 在工程文件夹上点击右键,然后点击NEW中的SOURCE FOLDER。

下一步,在红圈处输入inc,点击finish,完成文件夹建立。

下一步,在这个新建的文件夹下建立一个头文件,方法如下图所示,在inc上点击右键,然后点击NEW中的header file,输入sopc.h。

打开刚才建立的头文件,补充完代码后如下:

 
 

#ifndef SOPC_H_ #define SOPC_H_ #include "system.h" #define _LED typedef struct { unsigned long int DATA; unsigned long int DIRECTION; unsigned long int INTERRUPT_MASK;; unsigned long int EDGE_CAPTURE; }PIO_STR; #ifdef _LED #define LED ((PIO_STR *)LED_PIO_BASE) #endif #endif /*SOPC_H_*/

其中定义了一个结构体,这个结构体被指向了LED_PIO_BASE,查相关手册, n2cpu_Embedded Peripherals.pdf。

这两个表格就是PIOCORE寄存器映射,我们这个结构体啊就是根据它写出来的,名字不重要,重要的是顺序,也就是偏移量。第一项是数据DATA,第二项是IO口方向,第三项是中断控制位,第四项是边沿控制位。他们每一项都有N位,这个N就是我们在软件构建中的宽度,这个时候我们这里的N等于几?

  • #define LED ((PIO_STR *)LED_PIO_BASE)

  • 它就是怎么把我们定义的结构体给勾上LED设备的。记得LED_PIO_BASE,它就是我们在SYSTEM.H中特别强调的。定义了一个宏,命名为LED,它是指向LED_PIO_BASE的结构指针,这个结构就是PIO_STR.

  • #define _LED

  • #ifdef _LED

  • #endif

  • 意思是为了控制定义#define LED ((PIO_STR *)LED_PIO_BASE)的,这样做是为了增强代码的严谨性和可控制性。

把之前的模板文件hello_world.c名字改为main.c并将它放到main文件夹中,右击rename后,选中main.c右击鼠标move后,选中main文件夹就ok了。

 
 

#include <stdio.h> #include <unistd.h> #include "../inc/sopc.h" int main (void) __attribute__ ((weak, alias ("alt_main"))); int alt_main() { int i; while (1) { for(i=0;i<4;i++){ LED->DATA =1<<i; usleep(500000); } } return 0; }

LED->DATA =1<<i;LED是在SOPC.H中定义的宏,是结构体指针,它的结构体中DATA的内容(不是地址)。这里的usleep是微秒级延时的。

总结一下:

  • 文档的归类管理。

  • Sopc.h定义来源是相关外设的文档寄存器。

  • 操作定义好的外设结构体变量编程。

并不是,要看什么要的外设,想FLASH这种外设,采用这种方式的话,累死你,我们就直接可以使用API来写就行了。这种方式对我们了解nios的本质是很有帮助的。

 

6.3 定时器应用

概览

该时间计数器是一个为诸如NIOS II 等基于Avalon架构的处理器设计的时间计数器。该计数器有如下特点:

(1)32位和64位计数;

(2)具有计数开始、计数停止、和复位计数器功能;

(3)两种技术模式:单次计数、连续计数;

(4)计数周期寄存器;

(5)当计数器计数到0时,可以选择使能或者禁止触发中断(IRQ);

(6)可选作为看门狗,产生系统复位;

(7)可选产生周期脉冲,当计数器计数到0时;

(8)可用于32位或者16位处理器中。如16位的NIOS和32位的NIOS II。

Interval TimerCore 功能描述

(1)Avalon-MM提供可对6个16位寄存器操作的功能;

(2)可选周期脉冲输出。

所有的寄存器都是16位宽度的,因此可适应于16位或者32位处理器。若该核被配置为一个固定的周期,那么,周期寄存器就不存在。

计数周期(Timeout Period)

计数周期决定了周期计数器值。当使能可写周期(Writeableperiod),处理器可以通过写周期计数器( period registers)改变计数器值。或者当禁止可写周期(Writeableperiod),周期计数器(period registers)不可经过处理器的写操作而改变;此时周期计数器只能是一个不可改变的固定周期计数值。Interval Timer Core的计数周期是系统时钟周期的整数倍。实际的时钟周期读者可以这样求。

(1)求出系统的时钟。指驱动Interval Timer Core的时钟。一般与NIOS II 时钟一致。

(2)将周期计数器里面高16位和低16位的值乘与时钟时期即得计数周期。

计数大小(Counter Size)

该设定决定了计数器的位宽。可以设定为32位或者64位。32位位宽的计数器包含有2个16位的寄存器;而64位位宽的计数器包含有4个16位宽的寄存器。该设定同样应用至snap单元。

硬件选项

(1)Simple periodic interrupt—该设定用于只需要一个带有中断(IRQ)的计数器。该方式下,计数周期是固定不可软件更改的,且计数不能停止但中断(IRQ)可禁止。

(2)Full-featured—该配置适用于一个可被处理器更改,可变计数周期,且其开始、停止均可被更改的计数器。

(3)Watchdog—适用于系统需要看门狗的情况。当系统停止响应,该配置能使系统复位。

寄存器(registeregister)设定说明

(1)Writeable period——当选中此项,则主外设(NIOS II)可通过写周期寄存器(period registers)达到修改计数周期的目的。若未选中此项,则计数周期被确定为(Timeout Period),不可更改;同时周期寄存器(period registers)不再存在。

(2)Readable snapshot——当选中此项,则主外设(NIOS II )可以读取当前计数值。若未选中此项,则主外设只能依靠查询状态寄存器(status register)或者中断(IRQ)标志来得知计数状态;此时(snap registers)并不存在,读取该寄存器会有不确定的数值。

(3)Start/Stop control bits——当选中此项,则主外设( NIOS II )可以通过写控制寄存器(control register)来启动、停止计数器。若未选中此项,则计数器默认为连续计数模式。值得注意的是,当系统看门狗复位(System reset on timeout (watchdog))是使能状态,则控制寄存器(control register)中的(start)位被置位,而不管Start/Stop 控制位的状态。

信号输出选项

( 1 ) Timeout pulse (1 clock wide) — — 当选中该项, 则计数器产生一个信号端口(timeout_pulse),该信号端口在计数器减计数至0时产生一个系统时钟周期的高电平。若未选中该项,则计数器不产生该信号端口。

(2)System reset on timeout (watchdog)——当选中该项,则计数器产生一个复位信号端口(resetrequest port)该信号在计数器减计数至0时产生一个系统时钟周期的高电平。若未选中该项,则该信号端口不存在。

配置计数器为看门狗

若要使用看门狗,则应作如下选择。

(1)presets:选择Watchdog;

(2)Timeout Period修改成所需要的时间

(3)Writeable period禁止;

(4)Readable snapshot禁止;

(5)Start/Stop control bits禁止;

(6)Timeout pulse禁止;

(7)System reset on timeout (watchdog)使能。

复位之后看门狗是禁止的。随后,处理器往控制寄存器(control register)的START位写1。开启看门狗计数器。看门狗一旦开启,就不能结束。为了不使系统复位,处理器应该定时地复位计数值。

Interval Timer Core 软件编写

状态寄存器(status Register Bits)

TO——当计数器减计数到0时,置1。一旦置1,则必须由主外设(NIOS II)清0;

RUN——当计数器在计数运行时,RUN=1;否则RUN=0。写RUN对值无影响。

控制寄存器(control register)

ITO——当ITO=1时,计数器会产生中断。反之则反。

CONT——若COUNT=1则计数器计数到0连续计数,知道STOP=1;若COUNT=0则计数器计数到0时,停止计数。

START——写1到START则使计数器开始计数。当计数器正在计数运行,则写START无效。

STOP——写1到STOP则使计数器停止计数。若计数器已经停止计数,则写STOP无效。当SOPC配置为Start/Stop control bits为关闭,则写STOP无效。

中断(IRQ)

当计数器减计数到0时并且控制寄存器(congtrol register)ITO位被置1,则可产生定时器中断。

处理中断应用以下两种方式之一:

(1)清除状态寄存器(status register)的TO位;

(2)清除控制寄存器(congtrol register)ITO位,禁止中断。否则会产生不确定结果。

实例程序

 
 

/**//************************ 定时器中断注册初始化函数*****************************/ void InitInterrupt() { //----------------------------定时器中断,系统时钟66.7MHz-------------------- ------// alt_irq_register(TIMER_IRQ,NULL,Timer_interrupts); //注册中断函数 IOWR_ALTERA_AVALON_TIMER_PERIODH(TIMER_BASE, 0x000A); IOWR_ALTERA_AVALON_TIMER_PERIODL(TIMER_BASE, 0x2C2A);//修改定时时间10ms IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_BASE, 7); //启动定时器允许中断,连续计数 } /**//*************************定时器中断服务函数*****************************/ void Timer_interrupts(void* context, alt_u32 id) { /**//***************************服务代码**************/ /**//**********************退出时清状态寄存器***********/ IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_BASE, 0); //清状态寄存器 } typedef struct{ union{ struct{ volatile unsigned long int TO :1; volatile unsigned long int RUN :1; volatile unsigned long int NC :30; }BITS; volatile unsigned long int WORD; }STATUS; union{ struct{ volatile unsigned long int ITO :1; volatile unsigned long int CONT :1; volatile unsigned long int START :1; volatile unsigned long int STOP : 1; volatile unsigned long int NC :28; }BITS; volatile unsigned long int WORD; }CONTROL; volatile unsigned long int PERIODL; volatile unsigned long int PERIODH; volatile unsigned long int SNAPL; volatile unsigned long int SNAPH; }TIMER;

FPGA 之 SOPC 系列第六篇就到这里结束,下一篇将带来第七篇,NIOS II 高级技术等相关内容。

 

【QQ交流群】

群号:173560979,进群暗语:FPGA技术江湖粉丝。

多年的FPGA企业开发经验,各种通俗易懂的学习资料以及学习方法,浓厚的交流学习氛围,QQ群目前已有1000多名志同道合的小伙伴,无广告纯净模式,给技术交流一片净土,从初学小白到行业精英业界大佬等,从军工领域到民用企业等,从通信、图像处理到人工智能等各个方向应有尽有。

 

【微信交流群】

现微信交流群已建立08群,人数已达数千人,欢迎关注“FPGA技术江湖”微信公众号,可获取进群方式。

后续会持续更新,带来Vivado、 ISE、Quartus II 、candence等安装相关设计教程,学习资源、项目资源、好文推荐等,希望大侠持续关注。

江湖偌大,继续闯荡,愿大侠一切安好,有缘再见!

已标记关键词 清除标记
相关推荐
实付 49.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值