Saturday, April 21, 2012

SPI OLED A-OK (or, I would like to apologize to my readers for the preceding title)

I've reached another milestone in the development of my sleep mask: the OLED module works.

This section of the project was relatively straightforward: basically nothing more complicated than establishing a serial connection to the device and starting it up appropriately.

The Hardware

This is identical to my original design, which was, in turn, copied from the module datasheet.  This is the same hardware as is sold by Adafruit Industries; I acquired mine from another source, without the breadboard-friendly PCB attached.  It has an on-board capacitor charge pump to provide the high-voltage (~7.5V) necessary to drive the OLED pixels.  The serial interface is identical to the Serial Peripheral Interface (SPI) with a Command/Data select line and a Reset line in addition to the usual Chip Select line.

The Software

The stripped-down testing firmware I used is posted here.  It's not much to look at; it just starts up the SPI on-chip peripheral and sends the necessary command bytes (while manipulating the control lines appropriately) to start up and activate the display module.  It then starts sending out data bytes to change what is shown on the display.  The commands sent are outlined in the module controller's data sheet (the Solomon Systech SSD1306).

The controller continuously updates the pixels in the display by reading from an internal display memory.  When data is written to the device, it is used to update the contents of this display memory.

The folks at Adafruit have also implemented some software to drive this display module.  My software is largely the same, with one noticeable difference.  The controller contains twice as much display memory as needed for the module (to make it capable of driving larger displays); when writing to this memory over the serial link, the memory is all written over in turn before restarting at the beginning.  The Adafruit software just writes zeros onto that second half of the driver memory; however, there is a command which allows you to set the limits of the memory to be written.  By setting this command to only write over the usable half of the memory, my software doesn't need to write the entire memory every time, only the half that is actually visible.  In this way, I don't need to devote as much of my computational resources to updating the display.

The Goods

The test hardware setup is shown below.  As usual, I used my oh-so-refined soldering and fabrication skills to gain access to the tiny pads on the end of the display's ribbon connector.  The connections are relatively simple; a few decoupling caps between power pins to ground, some pass-throughs for the serial link, and the two capacitors for the charge pump.


To prove that I actually got this to work, here is a short video of the device (and ATXMEGA controller) as power is applied; first the display is told to turn all the pixels on, then it displays from the display memory (which is, initially, full of noise; this is in contrast with the data sheet, which states that the RAM should be blanked after a reset cycle).  Then, the controller starts sending alternating frames of display data.



The firmware source containing the specification of the alphabet/symbols is here.

Sunday, April 15, 2012

REM detection hardware, firmware and software tests (or, I honestly had some doubts that this would work so well)

On the REM-detecting, white-noise-generating, potato-julienne-ing project front, I have finalized the hardware (and toyed with the firmware) for the REM detector subsystem.

To recap this project: I am developing a sleep mask which will be able to detect the REM (rapid eye movement) phase of sleep, and wake the user up at the 'optimal' point in their sleep cycle.  Additionally, it will be able to record the timing and duration of REM sleep phases (potentially useful for improving sleep) and it will be able to generate white, pink or red noise through speakers at the ears to improve sleep.

I mocked up the hardware and some firmware which sends acquired REM detector samples over a serial channel; I also had to put together some software to acquire, interpret and plot this serial information.  The results of this effort have allowed me to finalize the hardware design for the REM detector subsystem.  As it stands, all I have left to finalize of the hardware is the display and the USB interface hardware; once these two things are nailed down, I can design and order the boards and fabricate the hardware, moving to the firmware-only phase of the project.

Finalized hardware

The hardware has been modified from the schematics I presented originally.  These changes are due primarily to two factors: the microcontroller has an internal gain (negating the need for a second external gain stage) and the desire to used a switched-emitter topology (that is, the illumination of the eye for REM detection will only be on for a small percent of the time to save power).

