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

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Вычисления на ATmega88
koluna
сообщение Dec 2 2008, 14:00
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061



Здравствуйте!

Использую WinAVR, ATmega88, сигнал синхронизации - внтутренняя RC-цепь (частота 8 МГц).
Необходимо как можно быстрее вычислить значение следующего выражения:

C = Y * C' / 255.
Причём:
C, Y, C' - unsigned char, т. е., действительные числа мне не нужны...

В данный момент вычисления производятся приблизительно за 92 мкс (в программе три выражения подряд).

Можно, конечно, кварц поставить на большую частоту, но хотелось бы пока без него smile.gif

Фрагмент программы:

Код
...
OCR0A = n_red * dmx[0] / 255;
OCR0B = n_green * dmx[0]  / 255;
OCR2B = n_blue * dmx[0] / 255;
...



Спасибо заранее!


--------------------
Благодарю заранее!
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Dec 2 2008, 14:12
Сообщение #2


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



а если поделить на 256? Компилер должен превратить такое деление в сдвиг (или можно руками написать >>8).
Разница будет довольно мала...
Go to the top of the page
 
+Quote Post
Арк К
сообщение Dec 2 2008, 14:16
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 45
Регистрация: 8-05-08
Пользователь №: 37 363



А надо делить именно на 255? не на 256?
тогда было бы нужно просто выкинуть младший байт
Критичные ко времени места лучше делать на ассемблере.
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Dec 2 2008, 14:24
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(Арк К @ Dec 2 2008, 17:16) *
Критичные ко времени места лучше делать на ассемблере.


Тут засада будет скорее именно в делении. И если от него не избавиться - врядли на асме получится сильно быстрее...
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Dec 2 2008, 14:24
Сообщение #5


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(n_bogoyavlensky @ Dec 2 2008, 18:00) *
Код
...
OCR0A = n_red * dmx[0] / 255;
OCR0B = n_green * dmx[0]  / 255;
OCR2B = n_blue * dmx[0] / 255;
...

Спасибо заранее!


Используйте предварительно посчитанные значения K=M*dmx[0]/255
где М выбирается таким, чтобы получалось то, что делается быстрее, т.е. умножение на К и взятие старшего байта произведения.
асмовый текст, раз уж заговорили про скорость
Код
  lds r24,K
  lds r25,n_red
  mul r24,r25
  out OCR0A,r1
  lds r25,n_green
  mul r24,r25
  out OCR0A,r1
  lds r25,n_blue
  sts OCR2A,r1

Надеюсь, принцип понятен.
Go to the top of the page
 
+Quote Post
=GM=
сообщение Dec 2 2008, 14:52
Сообщение #6


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Цитата(n_bogoyavlensky @ Dec 2 2008, 14:00) *
Необходимо как можно быстрее вычислить значение следующего выражения: C = Y * C' / 255

C=(Y*C1*257) >> 16;

Или совсем уж убыстрить

С2=Y*C1;
C=((C2 << 8)+С2) >> 16;

На асме просто взять два старших байта.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Dec 2 2008, 15:00
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(=GM= @ Dec 2 2008, 17:52) *
C=(Y*C1*257) >> 16;


Тогда уж так

C=((unsigned long)Y*C1*257) >> 16;

- у топик стартера Y и С1 - unsigned char

Кстати, классное решение a14.gif
Go to the top of the page
 
+Quote Post
=GM=
сообщение Dec 2 2008, 15:05
Сообщение #8


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Цитата(Непомнящий Евгений @ Dec 2 2008, 15:00) *
Тогда уж так C=((unsigned long)Y*C1*257) >> 16;
Кстати, классное решение

А то! Но всё-ж-таки, нормальный компилер должен сам типы приводить.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Dec 2 2008, 15:14
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(_Pasha @ Dec 2 2008, 17:24) *
Используйте предварительно посчитанные значения K=M*dmx[0]/255
где М выбирается таким, чтобы получалось то, что делается быстрее, т.е. умножение на К и взятие


Не могли бы вы пояснить эту мысль? К зависит от двух 1-байтных чисел, объем таблицы получится 65536 байт... Или я вас не так понял?

Цитата(=GM= @ Dec 2 2008, 17:52) *
C=(Y*C1*257) >> 16;

Или совсем уж убыстрить

С2=Y*C1;
C=((C2 << 8)+С2) >> 16;


А кстати, нифига smile.gif

(С2*257) >> 16 =( (С2 <<8) + C2)>>16 = ((C2<<8)>>16) + (C2>>16) = C2>>8 = C2 / 256 ...

сдвиг на 16 - это ж деление на 65536, а не на 65535 smile.gif
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Dec 2 2008, 15:20
Сообщение #10


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(Непомнящий Евгений @ Dec 2 2008, 19:14) *
Не могли бы вы пояснить эту мысль? К зависит от двух 1-байтных чисел, объем таблицы получится 65536 байт... Или я вас не так понял?

Я обратил внимание на то, что эта часть dmx[0] / 255; должна быть вычислена один раз и больше не участвовать в окончательных выражениях. Таблицей, конечно, не получится
ЗЫ - наверное, автору все-таки нужно сразу делить на 256, потому что разница в 3 промилле, наверняка, не важна.
Go to the top of the page
 
+Quote Post
LordVader
сообщение Dec 2 2008, 16:48
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 127
Регистрация: 18-10-06
Пользователь №: 21 418



