NIOS II 相关资料以及基础入门

《NiosII的奇幻漂流》

《Nios II那些事儿》

本文所有的硬件基础以及工程参考来自魏坤示波仪,重新实现驱动并重构工程。

基于NIOS II的示波器实现

Version 0.1 按键驱动&显示屏驱动&界面实现

Part 0.1.0 硬件准备





由于屏幕会挡住烧录口,这里飞线以供调试。

Part 0.1.1 创建Quartus工程

  • 软核部分:利用SOPC Builder建立kernel,软核具体配置如下

    • 由于显示芯片利用的ILI9481,这里利用LCD前缀字样PIO口与LCD芯片通信,利用、PWM_LED控制LCD的亮度
    • 利用KEY_PORT读取按键的输入

    这里待补全各组件参数设置

  • 顶层图

    其中SYS_PLL输出S0 S1均为100MHZ的时钟信号

    pwm_controller则通过计数器控制屏幕的亮度,代码如下

    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_unsigned.all; entity pwm_controller is
    port(
    clk:in std_logic;
    pwm_led_in:in std_logic_vector(13 downto 0);
    pwm_led_out:out std_logic
    );
    end pwm_controller; architecture pwm_arch of pwm_controller is signal counter:std_logic_vector(13 downto 0); begin
    process(clk)
    begin
    if(clk'event and clk = '1') then
    if(counter >= pwm_led_in) then
    pwm_led_out<= '0';
    else
    pwm_led_out<= '1';
    end if;
    counter <= counter + 1;
    end if;
    end process;
    end pwm_arch;

Part 0.1.2 软件设计

一些基本工具以及按键、显示器驱动实现
显示器驱动
  • LCD显示屏初始化

    void LCD_init() {
    //************* Reset LCD Driver ****************//
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_RESET_BASE, 1);
    delay_ms(200);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_RESET_BASE, 0);
    delay_ms(200);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_RESET_BASE, 1);
    delay_ms(10);
    //************* Start Initial Sequence **********//
    //剩余参数配置见源代码,这里不予展示
    }

    LCD初始化可以直接利用芯片厂商提供的代码,或者参考芯片资料中的参数配置自行完成。

  • LCD显示驱动

    查阅ILI9481芯片手册,可以将发送一次指令和内容打包成Indexcmd两个函数。

    这两个函数内容如下:

    void LCD_ILI9481_INDEX(unsigned int data) {
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 1);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
    }
    void LCD_ILI9481_CMD(unsigned int data) {
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 0);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
    }

    发送一个指令的流程为先利用cmd函数发送指令,再用INDEX函数发送指令内容。

    再将LCD显示一个像素的图像打包为set_addrsend_data两个步骤,先通过set_addr发送像素地址,再用send_data发送像素颜色信息。

    send_addr的时序可以通过查阅芯片手册来得知,其代码如下:

    void set_addr(unsigned int x, unsigned int y){
    LCD_ILI9481_CMD(0x002b);
    LCD_ILI9481_INDEX(x >> 8);
    LCD_ILI9481_INDEX(x & 0x00ff);
    LCD_ILI9481_INDEX(0x0001);
    LCD_ILI9481_INDEX(0x00df); LCD_ILI9481_CMD(0x002a);
    LCD_ILI9481_INDEX(y >> 8);
    LCD_ILI9481_INDEX(y & 0x00ff);
    LCD_ILI9481_INDEX(0x0001);
    LCD_ILI9481_INDEX(0x003f); LCD_ILI9481_CMD(0x002c);
    }

    同样,可以写出send_data如下:

    void send_data(unsigned int data) {
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_RS_BASE, 1);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 0);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_DATA_BASE, data);
    IOWR_ALTERA_AVALON_PIO_DATA(LCD_WR_BASE, 1);
    }
  • LCD显示工具

    ascii码显示工具(中文显示工具原理相同),利用lcd_buffer传参数,字母数据保存在word_libc

      void display_ascii(unsigned int x, unsigned int y, unsigned int w_color,
    unsigned int b_color) {
    unsigned int i, j, k = 0;
    unsigned char str;
    unsigned int OffSet, z; while (1) {
    if (lcd_buffer[k] == 0) {
    set_addr(0, 0);
    return;
    }
    z = lcd_buffer[k];
    //每个字符在wordlib中用11
    OffSet = z * 11;
    //显示一个字符 该字符的像素大小为
    for (i = 0; i < 11; i++) {
    //读取字符表示中的一个字符的一行
    str = word_lib[OffSet + i];
    for (j = 0; j < 8; j++) {
    //设置显示像素点的相对左边
    set_addr(x + j, y - i);
    //如果是要显示的话,就显示前景颜色
    if (str & 0x80) {
    send_data(w_color);
    } else {
    //如果是不显示的话,显示背景颜色
    send_data(b_color);
    }
    str <<= 1;
    }
    }
    x += 8;
    k++;
    }
    }

    通过如下方式利用该工具

      sprintf((char *)lcd_buffer, "CH1 Freq:");
    display_ascii(8, 55, 0x0000, MENU_FULL_COLOR);

    图片显示则利用如上所诉的set_addrsend_data完成,欢迎界面显示函数如下

    (图像利用工具转换后放在welcome数组之中)

      void display_Welcome() {
    unsigned int i, j, data;
    unsigned long k = 0;
    //设置初始位置
    set_addr(0, 0);
    //显示欢迎页,先输出一列再输出一行
    for (i = 0; i < 480; i++) {
    for (j = 0; j < 320; j++) {
    data = welcome[k++];
    data = data + (welcome[k++] << 8);
    send_data(data);
    }
    }
    }

    其余显示函数原理如上,不再赘述。

