Use interrupt with IO60P16 module

I spent several hours on this tonight and so far I’ve yet to be able to generate a single valid interrupt. I know the last time we tested this it was working fine. So, my assumption at this point then is that there’s something in the new 4.2 SDK that is messing it up but I’m not sure what yet. I’ve tried SoftwareI2C and hardware I2C.

Dobova, are you able to generate any interrupts from yours?

What versions of the SDK are you guys using?

I did find one little bug. Gus, you’ll want to fix this in your driver. In Port.cs, OnParentInterrupt() should be as follows…

        
        private void OnParentInterrupt(object sender, InterruptEventArgs args)
        {
            if (args.Port != PortNumber || args.Pin != PinNumber) return;
            if (OnInterrupt != null)
            {
                OnInterrupt(args.Port, args.Pin, args.Timestamp);
            }
        }

I’m going to go sleep on it now and will try again tomorrow night. Either the module is not longer throwing interrupts or the mainboard is no longer detecting them.

Hi ian,
I’ve done some testing on interrupt and I got it working. But I’ve used your last codeplex driver not the sdk from ghi ver. I’ve used hydra with last fw and last sdk.
I’ve some suggestion about this stuff, but now I’m writing from iPhone and getting crazy… I will be back in office on Saturday and I will do more testing. I will back again heretofore report.

I hope you can figure this out because I’m getting nowhere. It seems that something in the I2C is not working again.

Tomorrow I will spend time on this test. But I have used int with your code 2 weeks ago and no problem. In a post I attached an image from logic analyzer showing it. Very strange…
I’ve used software i2c built inside the last sdk from ghi.

the curse of the module io60p16 …

Were you using GTI.SoftwareI2C or SoftwareI2CBus?

I just tried it on my Cerberus and it works perfect. It appears the problem is with the Hydra. I’ve tried it with two different Hydras all running the latest 4.2 QFE2 (v4.2.3.0 Aug 23) firmware and got the same result from both. Is that the same version as you?

Here’s my test code. I have a wire between op1 and ip.

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

            Debug.Print("Program Started");

            Debug.Print("InterruptEnable:  " + io60p16.GetInterruptsEnabled(7));
            var op1 = io60p16.CreateOutputPort(IOPin.Port6_Pwm6, false);
            var ip = io60p16.CreateInterruptPort(IOPin.Port7_Pwm14);
            ip.OnInterrupt += (data1, data2, time) => Debug.Print("Exterminate!");
            Debug.Print("InterruptEnable:  " + io60p16.GetInterruptsEnabled(7));
            var t = new GT.Timer(1000);
            t.Tick += tmr =>
            {
                Debug.Print("Tick.");
                op1.Write(true);
                Thread.Sleep(100);
                op1.Write(false);
            };
            t.Start();
}

EDIT: In my original test that worked, I was using SoftwareI2CBus. I tried again using GTI.SoftwareI2C. This did not work and seemed to result in exactly the same results as I was getting with the Hydra.

I’m using this code on Hydra, last SDK and your driver in codeplex, serial Softwarei2cBus connection:


void Test_2()
{
            iport = new GTM.GHIElectronics.IO60P16.InterruptPort(io60p16, IOPin.Port1_Pin0);
            Debug.Print("InterruptEnable: " + io60p16.GetInterruptsEnabled(1));        // prints 255
            //iport.ClearInterrupt();
            iport.OnInterrupt += (port, pin, time) =>
                {
                    iport.ClearInterrupt(); // why I need this !!!????
                    if (port != 1) return;
                    io60p16.Write(IOPin.Port0_Pin2, int_state);
                    //Debug.Print("Port: " + port + "  Pin: " + pin);
                    int_state = !int_state;
                };

            Thread th = new Thread(new ThreadStart(Test_Thread));
            th.Start();
            Thread.Sleep(5);
            //new Thread(new ThreadStart(Test_Thread2)).Start();
            return;
}

        void Test_Thread()
        {
            Thread.Sleep(50); // wait some settle time
            while (true)
            {
                //io60p16.Write(IOPin.Port0_Pin0, true);
                io60p16.Write(IOPin.Port3_Pin7, false);
                io60p16.Write(IOPin.Port5_Pin0, true);                
                Thread.Sleep(300);
                //io60p16.Write(IOPin.Port0_Pin0, false);
                io60p16.Write(IOPin.Port3_Pin7, true);                
                io60p16.Write(IOPin.Port5_Pin0, false);
                Thread.Sleep(300);
            }
        }

a wire is connected from Port5 pin0 to port1 pin0 (int pin selected). As you can see I’m using interrupt handler on the InterrupPort class, not on the generic module class.
I noted that if you use debug.print inside loops it probably makes some lock on threads and int does work just one or two times than it locks up in high condition.

PS: Try to avoid timer and use a thread to see if it is better. Timer is not good on my test.

The driver mostly works on Hydra but only if I keep a very long time loop (from 700ms and up). My idea was to use something like this method:


        /// <summary>
        /// Read in one shot all status registers (10h..17h)
        /// </summary>
        /// <returns>an array of 8 bytes representing the 8 registers values </returns>
        public byte[] ReadAllStatusRegisters()
        {
            lock (_lock)
            {
                var writeBuffer = new byte[] { INTERRUPT_STATUS_PORT_0_REGISTER };
                var data = new byte[8]; // read 8 registers in sequence
 #if HARDWARE_I2C
                _i2c.Write(writeBuffer, 20);
                _i2c.Read(data, 20);
 #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
                // Bring the pointer to the needed address
                _i2cDevice.Write(writeBuffer, 0, 1);
                // Read the address
                _i2cDevice.Read(data, 0, data.Length);
 #endif
 #endif
                return data;
            }
        }


The chip can be read as multiple consecutive bytes from a register . So setting register 10h and reading 8 bytes you get all status register from 10h to 17h.
This would speed up a lot the clear interrupt code, but for some reason the sw i2c doesn’t work reliable, somtimes reading, sometimes not.

As a trick, I think that the best approch for Int is to use a structure/variable, local to the driver, to keep track of which int is enabled and than which status reg need to be read during int routine. Making 8 transaction anytime an int is fired is messing up a lot the things.

Just FYI the code is working fine on Cerberus. So the problem is relative to Hydra.

Good idea regarding reading all 8 bytes at once. I’ve updated the driver to take advantage of this efficiency. However, this didn’t seem to help the Hydra. The problem seems to be at a lower level on the Hydra because the pin #3 interrupt signal is never being raised. Therefore, none of this code ever gets a chance to execute.

Gus, are you following this thread?

Ian, I’m now working with Hydra in hardware I2C and still doesn’t work. I will try to change socket. I’m using n.6 and not working INT.
Mhhh… what’s going on here …???

Software i2c was fixed and you shouldn’t need to use hardware anymore.

I understand but no method seems to be working on the Hydra. Works fine on Cerberus.

Yea. I’ve done all that too. Nothing seems to help.

On Hydra seems that INT is misterious. With I2C Hardware and software reach same result: not working. I’ve analyzed i2c traffic and I found nothing wrong. All other function of the Cypress chip works fine, but no INT available.

When issue a Reset() command (reg 30h, function 07h) I see INT line go down, but then it goes up again when enable int on pin, and never reset anymore.

That seems consistent with the behavior that gnomathibus is seeing and I see sometimes. When I first start up the app it will sometimes fire an [false] interrupt for all pins and then never fire another interrupt after that. So, it would seem that maybe there’s a pullup resistor being enabled on pin #3 on the Hydra?

EDIT: Scratch the pullup theory. Stepping through the code slowly proved this to not be a possibility as the cause.

Something else to add that I just discovered… If I F10 step through the code from the very beginning then it will work on the Hydra. I can step through the code and trigger an interrupt and the events get thrown as expected. As soon as I hit F5 and let it go full speed then nothing happens again. Could the Hydra be having a hard time keeping up with I2C? I’m wondering if some of the optimizations to the Hydra in the last release have done something to cause the timing to change. I’m going to start experimenting with adding waits at various spots.

I was supposing something like you are saying and I have inserted some delay in critical parts but need better testing. The problem still exist in hardware i2c … I had int working fine 2 weeks ago, same sdk and firmware… I’m confused now. Take a look at msg #11 of this thread … that was hydra!!!

Tomorrow will dedicate some time more… I hope to help solving the problem.

Making futher tests:

  1. Hydra with Ethernet firmware works differently from Hydra with NON Ethernet firmware. This means that operations time does have sense. The ethernet fw works better, so some delay gets better results.
  2. using this modification:

        void Test_Thread()
        {
            //lcd.Clear();
            //Thread.Sleep(20);
            //lcd.SetCursor(0, 0);
            //lcd.PrintString("Program Started");
            Thread.Sleep(100);
            while (true)
            {
                iport.ClearInterrupt(); //// <---------------------------with this line the INT works fine !!!
                //io60p16.Write(IOPin.Port0_Pin0, true);
                io60p16.Write(IOPin.Port3_Pin7, false);
                io60p16.Write(IOPin.Port5_Pin0, true);                
                Thread.Sleep(200);
                //io60p16.Write(IOPin.Port0_Pin0, false);
                io60p16.Write(IOPin.Port3_Pin7, true);                
                io60p16.Write(IOPin.Port5_Pin0, false);
                Thread.Sleep(500);
            }
        }


This modification show that the reading back status regs in the interrupt routine fails to clear int most of the time !! Why ???
Obviously in a thread loop like this in the test is easy to work out, but what if I use an asyncronous event like a button ??
I point my fingers to the “lock” statement …

That does help some. If you add the following as the first line of your loop then you’ll see that the value of the interrupt enable register fluctuates from 255 to the correct number. I don’t believe that the value is actually changing. It seems that the reads are still not working properly.

                Debug.Print("InterruptEnable:  " + io60p16.GetInterruptsEnabled(7));

I’ve been using the non-ethernet firmware. I haven’t test yet on the ethernet version.