Вот что нагуглилось: http://www.sharpthinking.net/cv/div255.pdf
Быстрое деление на 255. Вкратце: a/255 = ((a>>8)+a+128)>>8 с округлением к ближайшему целому.
Go to the top of the page
 
+Quote Post
=GM=
сообщение Dec 2 2008, 16:53
Сообщение #12


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Цитата(Непомнящий Евгений @ Dec 2 2008, 15:14) *
(С2*257) >> 16 =( (С2 <<8) + C2)>>16 = ((C2<<8)>>16) + (C2>>16) = C2>>8 = C2 / 256 ...
сдвиг на 16 - это ж деление на 65536, а не на 65535 smile.gif

Так и задумывалось, делить на 65536, чтобы был сдвиг на 16 бит, а не деление на 65535.

Вот здесь ошибочка у вас ((C2<<8)>>16) + (C2>>16) = C2>>8+(C2>>16).

Округление можно так сделать C=((C2 << 8)+С2+32768) >> 16;


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
VDG
сообщение Dec 2 2008, 22:02
Сообщение #13


Знающий
****

Группа: Участник
Сообщений: 845
Регистрация: 10-02-06
Пользователь №: 14 193



Человек скорее всего управляет RGB-светодиодом, а деление на 255 - это соответственно "нормализация в восьмибитное число" после умножения на коэффициент яркости. В таком случае, деление на 255 - ошибка. На 256 надо делить, или как выше сказали - взять HIBYTE.


--------------------
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Dec 3 2008, 05:26
Сообщение #14


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(=GM= @ Dec 2 2008, 19:53) *
Вот здесь ошибочка у вас ((C2<<8)>>16) + (C2>>16) = C2>>8+(C2>>16).


С2 = У * С1

У и С1 - unsigned char, т.е. их произведение <=65535. Сдвиг на 16 влево такого числа даст 0. Поэтому (C2>>16) == 0

Цитата
Так и задумывалось, делить на 65536, чтобы был сдвиг на 16 бит, а не деление на 65535.


Ну просто это получается эквивалентно C2/256. Просто малость замаскировано smile.gif
Go to the top of the page
 
+Quote Post
koluna
сообщение Dec 3 2008, 08:26
Сообщение #15


Профессионал
*****

Группа: Участник
Сообщений: 1 040
Регистрация: 3-01-07
Пользователь №: 24 061



Цитата(Арк К @ Dec 2 2008, 18:16) *
А надо делить именно на 255? не на 256?
тогда было бы нужно просто выкинуть младший байт
Критичные ко времени места лучше делать на ассемблере.


Понятно, что на ассемблере быстрее будет работать...
Но я не знаю как сопрячь WinAVR C и ассемблер sad.gif

Цитата(_Pasha @ Dec 2 2008, 18:24) *
Используйте предварительно посчитанные значения K=M*dmx[0]/255
где М выбирается таким, чтобы получалось то, что делается быстрее, т.е. умножение на К и взятие старшего байта произведения.
асмовый текст, раз уж заговорили про скорость
Код
  lds r24,K
  lds r25,n_red
  mul r24,r25
  out OCR0A,r1
  lds r25,n_green
  mul r24,r25
  out OCR0A,r1
  lds r25,n_blue
  sts OCR2A,r1

Надеюсь, принцип понятен.


К сожалению принцип не понятен пока.
Сколько нужно памяти для предварительно посчитанных значений?

Цитата(_Pasha @ Dec 2 2008, 19:20) *
Я обратил внимание на то, что эта часть dmx[0] / 255; должна быть вычислена один раз и больше не участвовать в окончательных выражениях. Таблицей, конечно, не получится
ЗЫ - наверное, автору все-таки нужно сразу делить на 256, потому что разница в 3 промилле, наверняка, не важна.


f = dmx[0] / 255 делается действительно 1 раз.
Я вынес эту операцию в другое место.
Теперь делаю только С = C' * f.
Время выполнения сократилось приблизительно на 10 мкс (кстати, я ещё кварц на 20 МГц поставил).
Но хотелось бы ещё побыстрее...


Цитата(VDG @ Dec 3 2008, 02:02) *
Человек скорее всего управляет RGB-светодиодом, а деление на 255 - это соответственно "нормализация в восьмибитное число" после умножения на коэффициент яркости. В таком случае, деление на 255 - ошибка. На 256 надо делить, или как выше сказали - взять HIBYTE.


Ими и управляю. Поясню.

Регулирую яркость 8-битным ШИМом микроконтроллера.
Имеем 4 внешних контролла, от которых зависит результирующий цвет луча и его интенсивность.

1 - Общая световая интенсивность dmx[0].
2 - Интенсивность красного n_red.
3 - Интенсивность зелёного n_green.
4 - Интенсивность синего n_blue.

Т. е., моя задача - вычислить значение 8-битного регистра сравнения OCR микроконтроллера, которое зависит от dmx[0] и n_red/n_green/n_blue.

Придумал управлять так:
Код
OCR0A = n_red * dmx[0] / 255;
OCR0B = n_green * dmx[0]  / 255;
OCR2B = n_blue * dmx[0] / 255;


Но подвело меня деление...

Почему надо делить на 256?
Ясное дело, это сдвиг вправо на 8 - выполняется молниеносно, но почему 256?
Т. е., просто согласиться с появляющейся ошибкой?

Сообщение отредактировал n_bogoyavlensky - Dec 3 2008, 08:26


--------------------
Благодарю заранее!
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 21st June 2025 - 05:37
Рейтинг@Mail.ru


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