Author Topic: A Verilog I2C initializer with integrated RS232 debugger  (Read 4439 times)

0 Members and 1 Guest are viewing this topic.

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
A Verilog I2C initializer with integrated RS232 debugger
« on: August 16, 2022, 12:48:16 pm »
***************************************************************************
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_debugger

To 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_EDITOR

     Once 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.
« Last Edit: June 26, 2023, 09:19:12 pm by BrianHG »
 
The following users thanked this post: tom66, paf, nockieboy

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #1 on: June 18, 2023, 02:37:55 pm »
Hi Brian
I trying to use this code but I get error in compile when using both Quartus and Efinity,

Code: [Select]
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.
r

In line 47 Quartus complain about the "'"
Code: [Select]
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 [url]https://www.altera.com/support/support-resources/knowledge-base/search.html[/url] 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 [url]https://www.altera.com/support/support-resources/knowledge-base/search.html[/url] and search for this specific error message number.

Same for line 47 ,56, 59 and other
Code: [Select]
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: [Select]
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

« Last Edit: June 18, 2023, 04:03:55 pm by Wiljan »
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #2 on: June 18, 2023, 08:19:56 pm »
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.v
to
BHG_I2C_init_RS232_debugger.sv

Changing 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.
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #3 on: June 19, 2023, 06:40:17 am »
Hi Brian, thank you for fast reply

In 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.vs

And 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.

« Last Edit: June 19, 2023, 06:58:59 am by Wiljan »
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #4 on: June 19, 2023, 10:56:56 am »
On the Efinix Ti60 board, RS232 works  :)

Now I just need to figure out to have the I2C to communicate as "oe" instead of "bidir" pins
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #5 on: June 19, 2023, 01:16:37 pm »
Quote
but now I have trouble with the INOUT wire SCL, SDA since Efinix insist to use in + out + oe on GPIO for inout pins.

Strange...  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: [Select]
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: [Select]
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: [Select]
assign                     I2C_scl    =I2C_scl_q ;
assign                     I2C_sda   = I2C_sda_q ;

My parameter on line 24:
Code: [Select]
      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.
« Last Edit: June 19, 2023, 02:13:10 pm by BrianHG »
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #6 on: June 19, 2023, 04:09:26 pm »
And 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.
I 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: [Select]
      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.
« Last Edit: June 19, 2023, 04:38:12 pm by BrianHG »
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #7 on: June 19, 2023, 04:39:15 pm »
I did some more testing

Code: [Select]
      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 init
      17'h1_0101,  //  1 Set rst_out high.
      17'h1_0100,  //  2 Set rst_out low.

      17'h1_008A,  //  3 I2C address 0x45

      17'h0_8000,  //  4 Reg 0x80 = 0x00
      17'h1_0202,  //  5 delay

      17'h0_8500,  //  6 Reg 0x85 = 0x00
      17'h1_0202,  //  7 delay

      17'h0_8501,  //  8 Reg 0x85 = 0x01
      17'h1_0202,  //  9 delay

      17'h0_8108,  // 10 Reg 0x81 = 0x08
      17'h1_0202,  // 11 delay

      17'h0_8600,  // 12 Reg 0x86 = 0x00
      17'h1_0202,  // 13 delay

      17'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: [Select]
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 = 0x00
Delay
Reg 0x85 = 0x00
Delay
Reg 0x85 = 0x01
Delay
Reg 0x81 = 0x08
Delay
Reg 0x86 = 0x00
Delay
Reg 0x86 = 0xFF
Delay

The 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 sda

So 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 byte

Also the delay are 5ms on the scope but defined as 2 in the HDL
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #8 on: June 19, 2023, 06:17:39 pm »
On Efinix site they have a forum (need to be signed in)  https://www.efinixinc.com/support/forum.php?cid=1&pid=589

A question was asked regarding the inout

Quote
Question: Bidirectional pins

Hi, I am wondering if there is a plan to evolve the efinity software to be able to use the VHDL/VERILOG inout signal type natively at top level? Porting old code with many inout signals is a real pain and it does not work well with existing testbench designs either.


Posts Reply: 1
you may refer to similar topic: Forum | Efinix (efinixinc.com)

or, How to Create GPIO video clips: Efinix, Inc. | Efinity Software (efinixinc.com)

Reply from:  adele (Efinix) 2022-07-05 10:26:38
Comments:

This really has to change!

Porting designs from other technologies becomes very painful, laborious and error prone when your tool doesn't support this fairly trivial thing.

Comment from:  RAEJ (Member) 2022-07-05 10:55:05

Have to agree on this one.  I can see the logic to having the interface designer as a "wrapper" for the upper level I/O, but forcing the user to connect 3 ports for every inout pin is unnecessarily laborious and especially painful when trying to port code that has bidrectional pins that propagate through multiple levels of hierarchy.  Adding automatic inout inference would really be appreciated.

Comment from:  fsather (Member) 2022-07-08 20:05:08

Posts Reply: 2
Arghh! I have a Verilog project that tries to be portable across several FPGAs.  Lack of this one feature means I can not use Efinix FPGAs.  Shoot, i've just finished porting the FireAnt counter demo to a Makefile too.

Reply from:  Bob.Smith (Member) 2022-07-09 19:32:27
Comments:

Agree 100%. I'm sure there was a good reason for the decision, but it definitely complicates porting existing designs. It would even be helpful if a single output enable signal could be used for an entire bus, versus needing an individual enable for each bus output.

Comment from:  CraftyMech (Member) 2022-07-10 00:01:55

You can still use your code across multiple vendors, you just need to include a top-level wrapper file that converts the tri-port I/O instances to inouts for non-Efinix FPGA's.  You can include the DDR hard memory controller from another vendor in this way as well.

Comment from:  fsather (Member) 2022-07-11 16:25:30

So a top level wrapper seems to be the answer, not sure how that should look like

Regarding 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
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #9 on: June 19, 2023, 06:30:37 pm »
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: [Select]
assign                     I2C_scl_out_w    = I2C_scl_q ;
assign                     I2C_sda_out_w   =  I2C_sda_q ;

For dedicated OEs:
Code: [Select]
assign              I2C_scl_oe_w = I2C_scl_oe;
assign              I2C_sda_oe_w = I2C_sda_oe;

For the input lines:
Code: [Select]
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.)
« Last Edit: June 19, 2023, 06:53:23 pm by BrianHG »
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #10 on: June 19, 2023, 08:26:40 pm »
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 why

Regarding 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
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #11 on: June 19, 2023, 10:11:35 pm »
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 why
Maybe something with your IO buffer configuration.  Have you tested the modified code with the 6 new IOs in modelsim?
Quote
Regarding 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.
That delay is the RS232 debugger TX-ing  the ASCII output.  if you comment out the:
`define  ENABLE_RS232_EDITOR
on line 1, then the I2C packets come out without delay, but, no more RS232.
Quote
I still don't get why a few SCL pulses are missing on the last byte
Last byte, or last bit?
Do you have a scope shot?
Can you run your setup in Modelsim?
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #12 on: June 20, 2023, 07:49:15 am »
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 why
Maybe something with your IO buffer configuration.  Have you tested the modified code with the 6 new IOs in modelsim?
Guess that's the problem. No I will have to find some time to look into the modelsim.
Quote
Regarding 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.
Quote
That delay is the RS232 debugger TX-ing  the ASCII output.  if you comment out the:
`define  ENABLE_RS232_EDITOR
on line 1, then the I2C packets come out without delay, but, no more RS232.
Sure makes sense, did try compile without any rs232 and  the I have exactly 1mS between packages as in RTL,
Quote
Quote
I still don't get why a few SCL pulses are missing on the last byte
Last byte, or last bit?
Do you have a scope shot?
Can you run your setup in Modelsim?
I 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
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #13 on: June 20, 2023, 01:02:19 pm »
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?
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #14 on: June 20, 2023, 02:02:07 pm »
Just run your startup script in Modelsim directly, no Quartus, with my modelsim .do batch setup as see what it does.
Having issues with Modelsim on this PC
Quote


What frequency are you running my core at?
25Mhz sysclk, 100Khz I2C, Serial 115200
Quote


