55.基于IIC协议的EEPROM驱动控制(2)

2024-08-28 09:12
文章标签 协议 驱动 控制 iic eeprom

本文主要是介绍55.基于IIC协议的EEPROM驱动控制(2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

        升腾A7pro的EEPROM芯片为24C64芯片,器件地址为1010_011。

        (1)Visio整体设计视图(IIC_SCL为250KHz,IIC_CLK为1MHz,addr_num为1,地址字节数为2字节,addr_num为0,地址字节数为1字节):

(2)IIC_ctrl模块状态转移图:

(3)按键消抖模块代码及注释解析:

module key_filter(clk,reset_n,key_in,key_p_flag,key_r_flag,key_state);input clk;input reset_n;input key_in;output reg key_p_flag;output reg key_r_flag;output reg key_state;reg key_in1;reg key_in2;reg key_in3;reg [3:0]STATE;//抖动时间往往小于20ms,20ms = 20_000_000ns = 20ns * 1_000_000;   (1_000_000)D = (1111_0100_0010_0100_0000)B   需要一个20位的寄存器,用于计数reg [19:0]cnt_20ms;reg en_cnt_20ms;wire podge;wire nedge;wire arrive_time_20ms;//状态设计parameter IDLE      = 4'b0001;          //释放稳定状态parameter P_SHAKE   = 4'b0010;          //按下抖动状态parameter DOWN      = 4'b0100;          //按下稳定状态parameter R_SHAKE   = 4'b1000;          //释放抖动状态parameter CNT_MAX   = 20'd999_999;//异步输入key_in 信号的同步化————“打两拍”always@(posedge clk)beginkey_in1 <= key_in;key_in2 <= key_in1;end//上升沿、下降沿设计always@(posedge clk)key_in3 <= key_in2;assign podge = key_in2  &&  (!key_in3);     //上升沿assign nedge = (!key_in2)  &&  key_in3;     //下降沿//20ms计数器模块设计    always@(posedge clk or negedge reset_n)if(!reset_n)cnt_20ms <= 20'd0;else if(en_cnt_20ms &&(cnt_20ms == CNT_MAX))cnt_20ms <= 20'd0;else if(en_cnt_20ms)cnt_20ms <= cnt_20ms + 20'd1;else cnt_20ms <= 20'd0;//计满20ms信号设计           assign arrive_time_20ms = (cnt_20ms == CNT_MAX);//状态机主程序设计always@(posedge clk or negedge reset_n)if(!reset_n)beginkey_r_flag  <= 1'd0;key_p_flag  <= 1'd0;key_state   <= 1'd1;STATE       <= IDLE;en_cnt_20ms <= 1'd0;endelse begincase(STATE)IDLE:beginkey_r_flag <= 1'd0;key_state  <= 1'd1;if(nedge)beginSTATE <= P_SHAKE;en_cnt_20ms <= 1'd1;endelse STATE <= STATE;endP_SHAKE:beginif(arrive_time_20ms)beginSTATE <= DOWN;en_cnt_20ms <= 1'd0;key_p_flag <= 1'd1;key_state <= 1'd0;endelse if(podge)beginSTATE <= IDLE;en_cnt_20ms <= 1'd0;endelse STATE <= STATE;  endDOWN:beginkey_p_flag <= 1'd0;key_state <= 1'd0;if(podge)beginSTATE <= R_SHAKE;en_cnt_20ms <= 1'd1;endelse STATE <= STATE;          endR_SHAKE:beginif(arrive_time_20ms)beginSTATE <= IDLE;en_cnt_20ms <= 1'd0;key_r_flag <= 1'd1;key_state  <= 1'd1;endelse if(nedge)beginSTATE <= DOWN;en_cnt_20ms <= 1'd0;endelse STATE <= STATE; enddefault:beginkey_r_flag <= 1'd0;key_p_flag <= 1'd0;key_state  <= 1'd1;STATE      <= IDLE;endendcaseendendmodule

(4)IIC_ctrl模块Verilog代码:

module IIC_ctrl(input   wire            clk         ,input   wire            reset_n     ,input   wire            IIC_start   ,input   wire            wr_en       ,input   wire            rd_en       ,input   wire    [15:0]  byte_addr   ,input   wire    [7:0]   wr_data     ,input   wire            addr_num    ,output  reg             IIC_SCL     ,inout   wire            IIC_SDA     ,output  reg             IIC_clk     ,output  reg             IIC_end     ,output  reg     [7:0]   rd_data     );reg     [4:0]       cnt_1M          ;      //计数最大值是25  一个五位宽的寄存器足以胜任计数任务reg     [15:0]      state           ;reg     [1:0]       IIC_clk_cnt     ;reg                 EN_IIC_clk_cnt  ;reg     [2:0]       bit_cnt         ;reg                 ack             ;reg                 sda_out         ;reg     [7:0]       rd_data_reg     ;wire                sda_in          ;wire                EN_IIC_SDA      ;parameter IDLE        =  16'b0000_0000_0000_0001    ;       //空闲状态parameter START       =  16'b0000_0000_0000_0010    ;       //发送开始信号parameter SEND_D_A    =  16'b0000_0000_0000_0100    ;       //发送控制命令(器件地址+写操作)   {7'b1010_011,1'b0}parameter ACK_1       =  16'b0000_0000_0000_1000    ;       //等待响应 parameter SEND_B_H    =  16'b0000_0000_0001_0000    ;       //发送存储地址高8位  parameter ACK_2       =  16'b0000_0000_0010_0000    ;       //等待响应parameter SEND_B_L    =  16'b0000_0000_0100_0000    ;       //发送存储地址低8位parameter ACK_3       =  16'b0000_0000_1000_0000    ;       //等待响应parameter WR_DATA     =  16'b0000_0001_0000_0000    ;       //写入单比特数据   parameter ACK_4       =  16'b0000_0010_0000_0000    ;       //等待响应parameter START_2     =  16'b0000_0100_0000_0000    ;       //发送开始信号parameter SEND_RD_A   =  16'b0000_1000_0000_0000    ;       //发送控制命令(器件地址+读操作)   {7'b0101_011,1'b1} parameter ACK_5       =  16'b0001_0000_0000_0000    ;       //等待响应parameter RD_DATA     =  16'b0010_0000_0000_0000    ;       //读出单比特数据parameter NO_ACK      =  16'b0100_0000_0000_0000    ;       //等待无响应信号parameter END         =  16'b1000_0000_0000_0000    ;       //结束单比特传输parameter DEVICE_ADD  =  7'b1010_011 ;                      //EEPROM器件地址设定/*-----------IIC_clk生成模块--------------------*/
//IIC_clk 频率要求1MHz,而系统时钟clk频率为50MHz,半个周期需要计数25次(5位寄存器)always@(posedge clk or negedge reset_n)if(!reset_n)cnt_1M <= 5'd0;else if(cnt_1M == 5'd24)cnt_1M <= 5'd0;else cnt_1M <= cnt_1M + 5'd1;always@(posedge clk or negedge reset_n)if(!reset_n)IIC_clk <= 1'd0;else if(cnt_1M == 5'd24)IIC_clk <= ~IIC_clk;else IIC_clk <= IIC_clk;/*----------------状态机设计-----------------------*/  always@(posedge IIC_clk or negedge reset_n)if(!reset_n)state <= IDLE;else begincase(state)IDLE      :if(IIC_start)state <= START;else state <= state;START     : if(IIC_clk_cnt == 2'd3)state <= SEND_D_A;else state <= state;           SEND_D_A  : if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))state <= ACK_1;else state <= state;ACK_1     : if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) &&  (addr_num == 1'd1))state <= SEND_B_H;else if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (addr_num == 1'd0))state <= SEND_B_L;else state <= state;  SEND_B_H  : if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))state <= ACK_2;else state <= state;ACK_2     : if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))state <= SEND_B_L;else state <= state;  SEND_B_L  : if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))state <= ACK_3;else state <= state;ACK_3     : if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (wr_en == 1'd1))state <= WR_DATA;else if((IIC_clk_cnt == 2'd3) && (ack == 1'd0) && (rd_en == 1'd1))state <= START_2;else state <= state;WR_DATA   : if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))state <= ACK_4;else state <= state;ACK_4     : if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))state <= END;else state <= state; START_2   : if(IIC_clk_cnt == 2'd3)state <= SEND_RD_A;else state <= state; SEND_RD_A : if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))state <= ACK_5;else state <= state;ACK_5     : if((IIC_clk_cnt == 2'd3) && (ack == 1'd0))state <= RD_DATA;else state <= state; RD_DATA   : if((bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))state <= NO_ACK;else state <= state;NO_ACK    : if(IIC_clk_cnt == 2'd3)state <= END;else state <= state; END       : if((bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))state <= IDLE;else state <= state;default   : state <= IDLE;endcase       end/*----------------IIC_clk_cnt 、 EN_IIC_clk_cnt设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)if(!reset_n)IIC_clk_cnt <= 2'd0;else if(!EN_IIC_clk_cnt) IIC_clk_cnt <= 2'd0;else IIC_clk_cnt <= IIC_clk_cnt + 2'd1;always@(posedge IIC_clk or negedge reset_n)if(!reset_n)EN_IIC_clk_cnt <= 1'd0;else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))EN_IIC_clk_cnt <= 1'd0;else if(IIC_start)EN_IIC_clk_cnt <= 1'd1;else EN_IIC_clk_cnt <= EN_IIC_clk_cnt;/*--------------------bit_cnt设计-----------------------*/
always@(posedge IIC_clk or negedge reset_n)if(!reset_n)bit_cnt <= 3'd0;else if((state == IDLE)||(state == START)||(state == ACK_1)||(state == ACK_2)||(state == ACK_3)||(state == ACK_4) ||(state == START_2)||(state == ACK_5)||(state == NO_ACK))bit_cnt <= 3'd0;else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))bit_cnt <= 3'd0;else if(IIC_clk_cnt == 2'd3)bit_cnt <= bit_cnt + 3'd1;else bit_cnt <= bit_cnt;/*--------------------ack 、 sda_in信号设计---------------------------*/
always@(*)begincase(state)ACK_1,ACK_2,ACK_3,ACK_4,ACK_5   : if(IIC_clk_cnt == 2'd0)ack <= sda_in   ;else ack <= ack      ;default                         : ack = 1'd1;endcaseendassign sda_in = IIC_SDA ;/*--------------------IIC_SCL设计-----------------------*/
always@(*)begincase(state)IDLE:IIC_SCL <= 1'd1;START:if(IIC_clk_cnt == 2'd3)IIC_SCL <= 1'd0;else IIC_SCL <= 1'd1;SEND_D_A,ACK_1,SEND_B_H,ACK_2,SEND_B_L,ACK_3,WR_DATA,ACK_4,START_2,SEND_RD_A,ACK_5,RD_DATA,NO_ACK:if((IIC_clk_cnt == 2'd1) || (IIC_clk_cnt == 2'd2))IIC_SCL <= 1'd1;else IIC_SCL <= 1'd0;END:if((bit_cnt == 3'd0) && (IIC_clk_cnt == 2'd0))IIC_SCL <= 1'd0;else IIC_SCL <= 1'd1;default:IIC_SCL <= 1'd1;endcaseend/*--------------------sda_out 、 rd_data_reg设计-----------------------*/
always@(*)begincase(state)IDLE        :beginsda_out <= 1'd1; rd_data_reg <= 8'd0;endSTART       :if(IIC_clk_cnt >= 2'd1)sda_out <= 1'd0; else sda_out <= 1'd1;SEND_D_A    :if(bit_cnt <= 3'd6)sda_out <= DEVICE_ADD[6 - bit_cnt];else sda_out <= 1'd0;ACK_1,ACK_2,ACK_3,ACK_4,ACK_5   :sda_out <= 1'd1;SEND_B_H    :  sda_out <= byte_addr[15-bit_cnt]; SEND_B_L    :  sda_out <= byte_addr[7-bit_cnt];     WR_DATA     :sda_out <= wr_data[7-bit_cnt];        START_2     :if(IIC_clk_cnt >= 2'd2)sda_out <= 1'd0; else sda_out <= 1'd1;   SEND_RD_A   :if(bit_cnt <= 3'd6)sda_out <= DEVICE_ADD[6 - bit_cnt];else sda_out <= 1'd1;                 RD_DATA     :beginsda_out <= 1'd1;if(IIC_clk_cnt == 2'd2)rd_data_reg[7 - bit_cnt] <=  sda_in;else    rd_data_reg <= rd_data_reg;endNO_ACK      :sda_out <= 1'd1;END         :if((bit_cnt == 3'd0) && (IIC_clk_cnt <= 2'd2))sda_out <= 1'd0;else sda_out <= 1'd1;default     :beginsda_out <= 1'd1;rd_data_reg <= rd_data_reg;endendcaseend/*--------------------rd_data设计-----------------------*/ 
always@(posedge IIC_clk or negedge reset_n)if(!reset_n)rd_data <= 8'd0;else if((state == RD_DATA) && (bit_cnt == 3'd7) && (IIC_clk_cnt == 2'd3))rd_data <= rd_data_reg;else    rd_data <= rd_data;/*--------------------EN_IIC_SDA设计-----------------------*/ 
//EN_IIC_SDA信号为1,表示IIC_SDA输出;反之,EN_IIC_SDA信号为0,表示IIC_SDA作为输入.assign EN_IIC_SDA = ((state == IDLE) || (state == START) || (state == SEND_D_A) || (state == SEND_B_H) || (state == SEND_B_L) || (state == WR_DATA)|| (state == START_2) || (state == SEND_RD_A) || (state == NO_ACK)|| (state == END));/*--------------------IIC_SDA设计-----------------------*/ 
assign IIC_SDA = EN_IIC_SDA ? sda_out : 1'dz;/*--------------------IIC_end设计-----------------------*/ 
always@(posedge IIC_clk or negedge reset_n)if(!reset_n)IIC_end <= 1'd0;else if((state == END) && (bit_cnt == 3'd3) && (IIC_clk_cnt == 2'd3))IIC_end <= 1'd1;else IIC_end <= 1'd0;endmodule

这篇关于55.基于IIC协议的EEPROM驱动控制(2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1114343

相关文章

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

Linux之platform平台设备驱动详解

《Linux之platform平台设备驱动详解》Linux设备驱动模型中,Platform总线作为虚拟总线统一管理无物理总线依赖的嵌入式设备,通过platform_driver和platform_de... 目录platform驱动注册platform设备注册设备树Platform驱动和设备的关系总结在 l

浅析Spring如何控制Bean的加载顺序

《浅析Spring如何控制Bean的加载顺序》在大多数情况下,我们不需要手动控制Bean的加载顺序,因为Spring的IoC容器足够智能,但在某些特殊场景下,这种隐式的依赖关系可能不存在,下面我们就来... 目录核心原则:依赖驱动加载手动控制 Bean 加载顺序的方法方法 1:使用@DependsOn(最直

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

如何在Spring Boot项目中集成MQTT协议

《如何在SpringBoot项目中集成MQTT协议》本文介绍在SpringBoot中集成MQTT的步骤,包括安装Broker、添加EclipsePaho依赖、配置连接参数、实现消息发布订阅、测试接口... 目录1. 准备工作2. 引入依赖3. 配置MQTT连接4. 创建MQTT配置类5. 实现消息发布与订阅

Spring如何使用注解@DependsOn控制Bean加载顺序

《Spring如何使用注解@DependsOn控制Bean加载顺序》:本文主要介绍Spring如何使用注解@DependsOn控制Bean加载顺序,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录1.javascript 前言2. 代码实现总结1. 前言默认情况下,Spring加载Bean的顺

使用Python进行GRPC和Dubbo协议的高级测试

《使用Python进行GRPC和Dubbo协议的高级测试》GRPC(GoogleRemoteProcedureCall)是一种高性能、开源的远程过程调用(RPC)框架,Dubbo是一种高性能的分布式服... 目录01 GRPC测试安装gRPC编写.proto文件实现服务02 Dubbo测试1. 安装Dubb

基于Python开发Windows屏幕控制工具

《基于Python开发Windows屏幕控制工具》在数字化办公时代,屏幕管理已成为提升工作效率和保护眼睛健康的重要环节,本文将分享一个基于Python和PySide6开发的Windows屏幕控制工具,... 目录概述功能亮点界面展示实现步骤详解1. 环境准备2. 亮度控制模块3. 息屏功能实现4. 息屏时间

Python远程控制MySQL的完整指南

《Python远程控制MySQL的完整指南》MySQL是最流行的关系型数据库之一,Python通过多种方式可以与MySQL进行交互,下面小编就为大家详细介绍一下Python操作MySQL的常用方法和最... 目录1. 准备工作2. 连接mysql数据库使用mysql-connector使用PyMySQL3.

如何搭建并配置HTTPD文件服务及访问权限控制

《如何搭建并配置HTTPD文件服务及访问权限控制》:本文主要介绍如何搭建并配置HTTPD文件服务及访问权限控制的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、安装HTTPD服务二、HTTPD服务目录结构三、配置修改四、服务启动五、基于用户访问权限控制六、