Showing posts with label hacks. Show all posts
Showing posts with label hacks. Show all posts

20130206

DIY TinyMarquee: an Attiny24 based scrolling marquee

This project uses charlieplexing and software serial to push the capabilities of the AtTiny24. The source code and design files are up on a github repository.

Other DIY LED marquee projects may be of interest, including a large one hand-routed on protoboard, one made from Christmas lights, a network enabled display, one using ping-pong balls, and one implemented in the rear window of a car.



A terminal stock ticker

The python module ystockquote pulls stock prices and other information from Yahoo finance, "get_price(stockname)". Here is a short python script that downloads and formats stock prices and writes them to a local file.

Bitmap fonts 

We need to translate text into a format that we can send to a scrolling marquee. We send raw pixels, so that we can adjust fonts and graphics without re-loading the firmware. Columns of pixel data are sent as 5-bit integers over serial. I used Gimp to draw a font and this Jython script to convert it into bit-packed integers representing columns of pixels for each letter.*


To test converting text to the bitmap font, the script "scroll" takes the scraped data and scrolls it across a simulated marquee in the terminal ( there is also the short "terminal_marquee" script which scrolls indefinitely, but updates intermittently in the background )

Hardware

The hardware consists of 90 3mm LEDs arranged in a 5x18 grid. These are driven by 10 IO lines of an AtTiny24. The remaining free IO line is used to poll and listen for serial data.

There is also a 10K pull-up resistor on the AtTiny's reset pin, and a 0.1μF decoupling capacitor near the power pins. The surface mount AtTiny bridges one row of the LED pins, a bit unusual but this allows a compact layout with through-hole LEDs. The marquee gets power and data from a USB to TTL serial adapter.


Charlieplexing

Charlieplexing is a way to drive tons of LEDs form only a few pins. Since LEDs only light up when current is passed in one direction, you can place two LEDs for every unique pair of IO lines at your disposal. This lets you drive N*(N-1) LEDs from N IO pins.**

PCB design

While it is possible to wire up the grid of LEDs by hand, I would not recommend it. Instead of going through this tedium, you can design a custom board and get it professionally fabricated. I use the free version of Eagle Cad to design and prepare boards for manufacture. A full Eagle tutorial is beyond the scope of this writeup, but numerous tutorials can be found elsewhere online. The Eagle design files for this project can be found here.




Exporting gerber files for board fabrication

One you have finalized a board, you need to prepare design files for fabrication. PCB designs get exported to so called "Gerber" files, which are like the PDFs of circuit board design. Once you have these files you can send them off to a fab house for production. My favorite tutorial for this is on Hackaday.

For one-off boards, BatchPCB is the go-to place. For small runs, consider Advanced Circuits or Seeed studio's Fusion PCB service. For larger runs (more than 30), depending on board size, Goldphoenix is the place to go. Depending on which service you choose, you should get boards in a few days to five weeks. I used Seeed because it is relatively cheap, and it took about a month to ship to the US.

Part sourcing 

For cheap LEDs I use Ebay. For all other components ( especially the AVR microcontollers ), I source from Mouser or Digikey. For a low cost USB to Serial adaptor, look for "USB To RS232 TTL PL2303HX" on Ebay . These are cheaper than, say, an FTDI cable from Sparkfun, and have worked great for me. I'd hoped to save a few bucks by using charlieplexing and the AtTiny14 in the design -- the total cost of each board, shipping and USB-TTL converter included, from a lot of 10, is about $7.50:
10   boards     $30   
1000 LEDs       $10   
10   AtTiny     $14   
50   Resistors  $ 1   
10   Capacitors $ 1   
10   Headers    $ 1   
10   USB-TTL    $18   
-------------------   
                $75   
       /10      $ 7.50

Cleaning the boards 

After you're finished soldering, remove any solder flux adhered to the board. Apart from being unsightly, flux can be conductive and corrosive and damage the board over time. Hackaday has a good tutorial on this. We filled an old jar with 90% Isopropanol, dunked the boards in there, and shook them around for a while -- it worked wonderfully.

Software serial 

The Attiny24 does not have hardware support for serial ( UART ), so we'll have to make a software implementation. For information about the RS-232 communication protocol, see the wiki. I used polling at twice the serial rate (4800Hz) to monitor incoming serial data, which is works for transmitting five bit packets. Further details about the firmware can be found in the C source file.

Compiling with avr-gcc 

I never remember the commands to compile and upload firmware, so here are the commands for future reference.

#compile source to a file a.o targeting the AtTiny24
avr-gcc -Os -mmcu=attiny24 ./display_serial.c -o a.o 

#extract the text and data sections to make a binary for the AVR
avr-objcopy -j .text -j .data -O binary a.o a.bin 

# check the size ( this should be smaller than the amount of available flash )
du -b ./a.bin

# upload the binary to ( in this case ) the AtTiny24 
avrdude -c avrispmkII -p t24 -B4 -P /dev/ttyUSB1 -U flash:w:a.bin 


_____________________________

*If you don't have Jython or a working JVM installed, it may be easier for you to re-enter the font as text data and write a short conversion routine in python.

**If you're familiar with multiplexing there's a simple way to conceptualize board layout for charlieplexing. When you multiplex an NxN grid of LEDs, you use N IO lines to control power to the (-) ends of the LEDs, and N IO lines to control power to the (+) ends of the LEDs.  To go from multiplexing to charlieplexing, note that microcontroller pins can take on three sates : Low (-), High (+), and Off ("high impedence"). Each IO line can serve as both a (+) line and a (-) line. What happens if we use the same N pins to drive both the (-) and the (+) a multiplexed display? Everything works fine, as long as we use the "off" state to stop current. One problem: there some LEDs along the diagonal of the matrix that have their (+) and (-) driven by the same IO pin -- there is no way to make these light up. But, no worries, since we are laying out our own board, we can just delete these LEDs, or connect their (+) terminals to a reserved IO pin to regain control of them! Charlieplexed PCB design can be relatively simple: lay out a grid of LEDs as if you were to multiplex them, but connect the N anodes to the N cathodes, and either delete the N LEDs that end up being connected to the same IO line at both ends, or wire these up to a separate IO pin to finish things off.


20110325

Technological Citizenship

In this post, I will advance an explanation of the differences between law and technology, and how ordinary people can reclaim control over their lives through what I refer to as “technological citizenship.”

The modern liberal state is defined by the rule of law, a fair and evenhanded treatment of all people according to clear rules. The most basic laws are constitutional, those that define the relationship between the parts of government, and government and the citizens. In democracies, and particularly in America, the Constitution has been carefully designed to allow for citizenship and participation in the law-making process. The Federalist papers debated and discovered how abstract principles like liberty and justice could be translated into the concrete institutions of policy, and despite occasional hiccups, and one major war, their framework endures today.

But laws are only half the story. The world is also full of technologies, and as Langdon Winner points out in The Whale and the Reactor, our technological constitution, the core systems for providing food, shelter, power, mobility, etc are not nearly as well-designed as the law. While the Constitution and the law grew through a process of considered debate and democratic input, technologies have accreted over time into centralized bureaucratic systems, operating according to a depersonalizing logic of efficient markets. For Langdon Winner, the power and omnipresence of these technological systems is a grave threat to democracy and liberty, as society become dependent on entities which are essentially autonomous from public control.

The democratic person is a political citizen, taking an active role in the process of governance by becoming informed on the issues, voting, communicating with their representatives and their neighbors. Our ideal of democracy remains ancient Athens (albiet with an updated version of who counts as a citizen), where every citizen participated equally in government, and positions were rotated regularly. The technological person is a consumer, and the end goal of technology is the 'utilitization' of everything, technologies becoming absolutely reliable, simple, and omnipresent. The more advanced a technology is, the fewer buttons, access panels, and failure modes it has; compare an early computer like ENIAC to an iPad. The best realized vision of this phenomenon is E.M. Forester's “The Machine Stops”, where planetary civilization is controlled by an immense computer system that is beyond the understanding of its inhabitants.

Now, reverse these roles. A political consumer is an unthinking, uncritical clod who unquestioningly obeys the dictates of The Party, whatever The Party might be. Political consumers are poison to democracy. But what is the technological citizen? By analogy, the technological citizen is somebody who takes an active stance towards technology, who is informed about the features and full scope of a given device or system, is prepared to think critically about the implications of that technology, and is not afraid to transform, adopt, or abandon technologies as alternatives become available. My friends at HeatSync Labs are great examples of technological citizens, actively experimenting with and adapting emerging technologies, and their lives have certainly been made richer through their close understanding of technology.

The challenge is therefore encouraging this new mode of technological citizenship. This will not be easy, citizenship demands deep, continuous engagement, (and political citizenship is on the decline in this country as well). And more and more technologies are becoming utilities, slick services that non-specialists can't even view, let alone think critically about. But conversely, with the internet, the cost of gaining expert technical knowledge is falling. As devices become smarter, making it easier to communicate with and analyze them should become a priority, such as a SmartGrid technology that tracks home energy usage room by room, device by device. Finally, education is a vital part of citizenship, and technological toys that are just visible enough should be developed to teach relevant skills, like computer programming, design and architecture, and ecosystems thinking. Personally, I've always been disappointed that Lego Mindstorms came out just after I lost interest in Lego; it would have made me a much better engineer. While developing technological citizenship is not easy, technological citizens will find it far easier to adapt and live in the future, and as partisan politics becomes increasing rancorous and alienating, technological citizenship may provide a new space for civic action and social development.


20110117

Augmenting Humanity @HeatSync Labs

Let's start this year off with a bang! I just got back from HeatSync Labs, where the local hackers are taking their eyes off of 3D printing, near-space missions, tesla coils, and cylon Roombas and working on something a little closer to home: themselves.

Okay, that requires a little explanation. HeatSync is a Phoenix area hackerspace, a place for technically inclined people to come together, pool resources, and work on interesting projects. Hackerspaces started in the nerdvanas of Silicon Valley and Route 128, but the movement is spreading across the country, and expanding from electronics to biotech. With the democratization of technical equipment, almost anybody can be a scientist. The hackerspace movement scales up the joy of just messing around with blinkenlights to an adult level, and it might just serve as the incubutator for the next wave of innovation.

Augmenting Humanity @HeatSync is a small group of hackers with an interest in transhumanism, and with using their DIY skills to improve themselves. They're well on their way. Jacob has an experimental magnetic sense, and wants more radical alterations. Harry is a recreational neuroscientist. He already has a 14 channel EEG he freed from an Emotiv controller, and his next step is to make an Arduino board DC neural stimulator, as well as his own version of ze goggles. With all this, he's well on his way to doing some real interesting science. Jeremy is into quantified self, and wants to use smartphones and wireless sensors to make data collection trivial. Bryan is blind, and is working with Apple to improve the accessibility of iDevices, while trying to find hacks to make his life easier. The current project is a liquid level sensor. As a father of three, Bryan spends a lot of time filling bottles, and a device which beeps at the proper level would be good for everybody.

These guys are definitely aware of the social and political aspects of what they're doing. They view themselves as citizen-scientists, in the vein of the old Royal Society, and they want to both improve themselves, and generate useful knowledge that the standard scientific research process won't touch, either because it won't be funded, or violates medical ethics (note: ethical medical research must treat a disease, so by definition, enhancement is unethical. The current work around has been 'medicalization', creating a disorder for people who want to be enhanced. Many people, myself included, think this is a major problem.) They also are very forward about getting their work out there, and connecting with like minded hackers across the world. In the absence of formal journals, all of this is being organized through social media, blogs, wikis, and video chat. We are lucky enough to live in an era where information can be shared easily, and advanced technology is cheap. In the next few months and years, I hope to spend a fair amount of time with Augmented Humanity, develop some projects, and get them out there. But for now, rest easy knowing that these people have the future well in hand.

((I'll also be taking suggestings on projects/topics to talk about with these guys))


20100902

Drop Day Octahedron

I was digging through the archives and I found some documentation for the CCFL Octahedron project from Drop Day that was never published. We don't have photos of the build process, just a text description and the source code, as well as pictures of the finished project in action. This should be good for inspiration and perhaps source code for a similar project, if not total duplication.

Physical construction

Each edge of the octahedron structure is a 2-foot piece of wooden dowel rod. A hole is drilled perpendicular to each rod at each end. The rods at each vertex are held together with a double loop of fishing wire through these holes. Rods and wire are spraypainted black.

The lights are cold cathode flourescent bulbs, as sold for lighting computer cases. A pair of bulbs are attached to the outside of each edge with cable ties. Each pair is powered through an inverter attached to the inside of the edge. I've left some spare bulbs in the elevator closet in alley 3. A pair of bulbs together with inverter can be purchased online for about $8.

A power cable runs from each inverter to a common vertex where they are bundled together and exit through one side. Each of the twelve cables is dual-conductor 18-gauge (?) speaker wire. One end terminates in a connector accepted by the inverter; the other is permanently soldered to the control board.

The control board is powered through a long three-conductor ribbon cable terminating in a Molex 8981 male connector, which will interface with a standard ATX computer power supply. (To make an ATX power supply turn on without a motherboard present, one must connect the ~PS_ON signal on the motherboard connector, normally green, to ground.)


Electronics

The control board is built around an ATtiny2313 processor, two CD4094BC 8-bit shift registers, and three ULN2068 quad-channel Darlington switch arrays. The processor is clocked by an external 16 MHz crystal. The fuse extended and high bytes are left at factory default. The fuse low byte is programmed to 0xFF: no prescalar, no clock output, external crystal, slow start-up. The shift registers are cascaded to act as a single 16-bit serial-in, parallel-out register. The processor has three outputs to the shift register: Data (pin PB3), Clock (pin PB2), and Latch (pin PB4). A single bit is loaded by setting Data high or low, setting Clock high for 4 processor cycles (250 ns), then bringing Clock low again. This is repeated 16 times, once per bit of a 16-bit word, with the least-significant bit first. After all 16 bits are loaded, the Latch pin is strobed high for 4 cycles, at which point the shift registers will present the 16 bits on their output pins.

12 of these 16 bits are wired to inputs of the Darlington switch arrays. When a switch-array input is at logic high, the corresponding output will sink current to ground, illuminating the corresponding lights. The unused bits of the shift register are (from LSB = 0) bits 6, 7, B, and F.

The power supply to the control board consists of ground, +5 V, and +12 V. The 12 V supply is wired directly to the positive side of each inverter's DC input. The negative side of each inverter's input sinks through a Darlington switch. When all bulbs are on, the system will draw about 5 amps on the 12 V line. It has an inline fuse holder loaded with a 10 amp fuse. The 5 V line is used for powering the logic chips only and should draw minimal current.

.. you see how much effort I'm putting here : screen shot of the monospace text figure

hdr2 is used to program the processor via a standard AVR programmer, such as the AVR ISP mkII. From top to bottom as oriented above, the pins are:

MOSI, MISO, SCK, VCC, ~RESET, GND

hdr1 is currently unused but is connected to the circuit. From top to bottom:

VCC, GND, not connected, PD4, PD5

This could be used to communicate with another board via a 2-wire serial protocol.

The push buttons will short PB5 or PB6 to ground when pressed. The switch will short PD6. Neither is used by the current software.


Software

See code at the end of this post. The software implements a few modes and switches between them. It includes a very simplistic random number generator (which is not random at all because the seed is hard-coded).


Bugs and quirks

Sometimes, especially when starting, the system will go into a bad state such as freezing or strobing synchronously in an unappealing fashion. I seem to have fixed this by adding another filtering capacitor on the 12 V rail, but the problem may return.

Sometimes after switching off the ATX power supply it will not turn back on for a number of minutes. Perhaps a large resistor between power and ground would fix this problem by acting as a stabilization load.

Many aspects of the circuit, such as the use of shift registers, an external crystal, and extra buttons and switches, are historical or arbitrary. Where the speaker wire meets the board it can short against unintended pins of the ULN2068 in ways that are not visually obvious. This can result in all four channels on that chip turning on when only one is activated in software.

You can pulse-width modulate a light channel in software, but it will not dim the light. Instead, it will light up part of the tube from one end, which looks cool and is probably very bad for the bulb.


Replacing the control board

The control board is a crufty prototype and it may be desired to replace it with something nicer: either a better-produced custom board or a totally off-the-shelf controller. Essentially all that is required is to switch on and off with some reasonable speed the sinking of ~ 500 mA current on each of 12 channels. This could be accomplished with any number of devices: Darlington pairs, power FETs, solid-state relays, etc. Optical isolation of the control signal may improve robustness. Many microcontrollers can provide the 12 I/O pins directly, so external shift registers are unnecessary.


Software


Here is the source code associated with the Octahedron. First, build-and-upload.sh, the bash commands used to compile and upload the program to the AVR.


#!/bin/sh -e


# build with avr-gcc suite
avr-g++ -o octahedron.bin -mmcu=attiny2313 -Wall -Winline -save-temps -fverbose-asm -Os octahedron.cpp
avr-size octahedron.bin
avr-objcopy -j .text -j .data -O ihex octahedron.bin octahedron.hex

# upload using AVR ISP mkII
avrdude -p t2313 -P usb -c avrispmkII -U flash:w:octahedron.hex


This is the straight up AVR C++. You'll need an in system programmer to upload it.



#define F_CPU 16000000L

#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

typedef uint8_t byte;

// a shitty "random" number generator
uint16_t xrand() __attribute__ ((noinline));
uint16_t xrand() {
static uint16_t y = 3;
y ^= (y << 13);
y ^= (y >> 9);
return y ^= (y << 7);
}

// delay by an amount known at runtime
void delay_ms(uint16_t ms) {
while (ms-- > 0) _delay_ms(1);
}


// Define pins for the shift registers
#define SREG_PORT PORTB
#define SREG_DDR DDRB
#define SREG_LCH (1 << 4) // latch, high to set
#define SREG_DAT (1 << 3) // data
#define SREG_CLK (1 << 2) // clock on rising edge

// Define pins for the buttons and switch
#define UI_PORT PORTB
#define UI_DDR DDRB
#define UI_PIN PINB
#define UI_BTN_A (1 << 6)
#define UI_BTN_B (1 << 5)

#define UI_BTN_A_DOWN (!(UI_PIN & UI_BTN_A))
#define UI_BTN_B_DOWN (!(UI_PIN & UI_BTN_B))

#define UI_SW_PORT PORTD
#define UI_SW_DDR DDRD
#define UI_SW_PIN PIND
#define UI_SW (1 << 6)
#define UI_SW_EN (DARK_PIN & DARK_SW)

// Init the shift registers
inline void sreg_init() {
SREG_DDR |= (SREG_LCH | SREG_DAT | SREG_CLK);
}

// Optional delay when setting pins for the
// shift registers.
// At 5V they will handle at least 12 MHz.
inline void sreg_delay() {
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
}

// Shift a bit into the shift registers.
void sreg_shift_bit(bool x) {
if (x)
SREG_PORT |= SREG_DAT;
else
SREG_PORT &= ~SREG_DAT;

sreg_delay();
SREG_PORT |= SREG_CLK;
sreg_delay();
SREG_PORT &= ~SREG_CLK;
}

// A full shift-register write.
// Shift 16 bits, then latch.
void sreg_write(uint16_t x) {
for (byte i=0; i<16; i++) {
sreg_shift_bit(x & 1);
x >>= 1;
}

sreg_delay();
SREG_PORT |= SREG_LCH;
sreg_delay();
SREG_PORT &= ~SREG_LCH;
}

// The bits corresponding to wired-up channels are:
// FEDC BA98 7654 3210
// XXX XXX XX XXXX
// This function maps 12 contig. bits onto these.
uint16_t lights_to_channels(uint16_t x) {
return (x & 0x003F) // 0000 0011 1111
| ((x & 0x01C0) << 2) // 0001 1100 0000
| ((x & 0x0E00) << 3); // 1110 0000 0000
}

// Set which lights are on according to a 12-bit value.
uint16_t lights = 0;
void set_lights(uint16_t new_lights) {
static uint16_t state = 0;
lights = new_lights;
uint16_t new_state = lights_to_channels(lights);
uint16_t mask = 0;

//if (new_state == state) return;

for (byte i=0; i<16; i++) {
mask = (mask << 1) | 1;
sreg_write((state & (~mask)) | (new_state & mask));
_delay_us(500);
}

state = new_state;
}


/*
inline void ui_init() {
// pull up both buttons and the switch
UI_DDR &= ~(UI_BTN_A | UI_BTN_B);
UI_PORT |= (UI_BTN_A | UI_BTN_B);

UI_SW_DDR &= ~UI_SW;
UI_SW_PORT |= UI_SW;
}

inline void ui_debounce() {
_delay_ms(50);
}
*/

#define L_R1 0x400
#define L_G1 0x002
#define L_B1 0x004

#define L_R2 0x008
#define L_G2 0x040
#define L_B2 0x010

#define L_R3 0x100
#define L_G3 0x020
#define L_B3 0x080

#define L_R4 0x001
#define L_G4 0x200
#define L_B4 0x800

/// RGBRBGGBRGRB
/// BRGR BGGB RBGR
/// 0101 0000 1001 = 0x509
/// 0010 0110 0010 = 0x262
/// 1000 1001 0100 = 0x894

#define ALL_R (L_R1 | L_R2 | L_R3 | L_R4)
#define ALL_G (L_G1 | L_G2 | L_G3 | L_G4)
#define ALL_B (L_B1 | L_B2 | L_B3 | L_B4)

#define ALL_LIGHTS (ALL_R | ALL_B | ALL_G)

const uint16_t tris[8] PROGMEM = {
L_R2 | L_G2 | L_B2,
L_R1 | L_G3 | L_B2,
L_R3 | L_G3 | L_B3,
L_R4 | L_G2 | L_B3,
L_R3 | L_G1 | L_B4,
L_R4 | L_G4 | L_B4,
L_R2 | L_G4 | L_B1,
L_R1 | L_G1 | L_B1
};

const uint16_t squares[3] PROGMEM = {
ALL_R, ALL_G, ALL_B
};

/// modes

uint16_t rand_mask() {
return (1 << (xrand() % 12));
}

void noise_fast() {
uint16_t len = 300 + (xrand() % 300);
for (uint16_t t = 0; t < len; t++) {
set_lights(lights ^ rand_mask());
_delay_ms(60);
}
}

void fade_down() {
while (lights != 0) {
set_lights(lights & (~rand_mask()));
_delay_ms(1);
}
}

void fade_up() {
while (lights != ALL_LIGHTS) {
set_lights(lights | rand_mask());
_delay_ms(1);
}
}

void updown_fast() {
uint16_t len = 20 + (xrand() % 20);
for (uint16_t t = 0; t < len; t++) {
fade_up();
fade_down();
}
}

void rgb() {
uint16_t len = 150 + (xrand() % 100);
for (uint16_t t = 0; t < len; t++) {
for (byte i=0; i<3; i++) {
set_lights(pgm_read_dword(&squares[i]));
_delay_ms(120);
}
}
}

void tri_rand() {
uint16_t len = 300 + (xrand() % 700);
for (uint16_t t = 0; t < len; t++) {
set_lights(pgm_read_dword(&(tris[xrand() % 8])));
_delay_ms(60);
}
}

/* causes reset?
void tri_strobe() {
uint16_t len = 100 + (xrand() % 300);
for (uint16_t t = 0; t < len; t++) {
set_lights(pgm_read_dword(&(tris[xrand() % 8])));
_delay_ms(30);
set_lights(0);
delay_ms(xrand() % 200);
}
}
*/

/*
void test() {
for (byte i=0; i<12; i++) {
set_lights(1 << i);
delay_ms(1000);
}
set_lights(0);
delay_ms(5000);
}*/

int main() {

sreg_init();
//ui_init();

set_lights(0);

for (;;) {
rgb();
updown_fast();
rgb();
noise_fast();
rgb();
tri_rand();
}

}