BusPirate / Bus_Pirate

Community driven firmware and hardware for Bus Pirate version 3 and 4
625 stars 130 forks source link

Add I2C clock stretching in software mode #90

Open agatti opened 6 years ago

agatti commented 6 years ago

As mentioned in #88, I2C clock stretching in software mode is currently missing.

ChristopherSamSoon commented 6 years ago

Hi Agatti,

I can work on this no problem. The strategy here is to allow the bit-bang mode be modified to allow clock stretching for I2C while still maintaining the same functionality for other modules (because the bitbang functions are shared with the other protocols)

There are two solutions 1) Add an extra parameter to the bitbang functions that indicate whether there should be clock stretching or not. I2C calls will set this parameter to true, the rest (SPI, 1 WIRE, etc...) will set it as false

2) Create a seperate bitbang function that only the i2c mode will call (lets say bitbang_i2c_write_value and bitbang_i2c_read_value)

I will go for the second solution as less things have to change

To add further, I have a slow I2C device here that I can use to test this clock stretching stuff!!

agatti commented 6 years ago

That may work - although I'd try to make sure that as much code is shared as possible between bitbang functions. Keep in mind that the RAW2WIRE protocol does use bitbang functions in an I2C-like fashion too.

ChristopherSamSoon commented 5 years ago

I2C clock stretching solution is available. Basic idea is to wait for clock line to go high (released by the slave) on the ACK bit. Code snippet below. Code also bails out after a maximum predefined amount of time to wait has been reached

bool bitbang_read_bit(bool CLKStretch) {
  bool bit_value, clk_value;
  uint32_t max_wait;

  /* Set the MISO pin as input. */
  bitbang_read_pin(miso_pin);

  /* Set CLK high. */
  bitbang_set_pins_high(CLK, delay_profile->clock);

  /* Wait for CLK to go high if desired*/
  if(CLKStretch == true){
      max_wait =0;
      do{          
          clk_value = IOPOR & CLK; // check if clock is released by slave
          if(clk_value != 0){
              break; // clk signal released by slave, exit
          }
          bp_delay_us(1); // wait 1us
          max_wait = max_wait + 1;

      }while(max_wait < I2C_SW_CLK_STRETCH_MAXWAIT_US);
  }

  /* Read value. */
  bit_value = bitbang_read_pin(miso_pin);

  /* Set CLK low. */
  bitbang_set_pins_low(CLK, delay_profile->clock);

  return bit_value;
}

Cheers

Christopher Sam Soon

agatti commented 5 years ago

I guess this calls for a change in menu commands and/or protocol. Will have to sit on this for a bit longer than expected, unfortunately.

jermonca commented 7 months ago

Do you have an update on clock stretching support during sniffer mode? I find that it is not decoding properly. Thank you.