DUELink and I2c

Hello,

I’m diving in more with GHIzzly and try to connect a Qwiic Button from sparkfun on Downlink slot.

I test this code:

            var b = duelink.I2c.Configuration(400);
            Console.WriteLine("I2C Configured: " + b);
            byte address = 0x6F;
            var dataWrite = new byte[1] { 0x00 };
            var dataRead = new byte[1];
            b = duelink.I2c.WriteRead(address, dataWrite, dataRead);
            Console.WriteLine("I2C WriteRead: " + b + ", Read: " + dataRead[0].ToString("X") );
            b = duelink.I2c.WriteRead(address, dataWrite, dataRead);
            Console.WriteLine("I2C WriteRead: " + b + ", Read: " + dataRead[0].ToString("X"));

From read I should get a 0x5D, but nothing…

Have you a clue ?

I believe the upstream port of the first module may be I2C, but the downstream port will be the DaisyLinking protocol not I2C. The specifications say “Only connect DUELink modules on the Downlink connection”.

If I am wrong, then would the button be device 1, the default device, or would it be device 2? If device 2, the a Sel(2) command would be needed.

You said it, Downlink. Your code is talking to the I2C pins and not to downlink port. See here Downlink | DUELink

1 Like

Yes correct. However, DUELink is very dynamic and you can take over the downlink port to manually control it if you want. Won’t be as dynamic and as easy when using DUELink modules but it will work.

Device addresses are a DUELink thing. When you add other devices then they are simply I2C devices and you would use them like you always did pre-DUELink.

On the surface DUELink seems simple. But the more I learn the more I realize how flexible and powerful it is.

2 Likes

YES! Those little things are HUGE on features and flexibility! But you know… it is made by GHI Electronics so it is expected :nerd_face:

1 Like

:+1: Of course ! So I must found how to manage this downlink in Net ! And I love this modularity.

I think there is a confusion:

It is also possible to have a daisylink of DUELink modules where the last module (and only the last module) is switched to I2C non-DUELink mode (mode #4). This last module can now use DLI2CWr() to access those I2C non-DUELink modules.

So mode must be 4. But in mode part:

4 None Inactive
5 None I2C

So mode must be 5.

Is there a mistake in doc (or maybe I’m tired :sleeping_face:, and it can be ! :wink:)

We will check and correct the docs. But I just thought of something. What about the pull up resistors?

Can you share your code please?

Have you tried it right from scripts?

# Switch Downlink to I2C mode
DLMode(4,0)
Dim B1[]=[0x11,0x22]
# Write 2 bytes to 0x44 and read nothing
DLI2CWr(0x44,B1,[])

What I want is reproduce the code below (It’s a qwiic button connect to FEZ Pico):

using GHIElectronics.TinyCLR.Devices.Gpio;
using GHIElectronics.TinyCLR.Devices.I2c;
using GHIElectronics.TinyCLR.Pins;
using System.Diagnostics;
using System.Threading;

namespace FEZ_Pico_qwiic
{
    internal class Program
    {
        static byte[] writeBuffer = new byte[2];
        static byte[] readBuffer = new byte[2];
        static I2cDevice device;

        static void Main()
        {

            var led = GpioController.GetDefault().OpenPin(SC13048.GpioPin.PA8);
            led.SetDriveMode(GpioPinDriveMode.Output);

            var settings = new I2cConnectionSettings(0x6F, 400_000); //The slave's address and the bus speed.
            var controller = I2cController.FromName(SC13048.I2cBus.I2c1);
            device = controller.GetDevice(settings);

            Debug.WriteLine("Register: 0x00, " + readSingleReg(0x00).ToString("X"));

            while (true)
            {
                led.Write(GpioPinValue.Low);
                Thread.Sleep(500);

                led.Write(GpioPinValue.Low);
                Thread.Sleep(500);
            }
        }

        static byte readSingleReg(byte address)
        {
            writeBuffer[0] = address;
            device.Write(writeBuffer,0,1);
            device.Read(readBuffer,0,1);
            return readBuffer[0];

        }
        static byte writeSingleReg(byte address,byte value)
        {
            writeBuffer[0] = address;
            writeBuffer[1] = value;
            device.Write(writeBuffer);
            return readSingleReg(address);

        }
    }
}

And now it’s the script in console:

# Switch Downlink to I2C mode
DLMode(4,0)
Dim B1[]=[0x00]
Dim B2[]=[0x00]
# Write 1 byte to 0x6F and read 1 byte
DLI2CWr(0x6F,B1,B2)
print("B2:",B2[0])

But B2 always contains 0.
I’ve tried to do 2 operations for write and read, but same result:

# Switch Downlink to I2C mode
DLMode(4,0)
Dim B1[]=[0x00]
Dim B2[]=[0x00]
# Write 1 byte to 0x6F and read no byte
DLI2CWr(0x6F,B1,[])
# Read 1 byte
DLI2CWr(0x6F,[],B2)

print("B2:",B2[0])

What module are you using? We may have the same one here!

We need @Dat_Tran help with this but your code…

static byte readSingleReg(byte address)
        {
            writeBuffer[0] = address;
            device.Write(writeBuffer,0,1);
            device.Read(readBuffer,0,1);
            return readBuffer[0];

        }

…should look like this

fn rdReg(a)
  Dim B1[1]
  DLI2CWr(0x6F,[a],[]) # write the register address
  DLI2CWr(0x44,[],B1)
  return B1[0]
fend

or this

fn rdReg(a)
  Dim B1[1]
  DLI2CWr(0x6F,[a],B1)
  return B1[0]
fend

Can you try this for me please? Instead of 0x6F for address, try (0x6F<<1)

I think this is what you are using SparkFun Qwiic Button - Red LED - SparkFun Electronics

Looking at the schematics, they already have pull up resistors, so that is not the problem

I think we have the same button somewhere at the office!

It’s this one (or green or blue …): SparkFun Qwiic Button - Red LED - SparkFun Electronics

For code:

fn rdReg(a,b)
  Dim B1[1]
  DLI2CWr(a,[b],[]) # write the register address
  DLI2CWr(a,[],B1)
  return B1[0]
fend

# Switch Downlink to I2C mode
DLMode(4,0)
print(rdReg(0x6F<<1,0x00))

I’ve try 1 and 2 step functions, both address but without success :smiling_face_with_tear:, maybe @Dat_Tran will save us :wink:

OK I dug through code and found this

#define DOWNLINK_MODE_NULL 0
#define DOWNLINK_MODE_INTERFACE 1
#define DOWNLINK_MODE_HOST 2
#define DOWNLINK_MODE_UART 3
#define DOWNLINK_MODE_INACTIVE 4
#define DOWNLINK_MODE_SI2C 5

Looks like we did change the modes at some point but the docs were partially updated! You need 5 not 4.

Good catch (it’s what I’m thinking DUELink and I2c - #9 by Bauland)
… but it is still not working

Good news:

# Switch Downlink to I2C mode
DLMode(5,0)
Dim B1[]=[0x19,0x00] # [0x19,0x02] will light on
# Write 2 bytes to 0x44 and read nothing
DLI2CWr(0x6f,B1,[])

Button light is off (previously is was on).
So Mode should be 5, and docs must be change. I notice a lot of reference to 4, and only 1 to 5.
Address is correct.
Now I have just to find how to read register, but it is a good start ! :wink:

1 Like

Oh that is great news. Docs were corrected, thanks for heling.

Now, to figure out the read issue. Are you sure you need to read register 0? Are there any other registers? I looked at the sparkfun docs but it was not clear to me.

Note that there might be a bug as this is a rarely used feature. We will check on Monday.

:+1: speedy as usual :wink:

I don’t need to read register 0x00 but for ensure device is responding. But I have to read register 0x03 to retrieve button status.

No worries, it could wait ! Even it is checked after Christmas or New year day :sweat_smile: Take time to rest too !

Register 3? Please share your entire script because I think you were reading register 0.