杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 1 -
NIOS II Step by Step7---- uart raw program and Nios II
Device architecture
软件的一个基本特征是问
题
快递公司问题件快递公司问题件货款处理关于圆的周长面积重点题型关于解方程组的题及答案关于南海问题
抽象,建立一个真实世界的软件模型(这个模型并不一定
真实反映被抽象的对象),抽象好啊,可以让人们理解、掌握和控制更多的东西,抽象让我
们当领导,不要做具体的事情,站在更高的层面上全局的理解问题,可以更大范围的控制更
多的对象(但愿我们不是对象:))。可是抽象的多了,却让我们必须花很多精力去掌握和理
解这个抽象体系,难以直接触摸到具体的编程控制过程,Nios II 中的很多功能就是如此,
为了提供一个大家熟悉的 ANSI C的应用开发环境,做了很多抽象,uart编程就是如此,我
们很多工程师是一线高手,需要直截了当的触及编程的实质,在此我们
分析
定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析
一下 Nios II中
的 Uart原始实现并进一步讨论 Nios II的设备体系结构。
1 UART外设寄存器控制基础
1.1 系统块图
首先我们来看看 uart core,uart core是一个 avalone总线的 slave设备,在 Sopc Builder
中是一个组件,用户可以非常方便的集成到系统中来。Uart core的结构如下图(uart_1):
看了这个图我们就有底了,这不和 51、avr中一样半斤八两嘛。
1.2 寄存器结构
如下图所示,正如下面提示的,有些寄存器不一定存在,是在 Sopc Builder中
可编程控制的。
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 2 -
1.3 寄存器读写
这些寄存器在 Nios II 程序中可以通过多种方法去读写(‘回’有两种写法J)
1.3.1 通过 IORD,IOWR两个宏去读写:
IORD(UART_0_BASE, 0x00);
1.3.2 通过包含 altera_avalon_uart_regs.h,然后通过下面的宏读写
IORD_ALTERA_AVALON_UART_RXDATA(UART_0_BASE);
注意不要用指针直接读写,因为在 CPU 带数据缓冲的情况下不一定能立即
得到更新并使控制有效。
1.4 寄存器位说明
有了以上的基础材料和读写控制手段,相信大部分人可以把我这个拐杖扔了J,
不要怕我罗嗦,还是把各个重要的寄存器控制位罗列一下吧:
1.4.1 rxdata、txdata:数据收发寄存器。
1.4.2 status:状态寄存器
PE(BIT0):1奇偶校验错误。写 0清除。
FE(BIT1):1数据帧错误,写 0清除。
BRK(BIT2):1
检测
工程第三方检测合同工程防雷检测合同植筋拉拔检测方案传感器技术课后答案检测机构通用要求培训
到 RXD线 0超过了一个字符的时间。写 0清除。
ROE(BIT3):1读覆盖错误。
TOE(BIT4):1写覆盖错误
TMT(BIT5):1发送移位寄存器空闲,0正在发送
TRDY(BIT6):1发送完成
RRDY(BIT7):1接收完成
E(BIT8):TOE, ROE, BRK, FE和PE位的逻辑或
DCTS(BIT10):CTS信号改变。
CTS(BIT11):CTS信号状态
EOP(BIT12):接收或发送end of packet字符。End of packet字符存放在
endofpacket寄存器。
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 3 -
1.4.3 控制寄存器。
0 IPE RW 使能校验错中断.
1 IFE RW 使能数据帧错误中断.
2 IBRK RW 使能暂停中断.
3 IROE RW 使能接收覆盖中断.
4 ITOE RW 使能发送覆盖中断.
5 ITMT RW 使能传输空闲中断
6 ITRDY RW 使能传输准备好中断.
7 IRRDY RW 使能接收准备好中断.
8 IE RW 使能所有例外中断.
9 TRBK RW 发送暂停(TXD输出信号到0)
10 IDCTS RW 使能CTS信号中断
11 RTS RW 发送RTS信号,当RTS位1, 逻辑低电平 (0)驱动到RTS_N输出(硬件
流量控制中使用)
12 IEOP RW 使能EOP中断。
1.4.4 波特率寄存器:
计算方法如下
divisor=int((clock frequency)/(baud rate)+0.5)
baud rate=(clock frequency)/(divisor+1)
1.4.5 endofpacket 寄存器:
存放endofpacket字符。
通过以上资料,我们了解了Nios II UART core的底层全貌,字符发送和接收的原理并
不复杂,但要处理好发送、接收、错误处理、传输校验(CRC等)、流量控制也不是一件容
易的事情。有很多基于字符的
协议
离婚协议模板下载合伙人协议 下载渠道分销协议免费下载敬业协议下载授课协议下载
可以参考(比如xmoden,有关Xmoden的完整的协议请参
考其它相关的资料)。
2 UART原始编程概要
在上一节中我们了解了UART core外设的硬件寄存器和控制位,同时也提供了NIOS
II 中编程控制的宏语句,有了上述资料编写 Uart 程序又成了老生常谈的事了,因为大
家在 51、avr、ARM和 DSP的 UART编程实现中已经做过 n遍了,在这里只提一下大
致过程,为我们下面的分析服务。
2.1 计算并设置波特率寄存器
divisor=int((50000000)/(9600)+0.5)
IOWR_ALTERA_AVALON_UART_DIVISOR(UART_0_BASE, divisor);
2.2 设置控制寄存器
control= ALTERA_AVALON_UART_CONTROL_TRDY_MSK |
ALTERA_AVALON_UART_CONTROL_RRDY_MSK |
ALTERA_AVALON_UART_CONTROL_E_MSK;
IOWR_ALTERA_AVALON_UART_CONTROL(UART_0_BASE, control);
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 4 -
2.3 编写中断处理程序
这里只给出一个中断处理程序框架。在 UART 通讯应用中,关键要处理好中
断处理程序和后台主程序(或其他任务)之间的信息交互体系。
void uart_irq(void *context,alt_u32 interrupt)
{
int iRet;
unsigned short int data,status;
/* 读取状态寄存值 */
status = IORD_ALTERA_AVALON_UART_STATUS(UART_0_BASE);
/* 错误处理 */
……
/* 读取数据入缓冲区 */
data =IORD_ALTERA_AVALON_UART_RXDATA(UART_0_BASE);
……
/* 清除状态寄存器相关位 */
IOWR_ALTERA_AVALON_UART_STATUS(UART_0_BASE, 0)
}
2.4 在主程序里面注册中断处理程序
/* 注册中断处理函数 */
if (alt_irq_register(UART_0_IRQ, NULL, uart_irq))
{
printf("alt_irq_register uart_irq error\n");
return -1;
}
以上关于 UART编程的实现过程不复杂,实现一个简单的 UART中断处理程序你应该信心
满怀了J。好事成双,我们还有一个更靓的对象要仔细看看,那就是 Nios II 是如何实现
UART的处理过程的,有没有我们学习的手法呀,let’s go!!
3 UART在 NIOS II实现(兼论设备体系)
有个朋友在网上留了贴:开始以为搞定 232 就能搞定 485,至少在以前做
51/ARM/DSP 时是这样的,但是在 NIOSII 里却完全不是这样的,所有的说明文挡和开
发板里附带的例子都是用的 printf/scanf 或当文件系统打开串口,相对简单的寄存器访
问方式却很少有人问津。
通过前面的分析我们已经能够满足这位朋友关于简单的寄存器访问方式的需求了,
我们再来看看 Nios II中 UART设备是如何进入 HAL体系的呢?
Uart在 NIOS II中是一个字符模式设备,它可以通过以下方式被方便的使用而不
必详细了解和直接使用寄存器控制。
Example: Writing Characters to a UART
#include
#include
int main (void)
{
char* msg = “hello world”;
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 5 -
FILE* fp;
fp = fopen (“/dev/uart1”, “w”);
if (fp)
{
fprintf(fp, “%s”,msg);
fclose (fp);
}
return 0;
}
上述程序是一个ANSI 风格的C程序,把UART外设作为一个文件打开并使用,典型的
UNIX系统的设备模式J。从前面的寄存器控制到这里的程序似乎有很大的跨度,这一
切是如何实现的呢?
下面的分析涉及到比较深入的程序细节,比较烦琐,需要扎实的C语言基础,还需
要耐心,供需要对Nios II做透彻分析的人士参考。
3.1 设备初始化过程
设备的初始化包括设备存储空间的分配和HAL设备的初始化,这个过程中一定会做
我们在第二部分《原始编程概要》里讲的内容,有了这样的认识,我们就有了分析的
基础,也能找到对号入座的地方了。设备初始化程序主要是由Nios II IDE系统在编译
系统的时候自动生成的,每个工程的sys库中都有生成文件:
system.h,alt_sys_init.c。这两个文件是Nios II IDE根据Sopc Builder生成的PTF文
件生成。
我们的分析工作就从alt_sys_init.c开始,这个程序中注明:DO NOT MODIFY THIS
FILE。这个文件主要包括两部分前一部分注明:Allocate the device storage。后
一部分注明:Initialise the devices。
UART的驱动程序在altera_avalon_uart目录中。
3.1.1 设备存储空间分配
在alt_sys_init.c中分配UART设备的是一条宏语句。
ALTERA_AVALON_UART_INSTANCE( UART_0, uart_0 );
这个宏详细定义在Sopc builder component de 的
altera_avalon_uart/HAL/inc/altera_avalon_uart.h中。
注意:Altera HAL有两中类型的驱动设备,small和fast类型。small类
设备驱动比较简化。你可以通过sys_lib属性的system_library表单中点
Reduced device driver选项来选用小模式的驱动程序。
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 6 -
上述操作会在generated_all.mk中增加-DALT_USE_SMALL_DRIVERS(用图形
化方式修改Makefile文件)。
下面是常规FAST类型的定义,比small复杂。
#define ALTERA_AVALON_UART_INSTANCE(name, dev) \
static alt_avalon_uart_dev dev = \
{ \
{ \
ALT_LLIST_ENTRY, \
name##_NAME, \
NULL, /* open */ \
NULL, /* close */ \
alt_avalon_uart_read, \
alt_avalon_uart_write, \
NULL, /* lseek */ \
NULL, /* fstat */ \
ALTERA_AVALON_UART_IOCTL, \
}, \
(void*) name##_BASE, \
0, \
0, \
0, \
0, \
0, \
ALTERA_AVALON_UART_TERMIOS(name##_STOP_BITS, \
(name##_PARITY == 'N'), \
(name##_PARITY == 'O'), \
name##_DATA_BITS, \
name##_USE_CTS_RTS, \
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 7 -
name##_BAUD) \
ALTERA_AVALON_UART_FREQ(name) \
(name##_FIXED_BAUD ? ALT_AVALON_UART_FB : 0) | \
(name##_USE_CTS_RTS ? ALT_AVALON_UART_FC : 0) \
}
在这个宏定义中其实是定义了一个static alt_avalon_uart_dev
uart_0的静态结构。要理解这个结构首先需要了解alt_avalon_uart_dev
结构以及相关结构的定义,然后把里面相关的宏定义替换成真实的名称符号就
可以理解了。注意:name##_NAME这是C语言宏定义的技巧,在这里替换的结
果是:UART_0_NAME(这是system.h中定义的设备名称),其他的依次类推。
3.1.1.1.1 相关结构
l alt_avalon_uart_dev
typedef struct
{
alt_dev dev; /* The device callback structure */
void* base;/* The base address of the device */
alt_u32 ctrl;/* Shadow value control register */
alt_u32 rx_start; /* Start of pending receive data */
volatile alt_u32 rx_end; /* End of the pending receive data */
volatile alt_u32 tx_start; /* Start of the pending transmit data */
alt_u32 tx_end; /* End of the pending transmit data */
#ifdef ALTERA_AVALON_UART_USE_IOCTL
struct termios termios; /* Current device configuration */
alt_u32 freq; /* Current baud rate */
#endif
alt_u32 flags; /* Configuation flags */
ALT_FLAG_GRP (events) /* Event flags used for
foreground/background in mult-threaded mode */
ALT_SEM (read_lock) /* Semaphore used to control access to the
read buffer in multi-threaded mode */
ALT_SEM (write_lock) /* Semaphore used to control access to the
write buffer in multi-threaded mode */
alt_u8 rx_buf[ALT_AVALON_UART_BUF_LEN]; /* The receive buffer */
alt_u8 tx_buf[ALT_AVALON_UART_BUF_LEN]; /* The transmit buffer
*/
} alt_avalon_uart_dev;
仔细观察上述结构我们可以了解很多信息,首先是一个alt_dev的结构,
这个结构是构成设备体系的核心,不同类型NIOS II HAL的设备结构后面的部分可以不同,
但前面两个成员是固定的,alt_dev具体内容在后面讨论,base是外设地址,就是外设地址。
设备读写缓冲区和相关的读写控制信号量都在结构中定义了,我们可以臆测到大致的处理手
法了。
l alt_dev结构
struct alt_dev_s {
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 8 -
alt_llist llist; /* for internal use */
const char* name;
int (*open) (alt_fd* fd, const char* name, int flags, int mode);
int (*close) (alt_fd* fd);
int (*read) (alt_fd* fd, char* ptr, int len);
int (*write) (alt_fd* fd, const char* ptr, int len);
int (*lseek) (alt_fd* fd, int ptr, int dir);
int (*fstat) (alt_fd* fd, struct stat* buf);
int (*ioctl) (alt_fd* fd, int req, void* arg);
};
这个结构是定义了设备的回调函数,供C
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
库使用。
在前面的定义中定义了读写函数以及alt_avalon_uart_ioctl函数。
3.1.2 设备初始化
经过一小节冗长烦琐的介绍,我们知道在系统生成的alt_sys_init.c中
已经定义了一个uart_0的静态alt_avalon_uart_dev类型的结构。在
alt_sys_init.c中还有一个alt_sys_init的函数,这个函数在Nios II
HAL体系中会在main函数前执行。里面其中一条就是:
ALTERA_AVALON_UART_INIT( UART_0, uart_0 );
这是一个宏,同样定义在altera_avalon_uart.h中,我们看看:
#define ALTERA_AVALON_UART_INIT(name, dev) \
if (name##_IRQ == ALT_IRQ_NOT_CONNECTED) \
{ \
ALT_LINK_ERROR ("Error: Interrupt not connected for " #dev ". " \
"You have selected the interrupt driven version of " \
"the ALTERA Avalon UART driver, but the interrupt is " \
"not connected for this device. You can select a " \
"polled mode driver by checking the 'small driver' " \
"option in the HAL configuration window, or by " \
"using the -DALTERA_AVALON_UART_SMALL preprocessor " \
"flag."); \
} \
else \
{ \
alt_avalon_uart_init (&dev, (void*) name##_BASE, name##_IRQ); \
}
宏定义最终执行alt_avalon_uart_init函数,注意前面定义的uart_0结构在
第一参数中被使用了,后面两个参数UART_0_BASE、UART_0_IRQ分别就是system.h
中定义的外设地址和中断向量了。
OK,我们继续深入分析alt_Avalon_uart_init函数。这个函数在
altera_avalon_uart.c中,注意这个文件中的函数也被分成两个类型small和
fast类型,注意区分,我们看fast类型的。(为了节省篇幅,同时也便于理解我
就把注解直接放在下面的.c中了,见谅)。
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 9 -
void alt_avalon_uart_init (alt_avalon_uart_dev* dev, void* base, alt_u32 irq)
{
int error;
/*生成多任务环境下的互斥信号量 */
error = ALT_FLAG_CREATE (&dev->events, 0) ||
ALT_SEM_CREATE (&dev->read_lock, 1) ||
ALT_SEM_CREATE (&dev->write_lock, 1);
if (!error)
{
/* 设置设备结构中的控制变量 */
dev->ctrl = ALTERA_AVALON_UART_CONTROL_RTS_MSK |
ALTERA_AVALON_UART_CONTROL_RRDY_MSK |
ALTERA_AVALON_UART_CONTROL_DCTS_MSK;
/* 写入到设备寄存器中 */
IOWR_ALTERA_AVALON_UART_CONTROL(base, dev->ctrl);
/* 注册中断处理程序 */
if (alt_irq_register (irq, dev, alt_avalon_uart_irq) >= 0)
{
/* make the device available to the system */
/* 设备注册 */
alt_dev_reg (&dev->dev);
}
}
}
看到这里我们是否有似曾相识的感觉啊,这就是我们在第二部分《原始编程
概要》中讲述的内容嘛。在程序中我们也可以看出有三中情况可以触发中断。其
中一种就是RRDY数据接收就绪。
在NIOS II HAL设备体系中,分不同的几类设备类型,UART属于字符类设备。
在alt_avalon_uart_init函数的最后把设备注册到字符设备的双向链表中去,注意参
数是alt_dev结构指针。
学习就是要肯钻研,通过前面的分析,我们七窍已经通了六窍了,让我们继
续钻下去看看alt_dev_reg做了什么,否则还有一窍不通啊。
int alt_dev_reg (alt_dev* dev)
{
/*
* check that the device has a name.
*/
/* 前面的宏定义中我们可以看出这个名字是UART_0_NAME 在system.h中
有具体的定义 */
if (!dev->name)
杭州自由电子 http://www.freefpga.com
作者:柳军胜 - 10 -
{
return -EINVAL;
}
/*
* register the device.
*/
/* 加入设备链表 */
alt_llist_insert(&alt_dev_list, &dev->llist);
return 0;
}
注意程序里alt_dev_list是alt_dev.c中定义的一个alt_llist_s类型的全
局结构变量,至此我们的跟斗算是翻到五指山了,留下到此一游吧:)。
struct alt_llist_s {
alt_llist* next; /* Pointer to the next element in the list. */
alt_llist* previous;/* Pointer to the previous element in the list */
};
通过以上分析,我们比较清楚的展示了UART设备的初始化过程。还有很多未尽之
处啊,比如alt_avalon_uart_irq是如何处理数据的等等,我想有以上资料的认识,
你完全可以继续分析下去。
3.2 设备使用实际调用过程
未完待续