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

 
 
3 страниц V  < 1 2 3 >  
Reply to this topicStart new topic
> Нужно оптимизировать код, Есть идеи как?
follow_me
сообщение Jan 21 2011, 15:34
Сообщение #16


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

Группа: Участник
Сообщений: 182
Регистрация: 4-11-10
Пользователь №: 60 646



В циклах кстати для приращения итератора стоит использовать ++i вместо i++ т.к. i++ выполняется за 3 такта а ++i за 1 итого выходит что только на итераторе 2* n итераций

хотя опять же нужно смотреть как такое оптимизирует оптимизатор
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 21 2011, 18:50
Сообщение #17


;
******

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



Цитата(demiurg_spb @ Jan 21 2011, 18:01) *
А при -Оs сколько?

тоже где-то 317-325 было

Цитата(follow_me @ Jan 21 2011, 19:34) *
В циклах кстати для ...

Это, как и предпочтения do{}while вместо for() - суетная часть. Где-то работает, где-то компилер умнее. Я вот, недавно бодаясь с МСС18, прогнулся так, что было стыдно. Потом перестал это делать - результат оказался хуже на 2-3 процента. Оно не надо.
Go to the top of the page
 
+Quote Post
defunct
сообщение Jan 23 2011, 22:41
Сообщение #18


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Концептуально можно ускорить код - если вместо проверки каждого канала в каждом "Loop'e" таймера, организовать всего 14+1 прерываний от таймера за период в 256 тиков. (Где 14 прерываний соответствуют 14-ти каналам PWM, 15-ое - сброс всех каналов в исходное состояние).
Итого для 8-ми битной глубины у вас будет не 256 прерываний за период длительностью меньше 300 тактов на обработку каждого,
а всего 14+1 с ресурсом 256 * 300 / 15 = 5120 тактов на каждое. Если время срабатывания расчитывать на цикл вперед, то обработчики прерывания будут очень короткими.

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

Код
Timer_CompA_ISR()
{
    turn_off( CurrentChan++ );

    if (CurrentChan > MAX_CHAN_COUNT)
    {
        CurrentChan = 0;
        return;
    }

    OCRA = ChanGetLifeTime( CurrentChan );
}


Timer_OvrISR()
{
    // врубить все
    turn_on( AllChannels );

    // посчитать такт отключения каждого из каналов (время "жизни")
    UpdateLifeTime( ... );

    // отсортировать каналы по времени жизни по-возрастанию
    SortChannelsByTimeAscending( ... );
}


А можно и в основном цикле программы. Обработка частных случаев (кода время жизни нескольких каналов будет совадать) тоже большого труда не составит:

Код
Timer_CompA_ISR()
{
    turn_off( CurrentChan++ );

    if (CurrentChan > MAX_CHAN_COUNT)
    {
        CurrentChan = 0;
        return;
    }

    if (OCRA == ChanGetLifeTime( CurrentChannel ) )
        Timer_CompA_ISR();  // запустить сл. канал прямо сейчас (лучше всего rjmp'ом)
    else
        OCRA = ChanGetLifeTime( CurrentChan );  // проапдейтить таймер на прерывание в нужное время
}
Go to the top of the page
 
+Quote Post
skyled
сообщение Jan 24 2011, 14:55
Сообщение #19


Местный
***

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



Навскидку разумное зерно есть. Надо бдумать. А не получится ли, что за счет сортировки будет "шило на мыло"?
Go to the top of the page
 
+Quote Post
pokos
сообщение Jan 24 2011, 15:05
Сообщение #20


Местный
***

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



У меня на 3 канала было вот так сделано:
Код
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitialize Timer 0 value
TCNT0=256-39+4;
//PWM-----------------------
pwr_cnt++;
if (red_a>pwr_cnt)
    { PORTD.7=1;}
else
    {PORTD.7=0;};
    
if (green_a>pwr_cnt)
    {PORTD.6=1;}
else
    {PORTD.6=0;};
    
if (blue_a>pwr_cnt)
    {PORTD.5=1;}
else
    {PORTD.5=0;};
}

Оттранслировалось в:
_timer0_ovf_isr:
    RCALL __SAVEISR
;      49 // Reinitialize Timer 0 value
;      50 TCNT0=256-39+4;
    LDI  R30,LOW(221)
    OUT  0x32,R30
;      51 //PWM-----------------------
;      52 pwr_cnt++;
    LDS  R30,_pwr_cnt
    SUBI R30,-LOW(1)
    STS  _pwr_cnt,R30
;      53 if (red_a>pwr_cnt) {PORTD.7=1;}
    LDS  R26,_red_a
    CP   R30,R26
    BRSH _0x2B
    SBI  0x12,7
;      54 else {PORTD.7=0;};
    RJMP _0x2C
_0x2B:
    CBI  0x12,7
_0x2C:
;      55 if (green_a>pwr_cnt) {PORTD.6=1;}
    LDS  R30,_pwr_cnt
    LDS  R26,_green_a
    CP   R30,R26
    BRSH _0x2D
    SBI  0x12,6
;      56 else {PORTD.6=0;};
    RJMP _0x2E
_0x2D:
    CBI  0x12,6
_0x2E:
;      57 if (blue_a>pwr_cnt) {PORTD.5=1;}
    LDS  R30,_pwr_cnt
    LDS  R26,_blue_a
    CP   R30,R26
    BRSH _0x2F
    SBI  0x12,5
;      58 else {PORTD.5=0;};
    RJMP _0x30
_0x2F:
    CBI  0x12,5
_0x30:
;      59 }
    RCALL __LOADISR
    RETI


Сообщение отредактировал pokos - Jan 24 2011, 15:21
Go to the top of the page
 
+Quote Post
defunct
сообщение Jan 24 2011, 16:22
Сообщение #21


кекс
******

Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326



Цитата(skyled @ Jan 24 2011, 16:55) *
А не получится ли, что за счет сортировки будет "шило на мыло"?

Должен быть выигрышь однозначно - если это будет сортировка массива из 14-ти указателей на цикл вперед.
И сортировать лучше не в прерывании, а в основном цикле программы.
Go to the top of the page
 
+Quote Post
pokos
сообщение Jan 24 2011, 17:37
Сообщение #22


Местный
***

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



Цитата(defunct @ Jan 24 2011, 19:22) *
Должен быть выигрышь однозначно...

Выигрыш будет, если забить на разницу между каналами меньше времени обработки прерывания. Если не забивать, то там ещё тот гемор получается. С соответствующей потерей бытродействия, понятно.
Поэтому, я просто уменьшил разрядность ШИМа до 6-ти, когда понадобилось моргать быстрее. На глаз это уменьшение было слабо заметно (в моём случае, понятно).
Go to the top of the page
 
+Quote Post
skyled
сообщение Jan 25 2011, 10:11
Сообщение #23


Местный
***

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



Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.
Код
for(unsigned char i=0;i<14;i++)
        {
            if((a & (1<<i))&(b & (1<<i))) {pwm_ch[i]=255;}//1и1
            if((a & (1<<i))&(!(b & (1<<i)))) {pwm_ch[i]=255;}//1и0
            if((!(a & (1<<i)))&(b & (1<<i))) {pwm_ch[i]=0;}//0и1
            if((!(a & (1<<i)))&(!(b & (1<<i)))) {pwm_ch[i]=0;}//0и0
        }

Даже если уменьшить разрядность ШИМ втрое... уже и не знаю как и быть.
Go to the top of the page
 
+Quote Post
kolobok0
сообщение Jan 25 2011, 10:15
Сообщение #24


практикующий тех. волшебник
*****

Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417



Цитата(pokos @ Jan 24 2011, 18:05) *
Код
...Оттранслировалось в:
_timer0_ovf_isr:
    RCALL __SAVEISR
....
    RCALL __LOADISR
    RETI


А теперь в азм листинге проставте тайминги. Только колл-рэт у вас 8 тактов. итого 16 ненужных тактов в плюсе. я не говорю у же о повторе одного и того же действия подряд аж 3 раза sm.gif юзается один порт. результат = обнуление определённых пинов. и если необходимая переменная больше ... то выставляем в единичку. Вам подсказать как три пина одновременно можно обнулить? sm.gif кстати можно не засовывать сразу в порт результат. ну надеюсь "куда копать" показал. думаю можно уложиться в 20-30 тактов. если в ущерб регистров - то и того меньше. короче говоря оптимизировать вагон и маленькую тележку можно ышо.

хотите оптимально - пишите на азм-е.
оптимизатор может "оптимизнуть" готовые функции из библиотеки - на 5+, а вот логику - тут уж сильно зависит от опыта того кто писал оптимизатор и за сколько вы его купили.

чиссо ИМХО:
собственно если пишите в одни руки, доводите проекты до коммерческого ума - то юзать выше чем азм не совсем в струю.

удачи вам
(круглый)
Go to the top of the page
 
+Quote Post
_Bill
сообщение Jan 25 2011, 10:46
Сообщение #25


Местный
***

Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219



Цитата(pokos @ Jan 24 2011, 19:05) *
У меня на 3 канала было вот так сделано:
Код
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitialize Timer 0 value
TCNT0=256-39+4;
//PWM-----------------------
pwr_cnt++;
if (red_a>pwr_cnt)
    { PORTD.7=1;}
else
    {PORTD.7=0;};
    
if (green_a>pwr_cnt)
    {PORTD.6=1;}
else
    {PORTD.6=0;};
    
if (blue_a>pwr_cnt)
    {PORTD.5=1;}
else
    {PORTD.5=0;};
}

Попробуйте так
Код
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
char _tmp;
// Reinitialize Timer 0 value
TCNT0=256-39+4;
//PWM-----------------------
_tmp = ++pwr_cnt;
if (red_a > _tmp)
    { PORTD.7=1;}
else
    {PORTD.7=0;};
    
if (green_a > _tmp)
    {PORTD.6=1;}
else
    {PORTD.6=0;};
    
if (blue_a > _tmp)
    {PORTD.5=1;}
else
    {PORTD.5=0;};
}
Go to the top of the page
 
+Quote Post
pokos
сообщение Jan 25 2011, 11:39
Сообщение #26


Местный
***

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



Цитата(kolobok0 @ Jan 25 2011, 13:15) *
А теперь в азм листинге проставте тайминги.

Проставлял, было дело. Преехал на IAR по этому поводу.
Цитата
...Вам подсказать как три пина одновременно можно обнулить?

Спасибо, я в курсе. А как одновременно обнулить 14 пинов, не подскажете? Которые в разных портах. И чтобы при этом максимальный коэф. заполнения был ровно 1? Займитесь на досуге этими вопросами, увидите, что моё решение не самое плохое.
Цитата
хотите оптимально - пишите на азм-е.

Не хочу писать на Асме, надоело. Оптимально - это когда задача выполнена за требуемое время. Потому и не хочу.

Цитата(_Bill @ Jan 25 2011, 13:46) *
Попробуйте так
..._tmp = ++pwr_cnt;...

Да, конечно. В конечном варианте pwr_cnt и так в регистре сидит. Тогда присваивание - лишнее, только тормозит.

Цитата(skyled @ Jan 25 2011, 13:11) *
Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.

Само собой. Индексация в массиве - это конь прожорливый. Цикл развернуть в линиию, указатель на массив сделать отдельным. Инкрементировать его. Помнится, IAR такие вещи правильно оптимизировал. Попробуйте.
И я не очень понимаю, зачем этот странный наворот со сдвигами. В чём его цель?


Сообщение отредактировал pokos - Jan 25 2011, 11:34
Go to the top of the page
 
+Quote Post
xemul
сообщение Jan 25 2011, 11:52
Сообщение #27



*****

Группа: Свой
Сообщений: 1 928
Регистрация: 11-07-06
Пользователь №: 18 731



Цитата(skyled @ Jan 25 2011, 13:11) *
Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.
Код
for(unsigned char i=0;i<14;i++)
        {
            if((a & (1<<i))&(b & (1<<i))) {pwm_ch[i]=255;}//1и1
            if((a & (1<<i))&(!(b & (1<<i)))) {pwm_ch[i]=255;}//1и0
            if((!(a & (1<<i)))&(b & (1<<i))) {pwm_ch[i]=0;}//0и1
            if((!(a & (1<<i)))&(!(b & (1<<i)))) {pwm_ch[i]=0;}//0и0
        }

Даже если уменьшить разрядность ШИМ втрое... уже и не знаю как и быть.

имхо, у Вас попутаны ! и ~.
Эта жуть приводится к
Код
for(unsigned char i=0, unsigned int tmp = 1; i<14; i++)
{
   if(a & tmp) pwm_ch[i]=255; //1и1, 1и0
   else pwm_ch[i]=0; //0и1, 0и0
   tmp <<= 1;
}

Можете ещё пооптимизировать в сторону unsigned char tmp = 1; и (high) a, (low) a (или как оно там в винавре)
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 25 2011, 12:16
Сообщение #28


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (skyled @ Jan 25 2011, 12:11) *
Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.
Мама!
1) Вы на каждой итерации делаете сдвиг единицы на i разрядов. Для процессора без аппаратного сдвигателя это очень накладная операция.
2) Вы используете двоичное "И" (&) вместо логического (&&).
3) заметьте, что у вас результат не зависит от значения b
CODE
uint8_t *ptr = &pwm_ch[13];
for(uint16_t mask = (1<<13); mask; mask >>= 1)
{
    if(a & mask)
        *ptr-- = 255;
    else
        *ptr-- = 0;
}


P.S. Ой, xemul уже то же самое написал. Возможно, у него код даже лучше.
P.P.S. ! и ~ у него не попутаны.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
pokos
сообщение Jan 25 2011, 20:30
Сообщение #29


Местный
***

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



Чото не могу найти в закромах финальные исходники того случая. А было там 12 каналов ШИМ по 6 разрядов. Успевало ещё два фильтра второго порядка плюс херитель постоянной составляющей и АРУ. Но на Цоде Визион это не успевало. Только на ИАР.
У ШИМа был принцип, что я изложил в сообщении 26. Сортировку и уменьшение колва прерываний пробовал. При минимальных зазорах мерцает неприятно.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Jan 25 2011, 21:07
Сообщение #30


;
******

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



Цитата(kolobok0 @ Jan 25 2011, 13:15) *
хотите оптимально - пишите на азм-е.
оптимизатор может "оптимизнуть" готовые функции из библиотеки - на 5+, а вот логику - тут уж сильно зависит от опыта того кто писал оптимизатор и за сколько вы его купили.


Поздно! Вот годика 4 назад, когда еще было много проблем с сями, тогда бы это звучало серьезно. Сейчас - увы.

Цитата(Сергей Борщ @ Jan 25 2011, 15:16) *
Мама!

crying.gif

Цитата(skyled @ Jan 25 2011, 13:11) *
Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.

Ара щто ти здэляль со мной? Йа плакаль, перед женщин стидно..
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 Текстовая версия Сейчас: 19th July 2025 - 23:58
Рейтинг@Mail.ru


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