Does the RS232 debugger show you 'W45 XX XX ACK=000' after a packet is sent?
Have to send  0x8A to get 0x45, and this is the debug dump
Code: [Select]
BHG_I2C_init_RS232_debugger V1.0, Aug 2022.
https://github.com/BrianHGinc

W 8A 80 00 ACK=000
W 8A 85 00 ACK=000
W 8A 85 01 ACK=000
W 8A 81 08 ACK=000
W 8A 86 00 ACK=000
W 8A 86 FF ACK=000

Init Done.

W 8A 86 FF

All based on
Code: [Select]
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 init
      17'h1_0101,  //  1 Set rst_out high.
      17'h1_0100,  //  2 Set rst_out low.

      17'h1_008A,  //  3 I2C address 0x45

      17'h0_8000,  //  4 Reg 0x80 = 0x00
      17'h1_0210,  //  5 delay

      17'h0_8500,  //  6 Reg 0x85 = 0x00
      17'h1_0201,  //  7 delay

      17'h0_8501,  //  8 Reg 0x85 = 0x01
      17'h1_0201,  //  9 delay

      17'h0_8108,  // 10 Reg 0x81 = 0x08
      17'h1_0201,  // 11 delay

      17'h0_8600,  // 12 Reg 0x86 = 0x00
      17'h1_0201,  // 13 delay

      17'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                                     ;
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #15 on: June 20, 2023, 02:32:32 pm »
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 fine

Next will be to try to get my code to work with the tb in ModelSim
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #16 on: June 21, 2023, 08:39:31 pm »
Hi Brian

I 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.
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #17 on: June 21, 2023, 11:09:59 pm »
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 hold
https://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.
« Last Edit: June 21, 2023, 11:11:59 pm by BrianHG »
 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #18 on: June 22, 2023, 08:51:54 am »
Hi Brian
If 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 display
Use a TC358762 DSI to LVDS bridge and Atmel microcontroller

My Bus Pirate v3.5 runs Firmware v6.1 r1676  Bootloader v4.4 does not seems to support Clock Stretching
https://www.eevblog.com/forum/testgear/bus-pirate-v4/
Quote
I have downloaded the source and built custom firmware for the Bus Pirate to suit my own needs. I enhanced the basic scripting mode with new commands, and I added I2C clock stretching, which the devs thought to be impossible due to a hardware errata in the I2C peripheral.... which they don't use because the I2C is bit-banged  :-// . Serisously guys?  I also significantly sped up some critical routines in the bit-bang code with inline functions and other techniques, which also reduced code size due to eliminating overhead of calling all those functions. I posted about my enhancements in their forums, and a few users seemed interested but the devs ignored my requests for help to get those enhancements into the code base, so unfortunately only I have them. Oh well.

Guess 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.

« Last Edit: June 22, 2023, 08:54:26 am by Wiljan »
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #19 on: June 22, 2023, 02:31:49 pm »
Guess 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.
Ok, 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.

 

Offline Wiljan

  • Regular Contributor
  • *
  • Posts: 225
  • Country: dk
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #20 on: June 22, 2023, 04:41:23 pm »
Well, this would give my I2C initializer a leg up on many others as they do not look for it.
Absolutely  :-+

You 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  :o
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #21 on: June 24, 2023, 02:37:02 am »
Ok Wiljan, here is my beta v1.1.

New:
I renamed my source to: BHG_I2C_init_RS232_debugger.sv
On line 2, I added this commented out define:
Code: [Select]
//`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: [Select]
      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.
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14438
  • Country: fr
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #22 on: June 24, 2023, 02:42:30 am »
(ewww, Efinix cant cope with a bottom end bare minimum INOUT, no special DDR, fancy clocking or anything, just the basement level stuff.)

Really? Doesn't bode too well.
 

Online BrianHGTopic starter

  • Super Contributor
  • ***
  • Posts: 7725
  • Country: ca
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #23 on: June 24, 2023, 03:02:46 am »
(ewww, Efinix cant cope with a bottom end bare minimum INOUT, no special DDR, fancy clocking or anything, just the basement level stuff.)

Really? Doesn't bode too well.
:palm: Here 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
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14438
  • Country: fr
Re: A Verilog I2C initializer with integrated RS232 debugger
« Reply #24 on: June 24, 2023, 03:30:45 am »
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.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf