|
|
  |
Нужно оптимизировать код, Есть идеи как? |
|
|
|
Jan 21 2011, 18:50
|
;
     
Группа: Участник
Сообщений: 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 процента. Оно не надо.
|
|
|
|
|
Jan 23 2011, 22:41
|

кекс
     
Группа: Свой
Сообщений: 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 ); // проапдейтить таймер на прерывание в нужное время }
|
|
|
|
|
Jan 24 2011, 15:05
|
Местный
  
Группа: Участник
Сообщений: 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
|
|
|
|
|
Jan 24 2011, 17:37
|
Местный
  
Группа: Участник
Сообщений: 270
Регистрация: 29-06-06
Пользователь №: 18 445

|
Цитата(defunct @ Jan 24 2011, 19:22)  Должен быть выигрышь однозначно... Выигрыш будет, если забить на разницу между каналами меньше времени обработки прерывания. Если не забивать, то там ещё тот гемор получается. С соответствующей потерей бытродействия, понятно. Поэтому, я просто уменьшил разрядность ШИМа до 6-ти, когда понадобилось моргать быстрее. На глаз это уменьшение было слабо заметно (в моём случае, понятно).
|
|
|
|
|
Jan 25 2011, 10:11
|
Местный
  
Группа: Участник
Сообщений: 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 } Даже если уменьшить разрядность ШИМ втрое... уже и не знаю как и быть.
|
|
|
|
|
Jan 25 2011, 10:15
|
практикующий тех. волшебник
    
Группа: Участник
Сообщений: 1 190
Регистрация: 9-09-05
Пользователь №: 8 417

|
Цитата(pokos @ Jan 24 2011, 18:05)  Код ...Оттранслировалось в: _timer0_ovf_isr: RCALL __SAVEISR .... RCALL __LOADISR RETI А теперь в азм листинге проставте тайминги. Только колл-рэт у вас 8 тактов. итого 16 ненужных тактов в плюсе. я не говорю у же о повторе одного и того же действия подряд аж 3 раза  юзается один порт. результат = обнуление определённых пинов. и если необходимая переменная больше ... то выставляем в единичку. Вам подсказать как три пина одновременно можно обнулить?  кстати можно не засовывать сразу в порт результат. ну надеюсь "куда копать" показал. думаю можно уложиться в 20-30 тактов. если в ущерб регистров - то и того меньше. короче говоря оптимизировать вагон и маленькую тележку можно ышо. хотите оптимально - пишите на азм-е. оптимизатор может "оптимизнуть" готовые функции из библиотеки - на 5+, а вот логику - тут уж сильно зависит от опыта того кто писал оптимизатор и за сколько вы его купили. чиссо ИМХО: собственно если пишите в одни руки, доводите проекты до коммерческого ума - то юзать выше чем азм не совсем в струю. удачи вам (круглый)
|
|
|
|
|
Jan 25 2011, 10:46
|
Местный
  
Группа: Участник
Сообщений: 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;}; }
|
|
|
|
|
Jan 25 2011, 11:39
|
Местный
  
Группа: Участник
Сообщений: 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
|
|
|
|
|
Jan 25 2011, 11:52
|
    
Группа: Свой
Сообщений: 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 (или как оно там в винавре)
|
|
|
|
|
Jan 25 2011, 12:16
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Jan 25 2011, 21:07
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(kolobok0 @ Jan 25 2011, 13:15)  хотите оптимально - пишите на азм-е. оптимизатор может "оптимизнуть" готовые функции из библиотеки - на 5+, а вот логику - тут уж сильно зависит от опыта того кто писал оптимизатор и за сколько вы его купили. Поздно! Вот годика 4 назад, когда еще было много проблем с сями, тогда бы это звучало серьезно. Сейчас - увы. Цитата(Сергей Борщ @ Jan 25 2011, 15:16)  Мама!  Цитата(skyled @ Jan 25 2011, 13:11)  Тут выяснилось, что еще вот эта конструкция кушает невообразимое число тактов. Ара щто ти здэляль со мной? Йа плакаль, перед женщин стидно..
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|