1 硬件部分
1.1 Avalon-MM接口(读作:阿窝龙妹妹接口)
Avalon Memory-Mapped接口,简称为 Avalon-MM接口,用于在存储映射系统中描述主从元件(component)的读/写接口。
图1.1 Amy_S_lcd12864 IP与System Interconnect Fabric的连线框图
图1.2 某带有Amy_S_lcd12864 IP的Avalon系统框图
1.2 从设备读写时序
请参考手册《Avalon Interface Specification》,此处略去。
1.3 HDL模块及说明
1.3.1 模块介绍
表1.1 Amy_S_lcd12864 IP的HDL源代码模块介绍
文件名称 | 功能描述 |
Amy_S_lcd12864_avalon_interface.v | Amy_S_lcd12864 Avalon接口文件 |
1.3.2 源代码
注:本文所涉及verilog代码,是按照Verilog 2001规范编写的。Avalon信号类型命名参考图1.3。
图1.3 Naming Convention for Avalon Signal Type
1.3.2.1 Amy_S_lcd12864_avalon_interface.v
ST7920的E、RW和RS都是单向的,而DATA总线是双向的;故在此处nios既需要写数据给ST7920,又需要从ST7920读数据。
从42行到68行,即nios向ST7920写数据。注意,谁给nios写数据呢?请看图1.4。
图1.4 NII、nios cpu和ST7920通信框图
从70行到90行,是nios从ST7920读数据。由于只有DATA总线需要读,其他的管脚就不写了,呵呵。
从93行到108行,是对DATA双向总线的处理。读或写只是简单由Avalon的读、写信号来控制的。这个技巧是我从open-cores里面的基于wishbone总线的IIC从设备的IP上学到的。注意:ST7920是低速设备,此处只做简单处理;高速设备请大家自行斟酌。
还有一点需要说明,chipselect在Nios II 9.0之后就不是必须的信号,此处加上,只为和以前的版本兼容。
2 软件部分
表2.1 Amy_S_lcd12864 IP的C源代码模块介绍
文件名称 | 功能描述 |
Amy_S_lcd12864.h | Amy_S_lcd12864 的C头文件 |
Amy_S_lcd12864.c | Amy_S_lcd12864 的C源文件 |
2.1 C头文件
2.1.1 Amy_S_lcd12864.h
/*-----版权声明-----
* 艾米电子工作室——让开发变得更简单
* QQ(邮箱):amy-studio@qq.com
*-----文件信息-----
* 文件名称:Amy_S_lcd12864.h
* 最后修改日期:3.20, 2009
* 描述:Lcd12864驱动宏文件
*------------------
* 创建者:张亚峰
* 创建日期:3.20, 2009
* 版本:1.0
* 描述:原始版本
*------------------
* 修改者:
* 修改日期:
* 版本:
* 描述:
*-------------------
*/
#ifndef __Amy_S_LCD12864_H__
#define __Amy_S_LCD12864_H__
//++++++++++++++++++++++++++++++++++++++
// 基地址 开始
// 根据SOPC Builder设置编写
//++++++++++++++++++++++++++++++++++++++
#include "system.h"
#define lcd12864_addr LCD12864_BASE
//--------------------------------------
// 基地址 开始
//--------------------------------------
//++++++++++++++++++++++++++++++++++++++
// 寄存器映射 开始
// 根据HDL编写
//++++++++++++++++++++++++++++++++++++++
#include
#define IOWR_LCD12864_E(base, data) IOWR(base, 0, data)
#define IOWR_LCD12864_RW(base, data) IOWR(base, 1, data)
#define IOWR_LCD12864_RS(base, data) IOWR(base, 2, data)
#define IOWR_LCD12864_DATA(base, data) IOWR(base, 3, data)
#define IORD_LCD12864_DATA(base) IORD(base, 3)
//--------------------------------------
// 寄存器映射 结束
//--------------------------------------
//++++++++++++++++++++++++++++++++++++++
// 管脚操作 开始
//++++++++++++++++++++++++++++++++++++++
#define SET_E IOWR_LCD12864_E(lcd12864_addr, 1)
#define CLR_E IOWR_LCD12864_E(lcd12864_addr, 0)
#define SET_RW IOWR_LCD12864_RW(lcd12864_addr, 1)
#define CLR_RW IOWR_LCD12864_RW(lcd12864_addr, 0)
#define SET_RS IOWR_LCD12864_RS(lcd12864_addr, 1)
#define CLR_RS IOWR_LCD12864_RS(lcd12864_addr, 0)
#define WR_DATA(data) IOWR_LCD12864_DATA(lcd12864_addr, data)
#define RD_DATA IORD_LCD12864_DATA(lcd12864_addr)
//--------------------------------------
// 管脚操作 结束
//--------------------------------------
//++++++++++++++++++++++++++++++++++++++
// 函数声明 开始
//++++++++++++++++++++++++++++++++++++++
extern
void
LCD12864_CheckBusy(
void
);
extern
void
Lcd12864_WrCmd(alt_u8 cmd);
extern
void
Lcd12864_WrData(alt_u8 data);
extern
void
Lcd12864_Init(
void
);
extern
void
Lcd12864_WrChar(alt_u8 row, alt_u8 col, alt_u8 *pCN, alt_u8 n);
//--------------------------------------
// 函数声明 结束
//--------------------------------------
#endif /* __Amy_S_LCD12864_H__ */
2.1.2 一些说明
最后面的那个</io.h>是发布博客的时候带出来的,不属于头文件。
从28行到37行,是根据SOPC Builder设置编写的lcd12864的基地址,需要system.h的支持。注:system.h就是和SOPC Builder设置一一对应的;当在NII中建立工程时,system.h就根据sopcinfo(Nios II 9.1 Software Build Tools for Eclipse使用,不是Nios II 9.1 IDE)文件自动生产。
第40行到第53行,是自己编写的一些宏,这个叫Register Map(寄存器映射),以前都是单独放在一个头文件里(如xxx_regs.h)。由于NII 9.1貌似不支持HAL的自动初始化(我研究的结果是不行,不知道Altera公司有没有相关的变动声明),因此就没有向8.1那样书写HAL。注意,0、1~3是OFFSET(偏移地址),请参考HDL代码编写。
从56行到69行,是一些管脚操作的宏,这样写,主要是方便移植。大家也可以不写寄存器映射,直接写管脚操作的宏也行,注意替换哟。
实际上大家也可以使用ARM方式的寄存器访问方式,譬如
1
|
#define CS *(volatile unsigned *) CS_BASE // 片选信号 --低有效 |
这种貌似更好操作。由于我没有深入研究这种寄存器访问方式,这里就不多说了。
下面的几行和各种MCU大同小异。
2.2 C源文件
2.2.1 Amy_S_lcd12864.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
/*-----版权声明----- * 艾米电子工作室——让开发变得更简单 * QQ(邮箱):amy-studio@qq.com *-----文件信息----- * 文件名称:Amy_S_lcd12864.c * 最后修改日期:3.20, 2009 * 描述:Lcd12864驱动源文件 *------------------ * 创建者:张亚峰 * 创建日期:3.20, 2009 * 版本:1.0 * 描述:原始版本 *------------------ * 修改者: * 修改日期: * 版本: * 描述: *------------------- */ #include "Amy_S_lcd12864.h" #include "alt_types.h" #include "unistd.h" void LCD12864_CheckBusy( void ) { CLR_RS; // 指令 SET_RW; // 读 SET_E; while ((RD_DATA&0x80) == 0x80); // 检测busy flag CLR_E; usleep(72); // 72us } void Lcd12864_WrCmd(alt_u8 cmd) { LCD12864_CheckBusy(); CLR_RS; // 指令 CLR_RW; // 写 SET_E; WR_DATA(cmd); CLR_E; usleep(72); // 72us } void Lcd12864_WrData(alt_u8 data) { LCD12864_CheckBusy(); SET_RS; // 数据 CLR_RW; // 写 SET_E; WR_DATA(data); CLR_E; usleep(72); // 72us } void Lcd12864_Init( void ) { usleep(40*1000); Lcd12864_WrCmd(0x30); // 8bit usleep(100); Lcd12864_WrCmd(0x30); // basic function usleep(37); Lcd12864_WrCmd(0x0F); // 整体显示开 游标开 反白 usleep(100); Lcd12864_WrCmd(0x10); // 游标左移 usleep(100); Lcd12864_WrCmd(0x01); usleep(10*1000); Lcd12864_WrCmd(0x06); // 画面整体右移 } void Lcd12864_WrChar(alt_u8 row, alt_u8 col, alt_u8 *pCN, alt_u8 n) { alt_u8 i, addr; row &= 0x03; // row < 4 col &= 0x07; // col < 8 switch (row) { case 0: addr = 0x80; break ; case 1: addr = 0x90; break ; case 2: addr = 0x88; break ; case 3: addr = 0x98; break ; } addr += col; Lcd12864_WrCmd(addr); for (i=0; i<2*n; i++) { Lcd12864_WrData(pCN[i]); // 写字符数据 } } |
2.2.2 一些说明
呵呵,这个就不说明了,大家自己看。
3 使用举例
注意:9.1环境。
3.1 在SOPC Builder中添加组件
从File-New Component..打开Component Editor,单击HDL Files标签,添加所编写的HDL文件。如图3.1所示。
图3.1 添加HDL文件
由于所编写的HDL完全是按照规范的,因此直接单击Component Wizard即可,编写IP信息,如图3.2所示。
图3.2 编写IP信息
单击Finish,IP添加成功,如图3.3所示。
图3.4 添加成功后的IP
3.2 在SOPC Builder中例化
这个就不多说了,直接上图,请看图3.5。
图3.5 例化后的IP 1
注意lcd12864是随便起的名字哟,只要不叫IP的名字(Ams_S_lcd12864)就行。
图3.6 例化后的IP 2
3.3 在Nios II中的使用范例
先将Amy_S_lcd12864.h和Amy_S_lcd12864.c拷贝到软件工程内。
3.3.1 使用范例main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
/*-----版权声明----- * 艾米电子工作室——让开发变得更简单 * QQ(邮箱):amy-studio@qq.com *-----文件信息----- * 文件名称:main.c * 最后修改日期:3.20, 2009 * 描述:Lcd12864测试文件 *------------------ * 创建者:张亚峰 * 创建日期:3.20, 2009 * 版本:1.0 * 描述:原始版本 *------------------ * 修改者: * 修改日期: * 版本: * 描述: *------------------- */ #include // strlen() #include "Amy_S_lcd12864.h" // 根据SOPC Builder的设置,修改该头文件中的Lcd12864基地址 int main() { Lcd12864_Init(); // 初始化Lcd12864 Lcd12864_WrChar(0, 0, "这不是单片机吗?" , strlen ( "这不是单片机吗?" )>>1); Lcd12864_WrChar(1, 0, "这就是单片机呀。" , strlen ( "这就是单片机呀。" )>>1); Lcd12864_WrChar(2, 0, "艾米电子出品。" , strlen ( "艾米电子出品。" )>>1); Lcd12864_WrChar(2, 0, "艾米电子出品。" , strlen ( "艾米电子出品。" )>>1); Lcd12864_WrChar(3, 0, "Amy-studio Pub." , strlen ( "Amy-studio Pub." )>>1); return 0; } |
3.3.2 一些说明
最后面的那个</string.h>是发布博客的时候带出来的,不属于头文件。
3.4 使用效果
图3.7 Amy_S_lcd12864 IP使用效果
4 参考资料
1.李兰英等.Nios II嵌入式软核SOPC设计原理及应用.北京航空航天大学出版社.2006
2.周立功等.SOPC嵌入式系统实验教程(一).北京航空航天大学出版社.2006
3.蔡伟刚.Nios II软件架构解析.西安电子科技大学出版社.2007
4.Altera Handbook.Quartus II Handbook Volume4: SOPC Builder.2009
5.Altera Handbook.Avalon Interface Specifications.2009
6.Altera Handbook.HAL API Reference.2009
7.Altera Website.Avalon Component Interfaces Supported in the Component Editor Version 7.2 and Later