Close

Part 5: Software? Maybe?

A project log for Purposeless LED Display

When life gives you an empty glass candle holder, why *wouldn't* you jam a ton of LEDs in it?

jorj-bauerJorj Bauer 04/06/2016 at 13:330 Comments

I suppose it's time to start talking about the software running this thing. But to do that I need to talk through the hardware some more.

My original design goals included:

* Use the parts I've got, as much as possible.

* Allow wireless programming so I don't have to open this once the hardware is stable.

So, as I've already mentioned, I decided to use an Arduino Pro Mini (5v, 16MHz) to run the LEDs; and a separate Moteino with an RFM69 and flash onboard. There's a single 5v 10A brick running the show (I didn't want to jam a DC-DC converter in the already-sahara-desert-conditions candle housing).

So the whole software design starts with programming.

If you go take a look at the LowPowerLabs github site (https://github.com/LowPowerLab/WirelessProgramming) you'll find that Felix already has a way to wirelessly program the Moteino. I love the flexibility of these little devices, and I'm ready to wax poetic here - not only do these make it easy for me to throw 5v at a 3.3v board and skip all the logic level shifting, but they let me reprogram them remotely? Sign me up.

If you look at the WirelessProgramming_node (in the Arduino programming environment's Examples -> RFM69 -> Examples) you'll see the hook buried in loop() - it's essentially this:

RFM69 radio;
SPIFlash flash(FLASH_SS, 0xEF30);

void loop()
{
  if (radio.receiveDone()) {
    CheckForWirelessHEX(radio, flash, true);
    // ... or go do something with your received packet if it still exists
  }
}

That CheckForWirelessHex() call will run the radio and not return to your code if it sees a magic "I want to program the Moteino now" packet. This abstracts the code reasonably well; while I would have preferred that it return some indication that it does its magic, I'm okay with it as-is. If it finishes receiving a wireless update it winds up resetting itself, so there's no real reason for it to return a value. I suppose. It just feels wrong.

Anyway, my coding preferences aside: now we have a Moteino that can be wired up and jammed in the housing, never to be seen again (well, mostly; see my post about adding DTR to a cheap PL2303). We just need to figure out how to wire it up.

I want two more things here. First: the Moteino has to be able to tell the Pro Mini what to display. Easy enough: let's wire up the RX/TX serial lines to each other (RX to TX both ways, and we can also read confirmation from the Pro Mini that it has read and enacted whatever we've told it to do).

Second: I never want to have to open the housing up to reprogram the Pro Mini. So I want to wirelessly be able to program it, too.

I thought about embedding the ArduinoISP sketch inside the Moteino's code, having it act as a wireless ArduinoISP programmer. I shied away from this because it wasn't clear to me that I'd be able to stick to the timing that this protocol expects.

Instead, since the Pro Mini has just one output pin (to control the LEDs), I figured I might as well take advantage of the other free pins! Using RST and pins 11-13, we can program the Atmel chip directly, bypassing the bootloader. Timing is very lax in this programming protocol, and I figured I could buffer the program in flash on the Moteino on its way to the Pro Mini.

Looking at the Moteino and Pro Mini and thinking about how I hoped to put them inside this housing, I figured that using Moteino pin 4 for RST and 15-17 for MOSI, MISO, and SCK (to connect to the Pro Mini pins 11-13 of the same) would let me put the two face-to-face and wire the pins directly to each other. Two sockets underneath them would give both boards power and ground, and connect the two serial lines TX-to-RX bidirectionally.

Fantastic. I just have to write some code to do the programming from the Moteino, which can wait until later.

As an afterthought, there's that fan I mentioned back in Episode 2 of this thrill-a-minute (perhaps I should get out more) build log. The fan is controlled by the Moteino, which has a temperature sensor in the radio (OH MY GOD IT CAN ALSO MEASURE TEMPERATURE I love these things and I should definitely get out more, shouldn't I?).

Once you've got an RFM69 object like above, it's this trivial to read the temperature from the radio module:

uint8_t temperatureC = radio.readTemperature(-1);
The "-1" is a user calibration factor. I figure I don't really care about calibration just yet, so I've told it to ignore my calibration and just tell me what it thinks. Maybe I'll come back around to look at how to properly calibrate this some other day.

Oakie-dokie: I've got a temperature reading, and a fan. I want to control the fan's speed relative to the temperature. I mentioned a couple articles ago that I set this up with PWM and a couple of NPN transistors, so let me try to recount how this thing's wired up... from memory: the Moteino pin 5 goes through a 200-ish-ohm resistor to the base of a 2n2222. The 2n2222's collector is wired up to +5v through another 200-ish-ohm resistor, with the emitter wired directly to the 3055's base, and the 3055's emitter is wired to ground.

The fan has a diode (a 1n914 or 1418 or some other small signal diode that I had lying around and seemed like it would suffice for the reverse current of a small fan starting and stopping) across its leads, backwards. The positive of the fan is then wired up to +5v, and the negative of the fan is wired to the collector of the 3055.

Did I mention that the 3055 is extreme overkill? Why in the heck did I put a 70V 10A NPN power transistor in here for a 5v fan that's going to be pulling a couple hundred milliamps, at best? I have no idea. I must have been looking for a MOSFET and stumbled across this instead. This is typical of my projects, really.

Maybe I'll reverse engineer what I wired up and draw that out more seriously, but the words are good enough for now. It's all sort of loosey-goosey, and is a terrible model of a two-stage transistor buffered amplifier. Basically I tried driving it directly from the 2n2222 and found that I couldn't reliably get it to run, so I threw a second stage on it haphazardly. Meh, it works.

It's like my ability to speak German. After spending three weeks in Germany, my brain rewired itself for language. When I came back I found myself continually mixing metaphors. It was all about getting the general point across, rather than using the right specific words and phrases. In both cases, I'm well aware of what I've done wrong, after the fact: I just have no intent in going back and fixing it because it does its job well enough.

Anyway.

With that get-up I can drive the fan with a PWM from the Moteino. Pin 5 is open, so I use it. Now, with some definitions of when I want the fan to come on at low speed and when I want it at full bore (which are all guesses right now):

// degrees C
#define MAXTEMP 35
#define MINTEMP 25

#define PIN_FAN 5

uint8_t temperatureC =  radio.readTemperature(-1); // -1 = user cal factor, adjust for correct ambient later

if (temperatureC >= MAXTEMP)
      temperatureC = MAXTEMP;

if (temperatureC >= MINTEMP) {
  uint8_t fanRate = map(temperatureC, MINTEMP, MAXTEMP, 0, 255); // scale the temperature value to a 0-255 fan rate
  analogWrite(PIN_FAN, fanRate);
} else {
  analogWrite(PIN_FAN, 0);
}

One last hardware tidbit before we close up the enclosure and move on to software. Adafruit recommends a beefy 1000uF capacitor across the power leads to the LEDs. I'm not filtering the power from the power brick at all (I really should), but I did put in the 1000uF cap across the power feed where it leaves my board and heads out to feed the LEDs. I figured I might as well learn from what they've already (presumably) screwed up.

And with that, I think we can close this baby up and see if we can write software to make it do anything even remotely interesting.

Discussions