first version of untested firmware

This commit is contained in:
Michael Egger
2017-10-27 17:38:08 +02:00
parent 1ae4f7d312
commit bdd2e39891
7 changed files with 502 additions and 119 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ COMPILE = avr-gcc -Wall -Os -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU)#-DDEBUG_LEVEL=
# NEVER compile the final product with debugging! Any debug output will
# distort timing so that the specs can't be met.
OBJECTS = build/main.o
OBJECTS = build/main.o build/light_ws2812.o
# symbolic targets:
+181
View File
@@ -0,0 +1,181 @@
/*
* light weight WS2812 lib V2.0b
*
* Controls WS2811/WS2812/WS2812B RGB-LEDs
* Author: Tim (cpldcpu@gmail.com)
*
* Jan 18th, 2014 v2.0b Initial Version
* Nov 29th, 2015 v2.3 Added SK6812RGBW support
*
* License: GNU GPL v2+ (see License.txt)
*/
#include "light_ws2812.h"
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/delay.h>
// Setleds for standard RGB
void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
{
ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
}
void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
{
ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
_delay_us(ws2812_resettime);
}
// Setleds for SK6812RGBW
void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds)
{
ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin));
_delay_us(ws2812_resettime);
}
void ws2812_sendarray(uint8_t *data,uint16_t datlen)
{
ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin));
}
/*
This routine writes an array of bytes with RGB values to the Dataout pin
using the fast 800kHz clockless WS2811/2812 protocol.
*/
// Timing in ns
#define w_zeropulse 350
#define w_onepulse 900
#define w_totalperiod 1250
// Fixed cycles used by the inner loop
#define w_fixedlow 2
#define w_fixedhigh 4
#define w_fixedtotal 8
// Insert NOPs to match the timing, if possible
#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000)
#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000)
#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000)
// w1 - nops between rising edge and falling edge - low
#define w1 (w_zerocycles-w_fixedlow)
// w2 nops between fe low and fe high
#define w2 (w_onecycles-w_fixedhigh-w1)
// w3 nops to complete loop
#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
#if w1>0
#define w1_nops w1
#else
#define w1_nops 0
#endif
// The only critical timing parameter is the minimum pulse length of the "0"
// Warn or throw error if this timing can not be met with current F_CPU settings.
#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
#if w_lowtime>550
#error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
#elif w_lowtime>450
#warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
#warning "Please consider a higher clockspeed, if possible"
#endif
#if w2>0
#define w2_nops w2
#else
#define w2_nops 0
#endif
#if w3>0
#define w3_nops w3
#else
#define w3_nops 0
#endif
#define w_nop1 "nop \n\t"
#define w_nop2 "rjmp .+0 \n\t"
#define w_nop4 w_nop2 w_nop2
#define w_nop8 w_nop4 w_nop4
#define w_nop16 w_nop8 w_nop8
void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
{
uint8_t curbyte,ctr,masklo;
uint8_t sreg_prev;
ws2812_DDRREG |= maskhi; // Enable output
masklo =~maskhi&ws2812_PORTREG;
maskhi |= ws2812_PORTREG;
sreg_prev=SREG;
cli();
while (datlen--) {
curbyte=*data++;
asm volatile(
" ldi %0,8 \n\t"
"loop%=: \n\t"
" out %2,%3 \n\t" // '1' [01] '0' [01] - re
#if (w1_nops&1)
w_nop1
#endif
#if (w1_nops&2)
w_nop2
#endif
#if (w1_nops&4)
w_nop4
#endif
#if (w1_nops&8)
w_nop8
#endif
#if (w1_nops&16)
w_nop16
#endif
" sbrs %1,7 \n\t" // '1' [03] '0' [02]
" out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
" lsl %1 \n\t" // '1' [04] '0' [04]
#if (w2_nops&1)
w_nop1
#endif
#if (w2_nops&2)
w_nop2
#endif
#if (w2_nops&4)
w_nop4
#endif
#if (w2_nops&8)
w_nop8
#endif
#if (w2_nops&16)
w_nop16
#endif
" out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
#if (w3_nops&1)
w_nop1
#endif
#if (w3_nops&2)
w_nop2
#endif
#if (w3_nops&4)
w_nop4
#endif
#if (w3_nops&8)
w_nop8
#endif
#if (w3_nops&16)
w_nop16
#endif
" dec %0 \n\t" // '1' [+2] '0' [+2]
" brne loop%=\n\t" // '1' [+3] '0' [+4]
: "=&d" (ctr)
: "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
);
}
SREG=sreg_prev;
}
+70
View File
@@ -0,0 +1,70 @@
/*
* light weight WS2812 lib include
*
* Version 2.3 - Nev 29th 2015
* Author: Tim (cpldcpu@gmail.com)
*
* Please do not change this file! All configuration is handled in "ws2812_config.h"
*
* License: GNU GPL v2+ (see License.txt)
+
*/
#ifndef LIGHT_WS2812_H_
#define LIGHT_WS2812_H_
#include <avr/io.h>
#include <avr/interrupt.h>
#include "ws2812_config.h"
/*
* Structure of the LED array
*
* cRGB: RGB for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106
* cRGBW: RGBW for SK6812RGBW
*/
struct cRGB { uint8_t g; uint8_t r; uint8_t b; };
struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;};
/* User Interface
*
* Input:
* ledarray: An array of GRB data describing the LED colors
* number_of_leds: The number of LEDs to write
* pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
*
* The functions will perform the following actions:
* - Set the data-out pin as output
* - Send out the LED data
* - Wait 50µs to reset the LEDs
*/
void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds);
void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask);
void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds);
/*
* Old interface / Internal functions
*
* The functions take a byte-array and send to the data output as WS2812 bitstream.
* The length is the number of bytes to send - three per LED.
*/
void ws2812_sendarray (uint8_t *array,uint16_t length);
void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask);
/*
* Internal defines
*/
#define CONCAT(a, b) a ## b
#define CONCAT_EXP(a, b) CONCAT(a, b)
#define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port)
#define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port)
#endif /* LIGHT_WS2812_H_ */
+167 -104
View File
@@ -15,171 +15,223 @@
#include <avr/io.h> // include I/O definitions (port names, pin names, etc)
#include <avr/wdt.h> // include watchdog timer support
#include <avr/interrupt.h> // include interrupt support
#include "light_ws2812.h"
// ==============================================================================
// Globals
// ------------------------------------------------------------------------------
unsigned char insync; // flag if we're changing outputs synced to video frame rate
unsigned char step_idx;
unsigned char steps[8];
unsigned char last_buttons[5];
unsigned char bank;
#define PIXELS 36
struct cRGB colors[8];
struct cRGB led[PIXELS];
unsigned char leds_changed;
// ==============================================================================
// Functions
// ------------------------------------------------------------------------------
void output() {
PORTC = (PORTC & ~0x07) | (step_idx & 0x07); // output address
PORTD = steps[step_idx]; // set muxes
leds_changed = 1;
}
void trigger() {
step_idx++;
step_idx %=8;
if (!insync) {
output();
}
}
//------------------------------------------ check SPI
unsigned char SPI_transmit(unsigned char cData) {
SPDR = cData;
while(!(SPSR & (1 << SPIF))){ ; }
return SPDR;
}
void checkSPI(void) {
unsigned char i,j,triggers,temp,step,mux;
PORTB |= (1 << 2); // latch
for (j = 0; j<5; j++ ) {
temp = SPI_transmit(0);
temp = ~temp;
if (temp != last_buttons[j]) {
triggers = temp & ~last_buttons[j];
for (i = 0; i < 8; i++) {
if (triggers & (1 << i)) {
leds_changed = 1;
if (j == 4) { // bank select
if (i > 3) { // don't look at unconnected row
bank = i - 4;
}
} else { // set step
step = j*2;
if (i > 3) {
step++;
mux = i-4;
} else {
mux = i;
}
steps[step] &= (0x03 << (bank*2)); // mask
steps[step] |= (mux << (bank*2)); // set new value
}
}
}
}
last_buttons[j] = temp;
}
PORTB &= ~(1 << 2); // unlatch
}
void update_leds() {
if (!leds_changed) return;
leds_changed = 0;
unsigned char i,a;
struct cRGB color1,color2;
color1 = colors[bank+2];
color2.r = color1.r/4;
color2.g = color1.g/4;
color2.b = color1.b/4;
for (i = 0; i < 36; i++) { // set all to black first, I'm too lazy
led[i] = colors[0]; // black
}
for (i = 0; i < 8; i++ ) {
if (i == step_idx) {
led[(i*4)] = color2;
led[(i*4) + 1] = color2;
led[(i*4) + 2] = color2;
led[(i*4) + 3] = color2;
}
a = steps[i] >> (bank * 2);
a &= 0x03;
led[(i*4)+a] = color1;
}
led[32 + bank] = color1; // bank color
}
// ------------------------------------------------------------------------------
// Init
// ------------------------------------------------------------------------------
void init (void) {
step_idx = 0;
//PORTB: ODD/even input, SPI
DDRB = (1 << PB2) | (1 << PB1); // PB1: Neopixels, PB2: Latch for buttons
PORTB = (1 << PC0); //pull up sync in??
//PORTC
DDRC = (1 << PC2) | (1 << PC1) | (1 << PC0); // Address Output
PORTC = (1 << PC4) | (1 << PC3); // pullup for trigger & reset inputs
PORTC = (1 << PC5) | (1 << PC4) | (1 << PC3); // pullup for trigger & reset inputs & in-sync input
//PORTD: Muxes
DDRD = 0xff;
// Pin change Interrupts:
// Trigger on PCINT11
// Reset on PCINT12
// ------------------ Pin change Interrupts:
// Trigger on PC3 = PCINT11
// Reset on PC4 = PCINT12
// Odd/EVEN on PCINT0
PCICR = (1 << PCIE1) | (1 << PCIE0);
PCMSK1 = (1 << PCINT13);
PCMSK0 = (1 << PCINT12);
PCMSK1 = (1 << PCINT12) |(1 << PCINT11);
PCMSK0 = (1 << PCINT2);
// ------------------ ADC
//"By default, the successive approximation circuitry requires an input clock frequency between 50kHz and 200kHz to get maximum resolution"
// "A normal conversion takes 13 ADC clock cycles. The first conversion after the ADC is switched "
// Max 200kHz @ 20 MHz -> >1700 clk cycles... to slow for 16khz sampling
ADCSRA = (1 << ADEN | 1 << ADATE | 1 << ADIE); // Enable ADC
// ------------------ ADC -> 0-0.7V Ramp input on ADC7
ADCSRA = (1 << ADEN | 1 << ADATE | 1 << ADIE); // Enable ADC, free running mode, ADC Interrupt
ADCSRA |= (1 << ADPS2) | (1 << ADPS1); // prescaler 64
ADMUX = (1 << ADLAR); // we're only reading 8bits, so left adjust result
ADCSRB = (1 << ADTS1) | (1 << ADTS0); // Trigger ADC on Timer 0 COMPA
ADMUX = (1 << ADLAR) | 0x07; // ADC7, we're only reading 8bits, so left adjust result
ADCSRA |= (1 << ADSC); // Start Conversion
// Timer 1 : speed of reading back samples -> output frequency
//
OCR1AL = 0xdf;
TCCR1A = ( 1 << COM1A0 ); // Toggle OC1A on compare match,
TCCR1B = ( 1 << WGM12 | 1 << CS10); // CTC Mode, no prescaler @20mhz / 256 -> max 78.125khz sampling rate
TIMSK1 = (1 << OCIE1A);
wdt_enable(WDTO_30MS); // enable watchdog timer
sei();
}
// ------------------------------------------------------------------------------
// Interrupts
// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
// odd/even - vertical blanking
// on one field sample cv, on other video
ISR (PCINT0_vect) {
line_idx = 0;
if (PINB & (1 << PB2)) {
if (PINB & (1 << PB3)) {
do_sample_video = 1;
ADCSRA |= (1 << ADPS2) | (1 << ADPS1); // prescaler 64
ADMUX = (1 << ADLAR); // adc0
}
} else {
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS1); // prescaler 128 for 10bit resolution
// odd/even - vertical blanking 25Hz
//
// check buttons, output steps if in sync with video
ADMUX = (1 << ADLAR) | 1;
do_sample_video = 0;
}
ISR (PCINT0_vect) {
// check switches
insync = PINC & (1 << PC5);
if (PINC & (1 << PC3)) {
fast_mode = 1;
} else {
fast_mode = 0;
}
// check buttons
checkSPI();
if (PINB & (1 << PB0)) {
ramp_input = 0;
TCCR1B |= (1 << CS10); // run with no prescaler
} else {
ramp_input = 1;
TCCR1B &= ~(1 << CS10); //stop timer
}
// set leds
ws2812_sendarray((uint8_t *)led,PIXELS*3);
// set muxes and address output
output();
}
// ------------------------------------------------------------------------------
// H-Sync
// Trigger
ISR (PCINT1_vect) {
// Start Timer -> Pulse delay
OCR0A = x_pos;
TCCR0B |= ( 1 << CS01 ); // clk/8 prescaler -> start timer
line_idx++;
ISR (PCINT11_vect) {
if (PINC & (1 << PC3)) { // positive edge only
trigger();
}
}
// ------------------------------------------------------------------------------
// Pulse Start
ISR (TIMER0_COMPA_vect) {
PORTC |= (1 << 4);
TCCR0B &= ~( 1 << CS01 ); // stop timer - adc is started automatically by interrupt
}
// Reset
ISR (PCINT12_vect) {
if (PINC & (1 << PC4)) { // positive edge only
step_idx = 0;
if (!insync) {
output();
}
}
}
// ------------------------------------------------------------------------------
// ADC complete interrupt
ISR (ADC_vect) {
PORTC &= ~(1 << 4); //stop pulseout
if (do_sample_video) {
if (line_idx > 35) {
if (line_idx < 292) {
table[line_idx - 36] = ADCH;
}
}
} else {
if (line_idx == 50) {
if (ramp_input) {
cv_input = ADCH;
PORTD = table[cv_input];
} else {
cv_input = (ADCL | ADCH << 2); // Left adjusted ADC result
cv_input = 1024 - cv_input;
cv_input = cv_input + 20; // keep minimum 20 clks -> 1MHZ overflow / 256 Table size -> 3.9kHz fastest
if (!fast_mode) {
cv_input *= 16;
}
OCR1AL = (unsigned char)cv_input;
OCR1AH = (unsigned char)(cv_input >> 8);
}
ADCSRA |= (1 << ADPS2) | (1 << ADPS1); // prescaler 64
ADMUX = (1 << ADLAR) | 2; // adc02
} else if (line_idx == 120) {
cv_input = ADCH;
cv_input /= 2;
if (cv_input > 1) { // only if there seems to be signal
x_pos = cv_input + 10;
}
ADCSRA |= (1 << ADPS2) | (1 << ADPS1); // prescaler 64
ADMUX = (1 << ADLAR) ; // adc0
}
unsigned char trigger_level;
trigger_level = step_idx + 1;
trigger_level %= 8;
trigger_level = trigger_level * 32;
if (ADCH > trigger_level){
trigger();
}
//todo: backwards
}
// ------------------------------------------------------------------------------
// Timer 1 Overflow: output next sample
ISR (TIMER1_COMPA_vect) {
PORTD = table[table_read_idx++];
}
// ==============================================================================
@@ -188,11 +240,22 @@ ISR (TIMER1_COMPA_vect) {
int main (void) {
//Rainbowcolors
colors[0].r=0; colors[0].g=0; colors[0].b=0; // black
colors[1].r=255; colors[1].g=000; colors[1].b=000;//red
colors[2].r=255; colors[2].g=100; colors[2].b=000;//orange
colors[3].r=100; colors[3].g=255; colors[3].b=000;//yellow
colors[4].r=000; colors[4].g=255; colors[4].b=000;//green
colors[5].r=000; colors[5].g=100; colors[5].b=255;//light blue (türkis)
colors[6].r=000; colors[6].g=000; colors[6].b=255;//blue
colors[7].r=100; colors[7].g=000; colors[7].b=255;//violet
init();
while(1) {
wdt_reset();
wdt_reset();
update_leds(); // low priority led update;
}
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
/*
* light_ws2812_config.h
*
* v2.4 - Nov 27, 2016
*
* User Configuration file for the light_ws2812_lib
*
*/
#ifndef WS2812_CONFIG_H_
#define WS2812_CONFIG_H_
///////////////////////////////////////////////////////////////////////
// Define Reset time in µs.
//
// This is the time the library spends waiting after writing the data.
//
// WS2813 needs 300 µs reset time
// WS2812 and clones only need 50 µs
//
///////////////////////////////////////////////////////////////////////
#define ws2812_resettime 300
///////////////////////////////////////////////////////////////////////
// Define I/O pin
///////////////////////////////////////////////////////////////////////
#define ws2812_port B // Data port
#define ws2812_pin 1 // Data out pin
#endif /* WS2812_CONFIG_H_ */
@@ -864,6 +864,7 @@ design rules under a new name.</description>
<element name="C20" library="rcl" package="C1206" value="15p" x="30.7975" y="13.97"/>
<element name="C21" library="rcl" package="C1206" value="15p" x="30.7975" y="27.94"/>
<element name="C22" library="rcl" package="C0603" value="100n" x="44.1325" y="25.7175"/>
<element name="INSYNC?" library="wirepad" package="3,17/1,1" value="" x="9.525" y="-16.1925"/>
</elements>
<signals>
<signal name="+5V">
@@ -1822,8 +1823,6 @@ design rules under a new name.</description>
<signal name="RESET">
<contactref element="ISP" pad="3"/>
<contactref element="IC1" pad="29"/>
<contactref element="BUTTONS" pad="3"/>
<wire x1="62.23" y1="18.0975" x2="62.23" y2="14.605" width="0.3048" layer="1"/>
<wire x1="62.23" y1="18.0975" x2="62.23" y2="19.685" width="0.3048" layer="1"/>
<wire x1="62.23" y1="19.685" x2="61.2775" y2="20.6375" width="0.3048" layer="1"/>
<via x="61.2775" y="20.6375" extent="1-16" drill="0.8" diameter="1.2" shape="square"/>
@@ -1858,10 +1857,8 @@ design rules under a new name.</description>
<signal name="MOSI">
<contactref element="ISP" pad="6"/>
<contactref element="IC1" pad="15"/>
<contactref element="BUTTONS" pad="6"/>
<wire x1="53.1175" y1="21.4249" x2="53.1175" y2="19.59" width="0.3048" layer="1"/>
<wire x1="53.1175" y1="19.59" x2="54.61" y2="18.0975" width="0.3048" layer="1"/>
<wire x1="54.61" y1="18.0975" x2="54.61" y2="14.605" width="0.3048" layer="1"/>
</signal>
<signal name="N$6">
<contactref element="IC1" pad="23"/>
@@ -1984,6 +1981,21 @@ design rules under a new name.</description>
<wire x1="64.3509" y1="44.45" x2="67.945" y2="44.45" width="0.4064" layer="1"/>
<via x="67.945" y="44.45" extent="1-16" drill="0.8" diameter="1.2" shape="square"/>
</signal>
<signal name="N$3">
<contactref element="INSYNC?" pad="1"/>
<contactref element="IC1" pad="28"/>
<wire x1="9.525" y1="-16.1925" x2="51.5175" y2="30.0101" width="0" layer="19" extent="1-1"/>
</signal>
<signal name="LATCH">
<contactref element="IC1" pad="14"/>
<contactref element="BUTTONS" pad="6"/>
<wire x1="54.61" y1="14.605" x2="52.3175" y2="21.4249" width="0" layer="19" extent="1-1"/>
</signal>
<signal name="PIXELS">
<contactref element="IC1" pad="13"/>
<contactref element="BUTTONS" pad="3"/>
<wire x1="51.5175" y1="21.4249" x2="62.23" y2="14.605" width="0" layer="19" extent="1-1"/>
</signal>
</signals>
</board>
</drawing>
@@ -15415,6 +15415,7 @@ new: Attribute TP_SIGNAL_NAME&lt;br&gt;
<part name="P+20" library="supply1" deviceset="+5V" device=""/>
<part name="GND67" library="supply1" deviceset="GND" device=""/>
<part name="C22" library="rcl" deviceset="C-EU" device="C0603" value="100n"/>
<part name="INSYNC?" library="wirepad" deviceset="3,17/1,1" device=""/>
</parts>
<sheets>
<sheet>
@@ -15618,6 +15619,7 @@ new: Attribute TP_SIGNAL_NAME&lt;br&gt;
<instance part="P+20" gate="1" x="-109.22" y="73.66"/>
<instance part="GND67" gate="1" x="-109.22" y="60.96"/>
<instance part="C22" gate="G$1" x="-109.22" y="66.04" rot="R180"/>
<instance part="INSYNC?" gate="1" x="-10.16" y="96.52" rot="R180"/>
</instances>
<busses>
</busses>
@@ -16428,11 +16430,6 @@ new: Attribute TP_SIGNAL_NAME&lt;br&gt;
<wire x1="-109.22" y1="109.22" x2="-91.44" y2="109.22" width="0.1524" layer="91"/>
<label x="-104.14" y="109.22" size="1.778" layer="95"/>
</segment>
<segment>
<pinref part="BUTTONS" gate="A" pin="3"/>
<wire x1="78.74" y1="58.42" x2="66.04" y2="58.42" width="0.1524" layer="91"/>
<label x="66.04" y="58.42" size="1.778" layer="95"/>
</segment>
</net>
<net name="SCK" class="0">
<segment>
@@ -16479,11 +16476,6 @@ new: Attribute TP_SIGNAL_NAME&lt;br&gt;
<wire x1="-43.18" y1="55.88" x2="-38.1" y2="55.88" width="0.1524" layer="91"/>
<label x="-43.18" y="55.88" size="1.778" layer="95"/>
</segment>
<segment>
<pinref part="BUTTONS" gate="A" pin="6"/>
<wire x1="78.74" y1="50.8" x2="66.04" y2="50.8" width="0.1524" layer="91"/>
<label x="66.04" y="50.8" size="1.778" layer="95"/>
</segment>
</net>
<net name="N$6" class="0">
<segment>
@@ -16599,6 +16591,37 @@ new: Attribute TP_SIGNAL_NAME&lt;br&gt;
<junction x="15.24" y="157.48"/>
</segment>
</net>
<net name="N$3" class="0">
<segment>
<pinref part="INSYNC?" gate="1" pin="P"/>
<pinref part="IC1" gate="G$1" pin="PC5(ADC5/SCL)"/>
<wire x1="-12.7" y1="96.52" x2="-43.18" y2="96.52" width="0.1524" layer="91"/>
</segment>
</net>
<net name="LATCH" class="0">
<segment>
<pinref part="IC1" gate="G$1" pin="PB2(SS/OC1B)"/>
<wire x1="-43.18" y1="58.42" x2="33.02" y2="58.42" width="0.1524" layer="91"/>
<wire x1="33.02" y1="58.42" x2="33.02" y2="40.64" width="0.1524" layer="91"/>
<wire x1="33.02" y1="40.64" x2="71.12" y2="40.64" width="0.1524" layer="91"/>
<wire x1="71.12" y1="40.64" x2="71.12" y2="50.8" width="0.1524" layer="91"/>
<pinref part="BUTTONS" gate="A" pin="6"/>
<wire x1="71.12" y1="50.8" x2="78.74" y2="50.8" width="0.1524" layer="91"/>
<label x="10.16" y="58.42" size="1.778" layer="95"/>
</segment>
</net>
<net name="PIXELS" class="0">
<segment>
<pinref part="IC1" gate="G$1" pin="PB1(OC1A)"/>
<wire x1="-43.18" y1="60.96" x2="48.26" y2="60.96" width="0.1524" layer="91"/>
<wire x1="48.26" y1="60.96" x2="48.26" y2="68.58" width="0.1524" layer="91"/>
<wire x1="48.26" y1="68.58" x2="66.04" y2="68.58" width="0.1524" layer="91"/>
<wire x1="66.04" y1="68.58" x2="66.04" y2="58.42" width="0.1524" layer="91"/>
<wire x1="66.04" y1="58.42" x2="78.74" y2="58.42" width="0.1524" layer="91"/>
<pinref part="BUTTONS" gate="A" pin="3"/>
<label x="10.16" y="60.96" size="1.778" layer="95"/>
</segment>
</net>
</nets>
</sheet>
</sheets>