SGM58031的IIC接口调试过程(附完整代码)

发布时间:2026/7/30 10:08:42

SGM58031的IIC接口调试过程(附完整代码) 圣邦微电子推出的SGM58031是具有16位分辨率的精密模数转换器ADC设计具有高精度、低功耗和易于实现的特点具有片内基准电压源和振荡器数据通过兼容I2C的串行接口进行传输。先来看看SGM58031的IIC接口时序图话不多说直奔主题调试主要分为两个模块一个是控制驱动模块进行读写操作下文中我们简称为控制模块。一个是IIC时序的驱动模块通过读写操作写入从机地址读写命令配置寄存器地址配置寄存器值读取寄存器值下文中我们简称为驱动模块。驱动模块是进行读写操作的驱动单元。首先来说写寄存器过程在写操作过程中当写使能信号出现后模块开始工作写入高7位从机地址加1位写使能和24bit的寄存器配置值寄存器地址8bit寄存器配置值16bit这里的24bit寄存器配置值将分化为三个8bit的数据依次写入。简单来说写操作就是写入高7位从机地址1位写使能8位配置寄存器地址高8位寄存器配置值低8位寄存器配置值。上图为一次完整的写操作过程从图中可以看出在写使能信号i_wr_reg_valid(单脉冲)信号触发后I2C_58031_dri模块开始写入数据首先写入高7位从机地址加1位写使能和24bit的寄存器配置数据将24bit的寄存器配置数据分化为三个8bit的数r_wr_reg_addrr_wr_reg_data1r_wr_reg_data2分别代表寄存器地址和配置数据高八位、低八位依次写入后将完成一次写操作过程。这次过程中我总共配置了四个寄存器这里只体现了配置一个寄存器值的全过程配置另外三个寄存器的过程是一样的。接下来说说读寄存器配置过程在读操作过程中当读使能信号出现后模块开始工作首先写入高7位从机地址加1位写使能然后写入读地址即转换寄存器地址0X00再写入高7位从机地址加1位读使能最后读取转换寄存器0X00的高8bit数据和低8bit数据。简单来说读操作就是写入高7位从机地址1位写使能8位转换寄存器地址高7位从机地址1位读使能然后读高8位寄存器数据读低8位寄存器数据。上图为一次完整的读操作过程在图中可以看出在i_rd_reg_valid单脉冲信号触发后首先写入高7位从机地址加1位写使能然后写入转换寄存器地址0X00再写入高7位从机地址加1位读使能最后读取转换寄存器0X00的高8bit数据和低8bit数据在读取高八位数据过程中将数据寄存在r_rd_data1中读取低八位数据时高八位数据保持不变低八位数据寄存在r_rd_data2中当结束读操作时将高八位和低八位同时输出至16位o_rd_data信号输出端口同时o_rd_data_valid数据输出有效信号拉高。至此读写操作完成。有几个地方是比较值得注意的1、读状态我们可以通过判断芯片的ALERT/RDY引脚状态这里我们通过配置寄存器来配置ALERT/RDY引脚是高电平有效还是低电平有效2、写过程中配置完高8位寄存器数据之后主机应给一个低电平的应答信号配置完低8位寄存器数据之后主机应给一个低电平的应答信号再给一个高电平的P信号这样一次配置写寄存器过程才算是结束。(关于这一点我之前在配置完高8位寄存器数据数据之后就给了一个高电平的应答信号这导致我读出来的寄存器数据的低8位是FF)。希望这篇帖子对各位小伙伴调试SGM58031有所帮助。附上最近新写的代码module i2c_bit_shift#( parameter P_SYS_FRE 50_000_000, parameter P_SCL_FRE 200_000 )( input i_rst_n , input i_clk ,//50M input i_Go , output reg o_Done , input [5:0] i_CMD , input [7:0] i_tx_data , output [7:0] o_rx_data , output reg o_ack , inout io_i2c_sda , output o_i2c_scl ); //参数 localparam SCL_CNT_M P_SYS_FRE/P_SCL_FRE/4 - 1; localparam IDLE 7b0000001;//空闲状态 localparam GEN_STA 7b0000010;//产生起始位 localparam WR_DATA 7b0000100;//写数据 localparam RD_DATA 7b0001000;//读数据 localparam CHECK_ACK 7b0010000;//检测应答 localparam GEN_ACK 7b0100000;//产生应答 localparam GEN_STOP 7b1000000;//产生停止位 localparam STA 6b000001 ;//起始位请求 localparam WR 6b000010 ;//写请求 localparam RD 6b000100 ;//读请求 localparam STO 6b001000 ;//停止位请求 localparam ACK 6b010000 ;//主机→从机的应答位请求 localparam NACK 6b100000 ;//主机→从机的无应答位请求 wire w_i2c_sdat_i; reg [7:0] r_rx_data; reg [6:0] r_state; reg r_i2c_clk; reg r_i2c_sdat_o; reg [7:0] r_i2c_sdat_i; reg [5:0] r_i2c_clk_cnt; reg r_i2c_sdat_en; //数据流向 //r_i2c_sdat_en 1,表示主机向从机发送数据 //r_i2c_sdat_en 0,表示从机向主机发送数据 assign io_i2c_sda r_i2c_sdat_en ? r_i2c_sdat_o : 1bz; assign w_i2c_sdat_i io_i2c_sda; //时钟计数 reg [19:0] r_div_cnt; reg r_div_en; wire w_sclk_plus; always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_div_cnt 20d0; else if(r_div_en) begin if(r_div_cnt SCL_CNT_M) r_div_cnt 20d0; else r_div_cnt r_div_cnt 1b1; end else r_div_cnt 20d0; end assign w_sclk_plus (r_div_cnt SCL_CNT_M);//将一个时钟周期划分成四个操作周期 //状态机 always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_i2c_clk 1b1; r_i2c_sdat_o 1b1; r_i2c_sdat_i 8d0; r_i2c_clk_cnt 6d0; r_i2c_sdat_en 1b0; r_div_en 1b0; r_rx_data 8d0; o_Done 1b0; r_state 7d1; end else begin case(r_state) IDLE : begin o_Done 1b0; r_i2c_sdat_en 1b0; if(i_Go) begin r_div_en 1b1; if(i_CMD STA) r_state GEN_STA; else if(i_CMD WR) r_state WR_DATA; else if(i_CMD RD) r_state RD_DATA; else r_state IDLE; end else begin r_div_en 1b0; r_state IDLE; end end GEN_STA : begin if(w_sclk_plus) begin if(r_i2c_clk_cnt 6d3) r_i2c_clk_cnt 6d0; else r_i2c_clk_cnt r_i2c_clk_cnt 1b1; case(r_i2c_clk_cnt) 6d0: begin r_i2c_sdat_en 1b1; r_i2c_sdat_o 1b1; r_i2c_clk 1b1; end 6d1: r_i2c_clk 1b1; 6d2: r_i2c_sdat_o 1b0; 6d3: r_i2c_clk 1b0; endcase if(r_i2c_clk_cnt 6d3) begin if(i_CMD WR) r_state WR_DATA; else if(i_CMD RD) r_state RD_DATA; end end end WR_DATA : begin if(w_sclk_plus) begin if(r_i2c_clk_cnt 6d31) r_i2c_clk_cnt 6d0; else r_i2c_clk_cnt r_i2c_clk_cnt 1b1; case(r_i2c_clk_cnt) 6d0,4,8 ,12,16,20,24,28: begin r_i2c_sdat_en 1b1; r_i2c_sdat_o i_tx_data[7-r_i2c_clk_cnt[4:2]]; r_i2c_clk 1b0; end 6d1,5,9 ,13,17,21,25,29: r_i2c_clk 1b1; 6d2,6,10,14,18,22,26,30: r_i2c_sdat_o r_i2c_sdat_o; 6d3,7,11,15,19,23,27,31: r_i2c_clk 1b0; endcase if(r_i2c_clk_cnt 6d31) r_state CHECK_ACK; end end RD_DATA : begin if(w_sclk_plus) begin if(r_i2c_clk_cnt 6d31) r_i2c_clk_cnt 6d0; else r_i2c_clk_cnt r_i2c_clk_cnt 1b1; case(r_i2c_clk_cnt) 6d0,4,8 ,12,16,20,24,28: begin r_i2c_sdat_en 1b0; r_i2c_clk 1b0; end 6d1,5,9 ,13,17,21,25,29: r_i2c_clk 1b1; 6d2,6,10,14,18,22,26,30: r_i2c_sdat_i {r_i2c_sdat_i[6:0],w_i2c_sdat_i}; 6d3,7,11,15,19,23,27,31: r_i2c_clk 1b0; default : begin r_i2c_sdat_o 1b1; r_i2c_clk 1b1; end endcase if(r_i2c_clk_cnt 6d31) begin if(i_CMD ACK) r_state GEN_ACK; end end end CHECK_ACK : begin if(w_sclk_plus) begin if(r_i2c_clk_cnt 6d3) r_i2c_clk_cnt 6d0; else r_i2c_clk_cnt r_i2c_clk_cnt 1b1; case(r_i2c_clk_cnt) 6d0: begin r_i2c_sdat_en 1b0; r_i2c_clk 1b0; end 6d1: r_i2c_clk 1b1; 6d2: o_ack w_i2c_sdat_i;//接收的从机应答信号 6d3: r_i2c_clk 1b0; default : begin r_i2c_sdat_o 1b1; r_i2c_clk 1b1; end endcase if(r_i2c_clk_cnt 6d3) begin if(i_CMD STO) r_state GEN_STOP; else begin r_state IDLE; o_Done 1b1; end end end end GEN_ACK : begin if(w_sclk_plus) begin if(r_i2c_clk_cnt 6d3) r_i2c_clk_cnt 6d0; else r_i2c_clk_cnt r_i2c_clk_cnt 1b1; case(r_i2c_clk_cnt) 6d0: begin r_i2c_sdat_en 1b1; r_i2c_clk 1b0; if(i_CMD ACK) r_i2c_sdat_o 1b0;//主机给从机的应答信号 else if(i_CMD NACK) r_i2c_sdat_o 1b1;//主机给从机的应答信号 else r_i2c_sdat_o r_i2c_sdat_o; end 6d1: r_i2c_clk 1b1; 6d2: r_i2c_clk 1b1; 6d3: r_i2c_clk 1b0; endcase if(r_i2c_clk_cnt 6d3) begin if(i_CMD STO) r_state GEN_STOP; else begin r_state IDLE; o_Done 1b1; end end end end GEN_STOP : begin if(w_sclk_plus) begin if(r_i2c_clk_cnt 6d3) r_i2c_clk_cnt 6d0; else r_i2c_clk_cnt r_i2c_clk_cnt 1b1; case(r_i2c_clk_cnt) 6d0: begin r_i2c_sdat_en 1b1; r_i2c_sdat_o 1b0; r_i2c_clk 1b0; end 6d1: r_i2c_clk 1b1; 6d2: begin r_i2c_clk 1b1; r_i2c_sdat_o 1b1; end 6d3: r_i2c_clk 1b1;//此时已经结束通信不管是时钟还是数据线应该都处于高电平状态 default : begin r_i2c_sdat_o 1b1; r_i2c_clk 1b1; end endcase if(r_i2c_clk_cnt 6d3) begin r_state IDLE; o_Done 1b1; end end end default :; endcase end end assign o_rx_data r_i2c_sdat_i; assign o_i2c_scl r_i2c_clk; endmodulemodule i2c_control#( parameter P_SYS_FRE 50_000_000, parameter P_SCL_FRE 200_000 , parameter P_SLAVE_ADDR 7b100_1000//Slave Device Address )( input i_rst_n , input i_clk ,//50M input i_wr_reg_req , input i_rd_reg_req , input [7:0] i_pointer_wr_addr, input [7:0] i_wr_data_1 , input [7:0] i_wr_data_2 , input [7:0] i_pointer_rd_addr, output reg [15:0] o_rd_data , output reg o_rw_done , output reg o_ack , inout io_i2c_sda , output o_i2c_scl ); //参数 localparam IDLE 7b0000001;//空闲状态 localparam WR_REG 7b0000010;//写数据 localparam WAIT_WR_DONE 7b0000100;//等待写数据 localparam WR_REG_DONE 7b0001000;//写数据完成 localparam RD_REG 7b0010000;//读数据 localparam WAIT_RD_DONE 7b0100000;//等待读数据 localparam RD_REG_DONE 7b1000000;//读数据完成 localparam STA 6b000001 ;//起始位请求 localparam WR 6b000010 ;//写请求 localparam RD 6b000100 ;//读请求 localparam STO 6b001000 ;//停止位请求 localparam ACK 6b010000 ;//主机→从机的应答位请求 localparam NACK 6b100000 ;//主机→从机的无应答位请求 localparam P_DEVICE_ADDR_WR {P_SLAVE_ADDR, 1b0}; localparam P_DEVICE_ADDR_RD {P_SLAVE_ADDR, 1b1}; //寄存器 reg [5:0] r_CMD ; reg [7:0] r_tx_data ; wire w_Done ; wire w_ack ; reg r_Go ; wire [15:0] w_reg_addr ; wire [7:0] w_rx_data ; reg [6:0] r_state ; reg [7:0] r_rd_data ; reg [3:0] r_cnt ; i2c_bit_shift#( .P_SYS_FRE (P_SYS_FRE ) ,.P_SCL_FRE (P_SCL_FRE ) )U_i2c_bit_shift( .i_rst_n (i_rst_n ) ,.i_clk (i_clk ) ,.i_Go (r_Go ) ,.o_Done (w_Done ) ,.i_CMD (r_CMD ) ,.i_tx_data (r_tx_data ) ,.o_rx_data (w_rx_data ) ,.o_ack (w_ack ) ,.io_i2c_sda (io_i2c_sda ) ,.o_i2c_scl (o_i2c_scl ) ); task read_byte; input [5:0] ctrl_cmd; begin r_CMD ctrl_cmd; r_Go 1b1;//单周期脉冲信号 end endtask task write_byte; input [5:0] ctrl_cmd; input [7:0] wr_byte_data; begin r_CMD ctrl_cmd; r_tx_data wr_byte_data; r_Go 1b1;//单周期脉冲信号 end endtask always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_CMD 6d0; r_Go 1b0; o_rd_data 16d0; r_rd_data 8d0; o_ack 1b0; r_state 7d1; o_rw_done 1b0; end else begin case(r_state) IDLE : begin r_cnt 0; o_ack 1b0; o_rw_done 1b0; if(i_wr_reg_req) r_state WR_REG; else if(i_rd_reg_req) r_state RD_REG; else r_state IDLE; end WR_REG : begin r_state WAIT_WR_DONE; case(r_cnt) 0 : write_byte(WR | STA,P_DEVICE_ADDR_WR ); 1 : write_byte(WR ,i_pointer_wr_addr); 2 : write_byte(WR ,i_wr_data_1 ); 3 : write_byte(WR | STO,i_wr_data_2 ); default :; endcase end WAIT_WR_DONE : begin r_Go 1b0; if(w_Done) begin o_ack o_ack | w_ack; case(r_cnt) 0 : begin r_cnt 1; r_state WR_REG;end 1 : begin r_cnt 2; r_state WR_REG;end 2 : begin r_cnt 3; r_state WR_REG;end 3 : begin r_state WR_REG_DONE; end default : r_state IDLE; endcase end end WR_REG_DONE : begin o_rw_done 1b1; r_state IDLE; end RD_REG : begin r_state WAIT_RD_DONE; case(r_cnt) 0 : write_byte(WR | STA,P_DEVICE_ADDR_WR ); 1 : write_byte(WR | STO,i_pointer_rd_addr); 2 : write_byte(WR | STA,P_DEVICE_ADDR_RD ); 3 : read_byte (RD | ACK ); 4 : read_byte (RD | ACK | STO ); default :; endcase end WAIT_RD_DONE : begin r_Go 1b0; if(w_Done) begin if(r_cnt 2) o_ack o_ack | w_ack; case(r_cnt) 0 : begin r_cnt 1; r_state RD_REG; end 1 : begin r_cnt 2; r_state RD_REG; end 2 : begin r_cnt 3; r_state RD_REG; end 3 : begin r_cnt 4; r_state RD_REG; r_rd_data w_rx_data; end 4 : begin r_state RD_REG_DONE; end default : r_state IDLE; endcase end end RD_REG_DONE : begin o_rw_done 1b1; o_rd_data {r_rd_data,w_rx_data}; r_state IDLE; end default :; endcase end end endmodulemodule i2c_control_top#( parameter P_SYS_FRE 50_000_000, parameter P_SCL_FRE 200_000 , parameter P_SLAVE_ADDR 7b100_1000//Slave Device Address )( input i_rst_n , input i_clk ,//50M input i_config_enable , input i_enable_rdy ,//模块读准备信号高电平有效 // input [2:0] i_config_channel ,//通道输出选择 // output reg o_config_done ,//模块配置完成信号高电平有效 inout io_i2c_sda , output o_i2c_scl , output reg [15:0] o_data_1 , output reg o_data_vld_1 , output reg [15:0] o_data_2 , output reg o_data_vld_2 , output reg [15:0] o_data_3 , output reg o_data_vld_3 , output reg [15:0] o_data_4 , output reg o_data_vld_4 ); //参数 localparam IDLE 7b0000001;//空闲状态 localparam WAIT_WR_REG 7b0000010;//等待写数据 localparam WR_REG 7b0000100;//写数据 localparam WR_REG_DONE 7b0001000;//写数据完成 localparam RD_REG_READY 7b0010000;//准备读数据 localparam RD_REG 7b0100000;//读数据 localparam RD_REG_DONE 7b1000000;//读数据完成 //寄存器 reg r_wr_reg_req ; reg r_rd_reg_req ; reg [7:0] r_pointer_wr_addr ; reg [7:0] r_wr_data_1 ; reg [7:0] r_wr_data_2 ; reg [7:0] r_pointer_rd_addr ; wire w_rw_done ; wire w_ack ; wire [15:0] w_rd_data ; reg [6:0] r_state ; reg [23:0] r_config_data_temp; reg [1:0] r_config_cnt ; reg [2:0] r_enable_rdy_hd ; reg [1:0] r_channel_cnt ; // i2c_control#( .P_SYS_FRE (P_SYS_FRE ) ,.P_SCL_FRE (P_SCL_FRE ) ,.P_SLAVE_ADDR (P_SLAVE_ADDR ) )U_i2c_control ( .i_rst_n (i_rst_n ) ,.i_clk (i_clk ) ,.i_wr_reg_req (r_wr_reg_req ) ,.i_rd_reg_req (r_rd_reg_req ) ,.i_pointer_wr_addr (r_pointer_wr_addr ) ,.i_wr_data_1 (r_wr_data_1 ) ,.i_wr_data_2 (r_wr_data_2 ) ,.i_pointer_rd_addr (r_pointer_rd_addr ) ,.o_rd_data (w_rd_data ) ,.o_rw_done (w_rw_done ) ,.o_ack (w_ack ) ,.io_i2c_sda (io_i2c_sda ) ,.o_i2c_scl (o_i2c_scl ) ); // always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_channel_cnt 2d0; else if((r_state RD_REG_DONE) (w_rw_done 1b1)) begin if(r_channel_cnt 2d3) r_channel_cnt 2d0; else r_channel_cnt r_channel_cnt 1b1; end else r_channel_cnt r_channel_cnt; end always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_enable_rdy_hd 3d0; else r_enable_rdy_hd {r_enable_rdy_hd[1:0],i_enable_rdy}; end always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) r_config_data_temp 24d0; else if(r_state WAIT_WR_REG)begin case(r_config_cnt) 2d0 : r_config_data_temp 24h038000;//00000011_10000000_00000000 2d1 : r_config_data_temp 24h020000;//00000010_00000000_00000000 2d2 : begin case(r_channel_cnt) 2d0 : r_config_data_temp 24h01C2E8;//00000001_11000010_11101000 2d1 : r_config_data_temp 24h01D2E8;//00000001_11010010_11101000 2d2 : r_config_data_temp 24h01E2E8;//00000001_11100010_11101000 2d3 : r_config_data_temp 24h01F2E8;//00000001_11110010_11101000 default :; endcase end default :; endcase end else r_config_data_temp r_config_data_temp; end // always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin r_state 7d1; r_pointer_wr_addr 8d0; r_wr_data_1 8d0; r_wr_data_2 8d0; r_pointer_rd_addr 8d0; r_config_cnt 2d0; r_wr_reg_req 1b0; r_rd_reg_req 1b0; end else begin case(r_state) IDLE : begin if(i_config_enable) r_state WAIT_WR_REG; else r_state r_state; end WAIT_WR_REG : begin r_state WR_REG; end WR_REG : begin r_wr_reg_req 1b1; r_pointer_wr_addr r_config_data_temp[23:16]; r_wr_data_1 r_config_data_temp[15:8] ; r_wr_data_2 r_config_data_temp[7:0] ; r_state WR_REG_DONE; end WR_REG_DONE : begin r_wr_reg_req 1b0; if(w_rw_done) begin if(r_config_cnt 2d2) begin r_config_cnt 2d0; r_state RD_REG_READY; end else begin r_config_cnt r_config_cnt 1b1; r_state WAIT_WR_REG; end end else begin r_config_cnt r_config_cnt; r_state r_state; end end RD_REG_READY : begin if(r_enable_rdy_hd[2] 1b1) r_state RD_REG; else r_state r_state; end RD_REG : begin r_rd_reg_req 1b1; r_state RD_REG_DONE; end RD_REG_DONE : begin r_rd_reg_req 1b0; if(w_rw_done) r_state IDLE; else r_state r_state; end default :; endcase end end always (posedge i_clk or negedge i_rst_n) begin if(!i_rst_n) begin o_data_1 16d0; o_data_vld_1 1d0 ; o_data_2 16d0; o_data_vld_2 1d0 ; o_data_3 16d0; o_data_vld_3 1d0 ; o_data_4 16d0; o_data_vld_4 1d0 ; end else if((r_state RD_REG_DONE) (w_rw_done 1b1)) begin case(r_channel_cnt) 2d0 : begin o_data_1 w_rd_data; o_data_vld_1 1b1; end 2d1 : begin o_data_2 w_rd_data; o_data_vld_2 1b1; end 2d2 : begin o_data_3 w_rd_data; o_data_vld_3 1b1; end 2d3 : begin o_data_4 w_rd_data; o_data_vld_4 1b1; end default :; endcase end else begin o_data_1 o_data_1; o_data_vld_1 1d0 ; o_data_2 o_data_2; o_data_vld_2 1d0 ; o_data_3 o_data_3; o_data_vld_3 1d0 ; o_data_4 o_data_4; o_data_vld_4 1d0 ; end end endmodule

相关新闻