数字IC实践项目(9)— Tang Nano 20K: I2C OLED Driver

news2024/11/27 9:38:35

Tang Nano 20K: I2C OLED Driver

  • 写在前面的话
    • 硬件模块
    • RTL电路和相关资源报告
    • SSD1306 OLED 驱动芯片
    • SSD1306 I2C协议接口
    • OLED 驱动模块RTL
    • 综合实现
  • 总结

写在前面的话

  • 之前在逛淘宝的时候偶然发现了Tang Nano 20K,十分感慨国产FPGA替代方案的进步之快;
  • 被Tang Nano 20K小巧精致的外形和丰富的内在资源震惊到了,买来想要体验一下国产FPGA的软件生态。

硬件模块

  • 项目主要设备是高云半导体的Tang Nano 20K开发板和0.96寸四针I2C模块的OLED模块;
  • OLED模块采用SSD1306驱动芯片;

Tang Nano 20K
在这里插入图片描述
0.96寸 I2C 接口OLED
在这里插入图片描述

RTL电路和相关资源报告

  • 采用GOWIN FPGA Designer平台查看RTL电路图;

在这里插入图片描述

  • 采用GOWIN FPGA Designer平台查看资源报告;
    在这里插入图片描述

SSD1306 OLED 驱动芯片

  • SSD1306是一个单片CMOS OLED/PLED驱动芯片可以驱动有机/聚合发光二极管点阵图形显示系统。由128 segments和64Commons组成。该芯片专为共阴极OLED面板设计。
  • SSD1306中嵌入了对比度控制器、显示RAM和晶振,并因此减少了外部器件和功耗。有256级亮度控制。数据/命令的发送有三种接口可选择:6800/8000串口,I2C接口或SPI接口。适用于多数简介的应用,移动电话的屏显,MP3播放器和计算器等。

SSD1306 芯片框图
在这里插入图片描述

SSD1306中内置128 * 64的GDDRAM,是一个为映射静态RAM保存位模式来显示,RAM分为8页,从PAFE0到PAGE7,用于单色128 * 64点阵显示,如下图所示:
GDDRAM:
在这里插入图片描述
当一个数据字节写到GDDRAM中,所有当前列的同一页的行图像数据都会被被填充(比如,被列地址指针指向的整列(8位)都会被填充)。数据位D0写到顶行,而数据位D7写到底行,如下图所示。

SSD1306 I2C协议接口

