3
\$\begingroup\$

I have an LPC1114(FN28) that I am writing some code for. Currently I am trying to provide an asynchronous view of the I2C interface to my code (the chip has a built-in I2C controller). The controller itself is basically a state machine, but since the I2C spec specifies no timeout or other restrictions on the SCL clock rate, I should be able to delay sending (it doesn't have to be perfectly synchronous) as long as the controller controls SCL correctly when data is being sent, and holds it low when no data is being sent.

The idea is to be able to buffer data to be sent on the I2C bus. A few libraries I see around deal with this by just buffering the whole thing and bitbanging it all at once, which is okay most of the time since you generally don't send lots of data over I2C, but I want to do it properly.

I've set up the base code and the problem I am having when transmitting data is that whenever the controller enters the "transmit data to slave" mode, it triggers an interrupt requiring me to fill in a byte of data to send (or send a STOP signal). The problem is if I do nothing, it immediately issues the same interrupt, so my main code can't even get the chance to execute! What I want is the ability to tell the controller "I have no bytes to send right now, so don't issue another interrupt until I tell you to from my main code"!

I've rigged something up that works by (ab?)using the NVIC to disable the I2C interrupt when I am waiting for data, and re-enabling it when I am ready to send on the I2C interface, but this seems very unorthodox and I don't know if it is actually reliable or even correct especially if bad stuff should happen to the bus in the meantime (bus error, etc...)

Here is the manual for the chip, the docs for the I2C controller are at page 239. I thought I could use the SI control bit to tell it to not issue an interrupt until I clear it again but apparently that's not what it's for.

Does anyone have experience with this or similar I2C controllers and know how I can achieve what I am looking for? Clearly it must be possible, since a protocol where you need to have all the data ready up front every time doesn't seem viable to me.

\$\endgroup\$
  • 1
    \$\begingroup\$ "a protocol where you need to have all the data ready up front every time doesn't seem viable to me" There probably are ways around it, for example polling the register state rather than running in interrupt mode. But in actuality, preparing all the data in advance would describe the vast majority of typical uses - if you look at NXP's driver, you typically hand over an entire transaction at a time, and make decisions only in between them. \$\endgroup\$ – Chris Stratton Aug 20 '16 at 5:33
  • 1
    \$\begingroup\$ "I want to do it properly." IMO bit-banging is the proper way to do things, unless you need some of the advantages of the hardware support (speed, hands-off operation). But you loose portability, which is IMO a big loss. \$\endgroup\$ – Wouter van Ooijen Aug 20 '16 at 6:22
  • \$\begingroup\$ @WoutervanOoijen I don't consider portability a huge issue for me at the moment, I will probably be working with Cortexes and NXP's chips for the foreseeable future so if there's good hardware integrated on the chip I want to use it damnit :) however in light of your and Chris' comments I will think about better ways to structure my code to not need to jump through hoops \$\endgroup\$ – Thomas Aug 20 '16 at 9:45
4
\$\begingroup\$

Disabling the interrupt when you have no data to send is exactly the correct approach to take with a hardware I2C master controller.

When the data is available, re-enable the interrupt and you'll immediately take it, which will transfer the byte to the controller.

\$\endgroup\$
  • \$\begingroup\$ Thanks, that reassures me a little. Is it common in embedded development to just be toggling interrupts on and off back and forth all the time? So far I have only needed to enable them once and that's it, but I haven't gone very far yet. \$\endgroup\$ – Thomas Aug 21 '16 at 1:43
  • 1
    \$\begingroup\$ Absolutely! That's what they're there for! You would, for example, do the same thing with a UART transmit interrupt when you don't have anything to send. \$\endgroup\$ – Dave Tweed Aug 21 '16 at 1:46
  • \$\begingroup\$ Oh, you make a good point... I haven't used transmit interrupt for UART but am sending synchronously at the moment, if I had used it I would have likely had the same issue that I did for I2C... that clears it up. Thanks! \$\endgroup\$ – Thomas Aug 21 '16 at 2:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.