Tags

, , ,

In the last post on the hydroponics sensor network, I detailed using a JeeNode as the wireless micro controller from which sensors would be connected.  Previous to that, I discussed the beginnings of a Base System that was based on an nRF24L01 wireless between a sensor node (not a JeeNode at the time) and Adafruit’s cc3000 (802.11) breakout board. 

I am calling the hardware and software that receives the sensor data – eventually from a number of sensor nodes that are monitoring and applying action from hydroponics systems throughout my house – the Base System.  I am still exploring what hardware features to include.  In this blog post, I am exploring a Base System that uses an Arduino Uno, JeeLab’s RFM12B board to receive data from a JeeNode, Adafruit’s cc3000 breakout board to send the data to an Internet service, and Adafruit’s SD Shield to keep a local store of the sensor data.

Goals

The goals of this post include:

  • Wiring up the components into a circuit that receives data from a JeeNode.
  • Discuss lessons learned.  Fortunately – or unfortunately if you have “been there, done that” since I fear my write up of these will bore you – there are plenty lessons learned since this is the first time I have put these separate components together under one Sketch.
  • Detail two areas of concern: 1) The amount of SRAM gobbled up by each component and 2) How well the components cooperate sending and receiving data over the Arduino’s SPI bus.

Challenges

The third goal makes special note of two areas of concern.  On the one hand, it is amazing how many libraries exist for all these components that “plug and play” with an Arduino.  On the other hand, there is no quality control on the libraries.  There is no mandate that says minimize the amount of SRAM used – even though SRAM on an Arduino is a very constrained resource.  There is no hardware compatibility assurances that make best efforts for components that share a bus to play well together.

For an example of hardware compatibly, take the use of the SPI bus.  A challenge with the SPI bus is summarized as a bullet point under “Disadvantages” in the SPI Wikipedia entry:

Without a formal standard, validating conformance is not possible

Wouldn’t it be great if there was a test harness for components that use the SPI device as there are for devices that are plopped into many operating systems?  Well, there isn’t. 

Steps 

The steps I’m going to take include:

  • Determine the SRAM memory footprint of each of the components to see how much of the 2K SRAM the ATmega 328p has that is being taken up.
  • Replace the JeeLink with the RFM12B board  since the JeeLink is not extensible.
  • Isolate each component with the Arduino and run the component’s “hello world” sketch.
  • Add each component to the Arduino Uno.  As each component is added, run their respective “hello world” sketch that comes with the supporting library.
  • Test if the devices “play well with others”  when they access the SPI bus. 

Amount of SRAM

Before we dive into the components, I wanted to share what I found out about determining the all important amount of available SRAM.

JeeLabs has an excellent post on measuring an ATmega’s memory use.  In addition, the Arduino memory tutorial also has some useful information. His post includes a function that will let me know how much SRAM is being taken up when a component is added.  This will give me an idea if (more likely when!) I will need an ATmega with more SRAM:

int freeRam () {

extern int __heap_start, *__brkval; 
int v; 
return (int) &v – (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

I find the above type of functions clever.  Look at this image
ATMega Memory
and note how the freeRam() function uses the address of v – the last variable put on the stack – to determine the gray area (i.e.: available memory) between the heap and the stack by subtracting the address of the top of the heap from the address of the top of the stack.  

The post also gives additional insight:

all C strings are also stored in SRAM! This explains why adding a single character to the string reduced available memory.

Luckily, the Arduino IDE provides a way to stick strings in Flash – of which the AtMega328P has 32KB:

You can pass flash-memory based strings to Serial.print() by wrapping them with F(). For example: Serial.print(F(“Hello World”));

So to minimize the memory use, I put all Serial.print[ln] strings inside an F().

Another thing the IDE lets me do is to store variables in Flash instead of SRAM.  For example, the line char payload[] = “Hello!”; can be put into Flash memory by using the prog_char typedef.  to prog_char payload[] = hello!”;  My thought was every little bit of SRAM counts.  But ultimately, the ATmega 328p will most likely run out of 1K or more of needed memory.  It does seem like good practice until someone with more experience tells me why doing so is a bad idea.

I’ll be using:
  • freeRam()
  • wrapping Serial.print[ln] strings inside an F()
  • storing variables into Flash memory
As I check the amount of SRAM used by each component’s libraries.

Amount of available SRAM

I wanted to follow up on a comment made by Matt:

“… the ATMEGA 328P only has 2K SRAM and if you intend to use SD cards, ethercards and wireless cards in your system, you might find this a limiting factor. You might want to look at maybe using something like an ATMEGA 1284P based system.”

Given the small amount of SRAM, Matt’s concerns are definitely valid.  But do I immediately need to the ATmega 1284P?

Here’s the additional amount of SRAM used by the component’s libraries:

 

bytes

prior to adding components

209

Adafruit’s SD Shield

693

RFM12B board

100

cc3000

590

Total

1592


After the components are piled on, I was left with 456 bytes. A tight fit! I will most likely change fairly soon to an ATmega with more SRAM.

 
Now it’s time to get the components to work.

Testing Each Component

Adafruit’s Data Logging Shield

I got the Data Logging Shield and shield stacking headers for an Arduino Uno from Adafruit.com.  For the SD card I found an old one that was lying around the house used in a now obsolete digital camera many years ago. 

Solder the Headers

I found this post by freetronics to give helpful hints on the best way to solder shield stacking headers onto a shield.

SD Shield Showing Solder Job

I was happy to see that my soldering skills have improved a bit.

Testing the Data Logging Shield

The libraries I used to test the shield included:

I followed Adafruit’s tutorial to test and become familiar with the shield.  There was a lot at the beginning of the tutorial I ignored because I am using an Uno and these sections were for other Arduino variants.The first thing is to try out the RTC (Real Time Clock).  This was easy and worked great.  It was exciting to read:

 For the RTC library, we’ll be using a fork of JeeLab’s excellent RTC library

within the tutorial.  I truly appreciate the great works that we build upon!  

The tutorial recommends formatting the SD.  This was easy enough using this formatter:

Download the formatter from https://www.sdcard.org/downloads/formatter_4/

I then ran the CardInfo.ino sketch which came with Adafruit’s SD library.  

Yippee!  Here’s what I got on the serial monitor:

______________________________________________________________________

Initializing SD card…
Card type: SDHC

Volume type is FAT32

Volume size (bytes): 3644850176
Volume size (Kbytes): 3559424
Volume size (Mbytes): 3476

Files found on the card (name, date and size in bytes

______________________________________________________________________

The first two times I ran CardInfo.ino, I was guilty of two checks noted below: 1) I didn’t insert the SD card 2) I had left the SPI chip select to 4.  I needed to set it to 10.  I found this initial check in the sketch helpful.  Taking debugging one more step, I wish all libraries were capable of providing APIs that debugged more deeply at each level.  During my stint at Microsoft, we realized the layers of interdependency at both the hardware and software level.  A lot of attention was put into making sure the various network stacks (e.g.: TCP/IP, security) had debugging output. It gets extremely time consuming to track down challenges without that.  I feel this is an area where these open source libraries and break out boards could help save us a lot of time.  However, I doubt it will sell more breakout boards.  Plus, I doubt the breakout boards are put in positions that could bring a Fortune 50 company’s network down.   So I can see why the extra effort is not applied to detailed testing and debugging.  

I found CardInfo’s “what might be wrong checklist” to be extremely helpful in debugging the most obvious reasons why the SD card is not read.

______________________________________________________________________

Initializing SD card…initialization failed. Things to check:
* is a card is inserted?
* Is your wiring correct?
* did you change the chipSelect pin to match your shield or module?

______________________________________________________________________

JeeLab’s RFM12B Board

Since the JeeLink does not support adding on additional components, I purchased JeeLab’s RFM12B Board Kit so RFM12B can be added to an Arduino through the SPI bus.  This will allow the base station to gather sensor readings from the JeeNode that was built in this post.

RFM12B Board Kit

The kit comes with all the goodies that need to be soldered together before the breakout board can be attached to an Arduino.  I used the info in this PDF to figure out where/how the resistors, capacitors, antenna, and RFM12B chip should be soldered.

Here is the breakout board after I soldered it together.


 
RFM12B FrontSide
 RFM12B BackSide
 
Clearly my soldering skills need improvement.   I like the way the board has made it easy to remember which pin of the board needs to be wired to which pin on the Arduino (note the D13 above SCK/D12 above SD0, etc.).  I outlined two other boxes which turned out to be trouble spots.  I’ll cover these later.

Can You Hear Me?

Time to test out the RFM12B sending and receiving packets to the JeeNode.  For this test, I uploaded the RF12Demo.ino sketch that is found within the RF12 Examples that come with the JeeLib library onto both the RFM12B board and JeeNode.  The RF12Demo sketch is great for getting a feel for how well communications are working between nodes.  
 
BUMMER…. 😦 ….The RFM12B board did not work.   A Challenge!  Why, why, why?
 
I wrote out how I eventually got the board working because I see debugging as a key part of the process of coming to something that actually works in real life – not just on paper.  Debugging is an amazing learning opportunity.

TroubleShooting

Here is what I get after using the AppleScript to set up two terminal sessions (and changing the serial ports to match those used by the RFM12B and JeeNode)
 
 
RF12Demo First Try
The screen shot is a bit hard to read – on the left is the JeeNode (serial port AE01DTYI).  On the right is the RFM12B board (serial port USBMODEMFD111).  I use the ‘t’ command to (as the help notes) “broadcast max-size test packet, request ack.”).  The JeeNode (left) is working.  But the RF12B board is not.   So I do what I normally do in my troubleshooting process: 1) self-doubt: “gee – the chances of me getting this working is small.  Should I just get another one?” 2) review the RF12Demo.ino sketch and the RF12.cpp library. 3) make sure communications settings are correct.  Are they both at the same frequency?  Are they in the same group?  What are the values for the node?  Originally the RFM12B board was on node 1, group 212, and sending/receiving data at a frequency of 433MHz.  Compare this to the JeeNode which was set at node 31, group 100, 868 MHz frequency.   
 

First Change

The first change I made was to set the node/group/frequency of the RFM12B board.  The RF12Demo.ino supports the serial input commands that are displayed when the ‘?’ command is enterred.  Entering 8b changes the frequency to 868MHz.  Entering 100g changes the group to 100.  Entering 31i changes the node to 31.  
 
Note: from the JeeLab FAQ:

Node ID’s should be unique within the netGroup in which this node is operating. ID 31 is special because it will pick up packets for any node (in the same netGroup). ID 0 is also special, it is used to transmit in a special “OOK” format.

In the future I will use different node id’s between 1 and 30.
 
Did it work?
 
Try again with the settings showing both nodes on the same frequency, within the same group, and on node 31.  Nope…still doesn’t work.
 

Second Change

My next step was to check the wiring.  Was GND and + and SPI pins all connected correctly?

Arduino And RFM12B

Always a good thing to check!  This time I seemed to have wired the pins correctly.

My next step is to cry for help on the JeeLabs support forum.  Once again, the members of this forum are incredibly helpful.  I have also found them to give insightful guidance.

Plutonomore recommended changing the 3v3 connection to 5v.  I did, but I should be able to use either since there is a connecting pin for either 3v3 or 5v (see the image above).

 RE: Trouble Shooting RFM12B Board Kit? – Added by plutonomore 1 day ago

It also just occurred to me that you are using an Arduino, therefore 5V, not a JeeNode 3V3.
Therefore try the previously suggested wiring setup but change the 3V3 connections on both
boards to 5V. Also you will need to have the 3x 4k7 and 3x10k ohm voltage divider resistors

cheers,

Comment
                                  

 JohnO noted the DATAFLASH #define (I agree that my soldering needs practice!).  It turns out the JeeLink and JeeNode have a data flash chip that is used for data logging.  So I took JohnO’s advice and set #define DATAFLASH 0 from #define DATAFLASH 1.  I saved the sketch with this change to RF12DemoUno.ino since now the JeeNode and Arduino UNO + RFM12B are different.  But I am not sure why data logging would get in the way of transmitting and receiving data…

 RE: Trouble Shooting RFM12B Board Kit? – Added by JohnO about 5 hours ago

Your soldering isn’t too bad although Rohan will be appalled – Rohan is Martyn’s son and a wiz with a soldering station.  

If you are happy to, can I ask that you load the RF12Demo while only changing “#define DATAFLASH 0”. With a terminal session connected to both running versions of RF12Demo and capturing output. Then press the ‘?’ once on each and follow up with a second or two of ‘t’ command. Then post the two output files that you captured.

 Did it work?
 Try again with these changes….Nope…still doesn’t work.
 

Third Change

 I had sent a reply that included the images above to show my soldering efforts.  It is not clear to me how to debug which resistor, capicitor, or other component I soldered is not working.  
And then a YIPPEE!!!! Moment when Martynj noted:

 RE: Trouble Shooting RFM12B Board Kit? – Added by martynj about 5 hours ago

Hmmm.. a couple of “dry” joints visible but more significantly, ANT // Vdd on the RFM12B module appear shorted. Worth a touch up with solder braid, but may prove to be terminal.

Take a look at the front and back of the RFM12B images above, focusing on the areas that have the red rectangle on them.  I used solder remover to get rid of excess solder around the antenna.  And then put more solder on pin on the back side of the board.

Solder Remover

I then cleaned off the flux using the inexpensive technique noted in this youtube video.  This technique seemed to work well.

Here is the front and the back of the RFM12B after removing solder around the antenna and adding solder to one of the pins for a resistor:

 Solder Off Ant  SolderOnResistor

 Did it work?

YIPPEE!  This worked. I was surprised.  I assumed I’d muffed up the soldering beyond repair.  Luckily, I had not.


JeeNode

Arduino Uno + RFM12B Board

[RF12demo.10] _ i31 g100 @ 868 MHz

Available commands:

 <nn> i     – set node ID (standard node ids are 1..30)

 <n> b      – set MHz band (4 = 433, 8 = 868, 9 = 915)

 <nnn> g    – set network group (RFM12 only allows 212, 0 = any)

 <n> c      – set collect mode (advanced, normally 0)

 t          – broadcast max-size test packet, request ack

 …,<nn> a – send data packet to node <nn>, request ack

 …,<nn> s – send data packet to node <nn>, no ack

 <n> l      – turn activity LED on PB1 on or off

 <n> q      – set quiet mode (1 = don’t report bad packets)

 <n> x      – set reporting format (0 = decimal, 1 = hex)

 123 z      – total power down, needs a reset to start up again

Remote control commands:

 <hchi>,<hclo>,<addr>,<cmd> f     – FS20 command (868 MHz)

 <addr>,<dev>,<on> k              – KAKU command (433 MHz)

Current configuration:

_ i31 g100 @ 868 MHz

OK 63 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

-> ack

OK 63 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

-> ack

> 0t

test 0

-> 66 b

OK 223

> 0t

test 1

-> 66 b

OK 223

[RF12demo.10] _ i31 g100 @ 868 MHz

Available commands:

 <nn> i     – set node ID (standard node ids are 1..30)

 <n> b      – set MHz band (4 = 433, 8 = 868, 9 = 915)

 <nnn> g    – set network group (RFM12 only allows 212, 0 = any)

 <n> c      – set collect mode (advanced, normally 0)

 t          – broadcast max-size test packet, request ack

 …,<nn> a – send data packet to node <nn>, request ack

 …,<nn> s – send data packet to node <nn>, no ack

 <n> l      – turn activity LED on PB1 on or off

 <n> q      – set quiet mode (1 = don’t report bad packets)

 <n> x      – set reporting format (0 = decimal, 1 = hex)

 123 z      – total power down, needs a reset to start up again

Remote control commands:

 <hchi>,<hclo>,<addr>,<cmd> f     – FS20 command (868 MHz)

 <addr>,<dev>,<on> k              – KAKU command (433 MHz)

Current configuration:

_ i31 g100 @ 868 MHz

> 0t

test 0

-> 66 b

OK 223

> 0t

test 1

-> 66 b

OK 223

OK 63 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

-> ack

OK 63 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66

-> ack

 
The commands I typed in don’t show up.  But it is easy to walk through.  The cell on the right represents the serial output of the sketch running on the Arduino Uno + RFM12B Board.  The cell on the right is output from the JeeNode.  I typed t as input to the sketch running on the Arduino Uno..  This wrote “>0t ->66 b OK 223” out to the serial port from the sketch running on the Arduino Uno.  On the left, the JeeNode received the data.  The sketch on the JeeNode wrote “OK 63 0 1 2 3 4 5….” to the serial port.  I type t twice to the Arduino Uno and twice to the JeeNode.
 
One more YIPPEE! because it was an amazing experience to “fix” this challenge!
 

Adafruit’s cc3000 Breakout Board

I’ve gone through testing the cc3000 in a previous post, so I won’t repeat the process here. 

Better Together?

Add the RFM12B to the Data Logging Shield

Time to find out if the RFM12B can ping/pong within the same sketch the SD Shield is spewing out info about the SD card.  This will test how well the components share the SPI bus.

Here’s where I ran into my first challenge.  Both the SD shield and the RFM12B board used pin 10 for the SPI CS (Chip Select).  Luckily, the RFM12B’s library has been enhanced to include rf12_set_cs() .   I set the CS pin for the RFM12B board to 9.  Although this solves my challenge of using two different pins for the two SPI CS pins, I was curious how easy it was to change the CS pin used by the SD Shield.  I asked how to do this on the Adafruit forum.  Here’s the answer I got.

Postby adafruit_support_bill » 08 Nov 2013 17:58

Yes. You can cut the trace between pin 10 and the adjacent breakout hole. Then you can run a jumper from the hole labeled “CS” to any other pin.

Image

 I didn’t try this – but good to know….

 

Sketch for JeeNode

Here is the sketch I downloaded onto the JeeNode:

 

#include <JeeLib.h>

 

MilliTimer sendTimer;

prog_char  payload[] = “Hello!”;

//char  payload[] = “Hello!”;

 

void setup () {

  Serial.begin(57600);

  rf12_initialize(2, RF12_915MHZ, 33);

}

void loop () {

  if (rf12_recvDone() && rf12_crc == 0) {

    Serial.println(F(“Receive data”));

    for (byte i = 0; i < rf12_len; ++i)

      Serial.print(rf12_data[i]);

    Serial.println();

  }

  if (sendTimer.poll(3000) && rf12_canSend()) {

    Serial.println(F(“Send data”));

    rf12_sendStart(0, payload, sizeof payload);

  }

}

Sketch for Base System

Note within this sketch:

  • The RFM12B CS pin is set to 9 right before the call to rf12_initialize().
  • The SD Shield library and pieces of the CardInfo sketch have been added so that data will have to flow between the components and the Arduino.

#include <JeeLib.h>

 // include the SD library:

#include <SPI.h>

#include <SD.h>

// set up variables using the SD utility library functions:

Sd2Card card;

SdVolume volume;

SdFile root;

// change this to match your SD shield or module;

const int chipSelect = 10;   

 

MilliTimer sendTimer;

prog_char  payload[] = “Hello!”;

//char  payload[] = “Hello!”;

 

void setup () {

  Serial.begin(57600);

  rf12_set_cs(9);

  rf12_initialize(1, RF12_915MHZ, 33);

   pinMode(SS, OUTPUT);

  // we’ll use the initialization code from the utility libraries

  // since we’re just testing if the card is working!

  while (!card.init(SPI_HALF_SPEED, chipSelect)) {

    Serial.println(“initialization failed. Things to check:”);

    Serial.println(“* is a card is inserted?”);

    Serial.println(“* Is your wiring correct?”);

    Serial.println(“* did you change the chipSelect pin to match your shield or module?”);

  } 

  

  // print the type of card

  Serial.print(“\nCard type: “);

  switch(card.type()) {

    case SD_CARD_TYPE_SD1:

      Serial.println(“SD1”);

      break;

    case SD_CARD_TYPE_SD2:

      Serial.println(“SD2”);

      break;

    case SD_CARD_TYPE_SDHC:

      Serial.println(“SDHC”);

      break;

    default:

      Serial.println(“Unknown”);

  }

void loop () {

  if (rf12_recvDone() && rf12_crc == 0) {

    Serial.println(F(“Receive data”));

    for (byte i = 0; i < rf12_len; ++i)

      Serial.print(rf12_data[i]);

    Serial.println();

  }

 

  if (sendTimer.poll(3000) && rf12_canSend()) {

    Serial.println(F(“Send data”));

    rf12_sendStart(0, payload, sizeof payload);

  }

}

 

YIPPEE!  I got the following output on my terminal windows when I ran these sketches:

Base System Serial Output

JeeNode Serial Output

Card type: SDHC

Receive data

72101108108111330

Send data

Receive data

72101108108111330

Send data

Receive data

Send data

Receive data

72101108108111330

Send data

Receive data

72101108108111330

Send data

Receive data

 

Note on the serial output for the Base Station there is info coming from both the SD Shield and the RFM12B.

SPI Misbehaving – Add the cc3000 to the SD Shield and RFM12B

I set the CS pin for the cc3000 to pin 8.  Now the SD Shield uses pin 10 for its CS, the RFM12B uses pin 9, and the cc3000 uses pin 8. 

So what happens when I put the components that share the SPI bus – the RFM12B board, SD Shield, and cc3000 – in the same sketch?  All is fine when the SD Card and the RFM12B board share the card.  Unfortunately, when I added in the cc3000, the Base System could no longer receive data.  

Drat… back to the Adafruit forum to see if I could get help troubleshooting.

Postby ktownsend » 05 Nov 2013 18:08

I really don’t know what this could be off the top of my head.
The TI modules do use a less common SPI mode (most devices use Mode 0). Alternatively, perhaps when the interrupt fires on the TI the CS lines on the TI side asserts at the same time that the CS line on the other module is asserted, so both devices are listening and everything goes off into the weeds?
The best solution would be to hook up a logic analyzer if you have one (Saleae Logic, etc.) and see if both CS lines at some point are asserted, just as somewhere to start?
Kevin

and

Postby adafruit » 06 Nov 2013 01:37

the breakout version of the cc3000 needs something to buffer MISO as it is not tristated
http://learn.adafruit.com/adafruit-cc30 … onnections
you can look at the cc3000+SD example sketches for how to share the SPI lines, but no, the CC3000 does not work great with other SPI devices without a lot of care & debugging. this kind of stuff is not easy to fix, if you’re “new to electronics”, you may find this project challenging and we don’t offer coding or library modification support and assistance.
our suggestion is to find an RF module that does not require sharing those pins. 

There was another thread in the forum that discussed other issues (and refers to the cc3000’s use of SPI mode 1):

by adafruit_support_rick » 23 Aug 2013 18:56

SD sets up the SPI control register once when you call begin(), and expects it to be correct forever after. Well-behaved SPI drivers should save SPCR, reconfigure it for their own purposes, and then restore SPCR on the way out.

Postby toegap » 27 Aug 2013 04:32

You are right about the SPCR. That needs be different for each of the libraries. If both libraries are set to SPI_CLOCK_DIV2, the only difference is that cc3000 uses SPI.setDataMode(SPI_MODE1) while sdfat(sd card) uses SPI.setDataMode(SPI_MODE0). Both of these effect the state of the SPCR variable. So you need to toggle the SPCR back and forth when you are using these libraries.

hmmmm….if anyone reading this has any suggestions – Please leave a comment.

Next Steps

 I want to complete the Base System.  I’ll look at the best options for: 1) wireless between nodes 2) Internet connectivity to send/receive from the Internet and 3) data logging.   I’ll also delve a bit more into the SPI challenge/conflicts noted above.  It looks like a good opportunity to learn!

Until next time…