реклама на сайте
подробности

 
 
> Выкроить 4 такта в коде прерывания надо
Dikoy
сообщение Apr 4 2018, 10:25
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 4-03-09
Из: Богота, Колумбия
Пользователь №: 45 676



Мучаю исходник http://www.vga-avr.narod.ru/main_rus.html "Простой VGA/Видео адаптер"
В проекте есть прерывание, в котором выполняется горизонтальная и вертикальная синхронизации, а также настройки указателей отрисовки.
Прерывание это нормировано по тактам, даже в ветвлениях 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;
Уже приводит к искажению картинки из-за увеличившегося времени выполнения прерывания.

В общем, с этим надо что-то делать... Либо соптимизировать прерывание и выкроить такты, либо управлять портом как-то иначе, например, через указатель, но сомневаюсь что по числу тактов будет выигрыш.

Вот текст прерывания:
CODE
//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********

}


Ассемблер:

CODE
//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>:


Сообщение отредактировал Dikoy - Apr 4 2018, 17:18
Причина редактирования: [codebox] для длинного кода. [code]-для короткого!!!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
Dikoy
сообщение Apr 4 2018, 11:57
Сообщение #2


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 4-03-09
Из: Богота, Колумбия
Пользователь №: 45 676



А есть для авр ассемблера что-то для быстрого подсчёта тактов? Например, от сих и до сих. А то на бумажке считать несколько уныло...
Go to the top of the page
 
+Quote Post
zombi
сообщение Apr 4 2018, 14:15
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 2 076
Регистрация: 10-09-08
Пользователь №: 40 106



Цитата(Dikoy @ Apr 4 2018, 14:57) *
А есть для авр ассемблера что-то для быстрого подсчёта тактов? Например, от сих и до сих. А то на бумажке считать несколько уныло...

Думаю должна быть возможность загрузить в студию прошивку.
Установить PC на нужный адрес "от сих" точку останова на "до сих" запустить эмуляцию и смотреть сколько тактов потребовалось.

bb-offtopic.gif формирование синхросигналов VGA на СИ - это жесть biggrin.gif
Go to the top of the page
 
+Quote Post
Dikoy
сообщение Apr 4 2018, 15:08
Сообщение #4


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 4-03-09
Из: Богота, Колумбия
Пользователь №: 45 676



Цитата(zombi @ Apr 4 2018, 17:15) *
bb-offtopic.gif формирование синхросигналов VGA на СИ - это жесть biggrin.gif

Жесть, это на ардуине https://forum.arduino.cc/index.php?topic=102181.0
Go to the top of the page
 
+Quote Post
zombi
сообщение Apr 4 2018, 17:19
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 2 076
Регистрация: 10-09-08
Пользователь №: 40 106



Цитата(Dikoy @ Apr 4 2018, 18:08) *
Жесть, это на ардуине https://forum.arduino.cc/index.php?topic=102181.0

Да хоть на чём угодно.
Но я не понимаю или не вижу:
где и как происходит выравнивание фронта синхросигнала в зависимости от времени выполнения прерываемой команды?
Go to the top of the page
 
+Quote Post
Dikoy
сообщение Apr 4 2018, 17:51
Сообщение #6


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 4-03-09
Из: Богота, Колумбия
Пользователь №: 45 676



Цитата(zombi @ Apr 4 2018, 20:19) *
где и как происходит выравнивание фронта синхросигнала в зависимости от времени выполнения прерываемой команды?

Оооо! Там такая содомия в коде творится! В мейнлупе то же самое происходит - вывод строки сделан в цикле и не дай кришна убрать один ноп!
Если б я знал заранее что будет такая жесть, не начинал бы это дело. Написал бы своё на СТМ или использовал ЖК панель. Но попробовал скомпилированный код автора, работает, ок, думаю, допишу вывод своих данных, это не сложно... rolleyes.gif

****
Кстати о содомии. То же самое там происходит и с портом В. Но там всё проще. Меняем ногодрыг на sbi/cbi:

Код
#define video_off    cbi(DDRB,5)  // DDRB=0x90
#define video_on     sbi(DDRB,5)  // DDRB=0xB0


Убираем по одному нопу после video_on; и до video_off;, т.к. команды sbi/cbi выполняются по 2 такта, а присвоение, преобразуемое в LDI - только 1 такт.

Код
//Cycle for render line
                i = vga_symbols_per_row;
                while(i--)
                {
                    SPDR = pgm_read_byte_near(_ptr1 + (* _ptr++)*vga_symbol_height/2);
                    video_on;
                    NOP;
                }
                //Delay for draw last symbol
                NOP;
                NOP;
                NOP;
                NOP;
                NOP;
                video_off;


Сообщение отредактировал Dikoy - Apr 4 2018, 17:53
Go to the top of the page
 
+Quote Post
zombi
сообщение Apr 4 2018, 18:43
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 076
Регистрация: 10-09-08
Пользователь №: 40 106



Цитата(Dikoy @ Apr 4 2018, 20:51) *
Оооо! Там такая содомия в коде творится!

Да это то понятно.
Вы наверное относитесь к людям которые не ищут простых и/или лёгких путей. biggrin.gif
Но я немного о другом спрашивал.
Прерывание таймера может произойти во время выполнения команды длительностью 1,2 или 3 такта.
Это где-то учитывается?
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 00:47
Рейтинг@Mail.ru


Страница сгенерированна за 0.01455 секунд с 7
ELECTRONIX ©2004-2016