中断处理
  • 时钟中断在此版本中暂时用于处理背光,中断的申请与定义可见各NIOS教程,处理函数如下

    void timer(void* context) {
    IOWR_ALTERA_AVALON_TIMER_STATUS(TIMER_BASE, 0);
    IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_BASE, 0x0b); //控制LCD的背光灯
    if (LED_PWM_DATA <= 130) {
    LED_PWM_DATA += 1;
    IOWR_ALTERA_AVALON_PIO_DATA(PWM_LED_BASE, LED_PWM_DATA);
    }
    IOWR_ALTERA_AVALON_TIMER_CONTROL(TIMER_BASE, 0x07);
    }
  • 按键中断则是SPI总线来读取按键值

    void KeyListener(void* context) {
    KEY_IS_DOWN = !KEY_IS_DOWN;
    unsigned char i = 0;
    for (i = 0; i < 8; i++) {
    send_KEY(((0xfeff << i) >> 8) & 0xff);
    if (IORD_ALTERA_AVALON_PIO_DATA(KEY_PORT_BASE) != 0x03) {
    if (IORD_ALTERA_AVALON_PIO_DATA(KEY_PORT_BASE) == 1) {
    switch (i) {
    case 0:
    KEY_DATA = 8;
    break;
    //...
    //见源代码 省去
    }
    } else if (IORD_ALTERA_AVALON_PIO_DATA(KEY_PORT_BASE) == 2) {
    switch (i) {
    case 0:
    KEY_DATA = 0;
    break;
    //...
    //见源代码 省去
    }
    }
    break;
    }
    }
    send_KEY(0x00);
    if(KEY_IS_DOWN == 0){
    sprintf(lcd_buffer,"keytest");
    display_ascii(417,95,0x0000,0xEF78);
    sprintf(lcd_buffer,"%2d",KEY_DATA);
    display_ascii(417,80,0x0000,0xEF78);
    }
    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(KEY_PORT_BASE, 0x0000);
    }

    SPI总线的驱动send_key见下

    void send_KEY(unsigned char data) {
    unsigned char u;
    IOWR_ALTERA_AVALON_PIO_DATA(SPI_LE_K_BASE, 0);
    //串行发送j的数据,通过移位发送j的数据
    for (u = 0; u < 8; u++) {
    if (data & 0x80) {
    IOWR_ALTERA_AVALON_PIO_DATA(SPI_DATA_BASE, 1);
    } else {
    IOWR_ALTERA_AVALON_PIO_DATA(SPI_DATA_BASE, 0);
    } IOWR_ALTERA_AVALON_PIO_DATA(SPI_CLK_BASE, 1); IOWR_ALTERA_AVALON_PIO_DATA(SPI_CLK_BASE, 0); data <<= 1;
    //左移发送信号
    }
    IOWR_ALTERA_AVALON_PIO_DATA(SPI_LE_K_BASE, 1);
    }
工具类

工具类主要提供了delay如下

void delay_ms(unsigned int i) {
unsigned int j, k;
for (j = 0; j < i; j++)
for (k = 0; k < 1000; k++);
}
void delay_us(unsigned int i) {
unsigned int j;
for (j = 0; j < i; j++);
}
按照示波器运行流程的代码描述
  • 主函数


    #include <stdio.h> #include "../inc/init.h" int main() {
    printf("OSC SYSTEM INIT!\n");
    SYSTEM_init(); //初始化系统,显示载入界面
    printf("SYSTEM INIT FINISHED!\n"); printf("INTERFACE INIT!\n");
    INTERFACE_init(); //初始化界面,显示示波器主界面
    printf("INTERFACE INIT FINISHED"); while (1) {
    //主循环,处理中断,更新界面
    }
    return 0;
    }

    主函数放在..\main\main.c下,主要是用于初始化系统,初始化界面,运行时维护界面。

  • 初始化系统,显示载入画面

    void SYSTEM_init() {
    LCD_init(); //初始化显示屏
    display_Welcome(); //显示欢迎界面
    //初始化中断服务
    alt_irq_init(ALT_IRQ_BASE);
    KEY_init(); //初始化按键中断
    TIMER_init(); //初始化按键中断
    //初始化AD模块 (未完成)
    delay_ms(5000);
    }
  • 初始化界面,显示示波器主界面

    void INTERFACE_init() {
    display_background(); //显示主界面背景
    display_area(); //显示波形显示区域
    display_menu();
    display_rightbox();
    display_parabar();
    display_toolbar();
    }

    利用上述显示驱动,将界面显示出来。

Part 0.1.F V0.1版本示意

视频演示:http://v.youku.com/v_show/id_XMTgxMjg1ODYzNg==.html

遇到问题解决方案

  • 无法烧录,提示system_ID有问题

    遇到这个情况是由于BSP改位置或者BSP没有更新,所以在BSP工程下右键NIOS II子菜单下BSP Editor更改BSP位置,最后Generate BSP即可解决。

基于NIOS-II的示波器:PART1 按键&显示屏驱动&界面的更多相关文章

  1. 【推荐图书】+ 基于Nios II的嵌入式SoPC系统设计与Verilog开发实例+C#入门经典等

    [推荐图书]+ 基于Nios II的嵌入式SoPC系统设计与Verilog开发实例+C#入门经典等 3赞 发表于 2016/7/4 21:14:12 阅读(1921) 评论(3) 初次接触FPGA,到 ...

  2. 基于NIOS II的双端口CAN通信回环测试

    基于NIOS II的双端口CAN通信回环测试 小梅哥编写,未经授权,严禁用于任何商业用途 说明:本稿件为初稿,如果大家在使用的过程中有什么疑问或者补充,或者需要本文中所述工程源文件,欢迎以邮件形式发送 ...

  3. FPGA回忆记事(一):基于Nios II的LED实验

    实验一:基于Nios II的LED实验 一.    创建Quartus II工程 1.打开Quartus II环境.开始->程序->Altera->Quartus II 9.1. 2 ...

  4. Nios II的Boot过程分析

    目录 1       概述....................................................................... 1 2       几种常见的 ...

  5. DE1-SOC开发板上搭建NIOS II处理器运行UCOS II

    DE1-SOC开发板上搭建NIOS II处理器运行UCOS II   今天在DE1-SOC的开发板上搭建NIOS II软核运行了UCOS II,整个开发过程比较繁琐,稍微有一步做的不对,就会导致整个过 ...

  6. 【小梅哥SOPC学习笔记】NIOS II处理器运行UC/OS II

    SOPC开发流程之NIOS II 处理器运行 UC/OS II 这里以在芯航线FPGA学习套件的核心板上搭建 NIOS II 软核并运行 UCOS II操作系统为例介绍SOPC的开发流程. 第一步:建 ...

  7. [置顶] 基于FPGA的VGA简易显存设计&NIOS ii软核接入

    项目简介 本项目基于Altera公司的Cyclone IV型芯片,利用NIOS II软核,2-port RAM与时序控制模块,实现64*48分辨率的显存(再大的显存板载资源m9k不够用) 实现效果如下 ...

  8. NIOS ii 流水灯

    为了做项目的前期验证工作,实验室购买了某开发板,下面是基于该板子的实现过程.作为笔记记录,供入门者参考. 1:创建一个Quartus II的工程 next选择器件,然后finish.我的器件是cycl ...

  9. NIOS II开发备忘录

    大概有一年没做NIOS II的开发了,回想上一次做NIOS II还是去年做毕业设计的时候.那时候做的是基于SOPC的频率特性测试仪,我大约花了2个月的时间,从无到有的学习了NIOS II开发.学习过N ...

随机推荐

  1. 7. leetcode 104. Maximum Depth of Binary Tree

    Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...

  2. Spring思维导图(MVC篇)

    写在前面 生活就像海洋,只有意志坚强的人才能到达彼岸. 已经很久没有发文章了呀,想必大家都挂念我了,哈哈. 温故而知新,今天一起来复习一下spring mvc的内容吧. spring mvc简介与运行 ...

  3. Java设计模式学习笔记,二:工厂模式

    工厂模式,主要实现了创建者和调用者的分离. 分类:1.简单工厂模式:2.工厂方法模式:3.抽象工厂模式. 核心:实例化对象时,用工厂方法代替new操作. 一.简单工厂模式 也叫静态工厂模式,工厂类中实 ...

  4. 强密码和弱密码并没有什么区别?NIST密码安全标准更新:不再建议密码要求混合大写字母、字符和数字

    作为一名认真负责的小编,每次注册账号设置密码的时候都是最痛苦的,太简单的怕被破解,太难的又记不住. 等你好不容易记住密码,三个月后IT同学过来拍拍你的肩膀,"你的密码到期了,记得改啊--&q ...

  5. DOS批处理中%cd%和%~dp0的区别[forward]

    DOS批处理中%cd%和%~dp0的区别   在DOS的批处理中,有时候需要知道当前的路径. 在DOS中,有两个环境变量可以跟当前路径有关,一个是%cd%, 一个是%~dp0.      这两个变量的 ...

  6. bash编程总结

    bash应该是目前Linux上最流行的shell脚本解释程序了(还有个shell叫dash,我太讨厌这个东东了.),只要你在linux上工作,并且希望自己能够工作得更愉悦,那么你应该熟悉最基本的bas ...

  7. Go语言结构体(struct)

    Go 语言结构体 Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型. 结构体是由一系列具有相同类型或不同类型的数据构成的数据集合. 结构体表示一项记录,比如保存图 ...

  8. MySQL用户管理:添加用户、授权、删除用户

    文章首发于[博客园-陈树义],请尊重原创保留原文链接. 添加用户 以root用户登录数据库,运行以下命令: create user zhangsan identified by 'zhangsan'; ...

  9. 如何修改ionic Popup的样式

    第一次用ionic的Popup时感觉很好用,但是太丑了.但是又不会修改自定义的样式,只能自己写了个模态框.后来仔细搜索了一下.发现还是可以修改的. var confirmPopup = $ionicP ...

  10. 【BZOJ3262】陌上花开 (CDQ分治+树状数组+排序)

    Time Limit: 3000 ms   Memory Limit: 256 MB Description 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),用三个整数表示. 现要对每 ...