Daily Archive for October 13th, 2013

Enabling the NRF24L01+ for ACRIS

Okay, it’s finally time for making a wireless version of ACRIS. I’m damn tired of stringing up CAT-5 cable everywhere.

So, I’m exploring possible wireless communications systems. My first choice is those based on the Nordic NRF24L01+ chip, which operates in the 2.4GHz spectrum. You can get a variety of turn-key modules from DealExtreme with PCB antennas or more powerful on-board amplifiers and external antennas for practically nothing.

I started by buying three PCB-antenna modules so that I could characterize them. Three weeks later, they finally showed up.

Designing a Reasonable Firmware Architecture

The next step was to write a library for ACRIS. Ultimately, the goal is to convert the whole system, bootloader and all, to be fully wireless. Of course, instead of just starting by writing some tests, I decided to redo the entire ACRIS firmware architecture. Originally, I was going to work on a separate branch, but then when I saw that Github doesn’t count non-master commits on your dashboard status, I got angry and merged it all into master. I also wrote a shitload of READMEs to describe what everything does (or rather, should do).

I finally learned how to make Makefiles from scratch instead of just going off of random other ones I found on the internet. I swear I’m going to start using make for everything ever now. But anyways, I wrote a framework for building and programming all projects in the [cci]avr/prj[/cci] directory. The new firmware architecture is described in this README.

Writing the NRF24L01+ Driver

After porting all the existing code to the new architecture, it was time to start writing a driver for the NRF24L01+. The NRF communicates with an MCU over SPI. Unfortunately, the ATmega168 only has one SPI module and I wanted to dedicate it only to the TLC5940 LED drivers since they use a non-standard way of latching the data (it’s possible to work around this and support everything on the one SPI bus but this would generate a lot of extra traffic on a bus I’m trying to keep quiet).

So, I decided to use the USART in SPI mode, as Atmel documents in their datasheet. In this mode, a third pin is used for the clock ([cci]XCK[/cci]) and [cci]TXD[/cci] and [cci]RXD[/cci] are used for [cci]MOSI[/cci] and [cci]MISO[/cci]. I was lucky enough to leave the [cci]XCK[/cci] pin unused in the LED controllers, so I can actually rework all of my existing LED controllers really easily.

At the same time, though, I need to make a device that translates commands from UART or USB to packets for the NRF. This means that I must use the USART for regular serial communication and SPI to communicate with the NRF.

So, I wrote a communication layer: a common set of commands for sending and receiving bytes and streams of data. The underlying driver can be selected as either SPI or USART depending on which file is compiled, but the API is the same.

On top of this layer, I wrote the actual driver for the NRF24L01+. Unfortunately, the code so far is pretty rigid. It doesn’t easily handle cases like being able to reconfigure the chip quickly. But it does expose functions for reading and writing registers, flushing buffers, transmitting a packet, set up reception, etc. I still have plenty of work to do on it, such as enabling double-buffering for received payloads, setting up ACK payloads (e.g. for communicating LED controller status information), etc. Maybe I’ll add support for their MultiCeiver architecture (automatic handling of multiple transmitters). Depending on how I intend to use it in the future, I may also modify the SPI architecture to be interrupt/event-based.

After a bunch of debugging, I finally got some test firmware working. Building the project [cci]test-nrf[/cci] with [cci]MODE=tx[/cci] will set the project up to be a transmitter and [cci]MODE=rx[/cci] will set it up as a receiver. When one of each is programmed onto two different boards, they’ll talk to each other and the receiver will spit data out via serial. The result?

The range of the modules is pretty decent. I can reach all the way to the other side of my apartment without any issues. But, the caveat is that the two must be in line-of-sight. Pretty much any wall will completely stop all communication. Now, this is using the 1Mbps data rate with Enhanced ShockBurst enabled. If I disable Enhanced ShockBurst and switch to 250Kbps, I might get better results.

OTOH, I also just bought a few of these modules. They use an external antenna and have onboard amplifiers which boost the gain by a whopping 30dB. So, I’m hoping that I’ll only need one of these and then can use the PCB-antenna modules in all of the lighting controllers for reception. The only possible problem with this is that the receivers may not be able to send back ACKs that the transmitter will hear. In this case, I’ll have to disable Enhanced ShockBurst and come up with some kind of isosynchronous transfer mode where the transmitter won’t care about ACKs. But then I won’t be able to enable auto-retransmission and reprogram the controllers wirelessly, which would really suck.

I’m waiting for some 3.3V LDO regulators to come in from Digikey so that I can rework the LED controllers. Right now, I’m using LM317s with a bunch of trimming resistors to make the supply voltage around 3V3.