FPGA-核nios全面接触 | NIOS II的 UART
NIOS II的UART 与通用串口兼容,用于可以设置自己的需求通信模式,比如波特率 奇偶校验 停止位 数据位和其他控制信号
主要的寄存器有: txdata,rxdata,status control divisor endof packet,串口要说的东西其实不是很多,但是其确有很多很多的位定义,比如irrdy itrdy等等发送接受传输和错误检测等控制位,这里就不一一列出了,太多了,用的东西在NIOS中看名字大概也能看出来.具体见头文件
#i nclude "altera_avalon_uart_regs.h"
下面是我曾经用过的一个UART通信中断程序
int handle_uart_interrupts(void* context, alt_u32 id)
{
FILE *uart_file;
uart_file=fopen("/dev/uart_0","r+");
if (uart_file == NULL)
{
printf("can't open uart_device!");
return 0 ;
}
uart_buf[k++]=IORD_ALTERA_AVALON_UART_RXDATA(UART_0_BASE);
if(uart_buf[k-1]=='f')
{
char search[20] = "s ";
uart_buf[k-1]='\0';
k=0;
//printf("串口%s ", uart_buf);
if (cur_panel.id == 0)
{
search[0] = 'c';
if (strlen(uart_buf) == 2)
{
search[2] = '0';
search[3] = '\0';
}
}
if (strlen(uart_buf) == 6)
{
search[2] = '9';
search[3] = '\0';
}
strcat(search, uart_buf);
strcpy(sendbuf, search);
}
fclose(uart_file);
return 0;
}
仔细看看上面的程序,并与头文件 #i nclude "altera_avalon_uart_regs.h"中所定义的可用寄存器比较一下会发现,上述写法并不可取,上述程序接受数据是字符的依次读入,其实可以在控制位和发送接受寄存器的配合下,则可以很高效的写出通信程序,而不必像上面那样显得有点"笨".
NIOS II的 PIO
PIO模块也作为SOPC Builder库中的一个组件,可以是1-32位的并行接口,有多种配置选项,比如输入\输出\双向\触发方式(若用于中断的话)
其相关的寄存器如下:
数据寄存器 data
方向寄存器 direction
中断允许寄存器 interruptmask
边沿捕获寄存器(edgecapture) (RISING.FALLING.ANY)
PIO的应用还是比较简单的,一般作为NIOS 与外部电路(还是FPGA内)的接口,比如数据\中断控制等等,下面贴上PIO的一些设置项,同样在system.h头文件中,几乎所有的设置都可以在 system.h和PTF文件中找到原型.
#define PIO_NAME "/dev/pio"
#define PIO_TYPE "altera_avalon_pio"
#define PIO_BASE 0x00001000
#define PIO_SPAN 16
#define PIO_DO_TEST_BENCH_WIRING 0
#define PIO_DRIVEN_SIM_VALUE 0x0000
#define PIO_HAS_TRI 0
#define PIO_HAS_OUT 1
#define PIO_HAS_IN 0
#define PIO_CAPTURE 0
#define PIO_EDGE_TYPE "NONE"
#define PIO_IRQ_TYPE "NONE"
#define PIO_FREQ 50000000
我想上述各个选项的含义就不多说了,应该很好理解,下面贴一个当时写过的一个PIO中断控制程序,求大家批评.
#i nclude "altera_avalon_pio_regs.h"
IOWR_ALTERA_AVALON_PIO_IRQ_MASK(BUTTON_PIO_BASE, 0xf);
alt_irq_register(BUTTON_PIO_IRQ,edge_capture_ptr,handle_button_interrupts);
void handle_button_interrupts()
{}
大概好象是这个样子的,不是记得很清楚了,仅供参考
| NIOS II 的定时器
如果你对单片机熟悉的话,那么NIOS II的定时器会很简单的理解,并很好的应用.定时器模块是NIOS 开发工具包的一个库组件,其可用于周期脉冲发生器或看门狗定时器.记得当时参加NIOS 竞赛的时候发现很多的资料不仅老,而且少,所以我这里先把一些关键寄存器说一下(想到哪,说到哪,有点乱)
NIOS 定时器模块是32位的内部定时器,以下寄存器均为16位.
寄存器名 status 位0 : to位,内部计时器为0时,to 位置1
位1: run位,内部计时器运行时,run位置1,否则0
control 位0: ito 位,如果该位置1,则当状态寄存器的to 位置1(定时器溢出),计时器发出中断请求.若其置0,则不产生中断.
位1: cont 位 内部计时器为0时,,计时器重载preiodl和preiodh,若cont 为1,则定时器连续计时,只有写stop位停止,若cont 为0,则重载初值后,停止计时.
位2: start 见名知意
位3: stop 见名知意
periodl 计数器低16位
periodh 计数器高16位
snapl 计数器捕捉寄存器(读地位状态)
snaph 计数器捕捉寄存器(读高位状态)
对nios中的定时器的具体功能设定可以通过SOPC中进行相应勾选
若需要watch dog的话,则在SOPC中选择Timer,在Preset configration选择 watch dog
关于对看门狗的具体设置,则在头文件system.h中加以修改,具体如下:
#define WATCH_DOG_NAME "/dev/watch_dog"
#define WATCH_DOG_TYPE "altera_avalon_timer"
#define WATCH_DOG_BASE 0x00001020
#define WATCH_DOG_SPAN 32
#define WATCH_DOG_IRQ 0
#define WATCH_DOG_ALWAYS_RUN 1
#define WATCH_DOG_FIXED_PERIOD 1
#define WATCH_DOG_SNAPSHOT 0
#define WATCH_DOG_PERIOD 1
#define WATCH_DOG_PERIOD_UNITS "ms"
#define WATCH_DOG_RESET_OUTPUT 1
#define WATCH_DOG_TIMEOUT_PULSE_OUTPUT 0
#define WATCH_DOG_MULT 0.001
#define WATCH_DOG_FREQ 50000000
若应用为计时器的话,则关于在NIOS IDE中的具体编程,在头文件 include "altera_avalon_timer_regs.h"中定义了所有的寄存器的地址,通过IOWR IORD等指令可以很方面的进行定时器的设计
/******************************************************************************
* *
* License Agreement *
* *
* Copyright (c) 2003 Altera Corporation, San Jose, California, USA. *
* All rights reserved. *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
* DEALINGS IN THE SOFTWARE. *
* *
* This agreement shall be governed in all respects by the laws of the State *
* of California and by the laws of the United States of America. *
* *
******************************************************************************/
#ifndef __ALTERA_AVALON_TIMER_REGS_H__
#define __ALTERA_AVALON_TIMER_REGS_H__
#i nclude <io.h>
/* STATUS register */
#define ALTERA_AVALON_TIMER_STATUS_REG 0
#define IOADDR_ALTERA_AVALON_TIMER_STATUS(base) \
__IO_CALC_ADDRESS_NATIVE(base, ALTERA_AVALON_TIMER_STATUS_REG)
#define IORD_ALTERA_AVALON_TIMER_STATUS(base) \
IORD(base, ALTERA_AVALON_TIMER_STATUS_REG)
#define IOWR_ALTERA_AVALON_TIMER_STATUS(base, data) \
IOWR(base, ALTERA_AVALON_TIMER_STATUS_REG, data)
#define ALTERA_AVALON_TIMER_STATUS_TO_MSK (0x1)
#define ALTERA_AVALON_TIMER_STATUS_TO_OFST (0)
#define ALTERA_AVALON_TIMER_STATUS_RUN_MSK (0x2)
#define ALTERA_AVALON_TIMER_STATUS_RUN_OFST (1)
/* CONTROL register */
#define ALTERA_AVALON_TIMER_CONTROL_REG 1
#define IOADDR_ALTERA_AVALON_TIMER_CONTROL(base) \
__IO_CALC_ADDRESS_NATIVE(base, ALTERA_AVALON_TIMER_CONTROL_REG)
#define IORD_ALTERA_AVALON_TIMER_CONTROL(base) \
IORD(base, ALTERA_AVALON_TIMER_CONTROL_REG)
#define IOWR_ALTERA_AVALON_TIMER_CONTROL(base, data) \
IOWR(base, ALTERA_AVALON_TIMER_CONTROL_REG, data)
#define ALTERA_AVALON_TIMER_CONTROL_ITO_MSK (0x1)
#define ALTERA_AVALON_TIMER_CONTROL_ITO_OFST (0)
#define ALTERA_AVALON_TIMER_CONTROL_CONT_MSK (0x2)
#define ALTERA_AVALON_TIMER_CONTROL_CONT_OFST (1)
#define ALTERA_AVALON_TIMER_CONTROL_START_MSK (0x4)
#define ALTERA_AVALON_TIMER_CONTROL_START_OFST (2)
#define ALTERA_AVALON_TIMER_CONTROL_STOP_MSK (0x8)
#define ALTERA_AVALON_TIMER_CONTROL_STOP_OFST (3)
/* PERIODL register */
#define ALTERA_AVALON_TIMER_PERIODL_REG 2
#define IOADDR_ALTERA_AVALON_TIMER_PERIODL(base) \
__IO_CALC_ADDRESS_NATIVE(base, ALTERA_AVALON_TIMER_PERIODL_REG)
#define IORD_ALTERA_AVALON_TIMER_PERIODL(base) \
IORD(base, ALTERA_AVALON_TIMER_PERIODL_REG)
#define IOWR_ALTERA_AVALON_TIMER_PERIODL(base, data) \
IOWR(base, ALTERA_AVALON_TIMER_PERIODL_REG, data)
#define ALTERA_AVALON_TIMER_PERIODL_MSK (0xFFFF)
#define ALTERA_AVALON_TIMER_PERIODL_OFST (0)
/* PERIODH register */
#define ALTERA_AVALON_TIMER_PERIODH_REG 3
#define IOADDR_ALTERA_AVALON_TIMER_PERIODH(base) \
__IO_CALC_ADDRESS_NATIVE(base, ALTERA_AVALON_TIMER_PERIODH_REG)
#define IORD_ALTERA_AVALON_TIMER_PERIODH(base) \
IORD(base, ALTERA_AVALON_TIMER_PERIODH_REG)
#define IOWR_ALTERA_AVALON_TIMER_PERIODH(base, data) \
IOWR(base, ALTERA_AVALON_TIMER_PERIODH_REG, data)
#define ALTERA_AVALON_TIMER_PERIODH_MSK (0xFFFF)
#define ALTERA_AVALON_TIMER_PERIODH_OFST (0)
/* SNAPL register */
#define ALTERA_AVALON_TIMER_SNAPL_REG 4
#define IOADDR_ALTERA_AVALON_TIMER_SNAPL(base) \
__IO_CALC_ADDRESS_NATIVE(base, ALTERA_AVALON_TIMER_SNAPL_REG)
#define IORD_ALTERA_AVALON_TIMER_SNAPL(base) \
IORD(base, ALTERA_AVALON_TIMER_SNAPL_REG)
#define IOWR_ALTERA_AVALON_TIMER_SNAPL(base, data) \
IOWR(base, ALTERA_AVALON_TIMER_SNAPL_REG, data)
#define ALTERA_AVALON_TIMER_SNAPL_MSK (0xFFFF)
#define ALTERA_AVALON_TIMER_SNAPL_OFST (0)
/* SNAPH register */
#define ALTERA_AVALON_TIMER_SNAPH_REG 5
#define IOADDR_ALTERA_AVALON_TIMER_SNAPH(base) \
__IO_CALC_ADDRESS_NATIVE(base, ALTERA_AVALON_TIMER_SNAPH_REG)
#define IORD_ALTERA_AVALON_TIMER_SNAPH(base) \
IORD(base, ALTERA_AVALON_TIMER_SNAPH_REG)
#define IOWR_ALTERA_AVALON_TIMER_SNAPH(base, data) \
IOWR(base, ALTERA_AVALON_TIMER_SNAPH_REG, data)
#define ALTERA_AVALON_TIMER_SNAPH_MSK (0xFFFF)
#define ALTERA_AVALON_TIMER_SNAPH_OFST (0)
#endif /* __ALTERA_AVALON_TIMER_REGS_H__ */
|
|
NIOS II DMA
NIOS DMA同样是Altera SOPC Builder库组件
DMA可用于存储器之间、存储器与外设、外设之间的数据传输,允许没有CPU干预,完成固定长度或者可变长度的数据传输
DMA外设通过两个Avalon主端口(一读一写)和一从端口控制。
典型DMA传递过程如下:
1。通过写控制端口设置DMA的数据传输方式
2。启动DMA外设,实施数据传输(CPU不干预)
3。DMA读传输主端口从目标地址(内存或者外设)读取数据,写端口向目的地址(内存或者外设)写数据。读写之间通过FIFO进行数据缓冲。
4。只指定字节数的数据传输完成或者传输了一个包结束(EOP)时,DMA将结束传输。DMA外设可以在传输结束时发出中断请求。
5。传输当中或者结束后,都可以通过查看DMA的状态寄存器来判断传输在进行还是已经结束
主要寄存器: status 第0位:done
第1位:busy
第2位:reop(读取当前数据包结束)
第3位:weop(写当前数据包结束)
第4位:len(完成一次DMA传输,len置1)
readaddress(主读取起始地址),存放的是传输数据的源地址,其宽度由用户在SOPC中自己定义。(与外设匹配)
writeaddress(主写入起始地址),与上类似
length ,存放读写端口之间需要传输的字节数,长度寄存器宽度由系统生成时的设置决定,DMA每完成一次写传输,length寄存器值减一,当减为0时,len位使能。其寄存器的值按照字节数计算,双字传输,必须是4的倍数,字的传输,当然是2的倍数啦!!
control 寄存器: 位0: byte 字节传输
位1: hw 字传输
位2: word 双字传输
位3: go DMA 使能
位4: i_en 中断使能
位5:reen 读数据包使能
位6:ween写数据包使能
位7:leen ,置1时,DMA在传输完length数目数据的时候结束传输(已经知道传输数据量),若设置0,则不会停止,使用于数据量不确定的场合。
位8:rcon 从固定地址读取
位9:wcon 从固定地址写入
读数据的地址每次访问递增1.2.4个字节,具体是几取决去传输的是字节、字、或者半字,若rcon置1,则地址不递增。
当done&&i_en == 1时候,dma向外设发出中断请求,典型的中断处理程序首先读取状态寄存器的len,reop,weop位来判断中断原因。然后,写转台寄存器清除中断,处理后,进行下一次DMA传输。
NIOS II常用函数详解
IO操作函数
函数原型:IORD(BASE, REGNUM)
输入参数:BASE为寄存器的基地址,REGNUM为寄存器的偏移量
函数说明:从基地址为BASE的设备中读取寄存器中偏移量为REGNUM的单元里面的值。寄存器的值在地址总线的范围之内。
返回值: -
函数原型:IOWR(BASE, REGNUM, DATA)
输入参数:BASE为寄存器的基地址,REGNUM为寄存器的偏移量,DATA为要写入的数据
函数说明:往偏移量为REGNUM寄存器中写入数据。寄存器的值在地址总线的范围之内。
返回值: -
函数原型:IORD_32DIRECT(BASE, OFFSET)
输入参数:BASE为寄存器的基地址,OFFSET为寄存器的的偏移量
函数说明:从地址位置为BASE+OFFSET的寄存器中直接读取32Bit的数据
返回值: -
函数原型:IORD_16DIRECT(BASE, OFFSET)
输入参数:BASE为寄存器的基地址,OFFSET为寄存器的的偏移量
函数说明:从地址位置为BASE+OFFSET的寄存器中直接读取16Bit的数据
返回值: -
函数原型:IORD_8DIRECT(BASE, OFFSET)
输入参数:BASE为寄存器的基地址,OFFSET为寄存器的的偏移量
函数说明:从地址位置为BASE+OFFSET的寄存器中直接读取8Bit的数据
返回值: -
函数原型:IOWR_32DIRECT(BASE, OFFSET, DATA)
输入参数:BASE为寄存器的基地址,REGNUM为寄存器的偏移量,DATA为要写入的数据
函数说明:往地址位置为BASE+OFFSET的寄存器中直接写入32Bit的数据
返回值: -
函数原型:IOWR_16DIRECT(BASE, OFFSET, DATA)
输入参数:BASE为寄存器的基地址,REGNUM为寄存器的偏移量,DATA为要写入的数据
函数说明:往地址位置为BASE+OFFSET的寄存器中直接写入16Bit的数据
返回值: -
函数原型:IOWR_8DIRECT(BASE, OFFSET, DATA)
输入参数:BASE为寄存器的基地址,REGNUM为寄存器的偏移量,DATA为要写入的数据
函数说明:往地址位置为BASE+OFFSET的寄存器中直接写入8Bit的数据
返回值: -
|
|
|
|