roboforum.ru

Технический форум по робототехнике.

TV-AVR

TV-AVR

HarryStar » 20 сен 2011, 14:27

Столкнулся с проблемой.

мне нужно выполнить критичный ко времени исполнения код вида:
Код: Выделить всёРазвернуть
PORTB.7=(*buffer) & 0b00001000;

Проблема в том, что время его выполнения сильно различается когда соответствующий бит в буфере равен 0 или 1, а мне надо что-бы было одинаково. Уже всю голову сломал :(

Может что подскажете?
Последний раз редактировалось HarryStar 24 фев 2012, 14:59, всего редактировалось 2 раз(а).

Re: Время выполнения PORTB.1 = ...

=DeaD= » 20 сен 2011, 14:44

А как измеряли, что время выполнения отличается?

Re: Время выполнения PORTB.1 = ...

avr123.nm.ru » 20 сен 2011, 14:49

в симуляторе наверняка. Оно наверно и должно отличаться.

так попробуйте, может чуть поровней будет.
Код: Выделить всёРазвернуть
PORTB.7 = 0b00001000 & (*buffer);


Можно листинг АСМ посмотреть на отличие.

Re: Время выполнения PORTB.1 = ...

HarryStar » 20 сен 2011, 15:07

В симуляторе не смотрел, оно на глаз отличается. Это для генерации видеосигнала.

Re: Время выполнения PORTB.1 = ...

avr123.nm.ru » 20 сен 2011, 15:10

Глаз АЛМАЗ!

Re: Время выполнения PORTB.1 = ...

dccharacter » 20 сен 2011, 15:10

Можа оптимизация какая-то???

Re: Время выполнения PORTB.1 = ...

HarryStar » 20 сен 2011, 15:19

Нет, тоже самое.
Вот выдержка из асма
Код: Выделить всёРазвернуть
;        PORTB.7=0b00100000 & (*(lvideo+1)); PIXEL_SIZE1b
   MOVW R30,R10
   LDD  R30,Z+1
   ANDI R30,LOW(0x20)
   BRNE _0x18
   CBI  0x18,7
   RJMP _0x19
_0x18:
   SBI  0x18,7
_0x19:
   nop


Там не глаз-алмаз, там получается что черный пиксель больше, чем белый. Пока выводил вертикальные полосочки, все было ок, как произвольное изображение - тут же заметно стало. Полностью черная строка длиннее белой на 10%.

Re: Время выполнения PORTB.1 = ...

avr123.nm.ru » 20 сен 2011, 15:39

Наверно надо АСМ вставкой оформить и более быструю часть дополнить НОП-ами.

Re: Время выполнения PORTB.1 = ...

HarryStar » 20 сен 2011, 15:53

В том и проблема что оч слабо разбираюсь в ассемблере, хотелось бы по возможности все на си.
Пробовал просто алгоритм сменить...
Идеальным решением было бы из массива в 16 байт все биты превратить в байты.
Т.е. например для одного байта
Код: Выделить всёРазвернуть
    lineram[16] = ((*(lvideo+2)) & 0b10000000)<<0;
    lineram[17] = ((*(lvideo+2)) & 0b01000000)<<1;
    lineram[18] = ((*(lvideo+2)) & 0b00100000)<<2;
    lineram[19] = ((*(lvideo+2)) & 0b00010000)<<3;
    lineram[20] = ((*(lvideo+2)) & 0b00001000)<<4;
    lineram[21] = ((*(lvideo+2)) & 0b00000100)<<5;
    lineram[22] = ((*(lvideo+2)) & 0b00000010)<<6;
    lineram[23] = ((*(lvideo+2)) & 0b00000001)<<7;

Но 16 байт таким образом очень долго преобразуются, нужно уложится в 12 мс примерно.

Re: Время выполнения PORTB.1 = ...

=DeaD= » 20 сен 2011, 16:16

Странно, а симулятор разное количество тактов показывает или нет?

Re: Время выполнения PORTB.1 = ...

Michael_K » 20 сен 2011, 16:23

HarryStar писал(а):Т.е. например для одного байта
Код: Выделить всёРазвернуть
    lineram[16] = ((*(lvideo+2)) & 0b10000000)<<0;

Но 16 байт таким образом очень долго преобразуются, нужно уложится в 12 мс примерно.


Наверняка так быстрее:
lineram[5] = 0x00; if (lvideo&0b00010000) lineram[5] = 0x80;

Но вообще перекладывать из массива в массив - зло.
Вы таким образом гробите и память и быстродействие.
Последний раз редактировалось Michael_K 21 сен 2011, 00:44, всего редактировалось 1 раз.

Re: Время выполнения PORTB.1 = ...

=DeaD= » 20 сен 2011, 16:44

Можно по полубайту готовый массив из 16 выбирать и выводить :)

Re: Время выполнения PORTB.1 = ...

HarryStar » 20 сен 2011, 20:53

Michael_K писал(а):Наверняка так быстрее:

Попробую завтра утром, но что-то сомневаюсь, что условие и ветвление быстрее, чем присваивание
Michael_K писал(а):Но вообще перекладывать из массива в массив - зло.
Вы таким образом гробите и память и быстродействие.

Вывод видео специфическая задача. Во время прохода строки времени очень мало, чтобы делать даже простейшие расчеты, а вот между строками есть 12 мс, во время которых можно подготовить данные для следующей строки. Если 1 точка = 1 байт, то вывод очень быстрый - практически можно сделать любое разрешение, главное подготовить одну строку-буфер. Без этого у меня получилось 2 режима: 32 х 32 х 8бит и 32 х 32 х 4бита. Дальше пробую 128 х 64 х 1 бит, но вот столкнулся с этой проблемой.

Re: Время выполнения PORTB.1 = ...

Flexz » 20 сен 2011, 23:29

У вас же SPI по сути, почему его не использовать?

Re: Время выполнения PORTB.1 = ...

Michael_K » 21 сен 2011, 01:50

HarryStar писал(а):что-то сомневаюсь, что условие и ветвление быстрее, чем присваивание

У вас там не присваивание, а маска и сдвиг.

А условие и ветвление возможно будут такими (от оптимизатора зависит)

Код: Выделить всёРазвернуть
lds  in, (in_array+2) - один раз для каждого входного байта
ldi  out,0x00
sbrs in,5
ldi  out,0x80
sts  (out_array+18), out


HarryStar писал(а):Вывод видео специфическая задача. Во время прохода строки времени очень мало

Далаадна... С вашими-то разрешениями да современными процами :wink:

Flexz писал(а):У вас же SPI по сути, почему его не использовать?

+1. Если между знакоместами допустимы промежутки, то удобно использовать SPI

У вас какой процессор и кварц?

Добавлено спустя 1 час 7 минут 49 секунд:
Сейчас попробовал написать. (Вслепую. Не отлаживал и не собираюсь :))
Использует знакогенератор символов из флэш. Частота вывода пикселей - 5Мгц (при кварце 20). 32 символа в строке (256 пикселей). Это примерно 51 с чем-то микросекунды. В начале строки выводится один лишний пиксель (черный).
Недостаток - занимает весь порт, но использует только младшую ногу порта (так проще).
Код: Выделить всёРазвернуть
init:   
   ; Тут сохраняем регистры, если надо, выравниваем времена и т.п.
   ; в ZH кладем адрес нужной строки знакогенератора
   ; в Y кладем адрес экранного буфера

   ldi   cnt,32   ; в cnt кладем число символов в строке
   ldi   sh1,0   ; в sh1 кладем нолик, это "лишний" бит - он будет черный.
   rjmp   entry   ; Поехали

loop:   out   sh1   ;1===   Седьмой
   lsr   sh1   ;1
entry:   ld   ZL,Y+   ;2   Берем код символа из экранного буфера
   out   sh1   ;1===   Выводим последний бит (сразу после входа - черный)
   lpm   tmp,Z   ;3   Берем нужный байт из знакогенератора
   out   tmp   ;1===   Сразу выводим первый бит
   mov   sh1,tmp   ;1   Перекидываем в "сдвиговый регистр"...
   lsr   sh1   ;1   ...и сдвигаем
   nop      ;1
   out   sh1   ;1===   Выводим второй бит
   lsr   sh1   ;1   ...и сдвигаем
   nop      ;1
   nop      ;1
   out   sh1   ;1===   Третий
   lsr   sh1   ;1
   nop      ;1
   nop      ;1
   out   sh1   ;1===   Четвертый
   lsr   sh1   ;1
   nop      ;1
   nop      ;1
   out   sh1   ;1===   Пятый бит
   lsr   sh1   ;1   сдвигаем
   mov   tmp,sh1   ;1   запоминаем результат  в tmp
   lsr   sh1   ;1   и сразу сдвигаем еще раз, чтобы потом быстро вывести
   out   tmp   ;1===   Шестой бит из tmp
   dec   cnt   ;1   Есть еще байты?
   brne   loop   ;2   Если да, зацикливаемся

   nop      ;1
   out   sh1   ;1===   Седьмой бит последнего символа в строке
   lsr   sh1   ;1
   nop      ;1
   nop      ;1
   out   sh1   ;1===   Последний бит последнего символа в строке

   ; Можно добавить инкремент строки знакогенератора, экранного буфера, подсчет строк, времени и т.п.
   ; Тут восстанавливаем регистры, если надо


Кучу нопов... можно занять чем-нибудь "полезным" :)
Последний раз редактировалось Michael_K 22 сен 2011, 12:38, всего редактировалось 1 раз.


Rambler\'s Top100 Mail.ru counter