📄 spokepov.lss
字号:
set_led(2, BACK);
// If the 4K EEPROM is installed, then up to 4 images
// can be displayed. The SpokePOV cycles between them
// at regular intervals. This interval is stored in
// the ATMEL internal EEPROM, which is seperate from
// the external EEPROM.
animation_time = internal_eeprom_read(EEPROM_ANIMATION);
// enable the interrupts. I think this is not needed
// since it'll immediately be done by the loop, below.
sei();
// Now loop processing commands that come in over the
// dongle. This is how the EEPROMs are programmed.
while (1) {
// Enable interrupts again
sei();
cmd = tx_computer_byte(0);
// This break is the only way out of
// this loop. If it executes (probably because of
// a timeout in tx_computer_byte()), then there is
// no way back other than resetting the chip by
// a long button-push.
if (cmd == 0)
break;
else
// Disable interrupts during command processing.
cli();
// Sensor_timer does double-duty here, as a timeout counter for
// the communications link. But this is OK since we never do
// comm and display at the same time...
// POSSIBLE BUG: it isn't cleared before the original cmd
// byte read, and since interrupts are off, it won't be
// incremented by the interrupt routine!
sensor_timer = 0; // overloaded to reset communications timeout
switch (cmd) {
// Read either a single byte, or 16 bytes, from either
// the external or internal EEPROM. If the high bit of
// the address is 1, then it's an internal read.
case COMP_CMD_RDEEPROM:
case COMP_CMD_RDEEPROM16:
if (cmd == COMP_CMD_RDEEPROM16)
n = 16;
else
n = 1;
// read 2 bytes to get the address
addr = tx_computer_byte(0);
addr <<= 8;
addr |= tx_computer_byte(0);
// internal or external?
if ((addr & 0x8000) != 0) {
// there are only 256 bytes of internal eeprom
tx_computer_byte(internal_eeprom_read(addr & 0xFF));
} else {
// read and transfer 1 or 16 bytes
spieeprom_read(addr, buff, n);
for (i=0; i<n; i++) {
tx_computer_byte(buff[i]);
}
}
// Tell the PC we're copacetic
tx_computer_byte(COMP_SUCCESS);
break;
// Write either a single byte or a block of 16. Same
// idea as above...
case COMP_CMD_WREEPROM:
case COMP_CMD_WREEPROM16:
if (cmd == COMP_CMD_WREEPROM16)
n = 16;
else
n = 1;
addr = tx_computer_byte(0);
addr <<= 8;
addr |= tx_computer_byte(0);
// Give a visual indication that we're loading data
set_led((addr/16)%32,FRONT);
// Receive the bytes
for (i=0; i<n; i++) {
buff[i] = tx_computer_byte(0);
}
// Tell the PC we got the data...
tx_computer_byte(COMP_SUCCESS);
// ...and actually do the write
if ((addr & 0x8000) != 0) {
internal_eeprom_write(addr & 0xFF, buff[0]);
} else {
spieeprom_write(addr, buff, n);
}
break;
}
}
// Loop until we timeout, at which point the ATMEL is
// put to sleep. If the communications routine timed
// out, or the user pressed the button for >500ms,
// then sensor_timer will be 0xFFFF and we'll immediately
// sleep.
while (1) {
// Reset the watchdog Timer.
//
// QUESTION: What's with toggling the PD0 output line here?
// it doesn't seem to be connected to anything according to
// the circuit diagram...
PORTD |= 0x1;
asm("wdr");
PORTD &= ~0x1;
// If the sensor_timer (incremented by TIMER0) maxes out
// (in about 3 minutes), then sleep everything.
if (sensor_timer == 0xFFFF) {
// Avoid pesky interruptions
cli();
// Turn off all LEDs - I guess LED 0 is one of the "invisible ones"
set_led(0, FRONT);
set_led(0, BACK);
// Turn off power to the Hall Effect sensor.
SENSOR_PORT &= ~_BV(SENSORPOWER);
// Deselect EEPROM
SPIEE_CS_PORT |= _BV(SPIEE_CS); // pull CS high to deselect
// Turn off Watchdog (must be restarted when we get the wakeup)
// Wakeup will be via the button interrupt.
WDTCSR |= _BV(WDCE) | _BV(WDE);
WDTCSR = 0;
MCUCR |= _BV(SM1) | _BV(SM0) | _BV(SE);
// Re-enable interrupts so we can get the wakeup!
sei();
// Go into sleep mode
asm("sleep");
}
}
PORTD |= 0x2;
}
// Talk to the PC. First a byte is sent, then a byte
// is received. This is a simple form of handshaking.
//
// The assembly wdr instruction resets the watchdog
// timer so it won't cause everything to abort.
//
// POSSIBLE BUG: this function quits when sensor_timer
// maxes out. But sensor_timer is incremented in an
// interrupt routine, and AFAICT interrupts are turned
// off in the communications loop (except for the
// cmd read, which is possibly the only time it's
// needed). But in addition, it isn't cleared before
// that read, so the timeout may occur a lot faster
// that expected.
//
// POSSIBLE BUG: if it does time out, then the returned
// value v is undefined.
//
// I won't worry at this point about figuring out how
// this works!
uint8_t tx_computer_byte(uint8_t b) {
uint8_t v;
DDRA = 0x0; // outputs
DDRB = 0x5F; // input on MOSI/DI (for SPI), all others output
USICR = _BV(USIWM0) | _BV(USICS1);
USIDR = b; // transfer 0x0
USISR = _BV(USIOIF); // ready
while (! (USISR & _BV(USIOIF)) ) {
asm("wdr");
if (sensor_timer == 0xFFFF) {
stopcomputertx = 1;
}
if (stopcomputertx) {
break;
}
}
v = USIDR;
DDRB = 0xDF;
USICR = 0;
return v;
}
// Move data over the serial link (to the 1K/4K EEPROM or the
// LED shift registers, or both!) This is black magic to me!
uint8_t spi_transfer(uint8_t c) {
USIDR = c;
USISR = _BV(USIOIF);
while (! (USISR & _BV(USIOIF))) {
USICR = _BV(USIWM0) | _BV(USICS1) | _BV(USICLK) | _BV(USITC);
//NOP; // slow down so that the eeprom isnt overwhelmed
}
return USIDR;
}
// Read the internal EEPROM
uint8_t internal_eeprom_read(uint8_t addr) {
loop_until_bit_is_clear(EECR, EEWE); // Wait for last write to finish
144: e1 99 sbic 0x1c, 1 ; 28
146: fe cf rjmp .-4 ; 0x144 <internal_eeprom_read>
EEAR = addr; // Store address to read
148: 8e bb out 0x1e, r24 ; 30
EECR |= _BV(EERE); // Trigger the EEPROM read - this takes only one
14a: e0 9a sbi 0x1c, 0 ; 28
// cycle, so the result can immediately be returned!
return EEDR;
14c: 8d b3 in r24, 0x1d ; 29
}
14e: 99 27 eor r25, r25
150: 08 95 ret
00000152 <ioinit>:
152: 83 e7 ldi r24, 0x73 ; 115
154: 81 bb out 0x11, r24 ; 17
156: 8f ed ldi r24, 0xDF ; 223
158: 87 bb out 0x17, r24 ; 23
15a: 80 e1 ldi r24, 0x10 ; 16
15c: 88 bb out 0x18, r24 ; 24
15e: 8c e4 ldi r24, 0x4C ; 76
160: 82 bb out 0x12, r24 ; 18
162: 98 e0 ldi r25, 0x08 ; 8
164: 95 bf out 0x35, r25 ; 53
166: 80 ec ldi r24, 0xC0 ; 192
168: 8b bf out 0x3b, r24 ; 59
16a: 10 be out 0x30, r1 ; 48
16c: 84 e0 ldi r24, 0x04 ; 4
16e: 83 bf out 0x33, r24 ; 51
170: 89 b7 in r24, 0x39 ; 57
172: 82 60 ori r24, 0x02 ; 2
174: 89 bf out 0x39, r24 ; 57
176: 1f bc out 0x2f, r1 ; 47
178: 9e bd out 0x2e, r25 ; 46
17a: 10 92 69 00 sts 0x0069, r1
17e: 10 92 6b 00 sts 0x006B, r1
182: 10 92 6a 00 sts 0x006A, r1
186: 08 95 ret
00000188 <spi_transfer>:
188: 8f b9 out 0x0f, r24 ; 15
18a: 80 e4 ldi r24, 0x40 ; 64
18c: 8e b9 out 0x0e, r24 ; 14
18e: 76 99 sbic 0x0e, 6 ; 14
190: 04 c0 rjmp .+8 ; 0x19a <spi_transfer+0x12>
192: 8b e1 ldi r24, 0x1B ; 27
194: 8d b9 out 0x0d, r24 ; 13
196: 76 9b sbis 0x0e, 6 ; 14
198: fd cf rjmp .-6 ; 0x194 <spi_transfer+0xc>
19a: 8f b1 in r24, 0x0f ; 15
19c: 99 27 eor r25, r25
19e: 08 95 ret
000001a0 <clock_leds>:
1a0: 1f 93 push r17
1a2: cf 93 push r28
1a4: df 93 push r29
1a6: 18 2f mov r17, r24
1a8: 84 30 cpi r24, 0x04 ; 4
1aa: 19 f4 brne .+6 ; 0x1b2 <clock_leds+0x12>
1ac: c0 e7 ldi r28, 0x70 ; 112
1ae: d0 e0 ldi r29, 0x00 ; 0
1b0: 02 c0 rjmp .+4 ; 0x1b6 <clock_leds+0x16>
1b2: cc e6 ldi r28, 0x6C ; 108
1b4: d0 e0 ldi r29, 0x00 ; 0
1b6: 8b 81 ldd r24, Y+3 ; 0x03
1b8: e7 df rcall .-50 ; 0x188 <spi_transfer>
1ba: 8a 81 ldd r24, Y+2 ; 0x02
1bc: e5 df rcall .-54 ; 0x188 <spi_transfer>
1be: 89 81 ldd r24, Y+1 ; 0x01
1c0: e3 df rcall .-58 ; 0x188 <spi_transfer>
1c2: 88 81 ld r24, Y
1c4: e1 df rcall .-62 ; 0x188 <spi_transfer>
1c6: 21 e0 ldi r18, 0x01 ; 1
1c8: 30 e0 ldi r19, 0x00 ; 0
1ca: 02 c0 rjmp .+4 ; 0x1d0 <clock_leds+0x30>
1cc: 22 0f add r18, r18
1ce: 33 1f adc r19, r19
1d0: 1a 95 dec r17
1d2: e2 f7 brpl .-8 ; 0x1cc <clock_leds+0x2c>
1d4: 82 b3 in r24, 0x12 ; 18
1d6: 82 2b or r24, r18
1d8: 82 bb out 0x12, r24 ; 18
...
1e2: 92 2f mov r25, r18
1e4: 90 95 com r25
1e6: 82 b3 in r24, 0x12 ; 18
1e8: 89 23 and r24, r25
1ea: 82 bb out 0x12, r24 ; 18
1ec: df 91 pop r29
1ee: cf 91 pop r28
1f0: 1f 91 pop r17
1f2: 08 95 ret
000001f4 <set_led>:
1f4: 28 2f mov r18, r24
1f6: 64 30 cpi r22, 0x04 ; 4
1f8: 19 f4 brne .+6 ; 0x200 <set_led+0xc>
1fa: e0 e7 ldi r30, 0x70 ; 112
1fc: f0 e0 ldi r31, 0x00 ; 0
1fe: 02 c0 rjmp .+4 ; 0x204 <set_led+0x10>
200: ec e6 ldi r30, 0x6C ; 108
202: f0 e0 ldi r31, 0x00 ; 0
204: 8f ef ldi r24, 0xFF ; 255
206: 83 83 std Z+3, r24 ; 0x03
208: 82 83 std Z+2, r24 ; 0x02
20a: 81 83 std Z+1, r24 ; 0x01
20c: 80 83 st Z, r24
20e: 82 2f mov r24, r18
210: 86 95 lsr r24
212: 86 95 lsr r24
214: 86 95 lsr r24
216: e8 0f add r30, r24
218: f1 1d adc r31, r1
21a: 27 70 andi r18, 0x07 ; 7
21c: 81 e0 ldi r24, 0x01 ; 1
21e: 90 e0 ldi r25, 0x00 ; 0
220: 02 c0 rjmp .+4 ; 0x226 <set_led+0x32>
222: 88 0f add r24, r24
224: 99 1f adc r25, r25
226: 2a 95 dec r18
228: e2 f7 brpl .-8 ; 0x222 <set_led+0x2e>
22a: 80 95 com r24
22c: 80 83 st Z, r24
22e: 86 2f mov r24, r22
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -