Продолжаю мучить
http://www.vga-avr.narod.ru/main_rus.html В проекте есть прерывание, в котором выполняется горизонтальная и вертикальная синхронизации, а также настройки указателей отрисовки.
Прерывание это нормировано по тактам, даже в ветвлениях if-ов нопами выровнено время выполнения. Я не знаю зачем автор так сделал, но если добавить хоть 1 nop в любое место, то вся синхронизация падает.
Проблема в том, что автор использует для выдачи сигналов синхронизации команды PORTD = 4; и PORTD = 0;
Что, естественно, приводит к невозможности использовать порт D для чего бы то ни было ещё.
Вторая проблема - PORTD = 4 на самом деле означает не только установку третьего бита, но и сброс второго. Третий бит это вертикальная синхронизация, второй - горизонтальная. И происходить эта операция должна одновременно.
Я пробовал менять на
PORTD |= (1<<3);
PORTD &= ~(1<<2);
Но всё тут же падает и из-за не одновременности вывода сигналов, и из-за возросшего времени выполнения.
Не помогает также и замена на ассемблерные cbi/sbi.
Единственный вариант, который мне видится, это
char temp;
temp = PORTD;
temp |= (1<<3);
temp &= ~(1<<2);
PORTD = temp;
Но даже
char temp;
temp = PORTD;
Уже приводит к искажению картинки из-за увеличившегося времени выполнения прерывания.
В общем, с этим надо что-то делать
Вот текст прерывания:
Код:
//Global definitions for VGA render
#define vga_field_line_count 525 //standart VGA quantity lines
#define vga_symbols_per_row 20 //symbols quantity per horizontal
#define vga_row_count 20 //symbols quantity per vertical
#define vga_symbol_height 24 //rendered symbol height
#define TIMER_LIMIT 0xC3 //set count, One VGA line 31.77us
//All VGA sincronize made here..
SIGNAL(SIG_OVERFLOW0) {
TCNT0 = TIMER_LIMIT; //reload counter value 0xC3 //set count, One VGA line 31.77us
//******Syncronization Handler********
//Count number of lines
if (++linecount == vga_field_line_count) {
linecount = 0;
//clear pointers for render display buffer
raw_render = 0;
y_line_render = 0;
}
// Вертикальный и горизонтальный синхроимпульсы должны быть одновременно, поэтому дёргать битами порта раздельно по cbi/sbi не получится.
// кроме того, тело прерывания крайне чувствительно ко времени исполнения, и добавление любой команды сбивает синхронизацию.
//Make Vsync length 2 VGA lines
if ((linecount == 10 )||(linecount == 11 )) {
//Make here vertical syncronization & HSYNC syncro level on
PORTD = 0; //vsync_on
} else {
//.. & HSYNC syncro level on
PORTD = 4;// vsync_off
}
video_enable_flg = true;
if (linecount < 45) {
video_enable_flg = false;
//Add to avoid flickering at top display
NOP; // 15 nops
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
} else {
//Forming current string for rendering
if (++y_line_render == vga_symbol_height) {
raw_render++;
y_line_render = 0;
} else {
NOP; // 8 nops
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
}
}
hsync_off; //HSYNC syncro level off sbi(PORTD,3)
//******Syncronization Handler********
}
Ассемблер:
Код:
//All VGA sincronize made here..
SIGNAL(SIG_OVERFLOW0) {
de4: 1f 92 push r1
de6: 0f 92 push r0
de8: 0f b6 in r0, 0x3f ; 63
dea: 0f 92 push r0
dec: 11 24 eor r1, r1
dee: 2f 93 push r18
df0: 8f 93 push r24
df2: 9f 93 push r25
//unsigned char port_buffer;
TCNT0 = TIMER_LIMIT; //reload counter value
df4: 83 ec ldi r24, 0xC3 ; 195
df6: 82 bf out 0x32, r24 ; 50
//******Syncronization Handler********
//Count number of lines
if (++linecount == vga_field_line_count) {
df8: 80 91 77 00 lds r24, 0x0077
dfc: 90 91 78 00 lds r25, 0x0078
e00: 01 96 adiw r24, 0x01 ; 1
e02: 90 93 78 00 sts 0x0078, r25
e06: 80 93 77 00 sts 0x0077, r24
e0a: 80 91 77 00 lds r24, 0x0077
e0e: 90 91 78 00 lds r25, 0x0078
e12: 8d 50 subi r24, 0x0D ; 13
e14: 92 40 sbci r25, 0x02 ; 2
e16: 41 f4 brne .+16 ; 0xe28 <__vector_11+0x44>
linecount = 0;
e18: 10 92 78 00 sts 0x0078, r1
e1c: 10 92 77 00 sts 0x0077, r1
//clear pointers for render display buffer
raw_render = 0;
e20: 10 92 73 03 sts 0x0373, r1
y_line_render = 0;
e24: 10 92 79 00 sts 0x0079, r1
// Вертикальный и горизонтальный синхроимпульсы должны быть одновременно, поэтому дёргать битами порта раздельно по cbi/sbi не получится.
// кроме того, тело прерывания крайне чувствительно ко времени исполнения, и добавление любой команды сбивает синхронизацию.
// я не смог победить этот глюк и использовал костыль с промежуточной переменной.
//Make Vsync length 2 VGA lines
if ((linecount == 10 )||(linecount == 11 )) {
e28: 80 91 77 00 lds r24, 0x0077
e2c: 90 91 78 00 lds r25, 0x0078
e30: 0a 97 sbiw r24, 0x0a ; 10
e32: 31 f0 breq .+12 ; 0xe40 <__vector_11+0x5c>
e34: 80 91 77 00 lds r24, 0x0077
e38: 90 91 78 00 lds r25, 0x0078
e3c: 0b 97 sbiw r24, 0x0b ; 11
e3e: 11 f4 brne .+4 ; 0xe44 <__vector_11+0x60>
//Make here vertical syncronization & HSYNC syncro level on
PORTD = 0; //vsync_on
e40: 12 ba out 0x12, r1 ; 18
e42: 02 c0 rjmp .+4 ; 0xe48 <__vector_11+0x64>
} else {
//.. & HSYNC syncro level on
PORTD = 4;// (PORTD | 0x04); //vsync_off
e44: 84 e0 ldi r24, 0x04 ; 4
e46: 82 bb out 0x12, r24 ; 18
}
video_enable_flg = true;
e48: 81 e0 ldi r24, 0x01 ; 1
e4a: 80 93 74 03 sts 0x0374, r24
if (linecount < 45) {
e4e: 80 91 77 00 lds r24, 0x0077
e52: 90 91 78 00 lds r25, 0x0078
e56: 8d 97 sbiw r24, 0x2d ; 45
e58: 90 f4 brcc .+36 ; 0xe7e <__vector_11+0x9a>
video_enable_flg = false;
e5a: 10 92 74 03 sts 0x0374, r1
...
NOP;
NOP;
NOP;
NOP;
NOP;
NOP;
e7a: 00 00 nop
e7c: 19 c0 rjmp .+50 ; 0xeb0 <__vector_11+0xcc>
} else {
//Forming current string for rendering
if (++y_line_render == vga_symbol_height) {
e7e: 80 91 79 00 lds r24, 0x0079
e82: 8f 5f subi r24, 0xFF ; 255
e84: 80 93 79 00 sts 0x0079, r24
e88: 80 91 79 00 lds r24, 0x0079
e8c: 88 31 cpi r24, 0x18 ; 24
e8e: 41 f4 brne .+16 ; 0xea0 <__vector_11+0xbc>
raw_render++;
e90: 80 91 73 03 lds r24, 0x0373
e94: 8f 5f subi r24, 0xFF ; 255
e96: 80 93 73 03 sts 0x0373, r24
y_line_render = 0;
e9a: 10 92 79 00 sts 0x0079, r1
e9e: 08 c0 rjmp .+16 ; 0xeb0 <__vector_11+0xcc>
...
NOP;
}
}
hsync_off; //HSYNC syncro level off sbi(PORTD,3)
eb0: 93 9a sbi 0x12, 3 ; 18
//******Syncronization Handler********
}
eb2: 9f 91 pop r25
eb4: 8f 91 pop r24
eb6: 2f 91 pop r18
eb8: 0f 90 pop r0
eba: 0f be out 0x3f, r0 ; 63
ebc: 0f 90 pop r0
ebe: 1f 90 pop r1
ec0: 18 95 reti
00000ec2 <display_Mega>: