Jump to content


[POTM] dAISy - A Simple AIS Receiver

POTM MSP430 MSP430G2553 RF

  • Please log in to reply
258 replies to this topic

#1 chicken


    Level 4

  • Members
  • 854 posts

Posted 25 December 2013 - 12:43 AM

dAISy (do AIS yourself) is a very simple AIS receiver that I developed from scratch. It is built around the Silicon Labs EZRadioPRO Si4362 receiver, using a Texas Instruments MSP430G2553 MCU for processing and the MSP-EXP430G2 v1.5 LaunchPad as development platform.

The complete project source code and schematics are available on GitHub: https://github.com/astuder/dAISy

Update 5/18/2015: A finished, self-contained AIS receiver based on this project is now available for purchase on Tindie.
AIS, short for Automatic Identification System, is a standard for tracking ships. Ships advertise their position, course and other information with short transmissions on specific frequencies (161.975 MHz and 162.025 MHz). More on Wikipedia.
An AIS receiver, like dAISy, receives and decodes AIS transmissions. It then re-packages the raw data into NMEA sentences (specifically formatted ASCII strings). Finally, using a serial connection, these strings are forwarded to more capable equipment for further processing.
If you're the lucky owner of a tricked out boat, you could connect dAISy to your navigation computer. For land lobbers like me, a more common use case is to run naval mapping software that supports AIS data input on a PC. In the screenshot below I've connected dAISy to OpenCPN (link), an open source chart plotter and navigation software.
On the top right you can see my setup war-driving at the Seattle waterfront as my lab is too far from the coast to receive anything. The LaunchPad sits on the dashboard with a white USB cable connecting to the notebook computer in the foreground.
dAISy's data is fed into OpenCPN, bottom right shows a log of the serial data received. OpenCPN maintains a database of all the collected data (lower left) and visualizes nearby ships on a map (top center), including past and projected course. Hovering the mouse over a ship will display its name (text on yellow ground) and clicking it will reveal more detail (top left).
I wanted to build my own, non-SDR, AIS receiver for a long time. There are a few projects floating around the internet (e.g. here) which refer back to an article by Peter Baston, published 2008 in Circuit Cellar magazine (copy available here gone.. google for Peter Baston Circuit Cellar to find other copies). Unfortunately, the CMX family of modem ICs by CMS Microcircuits (link) used in these projects are relatively expensive ($15+) and hard to find for hobbyists. In addition you'd need a radio to do tune into and down-convert from the ~162 MHz carrier frequency.
So I was quite excited when earlier this year a parametric search on Mouser brought up a new IC  that covered the required range (162 MHz) and modulation (GMSK). And best of all, available in single quantities for $3.56 $2.27 $2.22! (link)
The Silicon Labs EzRadioPRO Si4362 (link) is a single chip receiver that covers frequencies from 142 to 1050 MHz and supports various modulations, including GMSK. It comes in a tiny 20-pin QFN package and the only external parts required are a 30 MHz crystal, an antenna with a few capacitors and inductors for impedance matching, and finally some decoupling caps and pull-down resistors.
Time to whip up a breakout board. I used the opportunity to give KiCad a try and quite like it.
Here's the schematic:
And the layout:
layout revA.png
I used OSHPark to make the PCBs. At a smidgen over one square inch it cost  $5.15 for 3 copies:
Note that the layout still has three issues that I already fixed in the schematic:

  • GPIO0 and GPIO1 were flipped
  • SDO required a pull-down resistor as the radio leaves it floating when not actively sending, which confused the hell out of me while trying to figure out the communication protocol.
  • Lastly, the holes for the headers turned out to be slightly too small to comfortably fit the cheap breakout headers I had at hand.

Edit: Here's Rev B where I fixed these issues: http://oshpark.com/s...ojects/WI6u3Qmk
Which brings us to the BOM:

  • Silicon Labs Si4362 (U1)
  • 30 MHz crystal (X1)
    • Si4362 datasheet specifies <11 pF load capacitance, but a crystal specified for 12pF load capacitance seems to work fine too
  • Antenna/LNA matching network, calculated based on SiLabs AN643 (link, approx. values, +/- 5% shouldn't matter too much):
    • 75 ohm (dipole): 10 pF (CR1), 5 pF (CR2), 280 nH (LR1), 200 nH (LR2)
    • 50 ohm: 12 pF (CR1), 6 pF (CR2), 240 nH (LR1), 160 nH (LR2)
  • Decoupling caps:
    • 100 pF, 100 nF, 1uF (C1, C2, C3)
  • Pull-down resistors
    • 100 k (R1, R2)

First thing I noticed when I received the parts: The 20-pin QFN at 4x4 millimeters is tiny! :blink:
I mounted it by first tinning the pads with a small quantity of solder. I then added flux and placed the chip on the pad. I then used a hot air station to carefully reflow the solder. Worked the first time around.

After using jumper wires to figure out how to talk to the chip, I mounted the breakout board on a makeshift BoosterPack using perfboard, double-sided tape and wire (see picture at the top of the post).


Here's how I ended up connecting the breakout board to the LaunchPad / MSP430G2553:

  • SEL -> P1.4 (SPI chip select)
  • SCLK -> P1.5 (SPI CLK)
  • SDO -> P1.6 (SPI MISO)
  • SDI -> P1.7 (SPI MOSI)
  • GPIO0 -> P2.0 (I/O unused)
  • GPIO1 -> P2.1 (I/O clear-to-send)
  • GPIO2 -> P2.2 (I/O RX clock)
  • GPIO3 -> P2.3 (I/O RX data)
  • SDN -> P2.4 (shutdown / reset)
  • IRQ -> P2.5 (I/O channel-clear)

The software of dAISy consists of three major blocks:

  • Radio configuration and control over SPI
  • Packet handler, including a basic FIFO for received messages
  • NMEA encoding and transmission to the PC over UART

For UART (TX only) and SPI (TX/RX) I use the MSP430G2553's USCI A0 and B0 respectively. In both cases I don't use interrupts which simplifies things considerably.
Upon reset the following steps happen:

  • Initialize MSP430 peripherals
  • Initialize packet handler, which will also reset FIFO
  • Initialize and configure of radio, which will also setup SPI
  • Start packet handler, which will also put the radio into receive mode

And in the main loop:

  • If debug messages are enabled, poll packet handler for status and errors and report them over UART
  • Check FIFO for new packets
  • If there is a new packet, invoke NMEA processing (which sends the message over serial to the PC) and remove packet from FIFO

Below follows a more detailed discussion of the radio integration and the implementation of the packet handler.
The communication with the radio is vanilla SPI using 4 wires: MOSI (SDI), MISO (SDO), CLK (SCLK) and CS (SEL). I used the MSP430's USCI B0 to implement SPI and a separate pin to control CS.
The only tricky thing to figure out was, that the Si4362 keeps the MISO line floating unless it actively transmits data. This is unfortunate as the master is supposed to poll for a specific response (FF) to detect when the radio is ready to receive more commands. This is easily fixed by adding a weak pull down resistor to SDO. I did this on the board, but it probably also works with using MSP430's internal pull-down.
Additional lines I used to control the radio are:

  • SDN to reset the radio
  • CTS, which by default is mapped to the radio's GPIO1, indicating that the radio is ready for the next command

While taking up an extra pin, CTS turned out to be much more convenient than the SPI response code to properly time communication flow with the radio. In dAISy, I wait for CTS to go high after each command to ensure the radio completed its task.
The communication protocol is quite extensive but well documented:

  • EZRadioPRO API Documentation describes the complete API and all registers
  • AN633 Programming Guide for EZRadioPro Si4x6x Devices describes how to use the API in common scenarios

Both are available on the Si4362 product page (link), under Documentation > Application Notes and are still updated quite frequently.
The radio is set up by dumping a large configuration sequence into it. This includes configuration of radio frequency, modulation, GPIO pins and more. This information is stored in radio_config.h, which has to be generated with a tool called WDS (Wireless Development Suite). WDS is available in the Tools section on the Si4362 product site.
WDS Settings.png
Above are the settings I used for dAISy. WDS will use this information to configure various amplifiers, filters, clocks and decoding algorithms inside the chip. As Si4362 supports GMSK encoding only indirectly (see this thread), I'm certain there's more optimization potential by tweaking registers, but that's currently way beyond my knowledge of RF theory.
While the Si4362 comes with its own packet handler, it unfortunately does not support NRZI encoding (Wikipedia). So I set up the radio to expose the 9600 baud clock and received data on separate pins and implemented my own packet handler.
Packet Handler
The packet handler (inspired by Peter Baston's implementation) is implemented as a state machine that is invoked on each rising edge of pin P2.2 which receives the data clock.
PH state machine.png
There are 5 main states:

  • Off, no processing of incoming data
  • Reset, start from anew, either on start up or after successful/failed processing of a packet
  • Wait for Sync, waiting for a training sequence to arrive (010101..) and start flag (01111110), implemented with its own state machine
    • Reset, start new preamble
    • 0, last bit was a zero
    • 1, last bit was a one
    • flag, training sequence complete, now process start flag
  • Prefetch, ingest the next 8 message bits to ease further processing
  • Receive Packet, process bits until the end flag (01111110) is found or an error situation occurs

Independent of state, the interrupt routine continually decodes NRZI into actual bit sequence.
In the "Receive Packet" state there's continuous calculation of the packet CRC and some bit-de-stuffing. When the end flag is found and the CRC is correct, the received message is committed into the FIFO. If an error is encountered, the bytes already written to the FIFO are discarded. In both cases, the state machine starts anew by transitioning into RESET.
This reads like a lot of code for an interrupt handler. However with the MCU running at 16MHz even the most complex state only uses a fraction (<10%) of the available time.
Future Improvements
Lastly a list of things I'd like to improve with the next version of dAISy.

  • Receiving on both AIS channels through channel-hopping done 1/5/2014
  • Tweak radio settings for better sensitivity and lower error rate
  • LED(s) for indicating reception of valid/corrupt packets


  • Proper antenna connector
  • Layout PCB as BoosterPack and/or USB dongle
  • Receiving on both AIS channels at once with two radio ICs

-- edit 12/25: replaced original post with high-level project description, more detailed documentation of implementation to come
-- edit 12/28: added documentation for hardware (here and on Github), fixed some typos
-- edit 12/31: added documentation for software and list of future improvements
-- edit 01/05: implemented channel hopping (change to state machine)
-- edit 01/15: changed state machine to reflect recent changes (see post further down for details), added link to shared project on OSHPark
-- edit 01/25: major rework of sync detection state machine

Attached Thumbnails

  • dAISy-visual1.jpg
  • ais-screenshot-wardriving.jpg
  • IMG_1373.jpg

  • bluehash, timotet, Rickta59 and 9 others like this

#2 bluehash


    Site Admin

  • Administrators
  • 6,429 posts

Posted 25 December 2013 - 02:00 PM

Let me try to guess.. sailboat controller? Excited!

43oh - MSP430, TivaC, ARM-Sitara and C2000 Discussion, News, Projects and Hacks



#3 chicken


    Level 4

  • Members
  • 854 posts

Posted 25 December 2013 - 04:50 PM

Ha ha :) Much less exciting unfortunately. The LaunchPad receives position data from ships and sends the data to a PC where it can be processed and visualized.
  • bluehash and simpleavr like this

#4 chicken


    Level 4

  • Members
  • 854 posts

Posted 25 December 2013 - 10:49 PM

Updated original post with a high-level project description. Source code is available on GitHub.


More detailed documentation of the implementation to come, including schematic for the breakout board for the Si4362.

#5 simpleavr


    Level 3

  • Members
  • 725 posts
  • Locationtoronto

Posted 25 December 2013 - 10:50 PM



Super cool! ...But why are boats on land? Do these things need calibrations?

www.simpleavr.com :: breadboard good, use breadboard

#6 chicken


    Level 4

  • Members
  • 854 posts

Posted 25 December 2013 - 11:03 PM

@simpleavr No, the received data is very precise. But unfortunately I forgot to update the default low-res vector map of OpenCPN on my notebook before heading out. There are free high resolution navigational maps that one has to download and install seperately.


Below how the background would have looked like when adding local maps. I'll do another screenshot when I head out next time.


--edit: forgot attachment

Attached Thumbnails

  • detailed map.jpg

  • bluehash likes this

#7 igendel


    Level 1

  • Members
  • 61 posts
  • LocationIsrael

Posted 26 December 2013 - 08:32 PM

Not very useful for the average joe I guess, but it's really awesome. I'd love to get a receiver like that but it'll probably be confiscated by the customs here... :smile: [edit: P.S. How close do you have to be to the port to read these signals?]

#8 chicken


    Level 4

  • Members
  • 854 posts

Posted 26 December 2013 - 09:34 PM

Not very useful for the average joe I guess


Thanks for shattering my plans for consumer gadget world domination :)


Technically the range of AIS is about 50 nautical miles, but that requires an unobstructed view and a properly placed and tuned antenna.



With my wimpy dipole antenna (two straight hookup wires) and the wrong impedance matching (50 ohm instead of 73 for a dipole) I was able to receive the packets from the base station 11 kilometers away when in line of sight. When I was parked at the waterfront with the antenna laying on my car's dashboard, I was able to receive messages of ships in line of sight about 2.5 kilometers away and 500 meters when obstructed by buildings.

  • tripwire and igendel like this

#9 igendel


    Level 1

  • Members
  • 61 posts
  • LocationIsrael

Posted 26 December 2013 - 10:15 PM

Thanks for shattering my plans for consumer gadget world domination :)


 Heh, with this and my oh-so-useful Morse code trainer, we can conquer the market :biggrin:


Thanks for the answer. BTW, your project reminded me a little of this - the bus location/timing signal. Now there's a system the bus faring hacker could really use!

  • chicken likes this

#10 chicken


    Level 4

  • Members
  • 854 posts

Posted 29 December 2013 - 12:03 AM

added more documentation about the hardware side of the project

#11 chicken


    Level 4

  • Members
  • 854 posts

Posted 31 December 2013 - 11:19 PM

Finished up project documentation by adding description of software implementation and a list of future improvements.


