A Verilog I2C initializer with integrated RS232 debugger - Page 1
Forum section: electronics / general

author: BrianHG
author_rank: Super Contributor
timestamp: August 16, 2022, 12:48:16 pm
content: ***************************************************************************New v1.1.BHG_I2C_init_RS232_debugger.sv & testbench V1.1, June 2023.----------------------------------------------------------------------------------------------------New v1.1 Features: Supports I2C CLK stretch.- Changes the source file from a .v to a .sv for better compiler compatibility.- Added parameters CLK_STRETCH. Enable with TRI_I2C_scl to properly support the feature.- Added on line 2, an optional `define USE_SEPARATE_DIN_DOUT_OE, which changes the I2C bus from 2x INOUTs to 6 ports, SCL/SDA _in, _out, _oe for manually driving Efinix's IO primitive.***************************************************************************BHG_I2C_init_RS232_debugger.v & testbench V1.0, August 2022.----------------------------------------------------------------------------------------------------Create and debug an I2C startup sequence with an integrated RS232 terminal editor,then, optionally disable the RS232 leaving a minimal initialization HDL.Written by Brian Guralnick.https://github.com/BrianHGinc/BHG_I2C_init_RS232_debuggerTo simulate this project in Modelsim:1) Run Modelsim all by itself. You do not need your FPGA compiler studio.2) Select 'File / Change Directory' and choose this project's folder.3) In the transcript, type: 'do setup_i2c.do'. (DONE!)4) To re-compile and simulate again, type: 'do run_i2c.do'. (DONE!)For public use. Just be fair and give credit where it is due.****************************************************************************Instructions:Parameter bit [16:0] TX_TABLE_data [0:TX_TABLE_len-1] is a 17 bit array which contains your startup sequence.In the TX_TABLE_data, you can specify multiple I2C device addresses, control an output port called .rst_out(), specify delays from 1 to 256 milliseconds and write data to any I2C register address.When you include the `define ENABLE_RS232_EDITOR at the top of the code, a real-time RS232 logger, debugger and editor will be included in the code. The editor will allow you to read and write registers as well as reset and re-initialize the startup sequence with any simple terminal software.The structure is: 1'b Func, 8'h register_address, 8'h data.When Func=1, the register_address=0, the 'data' will set the current I2C_Device_Address.When Func=1, the register_address=1, the 'data' will specify the .rst_out() port value.When Func=1, the register_address=2, the 'data' will specify a delay timer from 1 through 255 milliseconds. 0=256.When Func=0, the 'data' will be written to the 'register_address' of the previously set I2C_Device_Address.In the RS232 debugger terminal, power-up will log the transmitted TX_TABLE_data initialization sequence, then leave you with the last address and data sent to be edited.Pressing the W / R will quickly toggle the I2C_Device_Address between a read and write address. Using backspace and entering new hex numbers will edit your command line. Until you hit enter, the edit line will not be transmitted.Pressing the 'ESC' key will reset the module, re-executing you pre-defined power-up 'TX_TABLE_data'.Remember, at the top of 'BHG_I2C_init_RS232_debugger.v', there is a:`define ENABLE_RS232_EDITOROnce you have your startup-sequence, comment out this line to save a huge amount of FPGA resources as all the RS232 editor's HDL will be removed from the code.Enjoy.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 18, 2023, 02:37:55 pm
content: Hi BrianI trying to use this code but I get error in compile when using both Quartus and Efinity,Code:ocalparam [plb-1:0] I2C_per_len = (plb)'(((I2C_per_len_x10+9) / 10) - 1) ; // We add the 9 then divide by 10 to make sure the fractional speed of the clock doesn't bleed slightly above the requested frequency.rIn line 47 Quartus complain about the "'"Code:Error (10170): Verilog HDL syntax error at BHG_I2C_init_RS232_debugger.v(27) near text: '. Check for and fix any syntax errors that appear immediately before or at the specified keyword. The Intel FPGA Knowledge Database contains many articles with specific details on how to resolve this error. Visit the Knowledge Database at https://www.altera.com/support/support-resources/knowledge-base/search.html and search for this specific error message number.Error (10170): Verilog HDL syntax error at BHG_I2C_init_RS232_debugger.v(27) near text: "'"; expecting an operand. Check for and fix any syntax errors that appear immediately before or at the specified keyword. The Intel FPGA Knowledge Database contains many articles with specific details on how to resolve this error. Visit the Knowledge Database at https://www.altera.com/support/support-resources/knowledge-base/search.html and search for this specific error message number.Same for line 47 ,56, 59 and otherCode:localparam [plb-1:0] I2C_per_len = (plb)'(((I2C_per_len_x10+9) / 10) - 1) ; // We add the 9 then divide by 10 to make sure the fractional speed of the clock doesn't bleed slightly above the requested frequency.Code:reg [pcl-1:0] seq_pc = (pcl)'(0), seq_ret=(pcl)'(0), seq_ret2=(pcl)'(0) ;So I need to understand how the ' are supposed to work, is it a bit of system Verilog using array which it not supported in Verilog or something else?After some thinking it must be the calculation of the width for the following constant which does not work

