📄 spokepov.lss
字号:
19c: 0f b6 in r0, 0x3f ; 63
19e: 0f 92 push r0
1a0: 11 24 eor r1, r1
1a2: 8f 93 push r24
// Wait until button no longer pressed
while (! (BUTTON_PIN & _BV(BUTTON))) {
1a4: 82 9b sbis 0x10, 2 ; 16
1a6: fe cf rjmp .-4 ; 0x1a4 <__vector_1+0xc>
}
if (sensor_timer.bytes.high_byte == 0xFF) {
1a8: 80 91 66 00 lds r24, 0x0066
1ac: 8f 3f cpi r24, 0xFF ; 255
1ae: 29 f4 brne .+10 ; 0x1ba <__vector_1+0x22>
// so in this instance, we set the watchdog to reset us
sensor_timer.bytes.high_byte = 0x00;
1b0: 10 92 66 00 sts 0x0066, r1
// Re-enable the watchdog timer, then loop until
// it fires off.
WDTCSR = _BV(WDE);
1b4: 88 e0 ldi r24, 0x08 ; 8
1b6: 81 bd out 0x21, r24 ; 33
for (;;);
1b8: ff cf rjmp .-2 ; 0x1b8 <__vector_1+0x20>
} else {
// We want to shut everything down. Setting sensor_timer
// to the pin value will cause both the communications
// loop and the regular timeout loop in the main() to
// give up, which results in the device going to sleep.
sensor_timer.bytes.high_byte = 0xFF;
1ba: 8f ef ldi r24, 0xFF ; 255
1bc: 80 93 66 00 sts 0x0066, r24
1c0: 8f 91 pop r24
1c2: 0f 90 pop r0
1c4: 0f be out 0x3f, r0 ; 63
1c6: 0f 90 pop r0
1c8: 1f 90 pop r1
1ca: 18 95 reti
000001cc <set_all>:
}
}
// Interrupt 1 executes when the hall effect sensor fires
// QUESTION: unlike the pixel output interrupt, this one
// doesn't sei(). Why?
SIGNAL (SIG_INT1) {
// make sure we don't get bitten by the watchdog
asm("wdr");
// The first issue we need to deal with when the hall-effect
// sensor tells us it sees the magnet is to avoid doing any
// processing if we get an interrupt too soon after the previous
// interrupt.
// hall_debounce is incremented by TIMER0, which fires every 3ms
// or so. At the current setting of 4, this means that at least
// 15ms must elapse per trigger, which translates to about 4000
// rpm.
if (hall_debounce > HALL_DEBOUNCE_THRESH) {
// We know the number of ms since the last hall sensor trigger
// and there are 128 radial 'pixels' per sweep so divide to get
// the necessary ms between the pixel interrupts
// QUESTION: 128 or 256?
// Then we just make TIMER1 trigger at that rate!
// Reset the Timer Count Register for TIMER1 to 0, so it will
// begin counting up.
TCNT1 = 0;
// sensor_timer contains the number of TIMER0 interrupts since
// the last time we updated TIMER1. If it has a reasonable
// value, then we use it to reset the TIMER1 clock.
if ((sensor_timer.bytes.low_byte < 0xFF) && (sensor_timer.bytes.low_byte > 0x3)) {
// TIMER1 works differently from TIMER0. It's a 16-bit timer
// that apparently increments at the system clock rate.
//
// Because TIMER0 increments at 1/256 of the clock rate, and
// fires the interrupt only when it overflows, sensor_timer
// is incremented once ever 256*256 cycles.
//
// We want TIMER1 to fire off 256 times around the loop, so
// we can display 256 lines of pixels. We do this by putting
// sensor_timer into the high byte of TIMER1's comparator
// value, and the residual of TIMER0 (what it's counted up
// to since the last time sensor_timer was incremented) into
// the low byte, effectively a fractional value!
//
// Since TIMER0 is incrementing at 1/256 of the rate of TIMER1,
// this results in TIMER1 firing off 256 times per rotation,
// with excellent time resolution.
//
// I was quite touched by the elegance of how this works out;
// it may be able to handle the extreme RPMs of BrightSaber
// without modification...
// Set the TIMER1 comparator value. As a hack to Limor's hack,
// reduce the timing a little bit so that the display doesn't
// span the full 360 degrees, thus giving us a little more time
// around hall-effect interrupt time to do things. An attempt
// to get more speed, it doesn't seem to help - so back to the
// old way of doing things.
// OCR1A = ((sensor_timer << 8) | TCNT0) - (sensor_timer);
// OCR1A = ((sensor_timer << 8) | TCNT0);
OCR1AH = sensor_timer.bytes.low_byte;
OCR1AL = TCNT0;
// Clear the residual of TIMER0
TCNT0 = 0;
// Check the line timer; if it has reached a particular value
// then decrement curTime. If that hits zero, then increment
// the curElementPtr and load in the new data
if (line_timer >= SCROLLSPEED) {
line_timer = line_timer - SCROLLSPEED; // reset in a safe way that retains any residual
curTime--;
if (curTime == 0x00) {
curElementPtr++;
if (curElementPtr == NUM_ELEMENTS) {
curElementPtr = 0;
}
curElement = pgm_read_byte(elementList+curElementPtr);
curTime = pgm_read_byte(elementTime+curElementPtr);
}
}
// figure out the eeprom start position
eepromPtr.bytes.high_byte = curElement << 2;
eepromPtr.bytes.low_byte = 0x00;
// and the end position
eepromLimit.bytes.high_byte = eepromPtr.bytes.high_byte+4;
eepromLimit.bytes.low_byte = 0x04;
// Start TIMER1 on its merry way...
TCCR1B |= _BV(CS10); // increment at clock/1
TIMSK |= _BV(OCIE1A); // enable interrupt when it matches OCR1A
} else {
// Since we don't have a valid setting for the rotation
// speed, set a couple of LEDs to let the human know we
// aren't dead yet, and turn off the timer.
set_all(~0x03);
TCCR1B &= ~_BV(CS10); // no incrementing = no interrupting
// reset the line timers so that when we get a valid spinup,
// they will start clocking the lines across the display
line_timer = SCROLLSPEED; // delay figure, will trigger wrap
}
// Whether we're displaying or not, we reset sensor_timer so we can
// time the next revolution.
sensor_timer.word = 0;
}
// Finally, reset hall_debounce so we won't execute the timer reset code
// until the Hall Effect sensor hasn't bothered us for a reasonable while.
hall_debounce = 0;
// *** PORTB &= ~0x8;
}
// Initialize the IO pins on the ATMEL.
void ioinit(void) {
// Set the data direction for the PORTD and PORTB pins; see the
// circuit diagram for more information on this.
DDRD = 0x73; // input on PD2 (button), PD3 (sensor), all other output
DDRB = 0xDF; // input on MOSI/DI (for SPI), all others output
// Deselect EEPROM. Not being an EE, I'm not going to worry about
// how the ATMEL talks to the EEPROM. It's black magic.
PORTB = _BV(SPIEE_CS);
// Just above, we set PD2 and PD3 to input. If we now set those
// bits to 1, they set into pullup mode (again, not EE, claim
// ignorance), which is essential for them to work. We also set
// the SENSORPOWER bit to 1, which sends out little dribbles of
// electrons to the hall effect sensor (see circuit diagram)
//
// Finally, we write 0's to the FRONT and BACK pins, which control
// which bank of 30 LEDs we are talking to. Having both of these
// on at the same time probably causes horrible things to happen.
PORTD = (_BV(BUTTON) | _BV(SENSOR) | _BV(SENSORPOWER))
& ~_BV(FRONT) & ~_BV(BACK);
// Rather than poll to see when the hall effect sensor and
// button are pressed, we configure an interrupt handler. If you
// look at the circuit diagram, you'll see that PD3 and PD2, which
// are wired to SENSOR IN and BUTTON IN, do double-duty as INT1
// and INT0. They are both SUPPOSEDLY set to interrupt on the
// falling edge of a pulse from the devices. (Page 63)
// POSSIBLE BUG: ISC0{1,0} seems to be being set to 00, not 10
// as ISC1{1,0} is being set to. So ISC0 will trigger when
// the button interrupt line goes low. Either this is a bug,
// or the original comment was not correct (likely, IMHO)
MCUCR = _BV(ISC11) & ~_BV(ISC01) & ~_BV(ISC00) & ~_BV(ISC10);
// Activate the interrupts by setting the General Interrupt Mask
// Register (Page 63)
GIMSK = _BV(INT1) | _BV(INT0);
// The ATMEL has built-in timers that can trigger an interrupt.
// SpokePOV uses them to update the LEDs 256 times per rotation.
// Timer 0 is set to update at a rate system-clock / 256 and
// interrupt when it overflows (8 bit). This means that it
// triggers every 65536 cycles.
TCCR0A = 0; // normal, overflow (count up to 256 == num pixels)
TCCR0B = _BV(CS02); // clk/256
TIMSK |= _BV(TOIE0); // turn on overflow interrupt
// Timer 1 (T1) is the pixel timer, which is used to update the
// LEDs 256 times per rotation. It's set up as a normal timer
// as well. See Page 108&71; it is apparently being set into CTC
// mode 4. This means that the counter is compared to a 16-bit value
// and interrupts when it reaches this value.
//
// Adjusting this value is how the SpokePOV compensates for
// changes in the rotation speed of the device.
//
// Note that at this point, the timer is initialized, but not
// activated.
TCCR1A = 0;
TCCR1B = _BV(WGM12);
// Clear the debounce values, which I haven't sussed out yet.
hall_debounce = 0;
sensor_timer.word = 0;
// set the element variables so they'll wrap around.
curElementPtr = NUM_ELEMENTS-1;
curTime = 0x01;
}
// Set all the LEDs on a side to have the same
// repeating 8-bit value (ie: 0x00 = all on, 0xFF = all off)
// Added by RJW to permit a more comprehensive reset display
void set_all(uint8_t blockValue) {
fleds[0] = fleds[1] = fleds[2] = fleds[3] = blockValue;
1cc: 80 93 6c 00 sts 0x006C, r24
1d0: 80 93 6b 00 sts 0x006B, r24
1d4: 80 93 6a 00 sts 0x006A, r24
1d8: 80 93 69 00 sts 0x0069, r24
clock_scroll(0);
1dc: 80 e0 ldi r24, 0x00 ; 0
1de: 43 df rcall .-378 ; 0x66 <clock_scroll>
1e0: 08 95 ret
000001e2 <__vector_2>:
1e2: 1f 92 push r1
1e4: 0f 92 push r0
1e6: 0f b6 in r0, 0x3f ; 63
1e8: 0f 92 push r0
1ea: 11 24 eor r1, r1
1ec: 2f 93 push r18
1ee: 3f 93 push r19
1f0: 4f 93 push r20
1f2: 5f 93 push r21
1f4: 6f 93 push r22
1f6: 7f 93 push r23
1f8: 8f 93 push r24
1fa: 9f 93 push r25
1fc: af 93 push r26
1fe: bf 93 push r27
200: ef 93 push r30
202: ff 93 push r31
204: a8 95 wdr
206: 80 91 64 00 lds r24, 0x0064
20a: 85 30 cpi r24, 0x05 ; 5
20c: 08 f4 brcc .+2 ; 0x210 <__vector_2+0x2e>
20e: 66 c0 rjmp .+204 ; 0x2dc <__vector_2+0xfa>
210: 1d bc out 0x2d, r1 ; 45
212: 1c bc out 0x2c, r1 ; 44
214: 80 91 65 00 lds r24, 0x0065
218: 8f 3f cpi r24, 0xFF ; 255
21a: 09 f4 brne .+2 ; 0x21e <__vector_2+0x3c>
21c: 53 c0 rjmp .+166 ; 0x2c4 <__vector_2+0xe2>
21e: 80 91 65 00 lds r24, 0x0065
222: 84 30 cpi r24, 0x04 ; 4
224: 08 f4 brcc .+2 ; 0x228 <__vector_2+0x46>
226: 4e c0 rjmp .+156 ; 0x2c4 <__vector_2+0xe2>
228: 80 91 65 00 lds r24, 0x0065
22c: 8b bd out 0x2b, r24 ; 43
22e: 82 b7 in r24, 0x32 ; 50
230: 8a bd out 0x2a, r24 ; 42
232: 12 be out 0x32, r1 ; 50
234: 80 91 60 00 lds r24, 0x0060
238: 80 31 cpi r24, 0x10 ; 16
23a: 68 f1 brcs .+90 ; 0x296 <__vector_2+0xb4>
23c: 80 91 60 00 lds r24, 0x0060
240: 80 51 subi r24, 0x10 ; 16
242: 80 93 60 00 sts 0x0060, r24
246: 80 91 63 00 lds r24, 0x0063
24a: 81 50 subi r24, 0x01 ; 1
24c: 80 93 63 00 sts 0x0063, r24
250: 90 91 63 00 lds r25, 0x0063
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -