Wednesday, April 3, 2013

New RF24 Driver Release - A Fork

New RF24 Driver Release

The RF24 driver was forked to add new features and fix bugs. These improvements are outlined below. This release's primary aim is to improve performance and increase operational reliability. I believe those aims were achieved.

The intention is to once again have my features and bug fixes merged back into Maniacbug's RF24 driver. While this is currently a fork, I hope in the near future this code will be part of the official RF24 driver repository.

My RF24 Fork: https://github.com/gcopeland/RF24

Auto-Acknowledgement Retry Bug Fix

The default timeout for auto acknowledgements is wrong. If using maximum payload size at 250Kbps, an erroneous timeout may cause errors in transmission, resulting in a failure to send. This timeout has been changed. Users who explicitly set their own timeouts via setRetries() function call are immune to this issue, assuming the provided values comply with operating requirements set out by the data sheet.


Reliability Improvements

Following each write(), the radio was explicitly powered down by the driver. I classify the previous behaviour as a bug. In order to improve reliability and performance, write() no longer powers down the radio

Additionally, powering down the radio after each write also means the radio will not receive data until a startListening() method is called. This in turn means the radio is completely deaf between the end of the write() call and the end of the following startListening() call. This latency increases the likelihood of a missed transmission for a busy, multi-node network. In doing so, needlessly adds additional SPI bus traffic. This bug decreases radio reliability and wastes time on the SPI bus. Fixing this behaviour means the radio can now function optimally from standby mode while using less application time.

By allowing the radio to enter standby mode, the radio will continue to listen for messages, including ACKs/NAKs, and transmissions which might otherwise be missed; as intended. The radio will respond dramatically faster from standby activation than it does from a powered down state. This in turn is a performance optimization. In turn reducing the window for lost packets.

This is an important improvement because while the radio is free to process both ACK/NAK reply messages, it can also receive other messages even though startListening() has not been called. The messages will simply wait in the corresponding rx pipe until it is processed by the application. As such, this change also increases the radio's parallel pipe performance. Another performance optimization.

See the Compatibility section for more details.

Higher Performance

The driver now has fewer delays and blocking calls. Fewer SPI read/writes now take place within various radio method call. This in turn means more CPU is available for applications. In doing so, a number of internal function calls were removed. This has the effect of very minor memory footprint improvements.

Multicasting

This driver adds support for multicasting. This allows a single transmitter to transmit exactly once, allowing for multiple concurrent receivers, without changing the radio's operational mode. This means use of this feature does not interfere with the use of auto-acknowledgement. This is because auto-acknowledgement is a radio's operational mode, whereby, the new multicasting implementation leverages a message's mode. As such, it does not interfere with auto-acknowledgements in any way.

Multicasted messages are inherently unreliable. Even with auto-acknowledgement enabled, multicast messages will never be ACK'd or NAK'd. They are fire and forget. Either the message is received, or its not.

To multicast a message, use the write() or startWrite() methods. There is now a third optional argument. If the third argument is not provided, or 'false' is used, it will transmit exactly as previously. If the third argument is, 'true', the packet will be multicasted.

Example: radio.write( &msg, sizeof(msg), true ) ;

Closing Pipes

A new method, closeReadingPipe() has been added. This allows for a previously opened reading pipe to be shut down. A pipe which has been closed will no longer accept messages for the corresponding pipe address.

Variable Timeouts

A new method, getMaxTimeout(), is now available. This method returns the maximum number of microseconds a read/write operation will take to successfully complete. The value is calculated based on radio configuration at the time the method is called. Reconfiguration of the radio via setRetries() will invalidate the results return from getMaxTimeout().

Compatibility

Compatibility should not be an issue unless your application depends on a power management side effect. If it does, see Power Management.

Power Management

Power management is now an explicit mechanism. Applications which errantly rely on the driver to handle power management as a side effect, will find higher power demands. The fix is for the application to properly implement powerDown() and powerUp() calls as needed.

Battery powered projects might see a minuscule increase of power requirements but ultimately its up to the application to match what was previously a side effect of the driver.

Timeout Calculation

If you previously have loops which look something like the following, where 'myTimeoutValue' is a fixed value, a better solution is now available.

unsigned long t = millis() ;
unsigned long myTimeoutValue = 250UL ;
while( !radio.available() || millis() - t < myTimeoutValue ) {
}

Now, you can initialize myTimeoutValue as follows. Notice it rounds up to the next millisecond.
unsigned long myTimeoutValue = 1 + (radio.getMaxTimeout()/1000) ;

Doing so will ensure the minimal amount of time is spent waiting for a transmission to complete.

As a reminder, if you attempt to use the code above, and if you enter that loop immediately after a write, unless you are using enableAckPayloads(), and a payload is immediately available for transmission on the remote's end, the timeout provided above will not provide time for remote's code execution to process its message and reply. As such, some experimentation may be required on a per application basis. Regardless, this mechanism allows for timed loop optimizations.

Testing

At this point, this fork has been tested by three users (me being one), on nine radios, two platforms (Arduino and Raspberry Pi), and four different makes and models of Arduino (uno, nano, mega2560, and due) of hardware. Thus far its been 100% compatible.

Update: At this point many people on both Arduino and rPi platform have tested this fork. All reports are good, confirming the validity of these changes.


Tuesday, April 2, 2013

Improve RF24 Radio Performance With Proper Addressing Schemes

RF24 Addressing Gotchas

The NRF24L01(+) radios require addresses be configured on each of its Multiciever pipelines. Without much thought, people assign addresses to these pipelines. This can be problematic because of RF decoding requirements as dictated by the preamble (data transmitted in front) of each message. Read 7.3.1 and 7.3.2 of the data sheet for more information.

A longer addressing scheme allows for more opportunity to disambiguate from the preamble. As such, in my opinion, the maximum available address length should be preferred. 40-bit addressing is most effective when proper addressing is provided to each pipeline. Per the data sheet, addresses which use single bit transitions should be avoided as they are more likely to confuse preamble message detection logic should the preamble become distorted from noise.

As such, addresses with the following octets and/or nibbles (half byte) should be avoided.

Octet values to avoid:
'0xaa' - '0b10101010'
'0x55' - '0b01010101'
'0x2a' - '0b00101010'
'0x15' - '0b00010101'

Nibble values to avoid:
'0x0a' - '0b00001010'
'0x05' - '0b00000101'
'0x02' - '0b00000010'
'0x01' - '0b00000001'

This in turn means addresses with those nibbles should not be used. Remember, a nibble is half an octet, so two of those nibbles can be used to create an octet. The octets of 0xaa and 0x55 are very bad. Always avoid them. Notice these appear in the octet list to avoid and that they are made up of a pair of nibbles from our nibble list to avoid. This is because both nibbles of both octets (both halves of the byte) are 0x0a or 0x05; making for an octet of 0xaa or 0x55. Accordingly, octets 0xaa and 0x55 represent the worst possible octet to use for an address because they exactly mirror the preamble of messages.

Other nibble combinations to avoid, for example, would be 0xa1, 0x52, x12, 0x25, so on and so on. But even simple octets, such as 0x01, 0x02, and 0x05, should also be avoided.

In general, use of values contained above is more likely to cause the loss of packets and in turn, require additional retransmissions if using the auto-acknowledgement hardware features.

But Wait, There's More

The list above is hardly the exclusive list of bit patterns to avoid. In section 7.3.2, the data sheet says, "Addresses where the level shifts only one time (that is, 000FFFFFFF) can often be detected in noise and can give a false detection, which may give a raised Packet Error Rate [(PER)]. Addresses as a continuation of the preamble (hi-low toggle; [single bit transitions, as referred above]) also raises the Packet Error Rate.

As such, an address of 0xFFFFFFFFFF should never be used. And in general, octet sequences of all bits on or off should be avoided. Which means, nibbles of 0x0F and 0x00 should be frowned upon.

Please note addressing is a little more complex and that the tips provided here. These tips should be regarded as rules of thumb rather than absolutes. Regardless, if you follow the advice here, your reliability is generally improved (PER is reduced).

Tuesday, February 14, 2012

The Arduino Learner's Project - Part II

The Rehash
In my previous blog post I explained the trials of simply starting the project and how I came about to creating my list of high level requirements. The requirements follow. As you can see, some have been crossed out since some purchases have been made.
  • microcontroller (uC) with enough ports
  • LCD for human interface
  • keypad for human interface
  • Real Time Clock (RTC)
  • power supply (and transformer)
  • wireless interface of some type
  • method for controlling irrigation solenoids
  • humidity & temperature sensor(s)
  • moisture sensor(s)
  • and eventually a nice case of some type
Since I already had purchased a 16x2 LCD arduino shield and picked my arduino (atmega2560), I had my first three items addressed. Remember, most LCD shields come with micro switches which serve as buttons, allowing for human interaction. And so these items are crossed off our list above.


Sprinkler Basics
Irrigation systems are broken into multiple zones. Each zone is sized based on the water pressure in an area. Each sprinkler head requires a fixed amount of pressure. So given a fixed amount of water pressure, each zone is broken into a given number of heads. Each zone, in turn, is controlled by a valve.

Basically the way a sprinkler controller works is by triggering a relay or triac to open or close a solenoid which opens or closes a valve. The valve in turn allows water to flow into the zone and out the sprinkler heads. Most residential solenoids require roughly 150-300mA of current while in operation. Because of water pressure constraints, normally no more than two valves (one zone) will be open at one time. By extension, no more than two solenoids need be active at one time. Though only one valve need actually be used, commonly two are used in conjunction with each other. The determining factor for one or two is based on your irrigation installation. Typically one solenoid is used per zone and optionally a master solenoid is used at the head of the system. So long as the irrigation system is running, the master value plus another for a specifically enabled zone, is active.

Some irrigation systems do no have a master valve. Others do. For some systems, the master valve is used to not only open a valve, but also to turn on a primary pump (e.g. well water) and/or boost water pump (low water pressure and/or over sized zones). Please keep in mind I'm speaking generalities here. I'm aware there are exceptions. Please verify your own installation requirements before assuming the details here are valid for you system.

As I'm using a relay board, my relay(s) holding current also needs to be added to the sum current required for operation. On my relay board, each relay requires 80mA while in operation. To keep two valves open requires a worst case of (300+300+80+80) 760mA of current. Once we add in the load for the uC, LCD display, radio interface, and inefficiency losses though our regulator, we'll be pretty close to our maximum of 1A. It may turn out I require a larger transformer, but for now, 1A (1000mA) remains my target. Worst case, I already have my eye on a refurbished 1.5A transformer for not a lot of bucks.


The Ultimate Power Source
There are many different directions to look at here but ultimately I decided to re-use the power supply of my existing sprinkler controller. This has the advantage in that it has the power required to directly drive the sprinkler solenoids without incurring additional cost.  This meant I still needed another power supply to drive the microcontroller (uC) side of things. The catch is the transformer's input is 120VAC and output is 1A@26.7VAC. I need 5VDC for my uC, display, and relays. So clearly I need to convert 26.7VAC to 5VDC.

After some asking around, most people pointed me at something like this, which provides for high efficiency switching regulation and minimal part count; which still requires several anti-ripple capacitors. After learning more about AC to DC conversion, I figured out its too small. This is because the peak-to-peak conversion will yield roughly 36VDC after basic rectification. What I really needed was something like this. Which means we just jumped from a $16.25 solution to a $26.50 solution, and I still needed my own front end circuitry to rectify AC into DC. That dog won't hunt as powering the device would become one of the single most expensive components of my build. Heresy I say, as it violates my frugal nature. And so I decided to keep looking. This is when I discovered devices based on the LM7805; switching regulators. That's more like it. After shipping its basically $10. Certainly looks like a good buy and it received a thumbs up from those who previously pointed me at the more expensive counterparts.

I then hit ebay and started looking for LM7805 based solutions. That's when I stumbled on LM2596 switching regulator based solutions. For cheap, roughly $3.00 or less, including shipping, you can get a variable output switching regulator. These typically accept up to 40VDC as input and can output up to 3A, so its perfect; even if I need to upgrade my transformer at a later date. Of course, this still requires rectification on the front end; but so did the higher priced solutions above. The disadvantage of this solution is that its larger. But even that is a little misleading as they all required several capacitors; two minimum, three recommended. The ebay solution has all that already included in its foot print.

If you need a tiny footprint, don't care about cost, or simply don't want to wait on the proverbial slow boat from China (or HK), I'm sure you'll be happy with one of the solutions above. If on the other hand, you're looking for a cheap solution, footprint doesn't matter, or delivery schedule isn't a first order concern, head to ebay. I guess time will tell if it turns out to be a frugal or foolish purchase. Having said that, I did find other frugal hobbyists who have found ample satisfaction with these low cost devices. That said, its not clear they are all equal.

Please note all of these solutions use a switching regulator for DC to DC regulation (often 85%-93% efficient). None of the above are linear regulators. For my project, this is very important as the conversion efficiency is typically much lower for the linear regulators (75%-85% efficient). In my case, would have also required a large heat sink to dissipate the heat from the inefficient conversion. Linear regulators do best when the voltage delta is small. In my case, the voltage difference is relatively very large, which results in a lot of current being converted to heat. Given my voltage spread is ~31 volts, and I only have 1A available on my transformer, and as you can see above we're already tight, I didn't consider it an acceptable loss.


Rectifying The Situation
The last part of our power source is a bridge rectifier. This is an incredibly simple circuit. It can be built with four diodes or as a single integrated package. Basically this converts the sinusoidal wave of AC input into a heavily rippled DC output.

Basically it converts the top sine wave...

...into the rippled DC wave at the bottom. I still have not decided if I'll use a bridge rectifier or make one out of diodes. In the short term I did go ahead and build a diode bridge and tested it. Super simple and easy to make. But having done so, it makes you realize how much of a foot print it requires so I certainly understand and appreciate the appeal of a smaller IC, which serves the same purpose. We'll see.

What we wind up with is a complete power supply for roughly $3.00USD, including some diodes for rectification and even some capacitors, should it turn out they are required.


The Driver
From what I've found and have been told, triacs are more commonly used for commercial controllers. But to keep things simple, I'm using a relay board, which is just a collection of relays on a board. In my case, the board is also optically isolated which means I don't need to worry about 26.7VAC ever jumping into my sensitive 5V circuitry. While triacs are typically lower current draw than relays, in my case, I believe a pre-built relay board just nicely simplifies things.

Relays do have a disadvantage beyond higher current draw, in that they are a mechanical device. As relays are an electromechanical device they do wear out with repeated use. But given the usage patterns associated with an irrigation system, I believe my choice of board will easily provide a lifetime of use. After all, if you water twice per day, three times per week, four months out of the year, you wind up with 96-cycles per year. Even if this is grossly under estimating, these relays should be good for hundreds of thousands of cycles so we should still have a lifetime of use. And even if one does fail, the relays are easy to find online and large enough for someone with bad eyes to replace them as needed.

Speaking for relay failures, should a relay fail in the open condition, since my system does have a master relay, I'm still protected. Basically my system will require the failure of two relays before I need worry about my yard becoming flooded, should it fail in the open position.


Episode Summary
So far we have selected our uC, user interface, and decided how we plan on powering everything. Next we'll start looking at our radio solution which turns into a tangent project in of itself.