Porting Built-in Ethernet and I2C bytes sent

Hi All,
I was digesting the new packages yesterday and porting my existing NETMF project to TinyCLR. I could find some helpful documentation about nearly all the features I use (USB, UART, I2C, RTC, PWM, GPIO, ADC). However, I had two questions:

1.) For I2C, is there a way to get the bytes sent? The new send function returns void. I see a struct I2CTransferResults, but don’t see how to use it. When the struct is created, does it populate the fields with the last send result? So, something like this would work?:

var result = new I2cTransferResult(); int nSent = result.BytesTransferred;

2.) Since networking support is 100% new in this, I couldn’t find any examples. Looking at the objects, I can see there is an INetworkProvider that does most of the same things the old ethernet drivers did. However, it appears that its no longer necessary to “Open” the network interface. Could you provide a simple sample for initializing the interface?

General comments so far:
1.) Transitioning a fairly large project over from pure NETMF was actually pretty straight forward. Took about two hours for a solution with 8 projects and ~6,000 lines of code.

2.) I understand why you went to the controller architecture for things like PWM, but having the frequency set on the controller and the duty cycle on the specific port is a little cumbersome. I preferred the old way, even though you had to know which ports were on the same timer. This approach makes modularity a bit harder since you need to pass in information for both the controller and the port.

Thanks,
Phil

1.int nSent = result.BytesTransferred should tell the number of byte transferred.
2.Network example:

{
    var networkController = NetworkController.FromName(EMAC_API_NAME);
    EthernetNetworkInterfaceSettings networkInterfaceSetting = new EthernetNetworkInterfaceSettings();

    // Do external Phy reset
    var gpioController = GpioController.GetDefault();
    var resetPin = gpioController.OpenPin(RESET);
    resetPin.SetDriveMode(GpioPinDriveMode.Output);

    resetPin.Write(GpioPinValue.Low);
    Thread.Sleep(100);

    resetPin.Write(GpioPinValue.High);
    Thread.Sleep(100);

    BuiltInNetworkCommunicationInterfaceSettings networkCommunicationInterfaceSettings = new BuiltInNetworkCommunicationInterfaceSettings();

    networkInterfaceSetting.Address = new IPAddress(new byte[] { 192, 168, 1, 122 });
    networkInterfaceSetting.SubnetMask = new IPAddress(new byte[] { 255, 255, 255, 0 });
    networkInterfaceSetting.GatewayAddress = new IPAddress(new byte[] { 192, 168, 1, 1 });
    networkInterfaceSetting.DnsAddresses = new IPAddress[] { new IPAddress(new byte[] { 75, 75, 75, 75 }), new IPAddress(new byte[] { 75, 75, 75, 76 }) };

    networkInterfaceSetting.MacAddress = new byte[] { 0x00, 0x4, 0x00, 0x00, 0x00, 0x00 };
    networkInterfaceSetting.IsDhcpEnabled = true;
    networkInterfaceSetting.IsDynamicDnsEnabled = true;

    networkInterfaceSetting.TlsEntropy = new byte[] { 0, 1, 2, 3 };

    networkController.SetInterfaceSettings(networkInterfaceSetting);
    networkController.SetCommunicationInterfaceSettings(networkCommunicationInterfaceSettings);
    networkController.SetAsDefaultController();

    networkController.NetworkAddressChanged += NetworkController_NetworkAddressChanged;
    networkController.NetworkLinkConnectedChanged += NetworkController_NetworkLinkConnectedChanged;

    networkController.Enable();

    while (linkReady == false) ;

    // Network is ready to used
}

const int RESET = 6 * 16 + 3; // just changed
const string EMAC_API_NAME = "GHIElectronics.TinyCLR.NativeApis.STM32H7.EthernetEmacController\\0";
static bool phyReady = false;
static bool linkReady = false;

private static void NetworkController_NetworkLinkConnectedChanged(NetworkController sender, NetworkLinkConnectedChangedEventArgs e)
{
    phyReady = e.Connected;
    System.Diagnostics.Debug.WriteLine("Phy staus " + phyReady);
}

private static void NetworkController_NetworkAddressChanged(NetworkController sender, NetworkAddressChangedEventArgs e)
{
    var ipProperties = sender.GetIPProperties();

    var address = ipProperties.Address.GetAddressBytes();
    var subnet = ipProperties.SubnetMask.GetAddressBytes();
    var gw = ipProperties.GatewayAddress.GetAddressBytes();

    var interfaceProperties = sender.GetInterfaceProperties();

    System.Diagnostics.Debug.WriteLine("Mac: " + interfaceProperties.MacAddress[0].ToString("x") + ":" + interfaceProperties.MacAddress[1].ToString("x") + ":" + interfaceProperties.MacAddress[2].ToString("x") + ":" + interfaceProperties.MacAddress[3].ToString("x") + ":" + interfaceProperties.MacAddress[4].ToString("x") + ":" + interfaceProperties.MacAddress[5].ToString("x"));

    System.Diagnostics.Debug.WriteLine("ip address :" + address[0] + "." + address[1] + "." + address[2] + "." + address[3]);
    System.Diagnostics.Debug.WriteLine("subnetmask :" + subnet[0] + "." + subnet[1] + "." + subnet[2] + "." + subnet[3]);
    System.Diagnostics.Debug.WriteLine("gate way :" + gw[0] + "." + gw[1] + "." + gw[2] + "." + gw[3]);

    var dnsCount = ipProperties.DnsAddresses.Length;

    for (int i = 0; i < dnsCount; i++)
    {
        var dns = ipProperties.DnsAddresses[i].GetAddressBytes();

        System.Diagnostics.Debug.WriteLine("dns[" + i + "] :" + dns[0] + "." + dns[1] + "." + dns[2] + "." + dns[3]);
    }

    linkReady = true;
}```

for Wifi:

    var settings = new GHIElectronics.TinyCLR.Devices.Spi.SpiConnectionSettings()
    {
        ChipSelectLine = SPI_CS,
        ClockFrequency = 4000000,
        Mode = GHIElectronics.TinyCLR.Devices.Spi.SpiMode.Mode0,
        DataBitLength = 8,
        ChipSelectType = GHIElectronics.TinyCLR.Devices.Spi.SpiChipSelectType.Gpio,
        ChipSelectHoldTime = TimeSpan.FromTicks(10),
        ChipSelectSetupTime = TimeSpan.FromTicks(10)
    };

    networkCommunicationInterfaceSettings.SpiApiName = SPI_API_NAME;
    networkCommunicationInterfaceSettings.GpioApiName = GPIO_API_NAME;
    networkCommunicationInterfaceSettings.SpiSettings = settings;
    networkCommunicationInterfaceSettings.InterruptPin = SPI_INT;
    networkCommunicationInterfaceSettings.InterruptEdge = GpioPinEdge.FallingEdge;
    networkCommunicationInterfaceSettings.InterruptDriveMode = GpioPinDriveMode.InputPullUp;
    networkCommunicationInterfaceSettings.ResetPin = RESET;
    networkCommunicationInterfaceSettings.ResetActiveState = GpioPinValue.Low;
    
    var networkController = NetworkController.FromName(WIFI_API_NAME);

    WiFiNetworkInterfaceSettings networkInterfaceSetting = new WiFiNetworkInterfaceSettings()
    {
        Ssid = "YourSSID",
        Password = "YourPass",
    };```

The rest should be same as  ethernet

No answer to your questions but i’m exited that this transition went so smooth :slight_smile: I have a 7 project 8000 lines solution that i have to port.

2 Likes

Thanks Dat_Tran! I am now ready for some hardware (I think)!

1 Like

I will let the experts answer the first 2 questions…

Glad you see the value of what we have.

This was a very bad thing in NETMF. IF 2 pins shared the same timer, modifying a pin would automatically modify the other pin, which created a lot of problems. It is more work now but you are now 100% sure of what pins are doing what.

Yeah, I suppose I can just make my own PWM objects that combine the controller and the port if I want it to behave as it did in the past. It is definitely more clear to those new to the platform the way you are doing it now, and will likely avoid significant confusion.

1 Like

Yeah David, I am sure there will be a few gotchas when I actually get on hardware, but the solution has no errors. I think the worst part was that Debug.Print was changed to Debug.WriteLine… that accounted for about 5,300 lines of my 6,000 lines of code :stuck_out_tongue:

1 Like

Aww… did a quick check, only 21 over here :roll_eyes:

I am having a bit of trouble with I2C now that I have hardware to test. Here is my initialization:

        newLEDStrip.config = new I2cConnectionSettings(address);
        
        var controller = I2cController.FromName(SC20260.I2cBus.I2c1);
        
        newLEDStrip.i2c = controller.GetDevice(newLEDStrip.config);
        newLEDStrip.StripName = name;

        return newLEDStrip;

Then my send method looks like:

    internal int SendCommand(byte[] command)
    {
        i2c.Write(command);

        var result = new I2cTransferResult();
        int nSent = result.BytesTransferred;
        //int nSent = I2cTransferResult;
        //int nSent = i2c.Execute(command, 100);
        if (nSent == 0)
        {
            throw new Exception("Error writing to LEDStrip");
        }
        //Debug.Print( nSent.ToString() +" bytes sent via I2C" );
        return nSent;
    }

When I attempt to run this, I am getting the following exception:

#### Exception System.Exception - CLR_E_TIMEOUT (1) ####
#### Message: 
#### GHIElectronics.TinyCLR.Devices.I2c.Provider.I2cControllerApiWrapper::WriteRead [IP: 0000] ####
#### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::WriteRead [IP: 0021] ####
#### GHIElectronics.TinyCLR.Devices.I2c.I2cDevice::Write [IP: 000c] ####
#### IPT.LEDStrip.LEDStrip::SendCommand [IP: 0009] ####
#### IPT.LEDStrip.FastEvent::Write [IP: 0009] ####
#### IPT.LEDStrip.InitMODE1::Run [IP: 000a] ####
#### BuzzerTest_TinyCLR.Program::initialize [IP: 0005] ####
Exception thrown: 'System.Exception' in GHIElectronics.TinyCLR.Devices.I2c.dll

I do not actually have a device connected yet, so I am expecting to get 0 back on the send.

Address is 0x67, speed 100 kHz. Debugging in, address shows properly as dec: 103. This runs on the G120 with the necessary mods to the send method and config. The data being sent is a byte[25] with a series of bytes the sets the registers of the LED controller.

you need a slave device connect to.

1 Like

got it. I’ll wire something up tomorrow to actually talk to. Just getting all my libraries ported over for now and making sure they all run.

1 Like

Hi Dat. Back to the ethernet for a second. It appears as if SocketOptionName.DontLinger is set to -129 and its throwing an exception (InvalidOperationException) in NetworkControllerApiWrapper.SetOption. Is this option not available? Is the enum just wrong? I see one other negative number, and its ExclusiveAddressUse = -5.

Following your example above, I can’t get my ethernet to do anything. I have tried with DHCP and with a static IP (I use static IP on the G120E). It won’t grab an IP address when using DHCP and I can’t ping it when using a static address. I have tried direct connection as well as through a known working switch (I can run it with my G120E hardware). Not sure posting code will do any good since I just directly copied your example. Any suggestions?

Could it be a MAC address issue?

I changed that to a valid one from the example as well.

Are you using G120E or SITCore?

Also change Reset pin if you are using SITCore, it was PG12

const int RESET = SC20260.GpioPin.PG3;

The example above posted from 2019 may old with your hardware. pin RESET need to change PG3

I am using SITCore, but validating my network infrastructure with a G120E. The G120E works in the same network environment that the SITCore does not.

I changed the reset pin, no dice. I also went to the SITCore docs and aligned directly with that example. Still no joy. Tried with and without DHCP on a switch and on my gateway. No love. I never get ANY packets from the static IP I assigned and the DHCP assigned address output 0.0.0.0 in the debug output, so looks like its not getting an address. Never a blink from the green light on the port except when the reset pin is toggled.

hi, preview2 has 2 versions, can you please try older one?

latest is 2.0.0.21000
older is 2.0.0.20000

thks a lot

No change.