Jared Sanson

Tags

 

Overview

As a side project, I decided it'd be neat to have a programmable wrist watch. I had an OLED lying around with the right dimensions (approx 1 inch diagonal), but I needed a breakout board to be able to use it. So instead of simply making a breakout board, I decided I'd turn it into a smart-watch platform!

My design uses a PIC24FJ256GB206 MCU, which is pin compatable with the PIC24FJ256DA206 (the DA series have an inbuilt graphics accelerator peripheral).

I also decided to include some cheap sensors, like an accelerometer, magnetometer, light, temperature, air pressure, etc. And of course, some GPIO.

I'm going to state now I have absolutely no idea where this will go, I'm learning a lot of new stuff to do this!

Design

I based quite a few of my designs off sparkfun products, since they already work properly. I decided to use an MMA7455 for the accelerometer, and a HMC5883L magnetometer, both of which are available from Element14.

The OLED requires a 12V supply, so I followed sparkfun's breakout board (which seems to be missing from their site now). Their design uses an LM27313 boost converter to generate the +12V.

Charging is done through the USB port using an MCP73831 Li-Ion charger.

Since the board is going to be the same size as an OLED, I found a Li-Ion battery that perfectly fits inside the dimensions: 400mAh Lithium Ion Battery

Development

After I was happy with the schematic, I started the PCB design. I have only had a little bit of PCB layout experience in Altium, so I was learning a lot of new things. The trickiest thing for me at first was figuring out which footprints I should assign to the components.

Starting PCB LayoutStarting PCB Layout
Assigning FootprintsAssigning Footprints

After I was happy with the footprints, I started organising the components roughly where I wanted them. Somewhere along the line I added a vibration motor, which will be very useful for alerts.

LayoutLayout
Completed LayoutCompleted Layout
Completed LayoutCompleted Layout

Now the board is ready to be produced! I decided to go with OSHPark, since they had a good price and also a gold ENIG finish. Since then BatchPCB have merged into OSHPark, so looks like they are quite a good choice!

Final TopFinal Top
Final BottomFinal Bottom

And here are the completed PCBs!

PCBs!PCBs!
Showing the purplenessShowing the purpleness

Then a realisation struck me...

Looks like it's time for Revision 2. Remember: Always double check everything before sending it off! Somehow I messed up the footprint for the MCU, and it's half the size of the actual chip!

Keep an eye out for my next blog post. I'll show my development of Revision 2, along with some more schematics and design stuff.

View Comments...

Datasheet Indexer

Mar 13, 2013 programming Uncategorized

Overview

I wrote a simple program a few years back, it's just a simple list of datasheet files (for example .pdf), with real-time filtering. While it seems like it may not do much, it makes it extremely quick to pull up an IC datasheet when I need it, instead of having to browse/search my filesystem or the web.

As an extra feature, it can also automatically download missing datasheets!

It is also completely non-invasive and runs stand-alone, so you can run it on a flash drive, or even have multiple datasheet libraries. Config files are stored in the same folder as the .exe

Tips:

  • Options can be accessed through right clicking the list
  • You can drag'n'drop new datasheets directly onto the window
  • You can add multiple aliases for a single datasheet by separating with a '/'
  • You can modify the auto-download behaviour by modifying the import.pas script, if you know a bit of pascal.
View Comments...

Overview

Me and a bunch of friends decided to build a 3D printer. We all collaborated and built different parts of it, and after a few months work we had a working printer! This particular model is called the Prusa Mendel, a popular DIY printer. You can read more about 3D printers on wikipedia: RepRap Project

Wires everywhere!Wires everywhere!

The 3D printer works by extruding a plastic filament through a hot nozzle (much like a hot glue gun), and onto a build plate, building layer upon layer. 

Depending on how high it stacks each layer, a print can take anywhere between 30 minutes and 8 hours! It is possible to get a resolution of 100 microns (0.01mm) with a lot of calibration and patience.

The plastic filament we're using is called PLA, or Polylactic Acid. It is a polymer that is derived from sugars, and is also biodegradable! When we're printing, it fills the room with a sweet sugary smell.

Other plastics can be used, such as ABS or Nylon, but they are harder to print and produce toxic fumes.

Building It

My task was wiring it up and getting the electronics together. I didn't want to use the Arduino + Plugin boards that most people use, since it's rather ugly and inefficient. Instead I decided to hand solder a Generation 6 Electronics board.

Unfortunately when I had finished soldering it, it didn't work! After another month, I realised that I had ordered 20ohm resistors instead of 0.2ohm resistors. doh!

After switching in some new resistors, it all worked beautifully. Unfortunately a day later, one of the motor driver chips blew up, so I decided to just go with a prebuilt module. This time I chose the Printrbot electronics, which is a step up from the Gen6.

Calibration

The next part was definitely the trickiest, and that was to calibrate the thing. Unfortunately our build plate wasn't very flat, so we only had marginal success. We found we could only really print small objects, since anything too big would either not stick or it would warp.

Here are some photos of our early calibration prints:

Prints

After calibration, we tried some harder prints:

Stanford BunnyStanford Bunny
Double TorusDouble Torus

One of the first prints we tried was the Stanford Bunny, a popular object in computer graphics classes.

I also tried a few other prints while I had it properly calibrated:

Misc Test PrintsMisc Test Prints

Failure Strikes Again!

There's a leak somewhere inside it, and the molten plastic is oozing into the firecement and causing it to crack. It was also causing large amounts of smoke! (Incidentally, it smells like burning sugar, which makes sense since PLA is derived from corn starch)

Future Improvements:

We're planning on replacing the build-plate with glass, which is very flat, and should hopefully enable us to do bigger prints. Finding glass the right size is proving to be tricky however.

We are also thinking of replacing the extruder with one that doesn't leak! Though the current one seems to be holding out for now.

View Comments...

Linear LED PWM

Feb 03, 2013 electronics, leds Article

In this blog post, I will show you how to properly control an LEDs brightness using PWM. It isn't as simple as you think!

PWM works by varying the duty cycle of a square wave, like so:

The effective voltage is equal to VCC * k (where k is the Duty Cycle), and for an LED its brightness will also be proportional to k (Assuming it is driven with a constant current and voltage). Pretty much every microcontroller supports PWM, either through a dedicated peripheral, or you can do it yourself in software!

However, there is a problem with the common approach of PWMing an LED. Take this Arduino code for example:

void loop() {
    byte i = 0;
    while (1) {
        analogWrite(2, i);
        delay(10);
        i++;
    }
}

This will fade an LED on pin 2 of the arduino, from dark to bright. But you may notice the LEDs don't fade very nicely. They will appear to fade very quickly at first, and then spend a long time at full brightness:

The reason behind this is because the human eye doesn't respond to light linearly, but logarithmically. That sure complicates things!

To fix it, we have to correct the PWM values to make them appear linear to the human eye.

A common misconception is that gamma correction should be used, as it does have a very similar response to the eye. However, gamma correction has nothing to do with how humans perceive light, it is just coincidence that it appears to work. The CIE 1931 lightness formula is what actually describes how we perceive light:

L* = 903.3Y,            if Y0.008856
L* = 119Y^1/3 – 16,   if Y > 0.008856

Where Y is the luminance (output) between 0.0 and 1.0, and L* is the lightness (input) between 0 and 100

The formula needs to be rearranged in terms of L*:

Y = (L* / 903.3)           if L*8
Y = ((L* + 16) / 119)^3    if L* > 8

EDIT 2020/12: Formula updated. Original formula incorrectly used 902.3 & 116 as coefficients

Of course, this formula would be too slow to implement on a microcontroller due to the power and division, so you should use a look-up table instead. I created a simple python script to generate a C header file that can be simply included into the project:

cie1931.py

INPUT_SIZE = 255       # Input integer size
OUTPUT_SIZE = 255      # Output integer size
INT_TYPE = 'const unsigned char'
TABLE_NAME = 'cie';

def cie1931(L):
    L = L*100.0
    if L <= 8:
        return (L/903.3)
    else:
        return ((L+16.0)/119.0)**3

x = range(0,int(INPUT_SIZE+1))
y = [round(cie1931(float(L)/INPUT_SIZE)*OUTPUT_SIZE) for L in x]

with open('cie1931.h', 'w') as f:
    f.write('// CIE1931 correction table\n')
    f.write('// Automatically generated\n\n')

    f.write('%s %s[%d] = {\n' % (INT_TYPE, TABLE_NAME, INPUT_SIZE+1))
    f.write('\t')
    for i,L in enumerate(y):
        f.write('%d, ' % int(L))
        if i % 10 == 9:
            f.write('\n\t')
    f.write('\n};\n\n')

Which produces a table that looks like this:

const unsigned char cie[256] = { 0, 0, 0, 0, 0, 1, 1, ..., 247, 250, 252, 255 };

Depending on the microcontroller being used, you may want to change the type so it stores the values in ROM instead of RAM.

The constants at the top can be changed to suit the microcontroller. For instance, if you wanted to use a 10 bit PWM, you could set INT_SIZE=1024. This would still generate a table with 256 entries, but the output will be 10 bits.

Because this conversion reduces the resolution of the PWM, it may indeed be wise to use a 10 bit PWM. This is exactly what I did in my LED Coffee Table Project.

Finally, using the lookup table to fade LEDs:

#include "cie1931.h"

void loop() {
    byte i = 0;
    while (1) {
        analogWrite(2, cie[i]);
        delay(10);
        i++;
    }
}

And now we have LEDs that fade linearly!

Thanks to all the comments below for helping with errors in my original article!

Also see this C++11 constexpr version by nitz

View Comments...