do using polling

actually this does not work, because polling requires:
        in
        andi
        brne
which takes 4 clock cycles, that, on average, means a 2 clock offset,
while interrupts occur during a rjmp, which takes 2 clocks, which means,
on average, only 1 clock cycle of offset

I am not interested in higher or lower overhead: I am just interested in
minimizing its variance.
Being late of a few clock cycles, is not a problem: it just means that
the picture will be slightly shifted toward the right border; but,
starting the picture 1 or 2 clock cycles before (on one line), and 1 or
2 clock cycles after, on another line, means that it just wiggles sligthly
left and right
This commit is contained in:
giomba 2021-08-08 22:29:16 +02:00
parent 53da6b7171
commit d91201dcfd
2 changed files with 59 additions and 101 deletions

139
main.S
View File

@ -8,24 +8,8 @@
main:
ldi r16, 0x30 ; port B, pin 4 and 5 as output
sts DDRB, r16
; set interrupt vectors at address 0x0, not bootloader
; timing is important, see atmel datasheet
ldi r16, (1 << IVCE)
ldi r17, 0
out IO(MCUCR), r16
out IO(MCUCR), r17
ldi r16, 0xa ; external interrupt 0 and 1, falling edge
sts EICRA, r16
ldi r16, 0x3 ; external interrupt 0 and 1, mask enable
sts EIMSK, r16
ldi r16, 0x02 ; don't connect output pins to timer, CTC[1:0] mode
sts TCCR0A, r16
ldi r16, 0x01 ; CTC[2] mode, no prescaler
sts TCCR0B, r16
cbi IO(DDRD), 2 ; port D, pin 2 and 3 as input
cbi IO(DDRD), 3
; init variables
ldi r16, 0
@ -35,85 +19,68 @@ main:
ldi r16, 1
sts line, r16
cli ; global interrupt disable
call setup_c
sei ; global interrupt enable
1:
call loop_c
rjmp 1b
.global int_horizontal_sync
int_horizontal_sync: ; +3
push r31 ; +5
in r31, IO(SREG) ; +6, status register
push r31 ; +8
push r30 ; +10
wait_next_line:
in r16, IO(PIND)
andi r16, 0x08
brne wait_next_line
/*
; if (line >= VERTICAL_OFFSET), then enter
lds r30, line ; +12
lds r31, line + 1 ; +14
adiw z, 1 ; +16
sts line, r30 ; +18
sts line + 1, r31 ; +20
cpi r31, 0 ; +21
brne enter ; +22, +23
cpi r30, VERTICAL_OFFSET ; +23
brlo int_horizontal_sync_end ; +24
lds r30, line ; +2, 2
lds r31, line + 1 ; +2, 4
adiw z, 1 ; +2, 6
sts line, r30 ; +2, 8
sts line + 1, r31 ; +2, 10
cpi r31, 0 ; +1, 11
brne enter ; +2, 13
cpi r30, VERTICAL_OFFSET ; TODO timing bad at 256 lines
brsh enter
jmp horizontal_line_end
*/
enter:
; here, +23 or +24 cycles have passed since horizontal sync
; so, there are still ~168 cycles before first useful data
ldi r31, 0
sts TCNT0, r31
ldi r31, HORIZONTAL_OFFSET ; set counter TOP
sts OCR0A, r31
; here, +13 cycles have passed since horizontal sync
; so, there are still (192 - 13) = 179 cycles before first useful data
ldi r31, 64 ; approx
1:
dec r31 ; 1
brne 1b ; 2
ldi r31, 0x7 ; clear any pending interrupt
sts TIFR0, r31
lds r31, TIMSK0
ori r31, 0x02 ; mask enable interrupt timer A
sts TIMSK0, r31
int_horizontal_sync_end:
pop r30
pop r31
out IO(SREG), r31
pop r31
reti
.global int_timer_0
int_timer_0:
; here we are at the beginning of the visible line
push r31
in r31, IO(SREG)
push r31
push r30
push r29
ldi r31, 16
1:
dec r31
brne 1b
; turn off interrupt
lds r31, TIMSK0
andi r31, 0xfd ; mask disable interrupt timer A
sts TIMSK0, r31
sbi IO(PORTB), 5
; draw things
ldi r30, lo8(line_buffer)
ldi r31, hi8(line_buffer)
.rept LINE_BUFFER_SIZE
ld r29, z+
out IO(PORTB), r29
sbi IO(PORTB), 4
nop
.endr
nop
nop
nop
cbi IO(PORTB), 4
pop r29
pop r30
pop r31
out IO(SREG), r31
pop r31
reti
# ; draw things
# ldi r30, lo8(line_buffer)
# ldi r31, hi8(line_buffer)
#.rept LINE_BUFFER_SIZE
# ld r29, z+
# out IO(PORTB), r29
# nop
#.endr
cbi IO(PORTB), 5
horizontal_line_end:
jmp wait_next_line
/*
.global int_vertical_sync
int_vertical_sync:
push r31
@ -139,4 +106,4 @@ int_vertical_sync_end:
pop r31
reti
*/

21
main.c
View File

@ -7,23 +7,13 @@ volatile uint16_t frame;
volatile uint16_t line;
volatile char line_buffer[LINE_BUFFER_SIZE];
ISR(INT0_vect, ISR_NAKED) {
asm("jmp int_vertical_sync");
}
ISR(INT1_vect, ISR_NAKED) {
asm("jmp int_horizontal_sync");
}
ISR(TIMER0_COMPA_vect, ISR_NAKED) {
asm("jmp int_timer_0");
void setup_c() {
for (int i = 0; i < LINE_BUFFER_SIZE; ++i) {
line_buffer[i] = (i > 50 && i < 100) ? '1' : 'A';
}
}
void setup_c() {
/*
for (int i = 0; i < LINE_BUFFER_SIZE; ++i) {
line_buffer[i] = (i % 2) ? 0x0 : 0xff;
}
*/
}
/*
void loop_c() {
for (;;) {
@ -53,3 +43,4 @@ void loop_c() {
}
}
}
*/