Go Down

Topic: Blocking Blues: TWI, Serial and SPI together (Read 2008 times) previous topic - next topic

I'm interfacing GPS (using New Soft Serial), Compass (I2C), and WiFi (SPI), along with miscellaneous simpler sensors.

The blocking behavior of the Wire (TWI) library and New Soft Serial strike me as probably incompatible, asking for all kinds of strange problems if I try to use them together. I'm creating an interrupt-driven, callback, version of Wire, but it looks to me like New Soft Serial is still going to spend all it's time blocking, while its reading the GPS.

Is there a library that can use arbitrary IO pins for Serial IO (as New Soft Serial does), that uses the built-in timers to generate interrupts, rather than blocking for the receipt of each bit on the serial line?
Thumbs Up!
Gene Knight

retrolefty

Quote
but it looks to me like New Soft Serial is still going to spend all it's time blocking, while its reading the GPS.


Newsoftserial uses interrupts on received data, so not blocking.

Lefty

Well, sort of. The interrupt does occur at the beginning of the start bit, *but* then it stays in the interrupt service routine, doing a series of "tunedDelay"s until the whole character is received!

from void NewSoftSerial::recv()
:
    for (uint8_t i=0x1; i; i <<= 1)

    {

      tunedDelay(_rx_delay_intrabit);

      DebugPulse(_DEBUG_PIN2, 1);

      uint8_t noti = ~i;

      if (rx_pin_read())

        d |= i;

      else // else clause added to ensure function timing is ~balanced

        d &= noti;

    }


The ISR returns when the stop bit is received, but then the whole process starts again a few microseconds later, with another start bit.

Unless I'm missing something important, it seems to me that NewSoftSerial spends 98% of the Arduino's resources doing tunedDelay.
Thumbs Up!
Gene Knight

PaulS

Quote
Unless I'm missing something important, it seems to me that NewSoftSerial spends 98% of the Arduino's resources doing tunedDelay.

I suppose that depends on how much data the Arduino is receiving. If there is that much data, you won't have resources left to do anything else, anyway.

To answer your original question, no, there is no better software serial implementation available for the Arduino.

Perhaps you just need to spend a few bucks and get a Mega.

What I'm thinking is that every second a GPS sends a torrent of data. During this time, the controller is basically swamped if it's using NewSoftSerial.

These are *not* low-processing-power devices! National defense hung on processors of less power not that long ago.

If the device isn't spending all its time in some silly delay loop, it can easily pack away the characters received, and do other useful stuff.

Is it possible to get an interrupt for both falling and rising edges on a digital pin? I believe it is. I'm going to try my hand at responding to those interrupts and assembling received characters that way. We'll see!
Thumbs Up!
Gene Knight

PaulS

Quote
Is it possible to get an interrupt for both falling and rising edges on a digital pin? I believe it is.

Yes, use CHANGE as the 2nd argument to attachInterrupt.

Nick Gammon


I'm interfacing GPS (using New Soft Serial), Compass (I2C), and WiFi (SPI), along with miscellaneous simpler sensors.

The blocking behavior of the Wire (TWI) library and New Soft Serial strike me as probably incompatible ...


You could use the hardware serial, couldn't you? Failing that, for around $6 add a second Atmega328 processor and have it handle the GPS (using hardware serial) and send the results via I2C to the main processor. Or use a Mega.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

I don't know why you guys have so little faith in the chips we've got!

20 Mips is a *lot* to work with. The problem is these stupid blocking libraries that we have. I have similar issues with the TWI Wire library. I'm not familiar yet with the SPI library, but I'll bet it has the same issues.  All of these are fixable.

I have an interrupt service routine written that takes Serial RX input from an arbitrary pin (like NewSoftSerial), finds the start bits, and packs the bits away properly as characters, with basically zero overhead (a few C lines for each interrupt). Tomorrow, I'll "normalize" it so that it can be used as the serial input to the TinyGPS library, and put it where others can use it. At some point I'll do a Tx part, and make it work as a replacement for NSS.

To answer some of the questions:

I don't want to use Rx and Tx, because it makes the programming and debugging significantly more difficult. I don't want to use the Mega, because I'm using LinkSprite's Diamondback, for the WiFi functionality.

The Arduino is a *way* powerful chip, but it's spending all it's time in wait loops!

No Blocking! Free the Arduino!
Thumbs Up!
Gene Knight

retrolefty

Quote
20 Mips is a *lot* to work with.


16 Mips in the case of an Arduino board.

Quote
Tomorrow, I'll "normalize" it so that it can be used as the serial input to the TinyGPS library, and put it where others can use it. At some point I'll do a Tx part, and make it work as a replacement for NSS.


That would be a nice contribution, thanks in advance.


Lefty

wayneft

I2C GPS Shield

Checkout my Open Source GPS Tracker on Kickstarter

It only does receive and doesn't actually put the last character into the buffer until the next one is received, but it doesn't block!

http://telobot.com/downloads/nbserial.zip

For GPS, I'm using the SkyNav SKM53 ($30 on ebay, including shipping!) on a prototyping board from Radio Shack, cut down to Arduino size. It accommodates the GPS, tilt-compensated LSM303 Compass (SparkFun, with added 1.8v to 5v level shifters), L293D Motor Controller, as well as connections for several distance sensors and a quadrature rotary encoder. And, of course, the SPI WiFi.

The GPS works great, easily acquiring a signal at my indoor workbench, next to the EMI-noisy computer.

It is to make all these things work smoothly together that I'm interested in non-blocking libraries.

Next: a master-only, non-blocking TWI Wire library, and then I'll come back and pretty-up NBSerial.
Thumbs Up!
Gene Knight

bHogan

Quote
What I'm thinking is that every second a GPS sends a torrent of data.


If that's part of your problem, shut off the constant data from the GPS and only request the sentence when you need a fix (so to speak). i.e.
Code: [Select]

// send the GPS these strings on init . . .
#define GGA_OFF  "$PSRF103,00,00,00,01*24\r\n"
#define GLL_OFF  "$PSRF103,01,00,00,01*27\r\n"
#define GSA_OFF  "$PSRF103,02,00,00,01*26\r\n"
#define GSV_OFF  "$PSRF103,03,00,00,01*27\r\n"
#define RMC_OFF  "$PSRF103,04,00,00,01*20\r\n"

// send this just before you check for a read . . .
#define RMC_READ  "$PSRF103,04,01,00,01*21\r\n" //  used to REQUEST a RMC sentance


"Data is not information, information is not knowledge, knowledge is not understanding, understanding is not wisdom."
~ Clifford Stoll

retrolefty

Quote
It only does receive and doesn't actually put the last character into the buffer until the next one is received, but it doesn't block!


Well that could be a show stopper depending on the protocol being used?

Lefty

The point is that the net processing power of the controller goes *way* down when its receiving data through NSS. If there's other stuff that it should be paying attention to, it's probably going to do funny things. True interrupt-driven code is definitely the way to go. Everything else is worse.

Indeed, holding onto that last character until another one comes along is definitely not good behavior! It's OK for my application, because there's always more GPS data coming to move it along, but that's not true for others. I'll fix it soon.

I got the transmit portion of TWI over to full-interrupt-driven, wait-for-semaphore mode. When the receive portion works, the hard part there will be done, and I'll fix the receive portion of NBSerial, and maybe add the Tx.
Thumbs Up!
Gene Knight

Nick Gammon

Sounds great! Look forwards to seeing it. Bear in mind many people are not comfortable with asynchronous programming models so some clear examples will help.

On this forum, for example, it is hard to explain the "blink without delay" technique. Doing something like starting a TWI transmit, and having it complete later, will require more coding complexity.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Go Up