EV Logger
A MSP430 based datalogger for an electric vehicle
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Data Structures | Macros | Typedefs | Functions | Variables
Logger

Data Structures

struct  RingBuffer
 A ring buffer which can be attached to given (preallocated) memory area. More...
 
struct  SampleBuffer
 A structure to contain one 'set' of samples from the vehicle. More...
 

Macros

#define rb_getused_m(b)   ((b->tail==b->head) ? 0:(b->head - b->tail + b->len) % b->len)
 Quick facility to get the used value of a ring buffer. More...
 
#define rb_getfree_m(b)   ((b->tail==b->head) ? b->len : (b->tail - b->head + b->len) % b->len)
 Quick facility to get the free value of a ring buffer. More...
 
#define rb_reset_m(b)   do {b->tail = b->head = 0} while (0)
 Reset a ring buffer to its original empty state. More...
 
#define S1_PORT_OUT   P1OUT
 
#define S1_PORT_REN   P1REN
 
#define S1_PORT_IES   P1IES
 
#define S1_PORT_IE   P1IE
 
#define S1_PORT_IFG   P1IFG
 
#define S1_PIN   _BV(7)
 
#define S2_PORT_OUT   P2OUT
 
#define S2_PORT_REN   P2REN
 
#define S2_PORT_IES   P2IES
 
#define S2_PORT_IE   P2IE
 
#define S2_PORT_IFG   P2IFG
 
#define S2_PIN   _BV(2)
 
#define SD_RINGBUF_LEN   2048
 Ring buffer length for the SD card, should be a multiple of 2 of the sector size (512 bytes)
 
#define SD_RINGBUF_MASK   (SD_RINGBUF_LEN - 1)
 The ring buffer mask value. More...
 
#define ADC_CHANNELS   7
 The number of ADC channels that we will sample from. More...
 
#define ACCEL_CHANNELS   3
 The number of accelerometer channels (typically 3) to be sampled from. More...
 

Typedefs

typedef struct RingBuffer RingBuffer
 
typedef struct SampleBuffer SampleBuffer
 

Functions

void logger_init (void)
 Set up the hardware for logging functionality, including the configuration of required peripherals such as the ADC and Accelerometer. More...
 
void update_lcd (RingBuffer *buf)
 Update the LCD with the current status of the logger, including buffer usage, data file size and SD card utilisation. More...
 
void start_logger (RingBuffer *sdbuf)
 Set up the SD card and the FATFS filesystem handler before commencing the logging service. More...
 
FRESULT sd_write (RingBuffer *rb, char *writebuf, FIL *fil, uint16_t n)
 Write n bytes from a ring buffer to an SD card controlled by fatfs. More...
 
uint8_t ringbuf_write (RingBuffer *buf, char *data, uint16_t n)
 Write n bytes to a RingBuffer. More...
 
uint8_t ringbuf_read (RingBuffer *buf, char *read_buffer, uint16_t n)
 Read n bytes from a ring buffer. More...
 
void logger_enable (void)
 Enable TA1 to begin logging by setting mode control to "up" mode, counter counts to TAxCCR0. More...
 
void logger_disable (void)
 Disable TA1 to halt logging by setting mode control to STOP. More...
 
 interrupt (TIMER1_A0_VECTOR)
 Interrupt service routine for Timer A1 (TA1), where we should log one block of data. More...
 
 interrupt (PORT1_VECTOR)
 Interrupt vector for button S1 which is used for enabled and disabling logging. More...
 
 interrupt (PORT2_VECTOR)
 Interrupt vector for button S2.
 

Variables

static volatile uint32_t time
 
static volatile uint8_t logger_running
 
static volatile uint8_t file_open
 
static char s [UART_BUF_LEN]
 
static char ringbuf [SD_RINGBUF_LEN]
 
static char writebuf [512]
 
static RingBuffer sdbuf
 A RingBuffer that we will use to buffer sets of samples that are to be moved to the SD card.
 
static volatile SampleBuffer sb
 A SampleBuffer to store a single set of readings before they are transferred into the SD transaction buffer. More...
 
FATFS FatFs
 A FATFS filesystem object which we use to handle files and directories on the SD Card. More...
 
FIL fil
 A pointer to the data file.
 
DWORD fsz
 Stores the current size of the data file.
 
char * RingBuffer::buffer
 A pointer to the start of the character buffer to be used by this ring buffer.
 
uint16_t RingBuffer::head
 A pointer to the head of the ring buffer (the next free byte available for writing).
 
uint16_t RingBuffer::tail
 A pointer to the tail of the ring buffer (the next unread byte)
 
uint16_t RingBuffer::len
 The length of the ring buffer.
 
uint16_t RingBuffer::mask
 This value is a ring buffer intrinsic and is automatically generated.
 
uint8_t RingBuffer::overflow
 A flag that will be set non-zero if a buffer overflow occurs (the head tries to "overtake" the tail.
 
volatile uint16_t SampleBuffer::adc [ADC_CHANNELS]
 Storage for the ADC channels.
 
volatile uint16_t SampleBuffer::accel [ACCEL_CHANNELS]
 Storage for the accelerometer channels.
 

Detailed Description

Macro Definition Documentation

#define ACCEL_CHANNELS   3

The number of accelerometer channels (typically 3) to be sampled from.

This must be set correctly such that the DMA transfer system will work correctly.

#define ADC_CHANNELS   7

The number of ADC channels that we will sample from.

It is vital that this is correctly set such that the DMA system will work properly.

#define rb_getfree_m (   b)    ((b->tail==b->head) ? b->len : (b->tail - b->head + b->len) % b->len)

Quick facility to get the free value of a ring buffer.

Parameters
bA pointer to the buffer which we wish to query
#define rb_getused_m (   b)    ((b->tail==b->head) ? 0:(b->head - b->tail + b->len) % b->len)

Quick facility to get the used value of a ring buffer.

Parameters
bA pointer to the buffer which we wish to query
#define rb_reset_m (   b)    do {b->tail = b->head = 0} while (0)

Reset a ring buffer to its original empty state.

Parameters
bA pointer to the buffer which we wish to query
#define SD_RINGBUF_MASK   (SD_RINGBUF_LEN - 1)

The ring buffer mask value.

This is automatically calculated.

Function Documentation

interrupt ( TIMER1_A0_VECTOR  )

Interrupt service routine for Timer A1 (TA1), where we should log one block of data.

We do this by copying the current SampleBuffer into the RingBuffer used for SD transactions. There is no processing of the data since it is too slow – this is left to post-processing on a desktop machine. We then trigger the next conversion runs for the ADC and accelerometer such that next time we enter this ISR, new data will be in the SampleBuffer sb.

interrupt ( PORT1_VECTOR  )

Interrupt vector for button S1 which is used for enabled and disabling logging.

We should debounce the button press using the system ticks timer, and then enable or disable logging as required.

void logger_disable ( void  )

Disable TA1 to halt logging by setting mode control to STOP.

The flag logger_running is deasserted so that the start_logger() loop notices and cleanly flushes and closes the data file. We also write to the LCD to show that logging has stopped.

Note
logger_running is deasserted after the timer is stopped.
void logger_enable ( void  )

Enable TA1 to begin logging by setting mode control to "up" mode, counter counts to TAxCCR0.

The flag variable logger_running is asserted such that the start_logger() loop notices that logging has started as should open the data file if it has not already done so. We also write to the LCD to show that logging has been started.

Note
logger_running is asserted before the timer is enabled.
void logger_init ( void  )

Set up the hardware for logging functionality, including the configuration of required peripherals such as the ADC and Accelerometer.

Timer A1 (TA1) is configured to interrupt at the log frequency (1kHz), the interrupt service routine (ISR) is TIMER1_A0_ISR() also found in this file (please see that function's documentation for details of what is done in the ISR).

Todo:
Calculate TAxCCR0 value based on F_CPU instead of hard-coding.
uint8_t ringbuf_read ( RingBuffer *  buf,
char *  read_buffer,
uint16_t  n 
)

Read n bytes from a ring buffer.

This is done via a fast memcpy operation and as such, there is logic in this function to transparently handle the copy even if we're wrapping over the boundary of the ring buffer.

Parameters
bufA pointer to the ring buffer we want to write to
read_bufferCopy data into this array
nThe number of bytes to be read from the ring buffer
Returns
0 for success, non-0 for failure
uint8_t ringbuf_write ( RingBuffer *  buf,
char *  data,
uint16_t  n 
)

Write n bytes to a RingBuffer.

This is done via a fast memcpy operation and as such, there is logic in this function to transparently handle the copy even if we're wrapping over the boundary of the ring buffer.

Parameters
bufA pointer to the ring buffer we want to write to
dataA pointer to the data to be written
nThe number of bytes to be written to the ring buffer
Returns
0 for success, non-0 for failure
FRESULT sd_write ( RingBuffer *  rb,
char *  writebuf,
FIL *  fil,
uint16_t  n 
)

Write n bytes from a ring buffer to an SD card controlled by fatfs.

We turn on the red LED on the board during an SD write transaction such that the user can monitor the frequency and duration of writes. This is particularly helpful in watching for SD clock stretching which often causes buffer overflow.

Note
n should always be at least one sector (typically 512 bytes), hence the RingBuffer rb. Doing otherwise will work but will likely cause significant slowdown. The calling function can use the rb_getused_m() macro to determine when there is one sector's worth (or more) of data in the buffer and then call sd_write().
Parameters
rbA pointer to the ring buffer from which we will read the required data.
writebufA short buffer where we can temporarily place a single before before writing it to the card.
nThe number of bytes to be written to the card.
filA pointer to the file to which we want to write.
Returns
FRESULT The fatfs result code for the write operation.
void start_logger ( RingBuffer *  sdbuf)

Set up the SD card and the FATFS filesystem handler before commencing the logging service.

The controls regularly moving blocks of data from the SD buffer to the card using sd_write(), which is done when the SD buffer size has reached at least the sector size such that we write as quickly as possible. It also calls for LCD display updates (with update_lcd()) and handling opening/closing of the data file when logging starts/stops.

Parameters
sdbufA pointer to the SD card buffer. This is a RingBuffer that we will use to buffer incoming samples before they are logged to the SD card, such that we can write entire sectors at once.
void update_lcd ( RingBuffer *  buf)

Update the LCD with the current status of the logger, including buffer usage, data file size and SD card utilisation.

Note
This should not be called too regularly on the MSP-EXP430 board due to the SD card and LCD panel being on the same SPI bus and will cause slowdown of SD transactions.
Parameters
bufA pointer to the RingBuffer which we are monitoring.

Variable Documentation

FATFS FatFs

A FATFS filesystem object which we use to handle files and directories on the SD Card.

volatile SampleBuffer sb
static

A SampleBuffer to store a single set of readings before they are transferred into the SD transaction buffer.