IO60P16 Module driver (strikes back!)

I’ve started a new thread for this module driver. The old thread is here
http://www.tinyclr.com/forum/topic?id=6860

@ Ian
I’ve switched back to ceberus and io60p16 module. I got last release from codeplex. The condition of my test is simply cerberus with io60p16 module and DP with external power. The board is running with native software I2C (no define set in the code).
Here are some testing issue:

[quote]1. I dicovered that if I use “iport = new GTM.GHIElectronics.IO60P16.InterruptPort(io60p16, IOPin.Port1_Pin0);” to create interrupt, there’s no way to drive Pin0 of Port0. Total darkness of the reason. If I use “io60p16.SetInterruptEnable(IOPin.Port1_Pin0, true);” to set interrupt, on the pin there’s no problem. I’ve checked code, checked on the analyzer … no clue.
[/quote]

[quote]2. I’ve tried to make a ReadStatusRegister() that read all the 8 status reg. It’s faster, and may be better than reading the 8 regs in a loop.


//// Read all the int status registers on one transaction
        public byte[] ReadInterruptStatus()
        {

            lock (_lock1)
            {
                var writeBuffer = new byte[] { INTERRUPT_STATUS_PORT_0_REGISTER };
                var data = new byte[8];

                // Bring the pointer to the needed address
                _i2cDevice.Write(writeBuffer, 0, 1);
                _i2cDevice.Read(data, 0, data.Length);

                return data;
            }

        }

[/quote]

[quote]3. Most of other functions of the driver are working fine, also PWM I’ve not tested in depth for now.
[/quote]

If I’ve news will post again.

[quote=“dobova”]I’ve started a new thread for this module driver. The old thread is here
http://www.tinyclr.com/forum/topic?id=6860[/quote]
I thought we were trying to break a record for longest thread over there :wink:

So, when you create an interrupt port on Port1_Pin0 you aren’t able to drive Port0_Pin0? Or did you mean Port1_Pin0? I know before you were having problems with Port0_Pin0 but I thought that was when you were working with that pin. As I recall, I was unable to reproduce that one when using hardware I2C and added that to a list of issues probably caused by SoftwareI2C. If you’re using different test code than before, post it and I’ll see if I can reproduce again.

[quote]2. I’ve tried to make a ReadStatusRegister() that read all the 8 status reg. It’s faster, and may be better than reading the 8 regs in a loop.


//// Read all the int status registers on one transaction
        public byte[] ReadInterruptStatus()
        {

            lock (_lock1)
            {
                var writeBuffer = new byte[] { INTERRUPT_STATUS_PORT_0_REGISTER };
                var data = new byte[8];

                // Bring the pointer to the needed address
                _i2cDevice.Write(writeBuffer, 0, 1);
                _i2cDevice.Read(data, 0, data.Length);

                return data;
            }

        }

[/quote]

Good point. This might be useful in some other places as well. I may just change ReadRegister to return a byte instead of just a byte then we wouldn’t need another function that essentially does the same thing.

I haven’t finished adding the new constructor and properties to PWM yet. I took a break for the Red Bull contest and haven’t gone back yet. I’ll be out of town this weekend but I’ll try to get something done tonight and when I return. I need to get this behind me so I can focus on some demos I need to create.

Minor issue: you don’t need to do these allocations under a lock since they’re locals - there’s no chance of concurrancy problems…

Or, if you made it like this…


public void ReadInterruptStatus(byte[] data)

…you could avoid one allocation per call and let the caller reuse an existing buffer. You might also be able to get away with making writeBuffer a const, which would make this method have 0 allocations.

I confess to not really having read the old thread. Appologies if this has already been discussed & rejected…

Don’t worry I’m out of town too, but I’ll bring a hydra with me and my dell… Just to get busy…
I confirm the problem is sure related to software i2c and the issue is exactly on port0 pin0 … Fancy that is only on that pin.

@ ddurant, the concern isn’t really regarding locking around writeBuffer or data. The concern has more to do with creating atomicity around these statements.

// Bring the pointer to the needed address
                _i2cDevice.Write(writeBuffer, 0, 1);
                _i2cDevice.Read(data, 0, data.Length); 

If another thread were to call Write() after the first statement and before the Read() then we could end up reading the wrong registers. In case you aren’t familiar with I2C, the Write() is used to position us at the register to start reading from and the Read() tells it how many bytes to read starting from where we currently are located. So, these things have to happen as a single operation. The lock could definitely be tightened up a little though to only surround these lines.

Yup - the comment was only that the allocations don’t have to be done while holding the lock. Probably doesn’t matter as much on the little boards we use but on a larger machine, having them outside the lock would allow a 2nd thread to do its allocations while the write/read was still happening in the 1st thread into the method.

It really was a post about minor stuff that just caught my eye since I’ve been so OCD about GC lately…

@ Gus, are you guys taking note of this? I made the assumption you were following these types problems in the other thread but I later found out that was probably a bad assumption. The problem seems to revolve around incorrect reads in SoftwareI2C. I’m not sure these are problems we’re going to be able to fix without some GHI help.

@ ddurant - you are right. Declaration can lay outside lock. My mistake…

I’m using Hardware i2c and i still cant get the interrupt to fire.
it is reading the input correctly but the interrupt is not workin for me .
please take a look at my code

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;
using Gadgeteer.Modules.GHIElectronics.IO60P16;
using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;

namespace GadgeteerApp1
{
    public partial class Program
    {

        private static GTM.GHIElectronics.IO60P16.IO60P16Module io60p16;
        private static Gadgeteer.Modules.GHIElectronics.IO60P16.InterruptPort ip0;
      


        void ProgramStarted()
        {
           


        
            io60p16 = new GTM.GHIElectronics.IO60P16.IO60P16Module(1);

     
            ip0 = io60p16.CreateInterruptPort(IOPin.Port1_Pin1);

            ip0.OnInterrupt += PulseInputX;

            var timer3 = new GT.Timer(1000);
            timer3.Tick += timer1 =>
            {

                Debug.Print("ip0: " + ip0.Read());
            };
            timer3.Start();


        }
        void PulseInputX(uint data1, uint data2, DateTime time)
        {
            Debug.Print("Interrupt triggered");
        

        } 
    }
}

is the most recient source labeled netmfx-17882?
thanks

Yes, that’s the latest version. You’re code appears to be correct. How are you triggering the interrupt?

I am just putting a jumper from ground to the solder pad
the read is seeing the input but the interrupt code “PulseInputX” never executes.

Try triggering it HIGH :wink:

do i need to changer the resister to Pullup to do that?
I tried it with the previous code but it doesnt work.
it doesn’t even read a change in input state

From what you’ve told me, I’m not sure there is a change in input state. The pin will be low by default. By connecting it to ground, you are simply ensuring that it’s still low. What I suggest, is that you connect a wire between two pins (ex. Port2_Pin0 and Port7_Pwm15) and run the following code. You should get a debug print every 200ms as the state changes from low to high. If this doesn’t work, then send me a picture of your setup & your code.


            // Test interrupts on an IO pin.
            io60p16.SetDirection(IOPin.Port2_Pin0, PinDirection.Output);
            io60p16.SetDirection(IOPin.Port7_Pwm15, PinDirection.Input);
            io60p16.SetInterruptEnable(IOPin.Port7_Pwm15, true);
            io60p16.Interrupt += (sender, args) => Debug.Print("Port: " + args.Port + "  Pin: " + args.Pin);
            var timer2 = new GT.Timer(200);
            timer2.Tick += timer1 =>
                               {
                                   io60p16.Write(IOPin.Port2_Pin0, false);
                                   Thread.Sleep(20);
                                   io60p16.Write(IOPin.Port2_Pin0, true);
                               };
            timer2.Start();   

Hi, I am new in community.
i’ have FEZ hydra kit with IO60P16 an bluetooth module.
So, i’m very interesting with your development driver for this board to make some robot.
but i didn’t found netmfx-17882 to download it.
I have some methods to configure Input/output but not PWM and interrupt :-/
I’ll like to try driver and make return to you.
Thanks :wink:

@ syl2078_fr - Welcome to the community!

The version of the driver we’re testing in this thread is located at:
http://netmfx.codeplex.com/SourceControl/changeset/view/17882

Note that some of the PWM functions are still in progress. Also, the SoftwareI2C still seems to have some issues. So, you may have problems running on an X or Y socket. I’m running on an I socket using hardware I2C w/o any problems but it does require some additional wiring. I look forward to your feedback.

tanks for the link ^^

I watch library and i have questions.
i think it’s more logic to have enum PwmPin/IOPin of “Pin.cs” into IO60P16Module class “IO60P16Module.cs”

I suppose io60p16.Interrupt is general for all interrupt, it it’ a possible mistake .
I haven’t board with me but it will very cool if interrupt works like this :

        void ProgramStarted()
        {
            io60p16 = new GTM.GHIElectronics.IO60P16.IO60P16Module(2);

            io60p16.Interrupt += new IO60P16Module.InterruptEventHandler(io60p16_Interrupt);
            Debug.Print("Program Started");
            .........
        }

        void io60p16_Interrupt(object sender, InterruptEventArgs args)
        {
            if (((io60p16.ReadRegister(0x10)) & (1 <<io60p16.IOPin. Port0_Pin0)) == 1) // 0x10 => @ of Interrupt Status Port 0 (cf doc page11 of 32)
            {
               ......
            }
        }

Looking back on it, I’d have to agree with you. I’ll probably move that around over the weekend.

The methods on the IO60P16Module class are meant to be the very low level functions that align closely with the way we have to communicate with the chip over I2C. So, there are some things like this that will communicate with multiple pins (or ports) in a single transaction.

I may have to study your example a little closer… I’m not sure why you would want to do it that way when you can do it like in post #8. This is much easier to understand and much easier to port existing code over to.

EDIT: I just realized I referred you back to the wrong sample. I meant #8 (changed above).

Thanks
indeed,^^ it’s better