Wednesday, July 30, 2014

Serial Data Logging

When developing and debugging firmware for a MCU, which is performing some quite extensive processing of the data from multiple sensors, it is very important to be able to look at this data as it is being collected and processed. Similarly, when tuning, for example, PID parameters it is critical to capture the RC input, attitude data, and control signals to motors. All of this points to a need to capture data from the board and subsequently transfer it to a PC for analysis.

Now that we identified the need for some form of the data transfer from MCU to a PC, we need to decide on the protocol for this communication. Article SerialProtocols Compared provides an overview of popular serial protocols.
  • RS-232 (in its “modified” form adopted for MCUs) protocol is an obvious choice for implementing communication between MCU and PC the following reasons:
  • Most MCUs (including my PIC) provide some form of a HW support for RS-232 communication in the form of UART modules. Actually, the PIC24EP512GP806, which I use for my board, supports four independent UART modules. 
  •  Most PCs support RS-232 serial protocol either through dedicated or emulated (over USB) serial ports.
  • There is a lot of third-party HW that supports RS-232 communication – FTDI cables, XBee wireless modules, Bluetooth modules, data loggers – just check Sparkfun.com.
  • RS-232 considerably fast – for PIC-to-PIC communication over a short range or PIC-to-PC communication over the FTDI cable it is reasonable to boost the speed to 1 Mbps; for wireless communication, for example – over a pair of XBee modules, speed usually limited to 115.2 Kbps.
  •  One MCU pin is required to implement RS-232 transmitter or two pins if you would like to implement HW Flow Control; I opt for the second choice.
Thus, my decision for this board was to use one of the available four UART modules to implement Serial Data Logger (SDLModule) interface. Project “11-SDL” tests SDL interface. However, prior to jumping into the implementation details, there are two issues that we need to discuss.

UART data stream is just a stream of bytes – serial protocol does not define any structure over this stream. From the logical perspective, we will be passing messages, so on the receiving end we need to know where one message ends and the new one begins so that we may correctly parse the stream and recreate the message even if some of the messages got distorted during transmission. In my implementation, I decided that every message would start with 0x5555 and end with 0xAAAA. For obvious reasons we could not use all 0s or all 1s (appear quite often in the data), but why this specific combination? No particular reason, except, maybe, that in both of these code words each successive bit is the inverse of the previous one (0x55 = 0b01010101 and 0xAA = 0b10101010), which results in a visually appealing and highly visible pattern in the logic analyzer.

Even at 115.2 Kbps transmitting 30-40 bytes takes between 2.5 and 3.5 msec – an eternity from the viewpoint of the processor running at 64 MIPS. During this time processor may execute about 20,000 commands – perform the whole iteration of the control loop! Thus, the implementation of data logging should be asynchronous with regard to the main execution thread with the maximum delegation of the whole transmission to the HW. Luckily, presence of the HW-based UART module together with the Interrupt system allows us easily achieve this goal on PIC.

Before we start discussing the code, a few words about the UART implementation on PICs and the timing errors. PIC supports 2 modes for UART timing – the so-called Standard mode and High-Speed mode. In Standard mode 16 timing pulses required for each bit, while in High-Speed mode only 4. The frequency of the timing pulses depends on the command frequency Fcy (which we set at 64 MHz) divided by the value in the Baud Rate Generator (BRG) register. More details on Baud rate generation and overall UART module operation provided in Microchip document UniversalAsynchronous Receiver Transmitter (UART). The important thing to remember is that with this mechanism most of the typical communication frequencies could not be defined exactly – there will be some error! However, certain amount of timing error is quite acceptable for serial communication – article TimingErrors in Serial Communication provides great background on the issue and defines the upper bound on the timing error acceptable for reliable communication.

Important thing to remember is that High-Speed mode allows for more precise setting for the communication frequency resulting in the lower error. I created an Excel file that calculates BRG values for typical communication speeds together with the respective errors for both UART modes assuming that the Fcy=64MHz.




Advantage of the Standard mode is that due to the larger number of timing pulses (16) the data line is sampled 3 times – on the 7th, 8th, and 9th pulse significantly reducing potential for read error. With just the four timing pulses in the High-Speed mode multiple sampling is impractical. However, multiple sampling important only for the UART Receiver; as here we are implementing UART Transmitter I opted for High-Speed mode, which reduces the timing error.

Now we may start looking at the code of the SDL Module. Header file SDL_Profile.h provides definitions that allow to associate code with one of the four available on the MCU HW UART Modules. Most of the HW modules (UART including) of the PIC MCU are not tied permanently to some MCU pins – when needed for particular design, modules may be associated with respective pins using advanced feature – Peripheral Pin Select. _SDLInitPinMap function, defined in SDL_Profile.h implements exactly that.

Header SDL.h defines thre functions implemented by SDL module – SDLInit, SDLPostIfReady, and SDLPostWhenReady. The former one initializes the module specifying required Baud rate and the interrupt level to be used by the module. SDLPostIfReady initiates data transmission if the SDL module is Ready – that is the previous transmission has completed. SDLPostWhenReadywaits until the SDL module is Ready, and then initiates data transmission. Both functions copy the data to be transmitted into the internal buffer and then load the message header (0x5555) into the UART FIFO buffer, at which point they return to the main thread without waiting for the transmission to complete.

The rest of the data transmission is carried out in the UART interrupt routine, defined in SDL_ISR.c, which is invoked when the FIFO buffer is empty. Interrupt routine moves bytes from the internal buffer into the UART FIFO buffer and immediately returns control. If the internal buffer exhausted, interrupt routine pushes into the FIFO buffer message trailer (0xAAAA) and set the indicator that SDL Module completed transmission and is ready for the next one.

While the actual transmission of the message may take several milliseconds, the UART routine will be active just a few microseconds during this time, leaving the rest of the time for the execution of the main thread.
Project 11-SDL provides the test platform for the SDL Module and may serve as a very trivial sample of usage. In the later projects we will see more examples of the SDL usage.

Finally, a few words about the practical use of SDL module – it is not enough just to send data, we need to have some ways to receive and process it! In my development depending on specific requirements (speed vs. flexibility) I use either an FTDI 3.3 V cable to link UART from my board to the USB port on my computer or a pair of XBees – one connected to the UART on the board and the other – to again the USB port using XBee Explorer USB from Sparkfun.com. To collect detailed telemetry during the flight I use MicroSD data logger (SD-Logger-V2).


To make sense of this log data on a PC I developed two Windows-based programs – LogStreamer to read the log data directly from the USB port and LogConverter to read the log file from the MicroSD card. Both programs store the log as a tab-delimited text file ready for load into Excel. Both programs rely on a XML-based format file, which defines the format of the data in the log. SDLTest.xml is the format file to interpret the log produced by the 11-SDL project. You are welcome to use these programs under the MIT License.

The format template file can be quite elaborate and detailed discussion of these log processing routines might be a topic for a separate blog. However we will be using them quite often while working with the sensors and will be looking at more templates, so their structure and basic usage should become obvious.

This closes the logging chapter and now we may start looking at sensors. The first one will be HMC5983 magnetometer connected over the SPI bus, but that will be the topic of the next post.

No comments:

Post a Comment