Search code examples
adai2cbbc-microbit

Ada for I2C on the BBC Micro:Bit with the MCP23017


I am trying to set up a very simple example using the ada I2C library with the MCP23017 IO expander on the micro:bit (V1.5) but I can't figure it out. For now, all I want to do is turn on an LED that is connected to a GPIOA pin. I have it working in python with the following:

from microbit import i2c


while True:
    # set pins to output
    # 0x20 is the address of the MCP23017
    # the first 0x00 is the IODIRA address for setting pin direction (input/output)
    # the second 0x00 sets all the pins to be outputs
    i2c.write(0x20, bytes([0x00, 0x00]))

    # set outputs to true to turn on led
    # 0x14 is the OLATA address for outputs
    # 0xFF sets all outputs to true
    i2c.write(0x20, bytes([0x14, 0xFF]))

and here is my attempt in ada:

with MicroBit.Display; use MicroBit.Display;
with MicroBit.I2C;
with HAL.I2C; use HAL.I2C;

procedure Main is
   I2C_Controller : constant HAL.I2C.Any_I2C_Port := MicroBit.I2C.Controller;
   I2C_Slave_Address : constant HAL.I2C.I2C_Address := 32;

   Pins_Out : constant I2C_Data (0 .. 1) := (0, 0);
   Outputs_On : constant I2C_Data (0 .. 1) := (20, 255);
   Status : HAL.I2C.I2C_Status;

begin
   MicroBit.I2C.Initialize;
   Display ('I');
   loop   
      I2C_Controller.Master_Transmit (Addr    => I2C_Slave_Address,
                                      Data    => Pins_Out,
                                      Status  => Status);
      I2C_Controller.Master_Transmit (Addr    => I2C_Slave_Address,
                                      Data    => Outputs_On,
                                      Status  => Status);
   end loop;
end Main;

I tried to translate the inputs from hex in the python example to the decimal that the ada library needs. So 0x20 in the python corresponds to 32 decimal for the ada. Similarly, 0x00 -> 0, 0x14 -> 20 and 0xFF -> 255. I must be missing something because this isn't working. I display the 'I' to make sure that it flashes successfully, but nothing happens other than that. Any help would be greatly appreciated,

Thanks!


Solution

  • I had an MCP23017 in 2012; can’t find it, so hard to help other than by suggesting lines of approach.

    Have you tied the three settable address lines in the datasheet Fig 3.6 (pins 15, 16, 17 in the diagram on the first page) to ground?

    You don’t check that the returned Status from the Master_Transmit calls is HAL.I2C.Ok.

    Looking at line 135 of nrf-twi.adb

          This.Periph.ADDRESS.ADDRESS := UInt7 (Addr / 2);
    

    and comparing it to Fig 3.6 again, I strongly suspect that the chip address you pass to the Ada Drivers Library should be 16#40#. There’s controversy as to whether the address you specify to your support library is bits 1..7 or 0..6, i.e. whether the library expects to divide or multiply it by 2 before sending to the hardware. To confuse the picture further, Table 272 in the nRF51 RM suggests that only the 7 bits of the address are written to the ADDRESS register, with the read/write bit sent after the address bits by the nRF51 hardware; while for the STM32 range, it’s up to our software to put the address bits in the right place (bits 1 .. 7), and the library software twiddles the read/write bit (0).

    Guessing here, but it looks as though the Python library writes the value you give it straight into the ADDRESS register.


    See this Ada Drivers Library issue.