UART Bitrate Converter for GPS on Nikon Cameras

Modern Nikon DSLR cameras supports the connection of a GPS on the remote shutter port to include automatic geotagging of the shoots.

The camera uses a small proprietary double-sided connector to receive the position data form a remote GPS unit. The protocol used is the standard NMEA 0183.

Nikon official GPS unit is quite expensive, and I had an old Bluetooth GPS unit which I’m not using anymore but had the NMEA output at the wrong bitrate, as the camera only accept NMEA data at 4800bps, while the GPS works at 38400bps.

This project, made for my good friend and photographer David (checkout his blog!), is a small firmware for an ATMega168 to read the data from an high speed UART port, and reply that on a slower port, using a circular buffer for the data.


The heart of most GPS radio chips is the NMEA 0183 protocol, which defines how GPS location data is transmitted on a serial link. Portable Bluetooth GPS unit streams that protocol over the Bluetooth, but often the original serial data is available on an external port, or can be easily found on some internal header of the device.

The problem in this case is that often the internal UART of GPS unit runs at 38400bps, probably to support additional protocol extensions of the GPS vendor, while the bitrate expected on the Nikon camera is the (standard) 4800bps.

To convert the data, the microcontroller has been mounted in the middle of the data cable. The challenge here is that as the input UART link is many times faster than the output one, the microcontroller needs a data buffer almost as big as the longest communication burst, which should be about 400 byte for an NMEA message set.

Also, the microcontroller only has one UART port, so the output port was bitbanged using a GPIO and a timer.

The GPS unit used in this project provides the 3.3V TTL UART data and a 3.3V power supply on a mini USB port.


Tha hardware UART driver is contained in the uart.c file, and is simply a polled UART driver implementing the usual uart_getchar() function, as well as a uart_poll() function to check if the port has any data available.

Data is fed to the circular buffer with the buf_put() function.

The UART in functions in the main loop are used as in:

  for (;;) {
    if (uart_poll()) {

    if (buf_havedata() && uout_idle())


The output UART is bitbanged on the PD2 pin using a simple state machine triggered by the TIMER0_COMPA irq vector.

The state machine implement the output shift-register with the required start and stop bits.

That’s the implementation, starting from a populated uart_data variable with uart_counter set to 10 to initialize the state machine.

  if (uout_counter == 0) {
    /* idle */
  } else if (uout_counter == 1) {
    /* stop bit */
  } else if (uout_counter == 10) {
    /* start bit */
  } else {
    if (uout_data & 0x01)
    uout_data >>= 1;


No schematics for this project! To build the cable I used a PDIP version of the ATMega168, from which I cut all the unneeded pins. The resulting thing is a long flat element which can be easily mounted in the middle of the cable and fixed with an heat shrinker.

The power is supplied from the GPS unit, and is a 3.3V, but the Nikon GPS port provides a 5V outputs if necessary. The GPS IN port of the camera seems to work without problems with 3.3V signals.

The project files for the converter can be found on GitHub!


19 Responses to UART Bitrate Converter for GPS on Nikon Cameras

  1. José Ferr says:

    Great Project!
    It’s possibel you share the code in .hex or .bin?
    Thanks in advance

  2. José Ferr says:

    Hello again,

    I have a Holux GPS Slim236 with mini-usb port, my question is possible directly connect to the mini-usb or i need to convert the signal of gps to nmea whit a rs232 cable before connect it to VART IN (pin2 of atmega168)?

    Holux Slim236:

    • That’s the same GPS I used with that circuit. NMEA output is a 3.3V TTL, so you can go directly into AVR RX pin.

      • José Ferr says:

        AVR RX pin? or TX (transmitter)?

        Holux pinout (miniUSB)
        1. GND
        2. Vout (3,6v Max. 100mA)
        3. TXD
        4. RXD
        5. Vcharged +5v

        GPSr ATmega
        1. GND 8. and 22.
        2. Vout 7.
        4. RXD 2.
        Is that correct?

        Thanks ;)

      • Well, Holux TX to ATmega RX (UART IN, pin 2).

  3. José Ferr says:

    Hello once again,
    it is possible to use a AT90S1200?
    Because it is smaller and fits better with cable


    • Hello Jose’,

      I’m afraid that the code requires an ATmega series AVR, both for the UART controller and for the SRAM, which must be big enough to fit an entire cycle of NMEA message sequences – which i think is about 400bytes – so no luck with the s1200.


      • José Ferreira says:

        Hello Fabio,
        Only today I received the ATmega and tested the circuit, but is not working to me, I suspect that the atmega is wrong programmed.

        I use a labprog + of ELNEC, here is a pic of settings are used:

        (I’ve tried several options and none of one worked)

        And can you confirm that the connections are correct?

        Thanks in advance and sorry for being so boring ;)

  4. José Ferreira says:

    i think is this settings, but continue not working

    • Hello Jose’,

      on the fuse: CLKDIV8 has to be disabled (i.e. the MCU has to run at 8MHz), CLKOUT is not needed (but doesn’t hurt), start-up time does not make any difference, others are ok as default.

      The diagram looks correct, so unless you messed up with the calibration byte somehow it should work!

      You may try to debug the firmware somehow, like attaching a LED on some pin and turn it on in some strategic point on the code (like checking if you read some known character/string).

  5. José Ferreira says:

    does not work because the Vout of GPS .
    I used the +5 v of camera and is now working very nice :)

    Thanks once again

  6. sergey says:

    Please tell me how to convert GPS data bit rate of 9600 38400 using your project

  7. sergey says:

    Sorry of 38400 in 9600

    • Hi Sergey,

      in theory it should be as easy as changing UOUT_SPEED #define from 4800 to 9600 in defines.h… the internal clock should be ok to handle that bitrate too. Give it a shot!


  8. sergey says:

    sad but I’m not a programmer I built to the program in the final firmware …?

  9. sergey says:

    I used AVR studio 4 the compiler avr-gcc (WinAvr) but I have to exit the trash

Leave a Reply to sergey Cancel reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: