Выкроить 4 такта в коде прерывания надо

Обсуждаем контроллеры компании Atmel.
Ответить
Аватара пользователя
Dikoy
Встал на лапы
Сообщения: 91
Зарегистрирован: Сб июл 18, 2009 21:38:43

Выкроить 4 такта в коде прерывания надо

Сообщение Dikoy »

Продолжаю мучить 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>:
Последний раз редактировалось Dikoy Ср апр 04, 2018 13:03:27, всего редактировалось 1 раз.
Реклама
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Выкроить 2 такта в коде прерывания надо

Сообщение Ivanoff-iv »

попробуй буфер - заполняешь его раньше (возможно много раньше, даже может в прошлой итерации прерывания, после всех кодов) а здесь только пуляй его в порт
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Реклама
Аватара пользователя
Dikoy
Встал на лапы
Сообщения: 91
Зарегистрирован: Сб июл 18, 2009 21:38:43

Re: Выкроить 4 такта в коде прерывания надо

Сообщение Dikoy »

Так было бы место где заполнять...
Я уже думал, что if (linecount < 45) с его нопами можно использовать для
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

Ибо 10 и 11 меньше 45... Но ещё не опробовал.
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Выкроить 4 такта в коде прерывания надо

Сообщение Ivanoff-iv »

эту часть

Код: Выделить всё

//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
               
         
         }
написать так

Код: Выделить всё

//Make Vsync length 2 VGA lines 
        PORTD = tempD; 
        if ((linecount == 9 )||(linecount == 10 )) {
            //Make here vertical syncronization & HSYNC syncro level on
            tempD = 0; //vsync_on
         } else    {
            //.. & HSYNC syncro level on
            tempD = 4;// vsync_off
               
         
         }
Добавлено after 31 minute 24 seconds:
может прокатит, а может и нет...
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Выкроить 4 такта в коде прерывания надо

Сообщение Аlex »

И происходить эта операция должна одновременно.
Про "одновременно" можно подробнее ?
А если бит, который нужно сбросить "одновременно" с установкой другого, уже до этого момента сброшен ? Это уже считается неодновременность ? И уже, априори, будет какой-то там глюк (не вникал в подробности) ? Или как ?
Реклама
Аватара пользователя
Ivanoff-iv
Друг Кота
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Re: Выкроить 4 такта в коде прерывания надо

Сообщение Ivanoff-iv »

я так понял - в середине экрана стрка кончается - приходит импульс строчной синхронизации, а кадровой как небыло, так и нет, а когда меняется кадр приходят обе, но одна из них инверсная, поэтому вариант с и/или не прокатит как и побитовые операции.
как вариант - либо внешняя обвязка либо внутренняя подстановочная маска, к стати - это мысль! вместо 4 или 0 вписывать туда темп,или даже темп4 и темп0 нужные для синхронизации биты которых не трогать в основной программе, а остальные - в любом месте (не в прерывании) менять на своё усмотрение, правда с портом они будут синхронизироваться вместе с развёрткой, но, на них можно возложить задачу, позволяющую такое обращение.
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Реклама
Аватара пользователя
BOB51
Друг Кота
Сообщения: 15574
Зарегистрирован: Вт мар 16, 2010 22:02:27
Откуда: ДОНЕЦК

Re: Выкроить 4 такта в коде прерывания надо

Сообщение BOB51 »

Можно попробовать таблично под ассемблером отработать - тот алгоритм, что я для программной ШИМ-манипуляции под WS2812 сделал.
С использованием команд косвенных переходов/вызовов подпрограмм (ICALL/IJMP) сразу по входу в прерывание.
А у каждой комбинации "база + смещение", находящейся в Z на момент прихода вызова прерывания указан адрес соответствующего фрагмента к исполнению.
У Си еще собственно загрузка/сброс стека, которую компилятор добавит (согласно своего разумения) - это может быть и весьма большой кусманчик кода (PUSH/POP)...
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Выкроить 4 такта в коде прерывания надо

Сообщение Аlex »

[uquote="Dikoy",url="/forum/viewtopic.php?p=3346155#p3346155"]Продолжаю мучить http://www.vga-avr.narod.ru/main_rus.html[/uquote]Это шутка какая то ?
По ссылке :
Изображение
Жму "Отмена" и опачки :
Изображение

:twisted:
emax
Первый раз сказал Мяу!
Сообщения: 38
Зарегистрирован: Пт мар 07, 2014 18:37:20
Откуда: Пермь

Re: Выкроить 4 такта в коде прерывания надо

Сообщение emax »

Hsync я формировал таймером в режиме ШИМ, сразу и импульс на выводе есть. Перед синхроимпульсом процессор надо укладывать спать, что бы не было дрожания изображения.
Аватара пользователя
Dikoy
Встал на лапы
Сообщения: 91
Зарегистрирован: Сб июл 18, 2009 21:38:43

Re: Выкроить 4 такта в коде прерывания надо

Сообщение Dikoy »

Победил, подробности тут https://electronix.ru/forum/index.php?s ... &p=1554994
Требования к одновременности оказались не таким жёсткими, а вот такты считать пришлось, да...

Добавлено after 4 minutes 15 seconds:
Кстати, оттуда же, я этого не знал:

"Может Вам пригодится...
Для многих АВРок есть возможность тоглить (инвертировать) состояние GPIO путём записи в регистр PINx." https://electronix.ru/forum/index.php?s ... &p=1555011

Добавлено after 2 minutes 13 seconds:
[uquote="Аlex",url="/forum/viewtopic.php?p=3346347#p3346347"]Жму "Отмена" и опачки :[/uquote]

Изображение
Ответить

Вернуться в «AVR»