📄 spokepov.lss
字号:
spokepov.elf: file format elf32-avr
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 000004e6 00000000 00000000 00000094 2**0
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .data 00000022 00800060 000004e6 0000057a 2**0
CONTENTS, ALLOC, LOAD, DATA
2 .bss 0000000f 00800082 00800082 0000059c 2**0
ALLOC
3 .noinit 00000000 00800091 00800091 0000059c 2**0
CONTENTS
4 .eeprom 00000000 00810000 00810000 0000059c 2**0
CONTENTS
5 .stab 00000354 00000000 00000000 0000059c 2**2
CONTENTS, READONLY, DEBUGGING
6 .stabstr 00000084 00000000 00000000 000008f0 2**0
CONTENTS, READONLY, DEBUGGING
7 .debug_aranges 00000028 00000000 00000000 00000974 2**0
CONTENTS, READONLY, DEBUGGING
8 .debug_pubnames 0000017a 00000000 00000000 0000099c 2**0
CONTENTS, READONLY, DEBUGGING
9 .debug_info 000004ac 00000000 00000000 00000b16 2**0
CONTENTS, READONLY, DEBUGGING
10 .debug_abbrev 000001d3 00000000 00000000 00000fc2 2**0
CONTENTS, READONLY, DEBUGGING
11 .debug_line 00000476 00000000 00000000 00001195 2**0
CONTENTS, READONLY, DEBUGGING
12 .debug_str 000001fb 00000000 00000000 0000160b 2**0
CONTENTS, READONLY, DEBUGGING
Disassembly of section .text:
00000000 <__vectors>:
0: 12 c0 rjmp .+36 ; 0x26 <__ctors_end>
2: 5f c0 rjmp .+190 ; 0xc2 <__vector_1>
4: f4 c0 rjmp .+488 ; 0x1ee <__vector_2>
6: 28 c0 rjmp .+80 ; 0x58 <__bad_interrupt>
8: 50 c1 rjmp .+672 ; 0x2aa <__vector_4>
a: 26 c0 rjmp .+76 ; 0x58 <__bad_interrupt>
c: 27 c0 rjmp .+78 ; 0x5c <__vector_6>
e: 24 c0 rjmp .+72 ; 0x58 <__bad_interrupt>
10: 23 c0 rjmp .+70 ; 0x58 <__bad_interrupt>
12: 22 c0 rjmp .+68 ; 0x58 <__bad_interrupt>
14: 21 c0 rjmp .+66 ; 0x58 <__bad_interrupt>
16: 20 c0 rjmp .+64 ; 0x58 <__bad_interrupt>
18: 1f c0 rjmp .+62 ; 0x58 <__bad_interrupt>
1a: 1e c0 rjmp .+60 ; 0x58 <__bad_interrupt>
1c: 1d c0 rjmp .+58 ; 0x58 <__bad_interrupt>
1e: 1c c0 rjmp .+56 ; 0x58 <__bad_interrupt>
20: 1b c0 rjmp .+54 ; 0x58 <__bad_interrupt>
22: 1a c0 rjmp .+52 ; 0x58 <__bad_interrupt>
24: 19 c0 rjmp .+50 ; 0x58 <__bad_interrupt>
00000026 <__ctors_end>:
26: 11 24 eor r1, r1
28: 1f be out 0x3f, r1 ; 63
2a: cf ed ldi r28, 0xDF ; 223
2c: cd bf out 0x3d, r28 ; 61
0000002e <__do_copy_data>:
2e: 10 e0 ldi r17, 0x00 ; 0
30: a0 e6 ldi r26, 0x60 ; 96
32: b0 e0 ldi r27, 0x00 ; 0
34: e6 ee ldi r30, 0xE6 ; 230
36: f4 e0 ldi r31, 0x04 ; 4
38: 03 c0 rjmp .+6 ; 0x40 <.do_copy_data_start>
0000003a <.do_copy_data_loop>:
3a: c8 95 lpm
3c: 31 96 adiw r30, 0x01 ; 1
3e: 0d 92 st X+, r0
00000040 <.do_copy_data_start>:
40: a2 38 cpi r26, 0x82 ; 130
42: b1 07 cpc r27, r17
44: d1 f7 brne .-12 ; 0x3a <.do_copy_data_loop>
00000046 <__do_clear_bss>:
46: 10 e0 ldi r17, 0x00 ; 0
48: a2 e8 ldi r26, 0x82 ; 130
4a: b0 e0 ldi r27, 0x00 ; 0
4c: 01 c0 rjmp .+2 ; 0x50 <.do_clear_bss_start>
0000004e <.do_clear_bss_loop>:
4e: 1d 92 st X+, r1
00000050 <.do_clear_bss_start>:
50: a1 39 cpi r26, 0x91 ; 145
52: b1 07 cpc r27, r17
54: e1 f7 brne .-8 ; 0x4e <.do_clear_bss_loop>
56: fc c1 rjmp .+1016 ; 0x450 <main>
00000058 <__bad_interrupt>:
58: d3 cf rjmp .-90 ; 0x0 <__vectors>
0000005a <get_line>:
// text are stored here (and hopefully don't use much ram!)
/* The lines that will be displayed on the SpokePOV */
void get_line(uint8_t *buff, uint16_t line_num) {
5a: 08 95 ret
0000005c <__vector_6>:
uint8_t *lines;
lines =
" "
" Episode IV "
" A New Hope "
" "
" It is a period "
" of civil war. "
" "
" "
;
}
// TIMER0 interrupt handler. This runs about every 3ms
// AFAICT. It increments the hall_debounce and sensor_timer
// values until they pin.
// QUESTION: what's with the setting and clearing of PORTB0?
// According to the wiring diagram, it isn't connected to
// anything. Is this vestigial code from when you were using
// Pin Change Interrupts? Or is it debugger code so you
// can monitor the pins and tell when something happens.
SIGNAL (SIG_TIMER0_OVF) {
5c: 1f 92 push r1
5e: 0f 92 push r0
60: 0f b6 in r0, 0x3f ; 63
62: 0f 92 push r0
64: 11 24 eor r1, r1
66: 2f 93 push r18
68: 8f 93 push r24
6a: 9f 93 push r25
// *** PORTB |= 0x1;
if (hall_debounce != 0xFF)
6c: 80 91 8a 00 lds r24, 0x008A
70: 8f 3f cpi r24, 0xFF ; 255
72: 29 f0 breq .+10 ; 0x7e <__vector_6+0x22>
hall_debounce++;
74: 80 91 8a 00 lds r24, 0x008A
78: 8f 5f subi r24, 0xFF ; 255
7a: 80 93 8a 00 sts 0x008A, r24
if (sensor_timer != 0xFFFF)
7e: 80 91 8b 00 lds r24, 0x008B
82: 90 91 8c 00 lds r25, 0x008C
86: 8f 5f subi r24, 0xFF ; 255
88: 9f 4f sbci r25, 0xFF ; 255
8a: 49 f0 breq .+18 ; 0x9e <__vector_6+0x42>
sensor_timer++;
8c: 80 91 8b 00 lds r24, 0x008B
90: 90 91 8c 00 lds r25, 0x008C
94: 01 96 adiw r24, 0x01 ; 1
96: 90 93 8c 00 sts 0x008C, r25
9a: 80 93 8b 00 sts 0x008B, r24
9e: 9f 91 pop r25
a0: 8f 91 pop r24
a2: 2f 91 pop r18
a4: 0f 90 pop r0
a6: 0f be out 0x3f, r0 ; 63
a8: 0f 90 pop r0
aa: 1f 90 pop r1
ac: 18 95 reti
000000ae <delay_ms>:
// *** PORTB &= ~0x1;
}
// As we sweep around the circle, we display 256 radial pixel
// lines, once per TIMER1 interrupt. This is broken down into
// 16 16-pixel wide characters, and we have two characters
// stacked vertically. To save time, we keep track of the
// character number, pixel number (in the character), and
// pointers into the eeprom for each of the two chars being
// displayed.
volatile uint16_t topChar = 0; // top character being displayed (address in EEPROM of data)
volatile uint16_t botChar = 0; // bottom character being displayed
volatile uint8_t charNum = 0; // character number
volatile uint8_t pixelNum = 0; // pixel number
volatile uint8_t clean = 0; // have these values been changed outside TIMER1?
// This routine gets called every time the pixel timer runs down;
// in other words, once per "scan line", 256 times per revolution
// of the SpokePOV. Its purpose is to update the LEDs.
SIGNAL (SIG_TIMER1_COMPA) {
uint16_t tChar; // local copies of the values
uint16_t bChar;
uint8_t cNum;
uint8_t pNum;
uint8_t cCode; // character code to display
// When an interrupt routine is called, interrupts are disabled.
// but it's important to let other interrupts interrupt us, so
// they need to be re-enabled.
sei();
// *** PORTB |= 0x2;
// Copy the volatile variables into their local equivalents
tChar = topChar;
bChar = botChar;
cNum = charNum;
pNum = pixelNum;
// If it has been less than STANDBY_TIMEOUT seconds since the last time we
// got a Hall Effect sensor update, then proceed as normal and
// update the LEDs.
// QUESTION: what is F_CPU?
if (sensor_timer < ((F_CPU/NUM_PIXELS)/256 * STANDBY_TIMEOUT)) {
// *** PORTA |= 0x1;
// The first thing we do is increment our character position; this
// is done here to avoid code duplication. This means that the
// Hall Effect interrupt routine must set them up so they "wrap"
// into the first valid values.
// Move to the next pixel in the character
pNum++;
// If we have moved off the edge of the character, then
// we need to move to the next character
if (pNum == 16) {
pNum = 0; // reset to first pixel
cNum = (cNum+1) % 16; // move, with wrap, to next character position
// Now we need to reset the pointers to the correct addresses
// in the EEPROM for the characters they display. The earlier
// decision to store these in a format that makes them display
// nicely on the original SpokePOV software makes this a little
// bit difficult.
cCode = topLine[cNum]-32; // character number for the top char, 0-95
// In the character set, 2 characters are stored vertically stacked.
// So each group of 2 characters takes up 64 bytes (4x16).
tChar = ((cCode >> 1) << 6) | ( (cCode & 0x01) << 1 );
// tChar = 1024UL; // debug, should be an @
// Ditto for bChar...
cCode = botLine[cNum]-32;
bChar = ((cCode >> 1) << 6) | ( (cCode & 0x01) << 1 );
// bChar = tChar + 2; // debug, should display A
} else {
// If we haven't wrapped around a character boundary, we just move
// to the next line in the character set, which is 4 pixels offset
// in each case
tChar += 4;
bChar += 4;
}
// Unfortunately, we can't do the cute "read from the EEPROM right
// into the LEDs trick" that limor can do in SpokePOV. We have to
// read the data into the ATMEL and then write it out.
spieeprom_read(tChar,fleds+2,2); // the top 2 bytes
spieeprom_read(bChar,fleds,2); // and the bottom 2
clock_leds(); // and send them to the LEDs
// Now we increment the variables. However, we
// only do it IF haven't been touched by some other part
// of the code while we were displaying the pixels. Also, we
// turn interrupts off so that nobody else can touch them
// while we are at it
cli();
if (clean) {
topChar = tChar;
botChar = bChar;
charNum = cNum;
pixelNum = pNum;
} else {
// Since we didn't update the data, we know it was changed, and
// we know that next time, we CAN update the data. So everything
// is clean now!
clean = 1;
}
sei();
// *** PORTA &= ~0x1;
} else {
// We have not seen the magnet in a while, so turn off the
// pixel timer...
// *** PORTA |= 0x2;
// Turn off this pixel timer
// Question: this is different from the code in SIG_INT1. Why?
cli();
TCCR1B &= ~0x7;
sei();
// Turn off all but one LED
set_led(2);
// *** PORTA &= ~0x2;
}
// *** PORTB &= ~0x2;
}
// Interrupt 0 executes when the button is pressed.
// QUESTION: unlike the pixel output interrupt, this one
// doesn't sei(). Why?
SIGNAL (SIG_INT0) {
uint16_t timer;
// *** PORTB |= 0x4;
// Twiddle our thumbs until the user releases the
// button - but measure how long he takes...
timer = 0;
while (! (BUTTON_PIN & _BV(BUTTON))) {
timer++;
delay_ms(1);
}
// A short (<500ms) press will just restart the watchdog
// timer. I think this explains the structure of the
// main() function; it doesn't have a loop to keep it
// listening for commands if it times out, but pressing
// the button will restart it.
// We do expect that the button will be down at least
// a small period of time...
if (timer > BUTTON_DEBOUNCE) {
// If a quick press...
if (timer < 500UL) {
// Re-enable the watchdog timer, then loop until
// it fires off.
WDTCSR = _BV(WDE);
while (1);
} 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 = 0xFFFF;
}
}
// *** PORTB &= ~0x4;
}
// Interrupt 1 executes when the hall effect sensor fires
// QUESTION: unlike the pixel output interrupt, this one
// doesn't sei(). Why?
SIGNAL (SIG_INT1) {
// *** PORTB |= 0x8;
// 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) {
stopcomputertx = 1;
// 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 < 0xFF) && (sensor_timer > 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -