Перейти к содержанию
    

Нужно оптимизировать код

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

 

хотя опять же нужно смотреть как такое оптимизирует оптимизатор

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А при -Оs сколько?

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

 

В циклах кстати для ...

Это, как и предпочтения do{}while вместо for() - суетная часть. Где-то работает, где-то компилер умнее. Я вот, недавно бодаясь с МСС18, прогнулся так, что было стыдно. Потом перестал это делать - результат оказался хуже на 2-3 процента. Оно не надо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Концептуально можно ускорить код - если вместо проверки каждого канала в каждом "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 );  // проапдейтить таймер на прерывание в нужное время
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Навскидку разумное зерно есть. Надо бдумать. А не получится ли, что за счет сортировки будет "шило на мыло"?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня на 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Должен быть выигрышь однозначно - если это будет сортировка массива из 14-ти указателей на цикл вперед.

И сортировать лучше не в прерывании, а в основном цикле программы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Должен быть выигрышь однозначно...

Выигрыш будет, если забить на разницу между каналами меньше времени обработки прерывания. Если не забивать, то там ещё тот гемор получается. С соответствующей потерей бытродействия, понятно.

Поэтому, я просто уменьшил разрядность ШИМа до 6-ти, когда понадобилось моргать быстрее. На глаз это уменьшение было слабо заметно (в моём случае, понятно).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.

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
        }

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...Оттранслировалось в:
_timer0_ovf_isr:
    RCALL __SAVEISR
....
    RCALL __LOADISR
    RETI

 

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

 

хотите оптимально - пишите на азм-е.

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

 

чиссо ИМХО:

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

 

удачи вам

(круглый)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня на 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;};
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А теперь в азм листинге проставте тайминги.

Проставлял, было дело. Преехал на IAR по этому поводу.

...Вам подсказать как три пина одновременно можно обнулить?

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

хотите оптимально - пишите на азм-е.

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

 

Попробуйте так

..._tmp = ++pwr_cnt;...

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

 

Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.

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

И я не очень понимаю, зачем этот странный наворот со сдвигами. В чём его цель?

 

Изменено пользователем pokos

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.

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 (или как оно там в винавре)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.
Мама!

1) Вы на каждой итерации делаете сдвиг единицы на i разрядов. Для процессора без аппаратного сдвигателя это очень накладная операция.

2) Вы используете двоичное "И" (&) вместо логического (&&).

3) заметьте, что у вас результат не зависит от значения b

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. ! и ~ у него не попутаны.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чото не могу найти в закромах финальные исходники того случая. А было там 12 каналов ШИМ по 6 разрядов. Успевало ещё два фильтра второго порядка плюс херитель постоянной составляющей и АРУ. Но на Цоде Визион это не успевало. Только на ИАР.

У ШИМа был принцип, что я изложил в сообщении 26. Сортировку и уменьшение колва прерываний пробовал. При минимальных зазорах мерцает неприятно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

хотите оптимально - пишите на азм-е.

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

 

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

 

Мама!

:crying:

 

Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов.

Ара щто ти здэляль со мной? Йа плакаль, перед женщин стидно..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...