For some time I was looking for a GPS tracking solution that would run from a single battery for several days. Smartphones are too power hungry, all GPS loggers I found are designed to track animals, cars, etc. by sending positon on request over GSM, but there are no loggers that would just save GPS position every few seconds and lasted several days on small battery. This fact forced me to design my very own solution.
This project is still in progress, most of the fw had been tested by unit tests, hw design is currently in the manufacturing house.
As the device is supposed to be running on a small battery for extended periods of time, the desing itself must be as low power as possible. There are four main power hungry blocks: MCU, data storage, GPS receiver and power supply.
Few years back I would go with the Atmega or Attiny MCU, but stm32 + jlink + atollic for debugging makes me too lazy to do the old style printf debugging. STM32F070 comes with integrated USB peripheral and tons of flash storage for under 3 bucks in single quantities, so this is the easiest way to go. Also the huge flash memory can be used for storing two firmware images (valid and backup). The power consumption can be reduced heavily by switching to sleep mode as often as possible.
SD cards are a perfect storage solution, except for the power requirement, current during writing can reach more than 100 mA, standby current is bit smaller than 1 mA. That's awful. SPI Flash memories can run at few uA when not used and won't take much space on PCB. The capacity is much lower, but with a reasonable data format, this shouldn't be an issue.
It's hard to find a different GPS receiver than U-Blocks modules. I've worked with these before, they are nice, but the price tag in single quantities is around half of the planned device cost. That's too much. After some search I found a SIM28ML module which has same footprint as MAX-M8Q from U-Blocks. It comes with integrated LNA and SAW filter, everything bundled in a tiny package. The power consumption is similar to U-Blox modules. Unfortunately, the GPS module is the most power hungry device in the design. To reduce it to the minimum, it will work only once a minute and will be switched off after getting a fix, shorter logging period = higher power consumption (not necessarily linear dependence).
Currents drawn from the battery will be in order of dozens of mA, it doesn't really make sense to use a switching power supply here, a LDO is a good solution here. BUT, the power consumption is a crucial parameter. The power consumption of the LDO itself must be as low as possible as it will be in the one state all the time. MCP1700 with it's consumption under 1,6 uA is a perfect choice here.
Also as I wanted to be able to recharge the device over the USB, e.g. from a power bank, I've added a LiIon charger MCP73832 to the desing. The charger can be dissabled by the MCU if non-rechargeable battery is used.
As I didn't want to run a special PC side software to read and convert data from the logger, I needed to find a way how to convert an internal representation of the track into GPX file on the fly. So I went for an epic journey of writing my own ramdisk and gpx file generator.
The filesystem on the ramdisk must be as simple as possible and all windows and linux machines should be able to read it without any additional software. The FAT was an obvious choice. There are several different FAT standards, FAT12 is the simplest one intended for floppy disks, FAT16 is for bigger disks and FAT32 is the most widely used FAT variant today. FAT32 is a bit more complicated that FAT16, FAT12 and FAT16 are mostly the same, only FAT table record length is different. So I went with FAT16.
USB storage device (implemented in libopencm3) is accessing the ramdisk in 512 bytes long chunks called sectors. The main idea behing the ramdisk is generating the FAT structure on the fly when the corresponding sector is accessed. The first sector is the boot sector and contains basic data about the FAT structure (length of the sector and cluster, name of the volume,...), the boot sector is followed by FAT table (linked list of clusters used by corresponding file) and root folder (contains info about all files and folders in the root folder). For precise layout and sectors content please refer to an excellent maverick-os webpage.
With knowledge of the FAT structure, it's pretty easy to generate the boot sector (it's just a static array of bytes hardwired in the firmware), for the rest of the filesystem I decided to keep the list of existing files (and info about file length and function that will generate it's content) in an array of structures. When FAT table is accessed the firmware generates a list of connected clusters for each file in the list, there are no gaps and one cluster is directly follower by another, pretty easy to generate. Similarly the root folder is populated on the fly with informations from the file list. When the data area is accessed, the ramdisk library decides to which file the currently accessed sector belongs to, calculates offset from the beginning of the file and passes this information to user function that's responsible for generating the valid file data.
This way the whole FAT implementation resides in few bytes of RAM and is not dependend on the data storage.
The current GPS position is stored in an external SPI flash memory in raw bytes format together with a current time and a elevation. One record takes 22 bytes, that means together with 4 MB flash that 181818 records can be stored (or 126 days if using 1 minute logging period).
When the device is connected over USB to the computer, data from the Flash memory are used to generate the GPX file, only 512 bytes (sector size) of the GPX file are generated at any given time. This way no RAM is wasted for buffering the huge GPX log. On the other side, this comes with a performance penalty, but it's not significant enough to be worried.
There are several ways how to reduce the power consumption (aside from these mentioned before) - not implemented yet: