Use interrupt with IO60P16 module

I get this value so I think it’s reading correctly. If you have a sequenze of code the thing works fine. I see that problems are arising when timers or thread continue to poll/write registers. I try now to make a small program, that use int with a button, and without loops running i2c commands. I still think that problem are mostly in the locking system.

I get that sometimes. Usually, the first time I get 255 & 255 on the Hydra. On the Cerberus, it’s always as expected. My earlier tests were with just a wire/button that I was manually connecting to the interrupt pin and no loop. It still didn’t work because it doesn’t think there are any interrupts enabled and the interrupt signal would get stuck on high.

Ok so you just tested it … I’ve Hydra working now with the ClearInterrupt() call in the loop.
Analyzing the I2C protocol I see that commands are correct starting with reset and activating int on port/pin. I clearly see that the sequence of i2c command is not as expected, but mixed up, becouse reading status regs 8 times in the int event is a long task. Also reading 8 regs at a time is fancy and it does not resolve the issue …
I don’t know why reading status register in the int doesn’t reset signal, and instead it works fine in the main loop !!!

Ian,
at this point I suggest:

  1. try to comment out all the interrupt event status reading in IO60P16module class and in Port class. You probably will see int running correctly. In my test it’s woking fine. Obviously in this case you get all the INT also on other pin/port.
  2. Get rid of the Port method EnableInterrup(), DisableInterrupt() and OnParentInterrupt() and move in InterruptPort class.
  3. I will write an helper method that check if INT is “mine”, so you read just your InterruptPort and not all the 8 registers. This logic move to user service routine the responsability to check if INT has to be managed.

As an alternative:

  1. we can create a static structure of some kind in the InterruptPort class just to set which port need to be read from status regs.

This just an idea …

I’ll give it a try but I’m not sure I understand why you think this will help. I haven’t seen anything yet that suggests the problem is in using the Port/InterruptPort classes. Do you have a test that is working consistently using any method on the Hydra?

I think that your classes are fine and they work perfectly, but I think the real hardware has some limitation on this side.
I’ve tried simpy to comment the port reading loop in OnInterrupt() event method and the thinks works fine on my Hydra. So I simply suggest to consider some modification to get a vary simple event management and let user to manage all the details in application.
I’ll show tomorrow some code about that.

Ok. I think I know where you’re going but I don’t think we can avoid the port reading loop since there’s no other way to determine which pin raised the interrupt. I’ve got a couple more ideas I’m going to try tonight.

Also, I think we need to be able to solve this at the driver level. As an end user, I would hate to have to deal with this every time a new board change comes out. Maybe we can do a startup test during module initialization to figure out latency and adjust automatically elsewhere (if we can figure out where “elsewhere” is exactly…).

@ ianlee74 - I understand what you mean and I absolutely agree. But at the end of the day, the user need just check if INT is of interest and simply clear Itself. We can supply very easy metodo to do that.

So, I broke this down into as simple a test as possible to set the interrupt enable for a single pin and then just continually read back the interrupt enable status. I eliminated all code except ReadRegister() & WriteRegister() and tried it with and without the locks enabled. The results clearly show that I2C reads are still not working correctly. I tried stepping through the loop slowly to give it plenty of time and still the values read back were inconsistent.

Dobova, unless you have an idea on how to make this simple test return correct results then I’m ready to hand this over to GHI. I’ve managed to waste another weekend on this module…


        void BareMetalTest()
        {
            // 1.  Read current status of interrupt enable register.
            io60p16.WriteRegister(0x18, 7);                 // Select port
            byte intStatus = io60p16.ReadRegister(0x19);
            Debug.Print("InterruptEnable:  " + intStatus);

            // 2.  Enable interrupt on port #7 pin #14.
            io60p16.WriteRegister(0x18, 7);                 // Select port
            io60p16.WriteRegister(0x19, 191);            // Set interrupt enable bit.

            // 3.  Keep reading values...
            while(true)
            {
                io60p16.WriteRegister(0x18, 7);                 // Select port
                intStatus = io60p16.ReadRegister(0x19);
                Debug.Print("InterruptEnable:  " + intStatus);
                Thread.Sleep(500);
            };
        }

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

            Debug.Print("Program Started");

            var t2 = new Thread(BareMetalTest);
            t2.Start();
        }

Results:

[quote]Program Started
InterruptEnable: 255
InterruptEnable: 191
The thread ‘’ (0x3) has exited with code 0 (0x0).
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 191
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 191
InterruptEnable: 191
InterruptEnable: 255
InterruptEnable: 255
The program ‘[88] Micro Framework application: Managed’ has exited with code 0 (0x0).
[/quote]

Thanks Ian …
For sure if problems are at this level we can go nowhere … At this point I’ve no more ideas …

Did you try a small

Thread.Sleep(5);

or similar wait after each write ? In the source, and if I understand it correctly, it would be at the end of the WriteRegister() method and before the i2c.Read() call in the ReadRegister() method.

This delay after a write operation is mandatory for some i2c modules (such as Eeprom) or else subsequent reads are not correct. I didn’t see any mention of such a delay in the Cypress datasheet though, but one never knows.
Maybe the delay could/should be tweaked, if necessary.

This is just an idea, I don’t promise anything.

Bec, thanks for the idea. Unfortunately, I’ve already tried putting small & large sleeps in every imaginable location :frowning: I believe this problem is unique to the Hydra.

Ian I’m lucky: I get 1 “255” every 20 “191” !!! (using Hydra with ethernet firmware)
So I2C software driver is fancy …

I will just make a test attaching cypress chip to a PIC32 …

PS: Ahahah, now using hardware I2C doesn’t work at all (read everytime 255) … mhhh

Just to clarify, also hardware I2C is NOT working correctly on Hydra. It get as repeated start what is not. So any register reading after a write, get always from reg 0h, indipendently from the previous write. This happens also on other i2c boards as well.

This NOT happen on Cerberus that works fine.

I’m not sure “fancy” is the word I’m using to describe it right now :wink:

Did you do this? Very curious.

Yea. I had tried this earlier also. There’s something very basic wrong with the Hydra & I2C.

Just for my knowledge, the GTI.I2Cbus class is a wrapper around I2CDevice class or it’s a separate implementation ?

@ ianlee74 -

Yes I did it in july becouse I’ll probably will use a cypress chip (the 9540) for a small project on pic32. I used very basic command with I2C and I’ve found no problem. I’d like to test INT now.

As far as I know it is just a wrapper. However, early in the development of this driver we found that SoftwareI2C would work where GT.I2CBus would not. I tested all three methods on the Hydra a few days ago and didn’t have any luck with any of them. I suspect they all work on the Cerberus at this point.

Probably it is separate, becouse using I2CDevice class the hardware I2C is woking fine on Hydra !!! GTI.I2Cbus has problem.


        public byte ReadRegister(byte register)
        {
            lock (_lock)
            {
                var writeBuffer = new byte[] { register };
                var data = new byte[1];
 #if HARDWARE_I2C
                _i2c.Write(writeBuffer, 200);
                _i2c.Read(data, 200);
 #else
 #if USE_DAISYLINK_SOFTWARE_I2C
                // Bring the pointer to the needed address
                _i2c.Write(DEV_ADDR, new byte[] { register });
                // Read the address
                _i2c.Read(DEV_ADDR, data);
 #else
 #if NETMF_I2C // Using this one ------> it works !!!!
                I2CDevice.I2CWriteTransaction w_trans = I2CDevice.CreateWriteTransaction(writeBuffer);
                I2CDevice.I2CReadTransaction r_trans = I2CDevice.CreateReadTransaction(data);
                // execute the i2c transaction ... 250ms timeout set.
                _i2c.Execute(new I2CDevice.I2CTransaction[]  { w_trans, r_trans }, 250 );
 #else
                // Bring the pointer to the needed address
                _i2cDevice.Write(writeBuffer, 0, 1);
                // Read the address
                // HACK:  Read multiple times until we get a repeat to help ensure we're getting the correct value.
                _i2cDevice.Read(data, 0, data.Length);
                //var r1 = data[0];
 #endif
 #endif
 #endif
                return data[0];
            }
        }


Nice find! I’ll update my driver tonight for folks to use until GTI.I2CBus is fixed.

Gus, are you still following this thread? Looks like GHI needs to look into this. Also, if you can push out your IO60P16 driver source to Codeplex then I can compare and send you some other updates/fixes I’ve made in the past week.