Pages: [1] 2   Go Down
Author Topic: Accessing a "Wire" object from an interrupt routine == hang, need solution  (Read 1043 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using an Arduino Uno R3 to talk to some I2C devices.  I've allocated a global pointer to my Wire instance and this works great.  I have great I2C communication.  I added an interrupt, and the interrupt works great.  Inside the interrupt I can manipulate global variables just fine (++, --, etc..).  Now my goal is when I receive the interrupt, I need to retrieve some data over the I2C bus, to see why my interrupt happened.  However, when I access my global pointer to my Wire instance, the Arduino hangs.  I'm thinking the problem is that the Wire library also uses interrupts, and this might be my problem...  Is there any way around this?  Would a different Arduino board allow me to use I2C from inside an interrupt routine? 
Logged

Offline Offline
Edison Member
*
Karma: 43
Posts: 1551
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You can set a flag variable in the interrupt routine - the variable must be global and declared volatile. In the loop function you can continuously check for the flag to be set. Once it is set, clear it and access the I2C bus.

Pete
Logged

Where are the Nick Gammons of yesteryear?

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'll give that a shot, I'm afraid I don't have enough time to do that though.  I'm using an IO Expander chip, this gives me 8 digital inputs.  When any pin changes level, I get an interrupt.  The states don't latch, so at that instant I need to capture the state of all of the pins.  The levels may only be changed for a few milliseconds, so if I don't get there in time I will miss the state.  This is why I was hoping to read the state immediately from the interrupt routine.  I'll try your suggestion, maybe I can make it happen fast enough.  Thanks for the idea.  I'm into hour 12 today, so even simple things are becoming complicated; time for a nap! smiley 
Logged

Offline Offline
Edison Member
*
Karma: 43
Posts: 1551
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I2C isn't the best protocol in that situation. At 400kHz it will take on the order of 8 milliseconds to receive a response even if you could respond to the interrupt immediately. If my suggestion doesn't work fast enough you might have to rethink the overall design.

Pete
Logged

Where are the Nick Gammons of yesteryear?

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using an IO Expander chip, this gives me 8 digital inputs.  When any pin changes level, I get an interrupt.

Which chip?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Which chip?

It's the PCA95544N:

http://www.karlssonrobotics.com/shop/i2c-io-expander-pca9554/

So far it seems to work as-advertised.  smiley
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I2C isn't the best protocol in that situation. At 400kHz it will take on the order of 8 milliseconds to receive a response even if you could respond to the interrupt immediately. If my suggestion doesn't work fast enough you might have to rethink the overall design.

Pete

Yes you have a good point...  I unfortunately don't have a scope here to time exactly how long my input state lasts, but I do know that I have to debounce it somehow and I'm thinking of using this chip:

http://www.digikey.com/product-detail/en/MAX6816EUS%2BT/MAX6816EUS%2BTCT-ND/774155

If my input state lasts long enough to work with the debouncer, then hopefully the debouncer will hold its output value long enough to give me plenty of time to read it.  I'll find out shortly. smiley   
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 91
Posts: 4690
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using an IO Expander chip, this gives me 8 digital inputs.  When any pin changes level, I get an interrupt.  The states don't latch, so at that instant I need to capture the state of all of the pins.

If you can get all 8 inputs on the same AVR Port then you can read them all at once with a Port Read. With a MEGA you have clear ports by default. With an UNO... not so easy if possible at all, better to use 2 Ports of 4 bits each.

Look up Port Manipulation on this site.
Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

Offline Offline
Newbie
*
Karma: 0
Posts: 10
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the suggestion, the port manipulation stuff looks interesting.  For this particular project, we're fixed on I2C and an Uno board (executive decision from above).  We're going to have several of these port expanders, both for more I/O and to reduce the wiring required, so unfortunately wiring direct to the Arduino isn't possible.  Our device will have a lot of modular hardware, many inputs and many outputs, and with I2C we only need to run 2 wires to each module.  We will be instructing hardware to do things, and receiving interrupts when events happen.  We have to detect the event and then control the hardware accordingly.  It worked great wired directly to a Mega 256, so now we're moving to the Uno to reduce per-unit costs.  It looks good on paper anyway..  smiley-cool 
Logged

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 91
Posts: 4690
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the suggestion, the port manipulation stuff looks interesting.  For this particular project, we're fixed on I2C and an Uno board (executive decision from above).  We're going to have several of these port expanders, both for more I/O and to reduce the wiring required, so unfortunately wiring direct to the Arduino isn't possible.  Our device will have a lot of modular hardware, many inputs and many outputs, and with I2C we only need to run 2 wires to each module.  We will be instructing hardware to do things, and receiving interrupts when events happen.  We have to detect the event and then control the hardware accordingly.  It worked great wired directly to a Mega 256, so now we're moving to the Uno to reduce per-unit costs.  It looks good on paper anyway..  smiley-cool 

To reduce per-unit cost you should use a stand-alone AVR chip (like a 328 or 1284) possibly running on internal oscillator. The external oscillator on the UNO uses 2 pins that would let you have 8 bits on one port, but I see that you don't need that.

Port expanders? I hope they're as cheap as shift registers ;^) or actually are shift registers, 2 or 3 for a buck. The kind I get are SPI bus which is 4 wires but 2 MB/sec fast (AVR running 16MHz). It's possible to write a line of those over 10,000x a second. There are bi-directional shift registers but for code simplicity I would go with daisy-chained shift register outputs on the one hardware SPI bus and perhaps inputs daisy-chained on soft-SPI.

Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

UK
Offline Offline
Faraday Member
**
Karma: 99
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Port expanders are far more than just shift registers:

1. They are bi-directional, just like a real port - set pins to be input or output.
2. Often they also provide internal pull-up resistors, just like a real port.
3. They usually provide interrupt-on-change so when an input changes state it triggers an interrupt signal (which is exactly what the OP is doing).

You can't do those with shift registers, which is why you pay more for them.

If you want to use I2C from within an interrupt routine you will have to write your own (or find one if you're lucky) I2C library that doesn't use interrupts in its operation.  The default I2C uses interrupts to manage the transfer of data from its internal buffer and the outside world and back again.  This gives a smoother transfer with no blocking happening while the transfer goes on.  If you write it to access the I2C registers directly and block waiting for each byte to transfer then it might be possible to do it inside the interrupt routine.

However, that is still not advised, as an interrupt routine should be kept as brief as possible, and doing blocking I2C inside the interrupt routine could get messy with interrupt collisions etc.
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 91
Posts: 4690
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have bi-directional shift registers, but they're surface mount. The port extenders are superior anyway. I'd just wonder about price since a small AVR might cost less.

ATtiny2313A-PU, 2k flash, 128 bytes RAM, 18 I/O pins for 95 CENTS at Futurlec.
http://www.futurlec.com/Atmel/ATTINY2313A-PU.shtml

But... do we have core data for programming them?
Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

UK
Offline Offline
Faraday Member
**
Karma: 99
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I use the MCP23017 a lot (also comes in the MCP23S17 SPI version for those that need greater throughput).  Gives 16 IO channels, 2 interrupt signals, pull-up resistors, etc.  Costs 95p at Farnell. - and no special firmware needed to get it going - just drop it in the circuit and use pre-existing Arduino libraries at the bus master end.  The extra 30p you spend on the device you save on not having to spend a week writing the firmware to emulate the port expander.

Which bi-directional shift registers do you use?  Can they be a mixture of input and output pins, or do they all have to be the same direction?
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Pittsburgh, PA, USA
Offline Offline
Faraday Member
**
Karma: 91
Posts: 4690
I learn a bit every time I visit the forum.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Got, not used. Got surface mount by mistake and I'm bad enough soldering pins.

What I should have bought are the 74F299 in PDIP 20-pin, just over US$1 ea.
http://www.futurlec.com/74F/74F299.shtml

If you're going to use enough of something like in a product, a bit of code is no big deal.
Logged

I find it harder to express logic in English than in Code.
Sometimes an example says more than many times as many words.

UK
Offline Offline
Faraday Member
**
Karma: 99
Posts: 4153
Where is your SSCCE?!?!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Those shift registers can either be all input or all output - you can't mix and match like you can with a port expander.  Useful bits of kit though, shift registers, for things like driving LED displays and such.
Logged

Get 10% off all 4D Systems TFT screens this month: use discount code MAJENKO10

Pages: [1] 2   Go Up
Jump to: