Solar Cluster: First charge controller board built

So, I ordered the parts last weekend and over the course of the last week, they arrived, in three dispatches.

Might’ve been cheaper for RS to wait for the lot to arrive, I’d have been happy for them to do that had they asked, but never mind, they all turned up. So today, in clouds of solder smoke out on the back deck, I set to work soldering up the first of these boards.

At first, I just put all the SMD parts on, the programming header, the 5V reg, and the DC input lead. This proved a little fun. When I ordered the parts, I had initially put a lot of resistors, all 0805 size, to fill some of my stock. Then I took some off the list because I was over budget a little. Murphy dictates the ones that you take off are the ones you need.

I had thought I had spares anyway… turns out those were 1206s. And, in a pinch, one can use 1206 size resistors on an 0805 size footprint, or at least the “hand-soldering” variants that Kicad produces. The 10k pull-up resistors used on the MOSFETs and the 47k pull-up on the reset line are all 1206s, and they fit okay.

Had I remembered I had 1206s not 0805s, I’d have used 1206s. They’re a little friendlier to work with.

Lessons:

  • always check the list before hitting the order button!
  • In a pinch, you might be able to squeeze a 1206 onto an 0805 footprint, but don’t bet on it!

The other thing I could have done better would be to nudge the footprint for the 7805 along a little so that the switch-mode alternative part (ROHM BP5293-50) would fit. Better yet would be to not be so darn lazy and actually make a footprint for it. It’s a little cosy, but it snuggles up nicely against the capacitor.

Similarly, slightly bigger holes for the power connectors would help too, although the pins on the MOSFETs aren’t exactly big and they’re supposed to handle 70A. The lead length is short though, so not much resistance, I’ll probably get away with it.

The LEDs also proved a challenge, namely figuring out which way around they went. Most were all Osram CHIPLED parts, had a milky-white lens, and no markings visible on the top (one nondescript marking on the bottom), so it was difficult to tell anode from cathode. I wound up using my electronics kit to supply 4.5V through a 1k resistor out to two wires (a twisted pair from some CAT5e) which I could touch to each side to know which was which.

The one exception was the batch of yellow LEDs I bought, Osram didn’t seem to do the yellow ones so wound up buying Kingbright ones, which featured two green dots showing the cathode (the “bar” end of the schematic symbol). When I run out of the existing stock of red, orange and green LEDs, I’ll get more like these I think as it makes life much easier.

This was shortly after programming, the code running on the board for the first time.

Seeing the LEDs blinking, I disconnected the board and proceeded to fit the remaining through-hole components. The resulting board seems to be making the right noises, turning the fan on and off in response to the internal temperature sensor, and running from a 9V source.

Now I guess I’ll wire up the remaining leads, hook it to DC power and see what happens.

Donation from the Northwest Digital Radio

Well, today’s mail had a surprise.  Back about 6 years ago, I was sub-contracted to Jacques Electronics to help them develop some device drivers for their video intercom system.  At the time, they were using TI’s TLV320AIC3204 and system-on-modules based on the Freescale i.MX27 SoC.

No driver existed in the ALSA tree for this particular audio CODEC, and while TI did have one available under NDA, the driver was only licensed for use with a TI OMAP SoC.  I did what just about any developer would do, grabbed the closest-looking existing ALSA SoC driver, ripped it apart and started hacking.  Thus I wound up getting to grips with the I²S infrastructure within the i.MX27 and taming the little beast that is the TLV320AIC3204, producing this patch.

As the code was a derivative work, the code was automatically going to be under the GPLv2 and thus was posted on the ALSA SoC mailing list for others to use.  This would help protect Jacques from any possible GPL infringement regarding the use of that driver.  I was able to do this as it was a clean-room implementation using only material in TI’s data sheet, thus did not contain any intellectual property of my then-employer.

About that time I recall one company using the driver in their IP camera product, the driver itself never made it into the mainline kernel.  About 6 months later, another driver for the TLV320AIC3204 and 3254 did get accepted there, I suspect this too was a clean-room implementation.

Fast forward to late August, I receive an email from Jeremy McDermond on behalf of the Northwest Digital Radio.  They had developed the Universal Digital Radio Controller board for the Raspberry Pi series of computers based around this same CODEC chip.  Interestingly, it was the ‘AIC3204 driver that I developed all that time before that proved to be the code they needed to get the chip working.  The chip in question can be seen up the top-right corner of the board.

Universal Digital Radio Controller

Timely, as there’s a push at the moment within Brisbane Area WICEN Group to investigate possible alternatives to our aging packet radio system and software stack.  These boards, essentially being radio-optimised sound cards, have been used successfully for implementing various digital modes including AX.25 packet, D-Star and could potentially do FreeDV and other digital modes.

So, looks like I’ll be chasing up a supplier for a newer Raspberry Pi board, and seeing what I can do about getting this device talking to the world.

Many thanks to the Northwest Digital Radio company for their generous donation! 🙂

Solar Cluster: Boards Arrived

So, after a couple of email enquiries, the truth is unveiled. As it turns out, Swiss Post send parcels via one or more transit countries which due to a quirk in their tracking UI, may appear as the destination.

Asendia were in touch last night informing me that: “Please kindly note that sometimes tracking website will show the wrong destination. Canada is only the transit country.” Ahh okay, no problem then. Confusing, but that’s fine. 🙂

I know now for later not to panic if it says Canada.

This morning, there was a surprise parcel arrived at work, containing 6 PCBs. Bonus! Guess I had better get the other parts on order. I won’t have them ready for this week end, but I predict much solder smoke in my future next weekend.

Solar Cluster: Getting PCBs made

So a few weeks ago, I gave the charge controller a test, seeing if it in fact reacted in the manner I expected before deciding whether to proceed with the existing prototype or whether I should iterate the design.

In the end, I decided I’d tweak the design and get new boards built. By using SMD parts and a 4-layer board, I was able to shrink my design down to a 5×5cm square, which is relatively inexpensive to have fabricated.

I’ll be getting a few boards which means I can have some spares in case something goes bang or if I want to scale out my battery bank.

The updated design is published in the files section. This also incorporates @K.C. Lee‘s advice regarding back-to-back MOSFETs.

After some fun and games, one PCB fab house telling me to “check my passwords match” (when I know for certain that they did match), and another seemingly ignoring the inner two layers, I settled on a PCB manufacturer (thanks to PCBShopper) and got the boards ordered.

I put down my home address for the billing address and my work address as the delivery address. Both given as being in “Queensland, Australia”.

This is a learning experience for me, I’m used to just drawing my circuit out with a dalo pen, but unfortunately my skills aren’t up to producing a board for SOICs.

They reported that they shipped the boards on the 21st, and had previously estimated about 2-3 weeks for delivery. No problem there.

Just one niggling concern…

Not familiar with Swiss Post procedures, I’d have expected it to show Hong Kong → Australia, but maybe that’s how they do things. I do hope someone didn’t get Queensland, Australia mixed up with Quebec, Canada!

Update: Just been in touch, no the manufacturer didn’t get it mixed up, and it’s the right tracking number. They’re chasing it up with Swiss Post.

Improved Helmets: Thinking about modelling the brain

So I’m doing some more thought exercises on this project. Yes, been a long time since I posted anything and I only just got around to having a look at the report into Phillip Hughes’ death.

In this case, the ball managed to strike a vertebral artery. There are typically two of these, and they flow to the basilar artery which feeds the brain stem. The other major route is via the carotid arteries . Both of these sets branch out into much finer blood vessels within the brain.

That, to my mind would have triggered a sharp impulse in the blood pressure in those arteries. The arteries are somewhat elastic, but they probably don’t appreciate that level of abuse: they have pretty thin walls in that part of the body and are quite small in diameter as they branch out from the brain stem. In the report, they talk about “traumatic basal subarachnoid haemorrhage“.

According to Wikipedia, that means blood is leaking out of vessels and into the protective layers that surround the brain. We often joke about the smoke escaping from an electronic component when we put too much current through it.

This would seem to be the blood vessel equivalent: a minor artery or three went “pop”.

It would appear that this is definitely one mode of failure in the brain that should be considered when designing protective gear. It’s particularly an issue for soldiers with IEDs. In their case, the helmet can work “perfectly”, but it’s the pressure wave hitting the body causing pressure up the blood vessels in the neck that do damage, as well as pressure waves in the cerebral fluid itself.

The other mode of failure seems to be in the neurons and their connections.

Thinking about this latter point, we know that the brain is a very delicate organ when taken out of its casing. It is described as having the consistency of tofu in some articles.

This makes me wonder whether the brain should be considered a solid at all. To my way of thinking, perhaps a very dense mesh of interconnected nodes is a more accurate representation of what’s going on.

As the head moves through space (which is what seems to do much of the damage), Newton’s First Law does its worst. If you consider a single node in this mesh travelling through a linear path, the node experiences a tension force from each connection to its neighbours.

These connections have a limit to the amount of tension they can withstand. When they break, that’s when brain damage takes place.

Now, under constant velocity, or at rest, these tension forces are within tolerance, nothing bad happens. However, when a sudden blow is experienced, it is this additional tension as individual nodes get jostled around from their own inertia and the transferred tensional forces from neighbouring nodes that may trigger these connections to break.

Modelling both of these situations is an interesting problem. The latter could be done with strain gauges, but they’d have to be sensitive ones. How sensitive? Not sure. 2AM isn’t a great hour to be answering such questions.

As for the vessels, perhaps piezo transducers at differing locations might give some insight into how much pressure is in different parts.

It may also be possible to have a tree-structure of tubes representing the arteries, and measure how much they expand as the pressure wave hits by measuring how much light is blocked between a LED and a photo diode with the “artery” running in the path: the fatter it is the less light hits the diode.

More food for thought I guess. 🙂

Solar Cluster: Load test using the power controller

So, last night I started doing some light testing of the power controller. I installed a 5A fuse and hooked it up to a 10Ah LiFePO₄ battery and a homebrew 3A charger (LM2576-based with a 16V IBM laptop PSU as mains source) set to its maximum voltage (~15V).

The controller came to life and immediately started flashing its “high voltage” and “low temperature” LEDs, indicating that:

  • It thought the temperature was high enough to warrant a fan turning slowly (above ~20°C)
  • It thought the battery voltage was too high for comfort (IPMI complains when the voltage gets much about 13.6V.)

In order to get the battery to discharge, I plugged in an old Icom IC-706MkII G transceiver, set it on receive mode. I didn’t have an antenna attached, so this would have represented a very light load for what would be production use.

The battery started discharging, and after a few tens of minutes, the high voltage warning LED had stopped flashing and instead the “good voltage” LED was staying constantly on. So battery was in a range the controller was happy with.

It was going to take a long time though, for that set to drain a 10Ah battery in receive mode.

This morning, I got out the big guns. I plugged the actual cluster in and fired it up. After about 30 minutes of run time, the battery had drained sufficiently that the charger started flashing the “good voltage” LED, indicating battery was getting low. It had also turned on the MOSFET controlling the charger I had plugged in, and the charger was desperately trying to keep up with the ~5A load that the cluster was drawing. (Did I mention this was a 3A charger?)

So far so good. I powered off the cluster and unplugged it. It continued to let the charger do its job, and after another short while, the battery had regained some charge. It kept the charger on until momentarily, it peaked over the “high voltage” threshold. The “high voltage” LED blinked a few times, then the MOSFET turned off and the “good voltage” LED remained solid.

The battery was sitting at 13V. A little short of my 13.5V set-point, but close enough given it was on a fairly weak charger. So that ATTiny24A is doing exactly what I intended.

Maybe the high set-point could do with some adjustment, or a turn-off delay added (with a separate “high critical” set-point for immediate shut-off), but so far, so good.

It might be worth me getting some PCBs fabricated and shrinking the prototype board down using SMD parts, but this controller works so far.

Solar Cluster: Power controller firmware taking shape

So after a long hiatus, some of it involving some yak shaving (e.g. #Open-source debugWire debugger yes, I’ll get back to that), I managed to get a version of the firmware together for the power controller that seems to be doing what I ask of it.

The means of overcoming the road block was knocking up a very crude (and slow!) UART driver so I could print data out on the serial port. I avoided doing this previously because I didn’t have an easy way to interface to a TTL serial port. Recently though, I bought some FTDI serial cables, one 5V and one 3.3V, so now I had little excuse.

I feel these will give me some valuable insights into tacking the debugWire project.

I was able though, to bit-bang a UART using avr-libc’s _delay_us, and get a respectable 4800 baud serial stream out. This obviously dropped to 300 baud when I had other tasks running, but still, that’s enough to do what I’m after. (Once upon a time, that was considered fast!)

After figuring out where I was going wrong… perhaps I had been sniffing too much solder smoke that day… I re-wrote my firmware, using this UART library as a means of debugging the code. I set up Timer1 to run at 1.2kHz, which meant I could also use it as a baud rate generator for my software UART and upping the baud rate to 1200bps.

Some further work on a breadboard, and I had more-or-less working firmware.

I’ve thrown the code up on GitHub, it’s very much in a raw state, and I might do a second revision of the PCB, since this prototype seems to be more or less on the money now.

How did I get to be an Engineer?

Sometimes I wonder.  Take this evening for example.

I recently purchased some microcontrollers to evaluate for a project, some Atmel ATTiny85s, because they have a rather nice PLL function which means they can do VHF-speed PWM, and some NXP LPC810s, because they happen to be the only DIP-package ARM chip on the market I know of.

The project I’m looking at is a re-work of my bicycle horn… the ATMega32U4 works well, but the LeoStick boards are expensive compared to a bare DIP MCU, and the wiring inside the original prototype is a mess.  I also never got USB working on them, so there’s no point in a USB-capable MCU.

I initially got ATMega1284s owing to the flash storage, but these being 40-pin DIPs, they’re bigger than anticipated, and the fact they’ve got dual USARTs, lots of GPIOs and plenty of storage space, I figured I’d put them aside for another project.

What to use?  Well I have some AT89C2051s from way back (but no programmer for them), some ATTiny24As which I bought for my solar cluster project, an ATMega8L from another project, a LeoStick (Arduino Leonardo clone).  The LeoStick I’m in the process of turning into a debugWire debugger so that I can figure out what the ADCs are doing in my cluster’s power controller (ATTiny24A).

I started building a programmer for the ‘2051s using my ATMega8L last weekend.  The MAX232 IC I grabbed for serial I/O was giving me jibberish, and today I confirmed it was misbehaving.  The board in general is misbehaving in that after flashing the MCU, it seems to stay in reset, so I’ve got more work to do.  If I got that going, I was thinking I could have PCM recordings in an I²C EEPROM and use port 1 on the ‘2051 with an R2R ladder DAC to play sound.  (These chips do not feature PWM.)

Thinking this morning, I thought the LPC810 might be worth a shot.  It only has 4kB of flash, half that of the ATTiny85, and doesn’t have as impressive PWM capabilities, but is good enough.  I really need about 16kB to store the waveforms in flash.  I do have some I²C EEPROMs, mostly <2kB ones that are sourced off old motherboards, but also a handful of 32kB ones that I had just bought especially for this… but then left behind on my desk at work.

I considered audio compression, and experimenting with ADPCM-style techniques, came to the conclusion that I didn’t like the reduced audio quality.  It really sounded harsh.  (Okay, I realise 4-bits per sample is never going to win over the audiophiles!)

Maybe instead of PCM, I could do a crude polyphonic synthesizer?  My horn effect is in fact synthesized using a Python script: the same can be done in C, and the chip probably has the CPU grunt to do it.  It’d save the flash space as I’d be basically doing “poor man’s MIDI” on the thing.  Similar has been done before on lesser hardware.

I did some rough design of data structures.  I figured out a data structure that would allow me to store the state of a “voice” in 8 bytes, and could describe note and timing events in 8-byte blocks.  So in a 2kB EEPROM, I’d store 256 notes, and could easily accommodate 8 or 16 voices in RAM, provided the CPU could keep up at 30MHz.

So, I pull a chip out, slap it in my breadboard, and start hooking it up to power, and to my shiny new USB-TTL serial cable.  Fire up lpc21isp and, nothing, no response from the chip.  Huh?  Check wiring, probe around, still nothing.  Tried different baud rates, etc.  No dice.

This stubborn chip was not going to talk to lpc21isp.  Okay, let’s see if it’ll do SWD.  I dig out my STLink/V2 and hook that up.

OpenOCD reports no response from the device.

Great, maybe a dud chip.  After a good hour or so of fruitless poking and prodding, I pull it out of the breadboard and go to get another from the tube it came from when I notice “Atmel” written on the tube.

I look closer at the chip: it was an ATTiny85!  Different pin-out, different ISP procedure, and even if the .hex file had uploaded, it almost certainly would not have executed.

Swap the chip for an actual LPC810, and OpenOCD reports:

Open On-Chip Debugger 0.10.0-dev-00120-g7a8915f (2015-11-25-18:49)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select '.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
adapter speed: 10 kHz
adapter_nsrst_delay: 200
Info : Unable to match requested speed 10 kHz, using 5 kHz
Info : Unable to match requested speed 10 kHz, using 5 kHz
Info : clock speed 5 kHz
Info : STLINK v2 JTAG v23 API v2 SWIM v4 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 2.979527
Warn : UNEXPECTED idcode: 0x0bc11477
Error: expected 1 of 1: 0x0bb11477
in procedure 'init'
in procedure 'ocd_bouncer'

I haven’t figured out the cause of this yet, whether the ST programmer doesn’t like talking to a competitor’s part. It’d be nice to get SWD going since single-stepping code and peering into memory really spoils a developer like myself. I try lpc21isp again.

Success!  I see a LED blinking, consistent with the demo .hex file I loaded.  Of course now the next step is to try building my own, but at least I can load code onto the device now.

Song-book for the spy agencies

Seems spying on citizens is the new black these days, most government “intelligence” agencies are at it in one form or another. Then the big software companies feel left out, so they join in the fun as well, funneling as much telemetry into their walled garden as possible. (Yes, I’m looking at you, Microsoft.)

This is something I came up with this morning. It’s incomplete, but maybe I can finish it off at some point. I wonder if Cortana has a singing voice?

Partial lyrics for the ASIO/GCHQ/NSA song book

Aliasing variables in gcc

A little trick I just learned today. First, the scenario.

I have a driver for a USART port, the USART on the ATMega32U4 in fact. It uses a FIFO interface to represent the incoming and outgoing data.

I have a library that also uses a FIFO to represent the data to be sent and received on a USART.

I have an application that will configure the USART and pipe between that and the library.

Now, I could have each component implement its own FIFOs, and have the main application shovel data between them. That could work. But I don’t want to do this. I could have the user pass in a pointer to the FIFOs in initialisation functions for the USART driver and the library, but I don’t want to store the extra pointers or incur the additional overheads.

Turns out, you can define a symbol somewhere, then alias it to make two variables appear in the same place. This is done with the alias attribute, and it requires that the target is defined with the nocommon attribute.

In the USART driver, I’ve simply declared the FIFOs as extern entities. This tells the C compiler what to expect in terms of data type but does not define a location in memory. Within the driver, use the symbols as normal.

/* usart.h */

/*! FIFO buffer for USART receive data */
extern struct fifo_t usart_fifo_rx;

/*! FIFO buffer for USART transmit data */
extern struct fifo_t usart_fifo_tx;

/* usart.c */
static void usart_send_next() {
  /* Ready to send next byte */
  int16_t byte = fifo_read_one(&usart_fifo_tx);
  if (byte >= 0)
    UDR1 = byte;
}

ISR(USART1_RX_vect) {
  fifo_write_one(&usart_fifo_rx, UDR1);
}

I can do the same for the protocol library.

/* External FIFO to host UART */
extern struct fifo_t proto_host_uart_rx, proto_host_uart_tx;

/*! External FIFO to target UART */
extern struct fifo_t proto_target_uart_rx, proto_target_uart_tx;

Now how do I link the two? They go by different names. I create aliases, that’s how.

/*
 * FIFO buffers for target communications.
 */
static struct fifo_t target_fifo_rx __attribute__((nocommon));
static uint8_t target_fifo_rx_buffer[128];
extern struct fifo_t usart_fifo_rx __attribute__((alias ("target_fifo_rx")));
extern struct fifo_t proto_target_uart_rx __attribute__((alias ("target_fifo_rx")));

static struct fifo_t target_fifo_tx __attribute__((nocommon));
static uint8_t target_fifo_tx_buffer[128];
extern struct fifo_t usart_fifo_tx __attribute__((alias ("target_fifo_tx")));
extern struct fifo_t proto_target_uart_tx __attribute__((alias ("target_fifo_tx")));

/*
 * FIFO buffers for host communications.
 */
static struct fifo_t host_fifo_rx __attribute__((nocommon));
static uint8_t host_fifo_rx_buffer[128];
extern struct fifo_t proto_host_uart_rx __attribute__((alias ("host_fifo_rx")));
static struct fifo_t host_fifo_tx __attribute__((nocommon));
static uint8_t host_fifo_tx_buffer[128];
extern struct fifo_t proto_host_uart_tx __attribute__((alias ("host_fifo_tx")));

Now a quick check with nm should reveal these to all be at the same locations:

RC=0 stuartl@vk4msl-mb ~/projects/debugwire/firmware $ avr-nm leodebug.elf \
     | grep '\(proto_.*_uart_.x\|host_fifo_.x\|target_fifo_.x\)'
0080022c b host_fifo_rx
008001ac b host_fifo_rx_buffer
0080019c b host_fifo_tx
0080011c b host_fifo_tx_buffer
0080022c B proto_host_uart_rx
0080019c B proto_host_uart_tx
0080034c B proto_target_uart_rx
008002bc B proto_target_uart_tx
0080034c b target_fifo_rx
008002cc b target_fifo_rx_buffer
008002bc b target_fifo_tx
0080023c b target_fifo_tx_buffer