As seen in the schematic below (the left op-amp), the current output from between the phototransistors on the mask is fed into a transimpedance amplifier whose output is fed directly into an ADC pin on the microcontroller.  This single-ended signal can eventually be used to set the emitter amplitude.  This signal is also fed into the positive side of a differential ADC (with gain); the negative side is fed from a lowpassed PWM output.  This negative input can be used to bias the differential ADC channel to maximize dynamic range; the lowpass converts the oscillating PWM signal into a DC signal whose level is the rail voltage times the Duty Cycle of the PWM waveform.  The transimpedance amplifier feedback resistor is set to 40kOhm to maximize signal amplitude while preventing saturation under normal (and even some abnormal) usage conditions.
The driver circuitry has been significantly improved in this schematic.  Specifically, an op-amp is used to 'linearize' the current control.  Above, a sense resistor is used in negative feedback to set the current through the infrared emitter; the set point is determined by a lowpassed PWM fed through a voltage divider.  Without the 'linearization' of the sense resistor and negative feedback, the highly nonlinear nature of the emitter's current/voltage characteristic meant that only a few of the possible PWM output levels were 'useful' (that is, corresponding to levels of current we would want to drive our emitter with).

Additionally, the op-amp makes driving the emitter simpler; its high input impedance simplifies the design process for the lowpass-PWM easier.  Additionally, it makes it simple to add an enhancement N-FET to allow for switching the emitter on and off (by tying the control input of the op-amp to ground).

Firmware/Software for debugging

To debug the REM detector hardware, I needed to implement a firmware to sample the REM detector input channel and transmit that data to my laptop.  I also needed to create software on my computer to acquire and plot the transmitted serial data.  The firmware and software are contained in this zip archive.

The big questions I needed to answer were: what do I need to do to keep the differential channel biased appropriately, and how long does the emitter need to be on to ensure that the phototransistor signal is stable before sampling.

The firmware samples the single-ended and differential ADC channels.  It then updates the PWM bias setting on the negative input of the differential channel to keep the differential signal centered.  It then formats a couple of serial bytes according to the ADC data and sends them to the computer.

To plot this serial stream, I made a function in MATLAB that opens the serial port and continuously samples the incoming bytes, breaking up the stream into sequences, translating them into floating-point numbers and displaying them on the screen, as seen below.  The blue trace is the single-ended ADC channel, the green trace is the differential channel, and the red is a moving-average of the green.

I waggled my eyes at the beginning and middle of the plotted waveform; you can see that the signal is well-modulated by eye-waggling, which is necessary for detection of REM.
I used a USB oscilloscope (the Hantek DSO-2090, highly recommended) to check out the settling time for the phototransistor signal in response to switching the emitter.  At the end of the day, I established that a switched emitter could be timed to allow for detection of REM using the specified circuit, so I have finalized that circuit and am moving on to validating the USB and display subsystems.

Wednesday, April 4, 2012

Plotting bars, whiskers and bridges in MATLAB (or, too much time spent getting the spacing just right)

I needed to plot the mean and variance of some data, and indicate pairs of data points which were significantly different.  I searched and searched, but there was no easy plot function in my environment of choice (MATLAB), so I made one myself.

The look of the plot is shown below; basically, you've got clusters of mean+variance data (or whatever you want to represent with a bar and whisker).  Within each cluster, there are pairwise relationships you want to indicate.  Relationships can be further specified by a variable number of marks above the bridges.
The function is here.  It takes three arguments: the first two are (number of clusters)-by-(number of bars per cluster), and represent (respectively) the height of the bars and the length of the whiskers.  The third argument is (number of bars per cluster)-by-(number of bars per cluster)-by-(number of clusters) and indicates whether a bridge should be drawn between a pair of bars; a nonzero value indicates that a bar should be drawn, and integers greater than one indicate that extra indication (in the form of circular marks) should be made above the bridges.

It's not the prettiest, but it works and it got the job done well enough for me.  Besides, any fine-tuning is going to be done in your vector editor of choice, so all that's important is getting the actors arranged on the stage.