As I've no inkling about RF, I'm open for any input on how to improve sensitivity and lower error rate.


And to an earlier question by @simpleavr, below a recent annotated screen capture with more detailed maps and some action. I was located at the red X.



  • bluehash, simpleavr, markf and 1 other like this

#12 chicken


    Level 4

  • Members
  • 854 posts

Posted 06 January 2014 - 03:11 AM

Implemented channel hopping, i.e. the receiver jumps between the two AIS channels.


A frequency hop happens when the preamble isn't found within a certain time, currently set to 6 clock ticks (PH_TIMEOUT_PREAMBLE macro).


Ideally the timeout should be short to minimize the chances of missing a preamble on the other channel (total preamble is 24 bits). However there's also the overhead of reconfiguring the radio (about 1.5 clock ticks). I will have to experiment with this in the field to see if I can shorten it to 4 clock ticks, or reduce the minimum preamble length (currently 16 bits). The goal is to catch a preamble no matter on what channel it is sent.

#13 markf


    Noob Class

  • Members
  • 8 posts

Posted 11 January 2014 - 05:51 PM

Really impressive project @chicken !


I live close to the port, so I think I could be able to receive the AIS signal. Did you considered about selling the PCB and parts for building own receiver?
If so, I'd be interested for buying a DIY kit.

#14 chicken


    Level 4

  • Members
  • 854 posts

Posted 11 January 2014 - 10:45 PM

Thanks @markf

Given the QFN package of the radio, selling kits would probably be a support nightmare. Also, the current version is not very sensitive. I'll need to do a few more revisions before I'd feel comfortable asking money for it.

I'm happy to send you a spare PCB and parts if you want to experiment yourself - and have the equipment to solder QFN!

#15 markf


    Noob Class

  • Members
  • 8 posts

Posted 12 January 2014 - 10:58 PM

@chicken : Actually I have some experience with SMD/BGA soldering, and that's why I asked about DIY kit ;-) If you'd like to share with your spare parts please let me know so we can determine all the necessary costs.

#16 ike


    Level 1

  • Members
  • 98 posts

Posted 13 January 2014 - 12:19 AM

However there's also the overhead of reconfiguring the radio (about 1.5 clock ticks). 

Isn't just change channel command? From DS:  EZ Frequency Programming
In applications that utilize multiple frequencies or channels, it may not be desirable to write four API registers each
time a frequency change is required. EZ frequency programming is provided so that only a single register write
(channel number) is required to change frequency. A base frequency is first set by first programming the integer
and fractional components of the synthesizer. This base frequency will correspond to channel 0. Next, a channel
step size is programmed into the FREQ_CONTROL_CHANNEL_STEP_SIZE_1 and
FREQ_CONTROL_CHANNEL_STEP_SIZE_0 API registers. The resulting frequency will be:
RF Frequency Base Frerquency Channel+ Stepsiļ‚“ ze=

#17 chicken


    Level 4

  • Members
  • 854 posts

Posted 13 January 2014 - 12:30 AM

Isn't just change channel command? From DS:


Right, changing the channel is as simple as passing it with the START_RX command. However, the radio requires some time to adjust its PLL. Looking at the CTS signal (indicator that chip is busy), this takes about 0.17ms.


There's a faster method using RX_HOP, but that takes some additional work on my side and I wanted to get the hop logic working first (the source on Github currently seems to be broken (fixed and tested)  )


Do you have some experience with this radio? Being a total n00b when it comes to RF, I definitely could need some help to make this project more reliable.

#18 chicken


    Level 4

  • Members
  • 854 posts

Posted 16 January 2014 - 05:07 AM

Did some work on the firmware.

  • Moved channel hopping and RSSI statistics (signal strength) into ISR to avoid blocking by long-running code in main thread (e.g. serial transfers). This also means that the state machine model reverts back to the original (no more separate hop state)
  • To reduce time spent in ISR, sped up SPI clock to 8 MHz (Si4362 can handle up to 10 MHz)
  • Optimized RSSI readout by using the radio's FRR (fast read registers)
  • Also inlineing of some code (SPI byte transfer, radio status check)
  • Put main thread into LPM4 until a successful sync (preamble + start flag), a complete packet is received, or an error occured.

This time I tested the changes in real-world before pushing the code to GitHub :smile:  (btw, very straight-forward and practical Git tutorials can be found on Atlassian's website: https://www.atlassian.com/git/)


Attached screenshots of two successful captures of an AIS message as seen by the logic analyzer. Note that in after.png there's channel hopping (channel 1), i.e. data processing while serial data is sent back to the computer (channel 7).

Attached Thumbnails

  • before.png
  • after.png

#19 chicken


    Level 4

  • Members
  • 854 posts

Posted 16 January 2014 - 05:35 AM

I also reworked the breakout board:

  • Replaced crystal with one that meets specs as per application note AN785 (load capacitance max. 10pF, ESR max 80 ohm). The crystal on Rev A was too high on both, and doing some experimentation with XO tuning I think frequency is a bit too high.. though just guessing as I don't have a signal generator to really test this.
  • Widened signal track from antenna to radio and also added a footprint for an optional AC coupling cap.
  • Added ground plane on top with plenty of vias around signal track and under radio.
  • Fixed known errors of Rev A (pull-down on SDO, swapped GPIO 0 and 1, widened holes to fit breakout headers)

Any feedback from people more knowledgeable about RF than me (i.e. with any RF know-how) is very welcome.. though I'm impatient and already sent the new design off to OSHPark :rolleyes:

Attached Thumbnails

  • OSHPark-Rev-B.jpg

#20 petertux


    Level 1

  • Members
  • 57 posts

Posted 18 January 2014 - 08:36 PM

I see it has a lot of IOs. maybe it would be cool to include a uC onboard that would output 3v3 UART for easier implementation?


also when you end up selling these (populated and tested) I would love to buy one.

Also tagged with one or more of these keywords: POTM, MSP430, MSP430G2553, RF

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users