I2C通讯接口由从机地址为SA0,I2C总线数据信号(SDAout/D2输出和SDAin/D1输入)和I2C总线时钟信号SCL(D0)组成。数据和时钟信号线都必须接上上拉电阻。RES#用来初始化设备。
I2C数据格式:
在这里插入图片描述
a. 从机地址位(SA0)
SSD1306在发送或接受任何信息之前必须识别从机地址。设备将会响应从机地址,后面跟随着从机地址位(SA0位)和读写选择位(R/W#位)。
SA0位为从机地址提供了一个位的拓展。0111100或0111101都可以做为SSD1306的从机地址。D/C#引脚作为SA0用于从机地址选择。R/W#为用来决定I2C总线接口的操作模式。R/W# = 1,读模式。R/W# = 0 写模式
b. I2C总线数据信号SDA
SDA作为主机和从机之间的通讯通道。数据和应答都是通过SDA发送。
c. I2C总线时钟信号SCL
每个数据位的传输任务发生在SCL的单个的时钟周期中。

项目难度:⭐
项目推荐度:⭐⭐
项目推荐天数:1~天

FPGA开发环境:
前仿: Modelsim SE-64 2019.2
综合: Gowin_V1.9.9Beta-4_Education

项目学习目的:
(1)熟练掌握项目中各文件的工程管理;
(2)熟悉 Verilog HDL仿真、FPGA综合工具及流程;
(3)学习OLED 驱动和I2C的基础原理;

OLED 驱动模块RTL

//oled_init  初始化模块
module OLED_Init(
	
	input					sys_clk			,
	input					rst_n			,
	
	input					init_req		,			//初始化请求
	input					write_done		,			//初始化数据完成信号
	
	output					init_finish		,			//初始化完成输出

	output[23:0]			Init_data					//初始化的数据
);

//WR CMD : 0X78+0X00+CMD
//WR Data: 0X78+0X40+Data
localparam			RST_T			=	1'b0;			//低电平复位有效

reg[23:0]		Init_data_reg;
reg[23:0]		Init_data_reg1;

reg[4:0]		Init_index;

reg init_finish_inside;


//OLED_WR
reg [10:0]  WR_index    ;   //TX data counter
reg [9:0]   WR_addr     ;   //TX ROM Data addr
wire [7:0]  WR_data     ;   //WR Data

//FSM
localparam IDLE =   2'b01   ;
localparam WR   =   2'b10   ;

reg [1:0]   CS ;
reg [1:0]   NS ;

always @(posedge sys_clk or negedge rst_n) begin 
    if(~rst_n) begin
         CS <= IDLE;
    end 
    else begin
         CS <= NS;
    end
end


always@(*) begin 
    case(CS)
        IDLE: begin
            if(Init_index >= 'd26 && write_done == 1'b1) begin
                NS = WR;
            end 
            else begin
                NS = IDLE;
            end 
        end 
        WR: begin
            if(rst_n==1'b0) begin
                NS = IDLE;
            end
            else begin
                NS = WR;
            end
        end 
        default: NS = IDLE;
    endcase 
end 

always@(*) begin 
    case(CS)
        IDLE: init_finish_inside = 1'b0;
        WR: init_finish_inside = 1'b1;
        default: NS = IDLE;
    endcase 
end





assign Init_data  = (init_finish_inside==1'b1)?Init_data_reg1:Init_data_reg;
assign init_finish = (write_done == 1'b1 && WR_index == 'd1047) ? 1'b1 : 1'b0;//完成信号

always@(posedge sys_clk or negedge rst_n)
begin
	if(rst_n == RST_T)
		Init_index <= 'd0;
	else if(Init_index == 'd26 && write_done == 1'b1 )
		Init_index <= 'd0;
	else if(write_done == 1'b1 && init_req == 1'b1)
		Init_index <= Init_index + 1'b1;
	else
		Init_index <= Init_index;
end

//初始化命令状态
always@(*)
begin
	case(Init_index)
		'd0:		Init_data_reg <= {8'h78,8'h00,8'hAE};
		'd1:		Init_data_reg <= {8'h78,8'h00,8'h00};
		'd2:		Init_data_reg <= {8'h78,8'h00,8'h10};
		'd3:		Init_data_reg <= {8'h78,8'h00,8'h40};
		'd4:		Init_data_reg <= {8'h78,8'h00,8'hB0};
		'd5:		Init_data_reg <= {8'h78,8'h00,8'h81};
		'd6:		Init_data_reg <= {8'h78,8'h00,8'hFF};
		'd7:		Init_data_reg <= {8'h78,8'h00,8'hA1};
		'd8:		Init_data_reg <= {8'h78,8'h00,8'hA6};
		'd9:		Init_data_reg <= {8'h78,8'h00,8'hA8};
		'd10:		Init_data_reg <= {8'h78,8'h00,8'h3F};
		'd11:		Init_data_reg <= {8'h78,8'h00,8'hC8};
		'd12:		Init_data_reg <= {8'h78,8'h00,8'hD3};
		'd13:		Init_data_reg <= {8'h78,8'h00,8'h00};
		'd14:		Init_data_reg <= {8'h78,8'h00,8'hD5};
		'd15:		Init_data_reg <= {8'h78,8'h00,8'h80};
		'd16:		Init_data_reg <= {8'h78,8'h00,8'hD8};
		'd17:		Init_data_reg <= {8'h78,8'h00,8'h05};
		'd18:		Init_data_reg <= {8'h78,8'h00,8'hD9};
		'd19:		Init_data_reg <= {8'h78,8'h00,8'hF1};
		'd20:		Init_data_reg <= {8'h78,8'h00,8'hDA};
		'd21:		Init_data_reg <= {8'h78,8'h00,8'h12};
		'd22:		Init_data_reg <= {8'h78,8'h00,8'hDB};
		'd23:		Init_data_reg <= {8'h78,8'h00,8'h30};
		'd24:		Init_data_reg <= {8'h78,8'h00,8'h8D};
		'd25:		Init_data_reg <= {8'h78,8'h00,8'h14};
		'd26:		Init_data_reg <= {8'h78,8'h00,8'hAF};
		default:
			Init_data_reg <= {8'h78,8'h00,8'hAE};
		endcase
end





always @(posedge sys_clk or negedge rst_n) 
begin
    if(~rst_n)begin
        WR_index <= 11'd0;
    end 
    else if(WR_index == 'd1048) begin
        WR_index <= 11'd0;
    end
    else if(init_finish_inside == 1'b1 && write_done == 1'b1 && init_req == 1'b1)
        WR_index <= WR_index + 1'b1;
    else
        WR_index <= WR_index;  
end



always @(posedge sys_clk or negedge rst_n) 
begin
    if(~rst_n)
    begin
        WR_addr <= 10'd0;
    end 
    else
    begin
        if ((WR_index >= 11'd2) && (WR_index <= 11'd129)) 
        begin
            WR_addr <= WR_index - 11'd2;
        end
        else if ((WR_index >= 11'd133) && (WR_index <= 11'd260)) 
        begin
            WR_addr <= WR_index - 11'd5;
        end
        else if ((WR_index >= 11'd264) && (WR_index <= 11'd391)) 
        begin
            WR_addr <= WR_index - 11'd8;
        end
        else if ((WR_index >= 11'd395) && (WR_index <= 11'd522)) 
        begin
            WR_addr <= WR_index - 11'd11;
        end
        else if ((WR_index >= 11'd526) && (WR_index <= 11'd653)) 
        begin
            WR_addr <= WR_index - 11'd14;
        end
        else if ((WR_index >= 11'd657) && (WR_index <= 11'd784)) 
        begin
            WR_addr <= WR_index - 11'd17;
        end
        else if ((WR_index >= 11'd788) && (WR_index <= 11'd915)) 
        begin
            WR_addr <= WR_index - 11'd20;
        end
        else if ((WR_index >= 11'd919) && (WR_index <= 11'd1046)) 
        begin
            WR_addr <= WR_index - 11'd23;
        end
    end
end


//初始化数据发送
always@(*) begin
            case (WR_index)
                11'd0: 	Init_data_reg1 <= {8'h78,8'h00,8'hB0};
                11'd1:	Init_data_reg1 <= {8'h78,8'h00,8'h00}; 
                11'd2:	Init_data_reg1 <= {8'h78,8'h00,8'h10};
                // page 0
                11'd131:Init_data_reg1 <= {8'h78,8'h00,8'hB1};
                11'd132:Init_data_reg1 <= {8'h78,8'h00,8'h00}; 
                11'd133:Init_data_reg1 <= {8'h78,8'h00,8'h10};
                // page 1
                11'd262:Init_data_reg1 <= {8'h78,8'h00,8'hB2};
                11'd263:Init_data_reg1 <= {8'h78,8'h00,8'h00}; 
                11'd264:Init_data_reg1 <= {8'h78,8'h00,8'h10};
                // page 2
                11'd393:Init_data_reg1 <= {8'h78,8'h00,8'hB3};
                11'd394:Init_data_reg1 <= {8'h78,8'h00,8'h00}; 
                11'd395:Init_data_reg1 <= {8'h78,8'h00,8'h10};
                // page 3
                11'd524:Init_data_reg1 <= {8'h78,8'h00,8'hB4};
                11'd525:Init_data_reg1 <= {8'h78,8'h00,8'h00}; 
                11'd526:Init_data_reg1 <= {8'h78,8'h00,8'h10};
                // page 4
                11'd655:Init_data_reg1 <= {8'h78,8'h00,8'hB5};
                11'd656:Init_data_reg1 <= {8'h78,8'h00,8'h00}; 
                11'd657:Init_data_reg1 <= {8'h78,8'h00,8'h10};
                // page 5
                11'd786:Init_data_reg1 <= {8'h78,8'h00,8'hB6};
                11'd787:Init_data_reg1 <= {8'h78,8'h00,8'h00}; 
                11'd789:Init_data_reg1 <= {8'h78,8'h00,8'h10};
                // page 6
                11'd917:Init_data_reg1 <= {8'h78,8'h00,8'hB7};
                11'd918:Init_data_reg1 <= {8'h78,8'h00,8'h00}; 
                11'd919:Init_data_reg1 <= {8'h78,8'h00,8'h10};
                // page 7
                default : Init_data_reg1 <= {8'h78,8'h40,WR_data}; //binary data
            endcase
end

assign WR_data = 8'hAA;


//Change the instance name and port connections to the signal names
//--------Copy here to design--------

    Gowin_pROM your_instance_name(
        .dout 		(WR_data 	), 			//output [7:0] dout
        .clk 		(sys_clk 	), 			//input clk
        .oce 		( 		    ),  		//input oce
        .ce 		(1'b1 		), 			//input ce
        .reset	 	(~rst_n 	), 			//input reset
        .ad 		(WR_addr 	) 			//input [9:0] ad
    );

//--------Copy end-------------------

endmodule

综合实现

采用GOWIN完成电路综合,并下板实现。
在这里插入图片描述
祝大家新年快乐呀
在这里插入图片描述

总结

没啥总结的,在这里祝愿大家龙年大吉,万事如意!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1450884.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51单片机项目(30)——基于51单片机的心率血氧脉搏检测的proteus仿真

1.功能设计 可以测量脉搏、心率、血氧浓度、体温&#xff0c;并且实时显示在LCD1602屏幕上&#xff0c;&#xff08;第一行是体温血氧&#xff0c;第二行是心率脉搏&#xff09;。 &#xff08;需要完整源文件的&#xff0c;直接看最后一节&#xff09; 另外&#xff0c;还…

PXE实现自动批量安装部署操作系统

目录 一、PXE介绍 二、PXE涉及的相关知识点 三、搭建PXE网络体系的前提 四、服务端要安装一系列的依赖环境 五、搭建 PXE 远程安装服务器 5.1、安装并启动TFTP服务 5.2、安装并启用 DHCP 服务 5.3、准备 Linux 内核、初始化镜像文件、准备 PXE 引导程序 5.4、安装FTP服…

【C++第二阶段】赋值运算符重载

你好你好&#xff01; 以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 赋值运算符重载 赋值运算符重载 实验①&#xff0c;还没有对析构运算符重载时 #include<iostream> #include<string> using namespace std;clas…

1Coze平台介绍

2023年随着OpenAI推出GPT 3.5&#xff0c;AI赛道变得更加火热。GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一种自然语言处理&#xff08;NLP&#xff09;模型&#xff0c;用于生成文本、理解语言和进行各种语言任务。GPT是由OpenAI开发的&#xff0c;它…

【C语言】简单贪吃蛇实现保姆级教学!!!

关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა 新年快乐呀小伙伴 引言&#xff1a; 小伙伴们应该都有一个做游戏的梦吧&#xff1f;今天让小庄来用C语言简单实现一下我们的童年邪典贪吃蛇&#xff0c;顺便巩固我们的C语言知识&#xff0c;请安心食用~ 文章目录 贪吃蛇效果一.游戏前工作…

ubuntu22.04@laptop OpenCV Get Started: 011_edge_detection

ubuntu22.04laptop OpenCV Get Started: 011_edge_detection 1. 源由2. edge_detection应用Demo2.1 C应用Demo2.2 Python应用Demo 3. 重点逐步分析3.1 GaussianBlur去噪3.2 Sobel边缘检测3.2.1 SobelX方向边缘检测3.2.2 SobelY方向边缘检测3.2.3 SobelXY方向边缘检测 3.3 Canny…

AI大模型专题:工业大模型技术应用与发展报告1.0

今天分享的是AI大模型系列深度研究报告&#xff1a;《AI大模型专题&#xff1a;工业大模型技术应用与发展报告1.0》。 &#xff08;报告出品方&#xff1a;中国信通院&#xff09; 报告共计&#xff1a;25页 人工智能的几个相关概念 大模型&#xff1a;即基础模型&#xff…

精品jsp+ssm汽车店维保信息系统

《[含文档PPT源码等]精品jspssm汽车店维保信息系统[包运行成功]》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程、包运行成功&#xff01; 使用技术&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;ssm 技术&#xff1a;JSP JDK版本&…

NBlog个人博客部署过程记录 -- 后端springboot + 前端vue

项目是fork的Naccl大佬NBlog项目&#xff0c;页面做的相当漂亮&#xff0c;所以选择了这个。可以参考2.3的效果图 惭愧&#xff0c;工作两年了也每个自己的博客系统&#xff0c;趁着过年时间&#xff0c;开始搭建一下. NBlog原项目的github链接&#xff1a;Naccl/NBlog: &#…

问题:宋朝为了加强皇帝对司法权的直接控制建立了() #微信#微信问题:宋朝为了加强皇帝对司法权的直接控制建立了() #微信#微信

问题&#xff1a;宋朝为了加强皇帝对司法权的直接控制建立了&#xff08;&#xff09; A.大理寺 B.刑部 C.审刑院 D.廷尉 参考答案如图所示

webpack实际实践优化项目

参考&#xff1a; 如何通过性能优化&#xff0c;将包的体积压缩了62.7% 雅虎35条 20210526-webpack深入学习&#xff0c;搭建和优化react项目 本文只专注于性能优化的这个部分。 总体来说分为两个方面&#xff1a;第一是开发环境中主要优化打包速度&#xff0c;第二是线上环境…

VScode+PlatformIO 物联网Iot开发平台环境搭建

1.vscode &#xff08;1&#xff09;安装platformIO插件 &#xff08;2&#xff09;新建项目或导入已有的arduino项目 Name&#xff1a;需要填写你项目的名称&#xff1b; Board&#xff1a;点开是一个下拉框&#xff0c;但是可以输入你想要的开发板&#xff0c;这里选择&quo…

Spring Task定时任务

目录 1、介绍 2、cron表达式 2.1、在线生成器 2.2、通配符 3、代码示例 3.1、使用步骤 3.2、 代码开发 3.3、测试 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅长web应用开发…

【前端高频面试题--Vue组件通信篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;前端高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac;前端高频面试题--Vue组件通信篇 往期精彩内容Vue与VueComponent的关系props / $emit父子组件传值父…

备战蓝桥杯---图论之最短路Bellman-Ford算法及优化

目录 上次我们讲到复杂度为&#xff08;nm)logm(m为边&#xff0c;n为点&#xff09;的迪杰斯特拉算法&#xff0c;其中有一个明显的不足就是它无法解决包含负权边的图。 于是我们引进Bellman-Ford算法。 核心&#xff1a;枚举所有的点&#xff0c;能松弛就松弛&#xff0c;直…

《剑指offer》

本专题是分享剑指offer的一些题目&#xff0c;开始刷题计划。 二维数组的中的查找【https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId13&tqId11154&ru/exam/oj】 描述 在一个二维数组array中&#xff08;每个一维数组的长度相同&#xff0…

[计算机提升] 备份系统:设置还原点

6.7 备份系统&#xff1a;设置还原点 在Windows系统中&#xff0c;系统还原点是指系统在特定时间存储的重要系统文件的备份。通过创建系统还原点&#xff0c;可以轻松地将系统恢复到之前创建还原点的状态。这有助于解决系统文件损坏或Windows操作系统出现问题的情况。 1、右键…

推荐在线图像处理程序源码

对于喜爱图像编辑的朋友们来说&#xff0c;Photoshop无疑是处理照片的利器。然而&#xff0c;传统的Photoshop软件不仅需要下载安装&#xff0c;还对电脑配置有一定的要求&#xff0c;这无疑增加了使用的门槛。 现在&#xff0c;我们为您带来一款革命性的在线PS修图工具——基…

Redis篇----第一篇

系列文章目录 文章目录 系列文章目录前言一、什么是 Redis?二、Redis 与其他 key-value 存储有什么不同?三、Redis 的数据类型?四、使用 Redis 有哪些好处?五、Redis 相比 Memcached 有哪些优势?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住…

GAN生成对抗性网络

一、GAN原理 出发点&#xff1a;机器学习中生成模型的问题 无监督学习是机器学习和未来人工智能的突破点&#xff0c;生成模型是无监督学习的关键部分 特点&#xff1a; 不需要MCMC或者变分贝叶斯等复杂的手段&#xff0c;只需要在G和D中对应的多层感知机中运行反向传播或者…