author: BrianHG
author_rank: Super Contributor
timestamp: June 18, 2023, 08:19:56 pm
content: Hi Wiljan,If you can do me the favor of telling me which version of Quartus you are using?I've been using Prime 20.1 as well as Modelsim.I have used my BHG_I2C_init_RS232_debugger to program the Audio DAC and HDMI on my Max 10 DECA board.Can you please do me the favor of changing this setting in Quartus.Please go into 'Assignment - Settings'go to -> 'Compiler Settings / Verilog HDL Input'Please choose -> 'Verilog Version - System Verilog'.Let me know if this works in Quartus.If so, I may have inadvertently used an advanced parameter bit width function. This can be patched, but it will take a day or two.In the meantime, another fix may be to rename my:BHG_I2C_init_RS232_debugger.vtoBHG_I2C_init_RS232_debugger.svChanging it to an .sv will make both Quartus and Efinity see my source file as a SystemVerilog file.Don't forget to change Quartus' file name in the project.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 19, 2023, 06:40:17 am
content: Hi Brian, thank you for fast replyIn Quartus 20.1.1 Lite after change the 'Verilog Version - System Verilog' it does compile in Quartus.In the Efinity I have just save your file as BHG_I2C_init_RS232_debugger.vsAnd it for sure compile further now, but now I have trouble with the INOUT wire SCL, SDA since Efinix insist to use in + out + oe on GPIO for inout pins.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 19, 2023, 10:56:56 am
content: On the Efinix Ti60 board, RS232 worksNow I just need to figure out to have the I2C to communicate as "oe" instead of "bidir" pins

author: BrianHG
author_rank: Super Contributor
timestamp: June 19, 2023, 01:16:37 pm
content: QuoteStrange... But if you need to do it the manual way:lines 40 through 43 in my source define the OE behavior of my INOUT port for the I2C pins.Code:reg I2C_scl_q = 1'b1, I2C_sda_q = 1'b1, I2C_sda_d = 1'b0 ; // Generate 3-state IObuffers for the 2x I2C cmd lines.reg I2C_scl_oe = TRI_I2C_scl, I2C_sda_oe = TRI_I2C_scl ;assign I2C_scl = I2C_scl_oe ? I2C_scl_q : 1'bz ;assign I2C_sda = I2C_sda_oe ? I2C_sda_q : 1'bz ;Is this what you are trying to do?Code:reg I2C_scl_q = 1'b1, I2C_sda_q = 1'b1, I2C_sda_d = 1'b0 ; // Generate 3-state IObuffers for the 2x I2C cmd lines.reg I2C_scl_oe = TRI_I2C_scl, I2C_sda_oe = TRI_I2C_scl ;assign I2C_scl = (I2C_scl_oe && !I2C_scl_q) ? 1'b0 : 1'bz ;assign I2C_sda = (I2C_sda_oe && !I2C_sda_q) ? 1'b0 : 1'bz ;IE: when my code wants to output and the output needs to be low, I turn on the output enable and always drive 0. In any other state, I go into high impedance.If you want an external output enable instead, just make a 2 output ports for the reg I2C_scl/sda_oe. Change the 2 assigns and make those 2 INOUTs into OUTPUTs:Code:assign I2C_scl =I2C_scl_q ;assign I2C_sda = I2C_sda_q ;My parameter on line 24:Code:parameter bit TRI_I2C_scl = ***0*** , // 0=I2C_scl & data output is tri-stated when inactive. 1=I2C_scl is always output enabled.Already ensures one my code is done, the I2C OE lines will remain in high impedance.You can use my custom script programmable rst_out IO to tell your code that everything is done and you may take over the shared I2C lines anywhere else in your design.Remember, you are allowed to tie multiple INOUT ports together in your HDL. Collisions in your simulator will show as a red 'X', however, in the FPGA hardware, they will end up being a 0 output if one bus is high and the other is simultaneously low. But to be sure and give preference, your best bet is to do my recommended mod above.I'm not familiar with Efinix, maybe someone else will know what to do. I've always used BIDIR with the 'assign' and 1'bz using the ? as my OE switch. Never had a problem.

author: BrianHG
author_rank: Super Contributor
timestamp: June 19, 2023, 04:09:26 pm
content: Quote from: Wiljan on June 19, 2023, 06:40:17 amI still think this is strange. Numerous IO ports for FPGAs like the DDR_IO function for CycloneIV use the same style INOUT/BIDIR as I have used to communicate throughout your HDL to the IO pins. Do these still function within Efinix? Or did Quartus do a gigantic patch job with their old libs?Try this:Code:inout wire I2C_scl , // I2C clock, bidirectional pin.inout wire I2C_sda , // I2C data, bidirectional pin.Remove the word 'wire' wherever I use the 'inout' port. I checked my DDR3 source code which was all system verilog. I remember I could not use the 'wire' is some places as it would lock a direction for the 3-state IO further up the chain in my HDL.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 19, 2023, 04:39:15 pm
content: I did some more testingCode:parameter CLK_IN_KHZ = 25000 , // Source clk_in frequency in KHz, typically at least 8x the desired I2C rate. Recommend 25000-100000KHz.parameter I2C_KHZ = 100 , // Desired clk_out frequency in KHz, use 100, 400, or 1000.parameter RS232_BAUD = 115200 , // Desired RS232 baud rate.parameter bit TRI_I2C_scl = 0 , // 0=I2C_scl & data output is tri-stated when inactive. 1=I2C_scl is always output enabled.parameter TX_TABLE_len = 14, // Number of entries in table.parameter bit [16:0] TX_TABLE_data [0:TX_TABLE_len-1] = '{// PRI 7" LCD init17'h1_0101, // 1 Set rst_out high.17'h1_0100, // 2 Set rst_out low.17'h1_008A, // 3 I2C address 0x4517'h0_8000, // 4 Reg 0x80 = 0x0017'h1_0202, // 5 delay17'h0_8500, // 6 Reg 0x85 = 0x0017'h1_0202, // 7 delay17'h0_8501, // 8 Reg 0x85 = 0x0117'h1_0202, // 9 delay17'h0_8108, // 10 Reg 0x81 = 0x0817'h1_0202, // 11 delay17'h0_8600, // 12 Reg 0x86 = 0x0017'h1_0202, // 13 delay17'h0_86ff // 14 Reg 0x86 = 0xFF} // Contents of table.)( input clk_in , // System source clock.input rst_in , // Synchronous reset.output reg rst_out = 0 , // I2C sequencer generated reset output option.output reg [2:0] I2C_ack_error = 3'd0 , // Goes high when the I2C slave device does not return an ACK.input wire I2C_scl_w , // I2C clock, bidirectional pin.input wire I2C_sda_w , // I2C data, bidirectional pin.output wire I2C_scl_oe_w , // I2C clock, bidirectional pin.output wire I2C_sda_oe_w , // I2C data, bidirectional pin.input wire RS232_rxd , // RS232 input, receive from terminal.output wire RS232_txd // RS232 output, transmit to terminal.);wire I2C_scl;wire I2C_sda;reg I2C_scl_q = 1'b1, I2C_sda_q = 1'b1, I2C_sda_d = 1'b0 ; // Generate 3-state IObuffers for the 2x I2C cmd lines.reg I2C_scl_oe = TRI_I2C_scl, I2C_sda_oe = TRI_I2C_scl ;assign I2C_scl = I2C_scl_oe ? I2C_scl_q : 1'bz ;assign I2C_sda = I2C_sda_oe ? I2C_sda_q : 1'bz ;assign I2C_scl_oe_w = !I2C_scl_q;assign I2C_sda_oe_w = !I2C_sda_q;Code:BHG_I2C_init_RS232_debugger(.clk_in(clk25),.rst_in(~rst_n),// .I2C_scl(o_scl),// .I2C_sda(o_sda),.I2C_scl_w(i_scl),.I2C_sda_w(i_sda),// .I2C_scl_oe(i_scl_oe),// .I2C_sda_oe(i_sda_oe),.I2C_scl_oe_w(o_scl_oe),.I2C_sda_oe_w(o_sda_oe),.RS232_rxd(RxD),.RS232_txd(TxD));assign o_scl = 1'b0;assign o_sda = 1'b0;So I want to send on I2C address 0z45 (0x8A)Reg 0x80 = 0x00DelayReg 0x85 = 0x00DelayReg 0x85 = 0x01DelayReg 0x81 = 0x08DelayReg 0x86 = 0x00DelayReg 0x86 = 0xFFDelayThe Efinix GPIO setting does have the GPIO block as a INOUT and I have input = i_scl, output=o_scl and output enable= o_scl_oe and same for sdaSo basically the data to Out it always "0" and the OE will switch between Tristate (extern pull up 10k 3v3) and 0, thats why I have the !I2C_sda_q;The input are always active.On the scope picture you can see I get signals... I do not like the rise time for the pull-up butwhat I think is strange I only have 6 pulses on the last byteAlso the delay are 5ms on the scope but defined as 2 in the HDL

author: Wiljan
author_rank: Regular Contributor
timestamp: June 19, 2023, 06:17:39 pm
content: On Efinix site they have a forum (need to be signed in)https://www.efinixinc.com/support/forum.php?cid=1&pid=589A question was asked regarding the inoutQuoteSo a top level wrapper seems to be the answer, not sure how that should look likeRegarding the rise time I forgot to enable the internal pull-up on the input pin, this help a bit on the rise time, see attachment

author: BrianHG
author_rank: Super Contributor
timestamp: June 19, 2023, 06:30:37 pm
content: Hi Wiljan,Thanks for looking into this. If you want the high speed I2C, not relying on the pullups, you require my original 3-state IO implementation. What you are looking for is:For high speed output OUT lines:Code:assign I2C_scl_out_w = I2C_scl_q ;assign I2C_sda_out_w = I2C_sda_q ;For dedicated OEs:Code:assign I2C_scl_oe_w = I2C_scl_oe;assign I2C_sda_oe_w = I2C_sda_oe;For the input lines:Code:wire I2C_scl = I2C_scl_in_r ; // the I2C_scl_in_r is now the input port to my module replacing the INOUT I2C_scl.wire I2C_sda = I2C_sda_in_r ; // ...... Ties these inputs to your IO Primitive's IN port .....The above should feed your Efinix IO Buffer Primitive's IN, OUT, & OE without that sluggish pull-up scope-shot you illustrated. You should be able to bypass the IO/Logic. IE: your illustration was for a full DDR buffer. You should be able to find a dumb Efinix IO buffer as my module already contains the DFF latches to drive the IO_Buffer portion.This means you have the data output pins & the OE controls separate.I'll read everything else tonight.(ewww, Efinix cant cope with a bottom end bare minimum INOUT, no special DDR, fancy clocking or anything, just the basement level stuff.)

author: Wiljan
author_rank: Regular Contributor
timestamp: June 19, 2023, 08:26:40 pm
content: Thank you Brian for your suggestion on the OE, when I added in you suggestion I just got low when the SCL pulses should be there, to tired to figure out whyRegarding the Delay between packages, I found that even if I remove the delay fully in the parameter list there are a like 3mS delay between packages.It fine and will work for me.I still don't get why a few SCL pulses are missing on the last byte

author: BrianHG
author_rank: Super Contributor
timestamp: June 19, 2023, 10:11:35 pm
content: Quote from: Wiljan on June 19, 2023, 08:26:40 pmMaybe something with your IO buffer configuration. Have you tested the modified code with the 6 new IOs in modelsim?QuoteThat delay is the RS232 debugger TX-ing the ASCII output. if you comment out the:`define ENABLE_RS232_EDITORon line 1, then the I2C packets come out without delay, but, no more RS232.QuoteLast byte, or last bit?Do you have a scope shot?Can you run your setup in Modelsim?

author: Wiljan
author_rank: Regular Contributor
timestamp: June 20, 2023, 07:49:15 am
content: Quote from: BrianHG on June 19, 2023, 10:11:35 pmGuess that's the problem. No I will have to find some time to look into the modelsim.QuoteQuoteSure makes sense, did try compile without any rs232 and the I have exactly 1mS between packages as in RTL,QuoteI have attached a scope image showing only 6 clk's on the last byte in a package, but it might have to do with something wrong in the IO part.In the dataframe image it's clear there should be 9 x SCL for each byte. the 9' is where the ACK is sampled

author: BrianHG
author_rank: Super Contributor
timestamp: June 20, 2023, 01:02:19 pm
content: Just run your startup script in Modelsim directly, no Quartus, with my modelsim .do batch setup as see what it does.What frequency are you running my core at?Does the RS232 debugger show you 'W45 XX XX ACK=000' after a packet is sent?

author: Wiljan
author_rank: Regular Contributor
timestamp: June 20, 2023, 02:02:07 pm
content: Quote from: BrianHG on June 20, 2023, 01:02:19 pmHaving issues with Modelsim on this PCQuote25Mhz sysclk, 100Khz I2C, Serial 115200QuoteHave to send 0x8A to get 0x45, and this is the debug dumpCode:BHG_I2C_init_RS232_debugger V1.0, Aug 2022.https://github.com/BrianHGincW 8A 80 00 ACK=000W 8A 85 00 ACK=000W 8A 85 01 ACK=000W 8A 81 08 ACK=000W 8A 86 00 ACK=000W 8A 86 FF ACK=000Init Done.W 8A 86 FFAll based onCode:module BHG_I2C_init_RS232_debugger #(parameter CLK_IN_KHZ = 25000 , // Source clk_in frequency in KHz, typically at least 8x the desired I2C rate. Recommend 25000-100000KHz.parameter I2C_KHZ = 100 , // Desired clk_out frequency in KHz, use 100, 400, or 1000.parameter RS232_BAUD = 115200 , // Desired RS232 baud rate.parameter bit TRI_I2C_scl = 0 , // 0=I2C_scl & data output is tri-stated when inactive. 1=I2C_scl is always output enabled.parameter TX_TABLE_len = 14, // Number of entries in table.parameter bit [16:0] TX_TABLE_data [0:TX_TABLE_len-1] = '{// PRI 7" LCD init17'h1_0101, // 1 Set rst_out high.17'h1_0100, // 2 Set rst_out low.17'h1_008A, // 3 I2C address 0x4517'h0_8000, // 4 Reg 0x80 = 0x0017'h1_0210, // 5 delay17'h0_8500, // 6 Reg 0x85 = 0x0017'h1_0201, // 7 delay17'h0_8501, // 8 Reg 0x85 = 0x0117'h1_0201, // 9 delay17'h0_8108, // 10 Reg 0x81 = 0x0817'h1_0201, // 11 delay17'h0_8600, // 12 Reg 0x86 = 0x0017'h1_0201, // 13 delay17'h0_86ff // 14 Reg 0x86 = 0xFF} // Contents of table.)( input clk_in , // System source clock.input rst_in , // Synchronous reset.output reg rst_out = 0 , // I2C sequencer generated reset output option.output reg [2:0] I2C_ack_error = 3'd0 , // Goes high when the I2C slave device does not return an ACK.input wire I2C_scl_w , // I2C clock, bidirectional pin.input wire I2C_sda_w , // I2C data, bidirectional pin.input wire I2C_scl_in_r,input wire I2C_sda_in_r,output wire I2C_scl_oe_w , // I2C clock, bidirectional pin.output wire I2C_sda_oe_w , // I2C data, bidirectional pin.input wire RS232_rxd , // RS232 input, receive from terminal.output wire RS232_txd // RS232 output, transmit to terminal.);//wire I2C_scl;//wire I2C_sda;reg I2C_scl_q = 1'b1, I2C_sda_q = 1'b1, I2C_sda_d = 1'b0 ; // Generate 3-state IObuffers for the 2x I2C cmd lines.reg I2C_scl_oe = TRI_I2C_scl, I2C_sda_oe = TRI_I2C_scl ;assign I2C_scl = I2C_scl_oe ? I2C_scl_q : 1'bz ;assign I2C_sda = I2C_sda_oe ? I2C_sda_q : 1'bz ;assign I2C_scl_oe_w = !I2C_scl_q;assign I2C_sda_oe_w = !I2C_sda_q;wire I2C_scl = I2C_scl_in_r ; // the I2C_scl_in_r is now the input port to my module replacing the INOUT I2C_scl.wire I2C_sda = I2C_sda_in_r ; // ...... Ties these inputs to your IO Primitive's IN port .....//assign I2C_scl_out_w = I2C_scl_q ;//assign I2C_sda_out_w = I2C_sda_q ;//assign I2C_scl_oe_w = I2C_scl_oe;//assign I2C_sda_oe_w = I2C_sda_oe;localparam I2C_per_len_x10 = (CLK_IN_KHZ*10 / (I2C_KHZ*4)) ; // Calculate the desired period to achieve a 40x clock rate.localparam plb = $clog2((((I2C_per_len_x10+9) / 10) - 1)) ;localparam [plb-1:0] I2C_per_len = (plb)'(((I2C_per_len_x10+9) / 10) - 1) ; // We add the 9 then divide by 10 to make sure the fractional speed of the clock doesn't bleed slightly above the requested frequency.reg [plb-1:0] I2C_period = I2C_per_len ; // Divider counter for I2C clock and sequencer program counter.reg per_pulse = 1'b0 ;

author: Wiljan
author_rank: Regular Contributor
timestamp: June 20, 2023, 02:32:32 pm
content: Got installed ModelSim 20.1 and ran the script on your original files (attached)For the I2C_scl there are 27 clk's 9 for 3 bytes to that's looks fineNext will be to try to get my code to work with the tb in ModelSim

author: Wiljan
author_rank: Regular Contributor
timestamp: June 21, 2023, 08:39:31 pm
content: Hi BrianI think I know why it's not working correctly.I try to send a I2C init data to a RPI 7" lcd which it connected to a DSI interface on the Efinix Ti60 board.I have logged the data string from a RPI to know what to send (it's also in the source code for RPI)I have then send the same with a BusPirate board and it worked fine @400k.Now with the FPGA sending the I2C I can see on the scope that the waveform no good for some clk pulses (like the LCD micro hold the SCk, SDA lines low where it's not supposed.This made me look on the scope again with the BusPirate sending the same data which does work... And now there it a delay between the (Start, Address, Register, Data and Stop) about 2mS and I do not see the wrong level.So I believe the problem is the processing time for the LCD micro.Are the any easy way to add a delay in your code between the (Start, Address, Register, Data and Stop)?I also think this might be out of spec of the I2C standard, but since RPI have done both codes they might not have been concerned.

author: BrianHG
author_rank: Super Contributor
timestamp: June 21, 2023, 11:09:59 pm
content: Are you saying your LCD panel requires a 'Clock Hold'.I believe this standard was made for interfacing with MCUs to wait for them to internally catch up and before we, the master transmitting, continuing sending the next byte so that receiving MCU doesn't miss the next byte coming in. (Note that you LCD panel may be internally driven by an MCU.)If so, yes, I can add that wait state to my state machine easily, but you will have to test for me as I dont have any such hardware lying around. I just need a source for that standard as I forgot it so long ago.Google here:Goggle I2C clock holdhttps://www.i2c-bus.org/clock-stretching/This means proper 3-State IO port, in,out & OE will be needed on both I2C lines to work.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 22, 2023, 08:51:54 am
content: Hi BrianIf you look on the attached "BHG_collision_with _slave.jpg" you will see that the slave tries to hold the clk down, while the master try to force high, did not see that with pullup only.So for sure we do talk about Clock stretching which is allowed when you have a slow slave like the mcu in the RPI displayUse a TC358762 DSI to LVDS bridge and Atmel microcontrollerMy Bus Pirate v3.5 runs Firmware v6.1 r1676 Bootloader v4.4 does not seems to support Clock Stretchinghttps://www.eevblog.com/forum/testgear/bus-pirate-v4/QuoteGuess there is just some extra delay in the BusPirate to compensate for potential clock stretch.So yes Brian it would be great if you could add in support to check if the SCL are hold down by the slave to delay the next byte send, and sure I will test it.

author: BrianHG
author_rank: Super Contributor
timestamp: June 22, 2023, 02:31:49 pm
content: Quote from: Wiljan on June 22, 2023, 08:51:54 amOk, I'll add a proper 'Clock Stretch' later tonight or tomorrow.It will be a parameter to enable or disable as you cannot officially use the clock stretch in some circumstances with 1MHz and above I2C buses as it just slows things down waiting for that 'pullup' resistor.Well, this would give my I2C initializer a leg up on many others as they do not look for it.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 22, 2023, 04:41:23 pm
content: Quote from: BrianHG on June 22, 2023, 02:31:49 pmAbsolutelyYou might also consider a I2C_trigger input to be able to fire the "Init" like the "ESC" in the terminal, I know you can of course trigger the reset input but it more for reset

author: BrianHG
author_rank: Super Contributor
timestamp: June 24, 2023, 02:37:02 am
content: Ok Wiljan, here is my beta v1.1.New:I renamed my source to: BHG_I2C_init_RS232_debugger.svOn line 2, I added this commented out define:Code://`define USE_SEPARATE_DIN_DOUT_OE // Enable this line ti use separate I2C_scl/sda_din/dout/oe IO ports.Enable this define and get 2 input ports and 4 output ports to directly drive your Efinix's dumb IO buffer.There are 2 new parameters:Code:parameter bit CLK_STRETCH = 0 , // 0=High speed, 1=wait for slave to release the I2C_clk line.parameter bit CLK_STRETCH_ALL = 0 , // 0=wait for slave only during the ACK, 1=wait for slave every clock cycle.For now, I am only using the 'CLK_STRETCH' and it should wait at every rise of the clock to see if the slave is ready before continuing.Let me know what this does and do a close scope inspection to verify that I didn't accidentally drive the clock low for an instant after detecting the rise. This has to do with the OE timing and I need to see if I need to add an extra delay before or after toggling the OE and reading the IO as an input.THX.

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 24, 2023, 02:42:30 am
content: Quote from: BrianHG on June 19, 2023, 06:30:37 pmReally? Doesn't bode too well.

author: BrianHG
author_rank: Super Contributor
timestamp: June 24, 2023, 03:02:46 am
content: Quote from: SiliconWizard on June 24, 2023, 02:42:30 amHere is a capture from Efinix's forum:https://www.eevblog.com/forum/fpga/bhg_i2c_init_rs232_debugger-an-i2c-initializer-with-integrated-rs232-debugger/msg4916917/#msg4916917

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 24, 2023, 03:30:45 am
content: Good to know.Another point I meant to ask: the Efinix toolchain is based on Yosys, right?I worked with Yosys a while back to test things out. At the time, you could define clock constraints, but there was no way of defining any IO timing constraint that I remember of.Note that I was using the Yosys+nextpnr toolchain (with an ECP5 target), possibly Efinix is using something else than nextpnr and has added means of defining IO timing constraints.I found this limitation pretty, uh, annoying.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 24, 2023, 10:57:24 am
content: Quote from: BrianHG on June 24, 2023, 02:37:02 amI have tested v1.1 and it does workHad to turn on:Code:`define USE_SEPARATE_DIN_DOUT_OETRI_I2C_scl = 1CLK_STRETCH = 1And add in some parameter to send data. First I just tried with the "8A 80 00" and "8A 85 00" with CLK_Stretch=0 and then with CLK_Stretch=1 and you see a clear difference on the scopeThen I added in the data needed for the RPI display and you see a long low clock you also a clk with half level on STOP condition on all the Scope grabsCode:`ifdef ENABLE_RS232_EDITOR`include "sync_rs232_uart.v" // Include the sync_rs232_uart.v source only if the ENABLE_RS232_EDITOR feature is enabled.`endifmodule BHG_I2C_init_RS232_debugger #(parameter CLK_IN_KHZ = 25000 , // Source clk_in frequency in KHz, typically at least 8x the desired I2C rate. Recommend 25000-100000KHz.parameter I2C_KHZ = 100 , // Desired clk_out frequency in KHz, use 100, 400, or 1000.parameter RS232_BAUD = 115260 , // Desired RS232 baud rate.parameter bit TRI_I2C_scl = 1 , // 0=I2C_scl & data output is tri-stated when inactive. 1=I2C_scl is always output enabled.parameter bit CLK_STRETCH = 1 , // 0=High speed, 1=wait for slave to release the I2C_clk line.parameter bit CLK_STRETCH_ALL = 0 , // 0=wait for slave only during the ACK, 1=wait for slave every clock cycle.parameter TX_TABLE_len = 14, // Number of entries in table.parameter bit [16:0] TX_TABLE_data [0:TX_TABLE_len-1] = '{// PRI 7" LCD init17'h1_0101, // 1 Set rst_out high.17'h1_0100, // 2 Set rst_out low.17'h1_008A, // 3 I2C address 0x4517'h0_8000, // 4 Reg 0x80 = 0x0017'h1_0204, // 5 delay17'h0_8500, // 6 Reg 0x85 = 0x00 Power 01 = on 00 = off17'h1_0204, // 7 delay17'h0_8501, // 8 Reg 0x85 = 0x01 Power 01 = on 00 = off17'h1_0204, // 9 delay17'h0_8108, // 10 Reg 0x81 = 0x08 Orientation 0x08 = landscape 0x04 = portrait17'h1_0204, // 11 delay17'h0_8600, // 12 Reg 0x86 = 0x00 Backlight 0 = 0% FF = 100%17'h1_0204, // 13 delay17'h0_86ff // 14 Reg 0x86 = 0xFF Backlight 0 = 0% FF = 100%} // Contents of table.The RPI Dipslay does turn ON nowI then have to look into the LS init over DSI but that's something very different.Brian let me know if you want me to test something specific, thank you lot for the quick help

author: BrianHG
author_rank: Super Contributor
timestamp: June 24, 2023, 01:46:47 pm
content: Hi Wiljan,If you look at my attached photo from your scope shot, you will see I also needed to do a 'clock stretch' before sending the 'I2C stop'. This is probably required in case we send multiple bytes in succession, the slave might still be busy, not see a stop, or it wont be ready to see the 'I2C Start' at the next transaction.I attached beta 1.1b. I also removed the 'CLK_STRETCH_ALL' parameter as the FPGA sees the pullup so fast checking at each clk rise, the bitrate loss is inconsequential.Please provide new scope shots so I can see if I cleaned up the 'I2C Stop' bus contention.Wiljan, if you could also do me the favor of do a recapture zooming (time/horizontal) into one of the clk rises so I can see if it doesn't stutter during that tiny partial step.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 24, 2023, 03:18:13 pm
content: Quote from: BrianHG on June 24, 2023, 01:46:47 pmYeah I saw that and did mention it in my last reply, guess the mcu are busy in processing the command. Sure a clk check will be correct before the Stop is send.If you look on block 3 send the "8A 85 01" you will see the ACK fails, not sure why there is a long low clk just before, was also in 1.1 (the LCD does not turn on)The low was there in 1.1 (I expect the mcu is doing it), I guess if I add in some delay it will work.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 24, 2023, 03:42:49 pm
content: Added in some delay and it works LCD is onCode:parameter TX_TABLE_len = 14, // Number of entries in table.parameter bit [16:0] TX_TABLE_data [0:TX_TABLE_len-1] = '{// PRI 7" LCD init17'h1_0101, // 1 Set rst_out high.17'h1_0100, // 2 Set rst_out low.17'h1_008A, // 3 I2C address 0x4517'h0_8000, // 4 Reg 0x80 = 0x0017'h1_0201, // 5 delay17'h0_8500, // 6 Reg 0x85 = 0x00 Power 01 = on 00 = off17'h1_0220, // 7 delay17'h0_8501, // 8 Reg 0x85 = 0x01 Power 01 = on 00 = off17'h1_0220, // 9 delay17'h0_8108, // 10 Reg 0x81 = 0x08 Orientation 0x08 = landscape 0x04 = portrait17'h1_0201, // 11 delay17'h0_8600, // 12 Reg 0x86 = 0x00 Backlight 0 = 0% FF = 100%17'h1_0201, // 13 delay17'h0_86ff // 14 Reg 0x86 = 0xFF Backlight 0 = 0% FF = 100%} // Contents of table.

author: BrianHG
author_rank: Super Contributor
timestamp: June 24, 2023, 05:57:49 pm
content: Quote from: Wiljan on June 24, 2023, 03:42:49 pmYup, that's why I wrote this I2C initializer. I had TI audio codecs on my dev board. They require multiple reset and delays until the next command, plus a string of settings just to get them to play a sound.As you can see, the two checks check out. I will update my GitHub and this page with the v1.1 release later today.

author: Wiljan
author_rank: Regular Contributor
timestamp: June 24, 2023, 09:24:30 pm
content: Quote from: BrianHG on June 24, 2023, 05:57:49 pmYeah all is fine, Thank you Brian

author: BrianHG
author_rank: Super Contributor
timestamp: June 24, 2023, 11:31:53 pm
content: Official v1.1 release:***************************************************************************New v1.1.BHG_I2C_init_RS232_debugger.sv & testbench V1.1, June 2023.----------------------------------------------------------------------------------------------------New v1.1 Features: Supports I2C CLK stretch.- Changes the source file from a .v to a .sv for better compiler compatibility.- Added parameters CLK_STRETCH. Enable with TRI_I2C_scl to properly support the feature.- Added on line 2, an optional `define USE_SEPARATE_DIN_DOUT_OE, which changes the I2C bus from 2x INOUTs to 6 ports, SCL/SDA _in, _out, _oe for manually driving Efinix's IO primitive.See top of thread or GitHub for new source files:bhg_i2c_init_rs232_debugger-an-i2c-initializer-with-integrated-rs232-debugger/https://github.com/BrianHGinc/BHG_I2C_init_RS232_debugger