NIOSII开发总结

发布时间:2012-01-14 10:47:36   来源:文档文库   
字号:

1.这个错误是由什么引起?提示LED_ PIO_BASE没有声明 

  答:这是因为名字不一致引起的比如,在生成SOPC系统时,双击PIO(Parallel I/O)(Avalon Modules -> Other 下),为系统添加输出接口,你没有把该组件改名成LED_PIO,而是保留了原始的名字:PIO_0;但你又通过 IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, led);来向该组件写入数据,就会导致上述错误。解决办法:1.可以修改sopc系统,为该PIO改名为LED_PIO ;2.hello_led.c的前面给LED_PIO_BASE赋值,如#define LED_PIO_BASE 0x00001800,后面的这个地址要与SOPC中的地址对应.

2. 怎样在NIOSII中操作PIO,提供一种参考方法。

  答:hello_led.c是这样写IO口的:

IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, led);

首先在altera_avalon_pio_regs.h找到定义

i nclude

#define IORD_ALTERA_AVALON_PIO_DATA(base) IORD(base, 0)

#define IOWR_ALTERA_AVALON_PIO_DATA(base, data) IOWR(base, 0, data)

因此在NIOSII中可以调用#i nclude库函数IORD/IOWR来操作PIO

smallsoftwarehello_led_0_syslibDebugsystem_des cription下的system.h

,有以下内容:

#define LED_PIO_TYPE "altera_avalon_pio"

#define LED_PIO_BASE 0x00004000

其中LED_PIO_BASEIO寄存器地址?)为0x00004000SOPCBuilder中设置一致!

(其实在SopcBuilder中有关NiosII的配置,就是通过system.h来传送给IDE!)

最后用IOWR(0x00004000, 0, led);替代

IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, led);编译,下载到开发板上,运行成功!

3.出错信息如下:

Linking hello_world_0.elf...

/cygdrive/e/DE2Project_restored/software/hello_world_0_syslib/Debug/libhello_world_0_syslib.a(alt_main.o)(.text+0x60): In function `alt_main':

/cygdrive/c/altera/72/nios2eds/components/altera_hal/HAL/src/alt_main.c:163: undefined reference to `main'

collect2: ld returned 1 exit status

make: *** [hello_world_0.elf] Error 1

Build completed in 1.953 seconds

    :将主函数名字写错了.

应该写成int main(void),结果写成了 int mian()

悲剧!!!!!!

4.IOWR_ALTERA_AVALON_PIO_DATA怎么使用?

    :IOWR_ALTERA_AVALON_PIO_DATA是一个宏定义,其位置在altera_avalon_pio_regs.h中,另外还要参考io.h头文件。NiosII IDE为了避开NiosIICache以及简化IO端口操作程序的编写,定义了两类基本的宏(IOWR_开头的为写PIO操作,以IORD_开头的为读PIO操作),其效果与使用指针的效果不完全一样。 

LED_PIO_BASE是在system.h中定义的一个宏,是LED_PIO端口的基地址。 

IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE,led)的含义就是往LED_PIO端口的数据输出寄存器写入led 

具体可以参考 Altera_embeded_peripherals 一文,这里讲解了一个PIO端口包含了那些寄存器。参考NiosII_software_developer's_handbook 进行驱动设计。这两个文件可以在Altera的官方网站上下载。

5.头文件及数据类型

在这里先简单介绍一下各头文件的作用,,这个头文件包含了标准输入、输出、错误函数库;"system.h",这个文件描述了每个设备并给出了以下一些详细信息:设备

的硬件配置、基地址、中断优先级、设备的符号名称,用户不需要编辑system.h 文件,此文件由HAL 系统库自动生成,其内容取决于硬件配置和用户在IDE 中设置的系统库属性;“altera_avalon_pio_regs.h ” 这个文件是通用I/O 口与高层软件之间的接口.IOWR_ALTERA_AVALON_PIO_DATA(LED_PIO_BASE, led)这个函数就是在此文件中定义的,此函数的功能为将数值(led)赋给LED_PIO_BASE 为基地址的用户自定义的I/O 口上,也就是将led 这个值赋给我们硬件中LED 灯所接的FPGA 管脚上;“alt_types.h”头文件定义了数据类型,如下表所示

类型 说明

alt_8    有符号8 位整数

alt_u8   无符号8 位整数

alt_16   有符号16 位整数

alt_u16  无符号16 位整数

alt_32   有符号32 位整数

alt_u32 无符号32 位整数

IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE,0xf);

IOWR_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE,0x0);

IORD_ALTERA_AVALON_PIO_EDGE_CAP(BUTTON_PIO_BASE)

alt_irq_register(BUTTON_PIO_IRQ,edge_capture_ptr,handle_button_interrupts)

在文件"altera_avalon_pio_regs.h"中有如下定义

#define IOWR_ALTERA_AVALON_PIO_IRQ_MASK(base,data)IOWR(base,2,data)

#define IOWR_ALTERA_AVALON_PIO_EDGE_CAP(base,data)IOWR(base,3,data)

#define IORD_ALTERA_AVALON_PIO_EDGE_CAP(base)IORD(base,3)

第一个函数是使能中断函数,是按位来势能的,比如0xf表示四位全部使能,而0x7表示使能

3位中断;



第二个函数是设置边沿捕获寄存器函数,用来重新设定寄存器的值;一般在读取之后会重新设定为0

第三个函数是读取边沿捕获寄存器函数,用来读取寄存器的值;

下面是alt_irq_register函数的原形,此函数用来声明ISR,在软使用IRS之前一定要先声明;

extern int alt_irq_register(alt_u32 id,

void*context,

void(*irq_handler)(void*,alt_u32));

一般在开发按键中断程序时,handle_button_interrupts()和init_button_pio()这两个函

数直接使用,不用再编辑。

6.关于alarm——使用系统时钟服务

在操作系统中,alarm是一个常用的概念,比如当一个进程需要等待某个事件又不想永远等待下去时,该进程会设置一个超时值(timeout)。当这个值到达时,操作系统会向进程发送一个alarm(警告信号),提醒进程不要再等待。在NIOS IIalarm也可以同样理解为是打断正在执行的流程,提醒系统不要等待的信号。

使用HAL提供的系统时钟服务大概分为3个步骤:

1. 调用alt_alarm_start()开启系统时钟服务,该函数位于:NIOS安装盘:\altera\kits\nios2\components\altera_hal\HAL\src文件夹下的alt_alarm_start.c中。

2. 按照格式要求编写回调函数。该回调函数将实现用户功能

3. 调用alt_alarm_stop()关闭系统时钟服务,该函数位于:NIOS安装盘:\altera\kits\nios2\components\altera_hal\HAL\src文件夹下的alt_tick.c中。

通过接口函数访问定时器对象中的变量。为达到隐藏信息的目的,Altera公司提供了一个接口函数alt_ticks_per_second()供用户获得一个设定alarm服务周期为1s的变量值。

4)系统时钟服务API函数分析

1.开启系统时钟服务函数:alt_alarm_start()

函数原型:int alt_alarm_start(alt_alarm* alarm,alt_u32 nicks,alt_u32(*callback) (void* context),void* context)

函数功能:启动系统时钟服务。

输入函数:alarm——一个指向alt_alarm结构体型的指针变量,用户需要为每个系统时钟服务创建一个alt_alarm类型变量。系统由该变量对系统时钟进行维护。例如,用户需要两个系统时钟服务,则需定义alt_alarm alarm_1alarm_2.

Nticks——指示每隔nticks执行一个回调函数。如果定时器预设的中断周期为1ms,则每个ticks的时间间隔为1ms.如果用户希望获得1s一次的服务,则nticks的输入值为1s/1ms=1000

Callback——用户回调函数指针。

Context ——传给回调函数的参数,一般为寄存器的地址。也可以是其他参数。如果不需要传递参数则此处填入NULL

2.用户回调函数:my_alarm_callback()

函数原型:alt_u32 my_alarm_callback(void* context)

输入参数:context——alt_alarm_start()函数传入的参数,函数名可以自己定义,但是函数原型一定要按上述格式写。

4. 停止系统时钟服务函数alt_alarm_stop()

函数:void alt_alarm_stop(alt_alarm* alarm)

输入参数:alarm——一个指向alt_alarm结构体类型的指针变量,用户希望停止哪一个系统时钟服务,即把该时钟服务对应的alarm变量传递给alt_alarm_stop()

7. 1使用时间标记服务的工作分两步:第一步调用alt_timestamp_start()开启时间标记服务,第二部调用alt_timestamp()测量用户感兴趣的时间点。这两个函数位于NIOS II安装盘:\altera\kits\nios2\components\altera_hal\HAL\src文件夹下的alt_avalon_timer_ts.c中。

2.定时器对时间标记功能的支持。NIOSII的定时器有两个快照寄存器snap1snaph主控制器可以通过对snaplsnaph寄存器的写操作(忽略写数据)请求当前32位内部计数器的快照。当执行写操作时,计数器的值复制到snaplsnaph中,且不会改变计时器的运行状态。Snapl保存计数器的低16位,snaph保存计数器的高16位。

3.时间标记API函数分析:

1alt_timestamp_start()

函数原型:int alt_timestamp_start(void);

函数功能:启动时间标记服务

输入参数:无

返回值:小于0,则失败;大于或等于0,则成功。

2alt_timestamp()

函数原型:alt_u32 alt_timestamp(void)

函数功能:返回某时刻的时间值

输入参数:无

返回值:某时刻的时间值

另外还有一个API函数alt_timestamp_freq()。该函数可以获知系统工作频率。

8.如何调用看门狗

看门狗的操作分两步:第一部是开启看门狗。需要注意的是,一旦开启看门狗将不能通过软件停止;第二部是“喂狗”。

1) 开启看门狗有以下宏定义实现:

IOWR_ALTERA_AVALON_TIMER_PERIODL(WATCHDOG_BASE,ALTERA_AVALON_TIMER_CONTROL_START_MSK);实现。

2) 喂狗操作由如下宏定义实现:

IOWR_ALTERA_AVALON_TIMER_PERIODL(WATCHDOG_BASE,0x1234);

向定时器的周期寄存器写一个任意的数即可实现喂狗操作。

宏名:IOWR_ALTERA_AVALON_TIMER_CONTROL(base,data)

功能:向定时器控制器写一个数据。

输入参数:base——定时器的基地址,本节实验是WACTHDOG_BASE;

Data——向控制寄存器写的数据,本节实验是向控制寄存器的START位写1.

宏名:IO_ALTERA_AVALON_TIMER_PERIODL(base,data);

功能:向定时器周期寄存器写一个数据。

输入参数:base——定时器的基地址,本节实验是WATCHDOG_BASE;

Data——向周期寄存器写的数据,本例是0x1234(该数据可以是任意值)

;9.串口调试问题

nios2-terminal: can't open uart: Permission denied

Nios 中调试Hello world!范例的时候往往会出现这样的错误,nios2-terminal: can't open uart: Permission denied。这是因为你在调试程序的时候,打开了另外的串口调试工具,或者可以说是串口侦听器。但实际上NIOS IDE中已经集成了串口调试工具,或者串口侦听器。在任务管理器中nios2-terminal.exe就是这个侦听串口的进程。

   所以很明了了,如果你想用nios ide来观察发送的数据,就不要用其他的串口调试工具,如果你在编译的前就打开了其他的串口侦听器的话,编译链接的时候就会出现以上的错误。而你在程序编译链接后再去打开其他的串口侦听器,串口就会因为nios2-terminal.exe占用而无法打开。

  解决的方法,如果你想用NIOS IDE观察的话就不要事先打开其他的串口调试工具。而如果你想用其他的串口调试工具来观察数据的话,很简单,通过USB_BLASTER把数据下载进去板子后,删除任务管理器中的nios2-terminal.exe,然后打开串口调试工具。如果程序没有问题的话,运行后就可以看到数据。

10.警告解决办法

出现: warning: no newline at end of file



解决办法:在*.c文件最好添加上一个回车,独立成一行。在编译就不出问题了。



分析:应该是编译器需要文件最后有一个回车,作为文件结尾。

11.系统ID核综述

系统ID核寄存器映像

偏移

寄存器名

/

位描述

0

ID

R

31~0

SOPC Builder 系统ID

1

时间戳

R

SOPC Builder 创建时间

*返回值是常数

1.ID—— 一个独一无二的32位值。取决于SOPC Builder 系统的内容。ID类似于检查累加和,具有不同元器件或不同配置选项的SOPC Builder系统产生不同的ID值。

2.timestamp —— 在系统创建时产生的一个唯一的32位值。该值等于从1970.1.1之后的时间(秒数)。

3.下载新软件到一个系统之前验证系统ID。该方法被软件开发工具使用,例如NIOS II IDE.

在下载程序之前NIOS II IDE 检查系统硬件ID是否与期望的系统值ID匹配。

12.PLL寄存器描述

PLL的寄存器映像

偏移

寄存器名称

/

位描述

15

2

1

0

0

status

R

*

locked

1

control

RW

*

*保留,读结果未定义,写操作使保留位为0.

设备驱动程序可通过216位寄存器映像的寄存器(状态和控制寄存器)控制内核并与之通信。

1. 状态寄存器

嵌入式软件可通过状态寄存器读取PLL的状态,对状态寄存器写操作无影响。表4-36描述了每位的功能。

状态寄存器

信号

位名称

复位后的值

描述

0

locked

1

altpll中的locked信号相连,当有效的时钟出现在PLL的输出端时,locked位为高

1~15

——

保留位,读结果未定义

2.控制寄存器

嵌入式软件可通过控制寄存器控制PLL,软件也能读取控制位的状态。

位号

位名称

复位后的值

描述

0

areset

0

altpll中的areset信号相连,写1到该位发起信号且保持为一个时钟周期

1

Pfdena

1

altpll中的pfdene信号相连

2~15

——

保留位,读操作结果未定义,写操作时设置保留位为0

13.mutex

1)概述

多处理器环境可使用具有Avalon接口的mutex核来协调对共享资源的访问。Mutex核提供一个协议来保证对共享资源的所有权的互斥。

Mutex核提供一个基于硬件的原子的测试的位置(test-and-set)操作,允许在多处理器环境下哪一个处理器拥有mutexMutex核和共享存储器一起可用作附加的处理器之间的协调部件,例如消息箱和软件互斥。

第二章 SOPC软件开发

.程序入口点和启动程序

一般而言,程序的入口点为main()函数,也可以使用alt_main()函数作为程序的入口点,这样用户可以使用该函数获得对启动顺序的更高级控制。

基于HAL程序的启动顺序

HAL提供了系统初始化代码,这些代码用于执行以下的启动顺序:

1. 刷新指令和数据高速缓存;

2. 配置堆栈指针

3. 配置全局指针

4. 使用_bss_start_bss_end来零初始化BSS区。

5. 复制. Rwdata.rodata和异常区到RAM

6. 调用alt_main()函数。

如果用户没有提供alt_main()函数,则缺省执行下面的操作:

1. 调用alt_os_init()执行操作系统初始化,如果系统中没有操作系统调度,则该宏没有作用;

2. 如果HAL使用了操作系统,则初始化alt_fd_list_lock信号量来控制访问HAL文件系统;

3. 初始化中断控制器,使能中断;

4. 调用alt_sys_init()函数,初始化系统所有设备驱动和软件部分,Nios II IDE自动创建和管理alt_sys_init.c文件;

5. 改变C标准I/O通道以便使用合适的设备;

6. 使用_do_ctors()函数调用C++构造函数;

7. 在系统关闭时调用C++析构函数;

8. 调用main()函数;

9. 调用exit()函数,把main()函数返回码作为exit()的输入函数

二.存储分区

包含Nios II处理器复位地址和异常地址的存储设备是一个特例。如果一个存储设备包含上诉地址之一,则低于该地址的存储单元从该区中被排除。在复位地址开始处创建一个32字节的复位地址,该复位区域被保留作为复位控制。

使用缺省存储器映射的系统,在设备存储器或Flash 存储器中复位地址的偏移量为0x0,异常地址的偏移量为0x20

三.使用HAL开发设备驱动程序

1.system.hSOPC Builder的关系

System.h头文件提供了Nios II系统硬件的完全的软件描述,是开发驱动程序的基础部分。

2.使用SOPC Builder进行最佳硬件配置

System.h头文件可以通过使用SOPC Builder改变底层硬件来进行修改。当用户在不是很理想的硬件编写设备程序之前,考虑这个硬件是否使用SOPC Builder进行改进是必要的。

3. 部件,设备和外设

SOPC Builder使用“部件”这个术语来描诉在系统中的硬件模块。在Nios II软件开发过程中,SOPC Builder是一些设备,如外设和存储器。

四.访问硬件

软件通过宏定义访问硬件,这些宏对设备的存储映射接口进行抽象化。

1. 寄存器存取宏,该宏提供对每个寄存器的读/写。宏名如下:

IOWR__

IORD__

2. 位域(bit-field)的屏蔽(mask)和偏移量,提供寄存器内单独的位域访问。宏名如下:

___MSK为域内位

屏蔽。

___MSK为域内位

偏移。

ALTERA_AVALON_UART_STATUS_PE_MASKALTERA_AVALON_UART_STATUS_PE_OFST用于访问寄存器的PE域。

本文来源:https://www.2haoxitong.net/k/doc/f61578ef6294dd88d0d26bce.html

《NIOSII开发总结.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式