ARM Embedded Tutorial - Raspberry Pi Pico Scanning for I2C Devices

From Lazarus wiki
Jump to navigationJump to search

Introduction

The I2C Protocol allows us in theory to connect and control more than 100 devices with a single pair of wires.

To be able to do so every device has an on-board 7-bit ID that often can be changed between several numbers to allow more than one instance of a device to be connected to the bus.

This small program allows us to scan the bus for all connected devices and it outputs the result in a little table.

Load the project into Lazarus

Please open the project i2c/i2c_scan-raspi_pico.lpi in Lazarus

program i2c_scan;
{$MODE OBJFPC}
{$H+}
{$MEMORY 10000,10000}

uses
  pico_gpio_c,
  pico_uart_c,
  pico_i2c_c,
  pico_timer_c,
  pico_c;

const
  BAUD_RATE=115200;
var
  addr : byte;
  ret : longInt;
  rxData : array[0..0] of byte;
  tmpStr : String;
begin
  gpio_init(TPicoPin.LED);
  gpio_set_dir(TPicoPin.LED,TGPIODirection.GPIO_OUT);

  uart_init(uart0, BAUD_RATE);
  gpio_set_function(TPicoPin.GP0_UART0_TX, GPIO_FUNC_UART);
  gpio_set_function(TPicoPin.GP1_UART0_RX, GPIO_FUNC_UART);

  i2c_init(i2c0Inst, 100000);
  gpio_set_function(TPicoPin.GP4_I2C0_SDA, GPIO_FUNC_I2C);
  gpio_set_function(TPicoPin.GP5_I2C0_SCL, GPIO_FUNC_I2C);
  gpio_pull_up(TPicoPin.GP4_I2C0_SDA);
  gpio_pull_up(TPicoPin.GP5_I2C0_SCL);

  repeat
    uart_puts(uart0,'I2C Bus Scan'+#13#10);
    uart_puts(uart0,'     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F'+#13#10);

    for addr := 0 to 127 do
    begin
      if (addr mod 16) = 0 then
      begin
        str(addr div 16,tmpStr);
        uart_puts(uart0,'$'+tmpStr+'0 ');
      end;
      ret := i2c_read_blocking(i2c0Inst, addr, rxdata, 1, false);
      if ret < 0 then
        uart_puts(uart0,' . ')
      else
        uart_puts(uart0,' X ');
      if addr mod 16 = 15 then
        uart_puts(uart0,#13#10);
    end;
    uart_puts(uart0,#13#10);
    busy_wait_us_32(2000000);
  until 1=0;
end.

What is important for the I2C bus is that it is always terminated to +3.3V. For this reason we enable pull-up's for both of the I2C Pins we use:

gpio_pull_up(TPicoPin.GP4_I2C0_SDA);
gpio_pull_up(TPicoPin.GP5_I2C0_SCL);

Without the pull up's the code does not work!

See also