Data collection and storage firmware is complete. Shown below is the high-level firmware structure, with files grouped by hardware component, and a gaitkeeper module with the main setup() and loop() functions.
Every module has a simple public interface of a setup function, a run function for the main busy loop, and a serial debug function that's optionally set at compile time.
Through experiment, it was found that writing any data to the SD card took 30ms, which was unacceptable given our 5ms data collection period. Closer examination of the Arduino SD library revealed that data is collected in a 512 byte buffer in software, before being flushed to the SD card. With a 24 byte package, this would allow for only ~100ms of data collection before a 30ms pause. However, by creating a larger, custom heap buffer, many user steps of data could be recorded at 5ms period before writing to the SD card in 512 byte increments.
According to the nRF52 datasheet, the heap size is determined at compile-time to be ~64KB. It was experimentally determined that 45KB could be contiguously allocated before overflowing, so 32KB was decided as the buffer size. Thus, the frame size needed to be minimized in order to maximize the period of time with 5ms data, which gives the gait algorithm the most reliable data to analyze.
Shown below is the dataframe format. Each frame is 24 bytes, which allows for 7 seconds of continuous data collection at 5ms period, interspersed with a ~50ms pause to write the 32KB buffer to SD. 3 bytes is allocated to storing the unix timestamp's upper 3 bytes, which records absolute time at a resolution of 256 seconds. 1 byte is allocated to storing the number of milliseconds elapsed since device power-on, which intentionally overflows every 256 milliseconds. This is to determine the relative time between dataframes, which is always below 256 milliseconds, so this is an acceptable range. Raw pressure+IMU data is 4 bytes, but are all scaled to 2 bytes in software. Pressure sensor data is scaled to between 0-300lb, giving a resolution of 0.005lb. Linear acceleration is scaled to +/-8g, giving a resolution of 0.002m/s. Angular rotation is scaled to +/-500deg/s, giving a resolution of 0.008 degrees/s. These resolutions are all sufficient for data analysis purposes.