Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Помогите оптимизировать
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
ScrambledStamp
Помогите оптимизировать код, надо его сделать побыстрее, очень не хочется уменьшать разрядность. .

unsigned char pwma[256], pwmb[256], pwmc[256];
unsigned char pwmstep;

// PWM main interrupt
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
// Place your code here
PORTA=pwma[pwmstep];
PORTB=pwmb[pwmstep];
PORTC=pwmc[pwmstep];
pwmstep++;
}

Компилятор (кодевижн) выдает такой листинг:

Код
;     189 // PWM main interrupt
;     190 interrupt [TIM2_COMP] void timer2_comp_isr(void)
;     191 {
_timer2_comp_isr:
    ST   -Y,R30
    ST   -Y,R31
    IN   R30,SREG
    ST   -Y,R30
;     192 // Place your code here
;     193 PORTA=pwma[pwmstep];
    MOV  R30,R9
    LDI  R31,0
    SUBI R30,LOW(-_pwma)
    SBCI R31,HIGH(-_pwma)
    LD   R30,Z
    OUT  0x1B,R30
;     194 PORTB=pwmb[pwmstep];
    MOV  R30,R9
    LDI  R31,0
    SUBI R30,LOW(-_pwmb)
    SBCI R31,HIGH(-_pwmb)
    LD   R30,Z
    OUT  0x18,R30
;     195 PORTC=pwmc[pwmstep];
    MOV  R30,R9
    LDI  R31,0
    SUBI R30,LOW(-_pwmc)
    SBCI R31,HIGH(-_pwmc)
    LD   R30,Z
    OUT  0x15,R30
;     196 pwmstep++;
    INC  R9
;     197 }
_0xF0:
    LD   R30,Y+
    OUT  SREG,R30
    LD   R31,Y+
    LD   R30,Y+
    RETI
;     198
Огурцов
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
PORTA=pwm[pwmstep++];
PORTB=pwm[pwmstep++];
PORTC=pwm[pwmstep++];
}
WHALE
Может,все-таки
{
PORTA=pwm[pwmstep];
PORTB=pwm[pwmstep];
PORTC=pwm[pwmstep++];
}
sergeeff
Можно попробовать так (компилятора нет под рукой для AVR):

Код
typedef struct
{
  unsigned char a;
  unsigned char b;
  unsigned char c;
} PWM;

PWM pwm[256];
unsigned  char pwmstep = 0;
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
  // Place your code here
  PWM *tmp = &pwm[pwmstep++];
  PORTA=tmp->a;
  PORTB=tmp->b;
  PORTC=tmp->c;
}
SysRq
Я идею подам, остальные результативно поругают rolleyes.gif
Из трех массивов сделать один, расположив данные из них как [pwma0][pwmb0][pwmc0]...[pwmaN][pwmbN][pwmcN], и:
Код
PORTA = thatArray[pwmstep];
PORTB = thatArray[pwmstep + 1];
PORTC = thatArray[pwmstep + 2];
pwmstep += 3;


Но ручками переписать на asm'е было бы самое то (он для того и нужен - оптимизировать).
DpInRock
Тогда уж так:
Цитата
PORTA = thatArray[pwmstep++];
PORTB = thatArray[pwmstep ++];
PORTC = thatArray[pwmstep ++];


Скорее всего именно так будет самое короткое.
Tiro
Мне кажется, постановка задачи немного неполна: насчитаны ли массивы заранее? Или они считаются между прерываниями?

Если считаются по ходу времени, то лучше иметь 3 глобальные переменные.

Теперь по существу. K&R говорят, что быстрее всего изменяется последний индекс массива. То есть массив pwm[256][3] даст самый быстрый доступ к элементам. Об этом уже сказали неявно предыдущие ораторы. Из практических советов - следует избегать адресной арифметики в прерывании в зависимости от мощности оптимизатора. Возможно, потребуется ручками указать последовательность действий. Можно написать так (не проверял, только для иллюстрации идеи):

unsigned char pwm [256] [3];
volatile unsigned char pwmstep;

// PWM main interrupt
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
// Place your code here
register unsigned char step = pwmstep;
register unsigned char * sample = pwm [step];
PORTA=sample[0]; // *(sample ++)
PORTB=sample[1]; // *(sample ++)
PORTC=sample[2]; // *(sample ++)
step++;
pwmstep = step;
}
Сергей Борщ
Цитата(sergeeff @ Oct 8 2008, 21:14) *
Можно попробовать так (компилятора нет под рукой для AVR):
Навскидку: размер получившегося массива 3 байта, компилятор будет вызывать умножение на 3. Можно попробовать вот так:
Код
typedef struct
{
    uint8_t a;
    uint8_t b;
    uint8_t c;
} pwm_point_t

union
{
    pwm_point_t point[256];
    uint8_t raw[];
} PWM;
uint8_t *pIndex = PWM.raw;

// PWM main interrupt
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
    // Place your code here
    PORTA = *pIndex++;
    PORTB = *pIndex++;
    PORTC = *pIndex++;
    if(pIndex == (uint8_t *)(&PWM + 1))
    {
        pIndex = PWM.raw;
    }
}
PWM.point[x] использовать для заполнения массива. По ним тоже можно шагать указателем.
Огурцов
Цитата(Сергей Борщ @ Oct 9 2008, 00:09) *
PORTA = *pIndex++;

На сколько я помню свои эксперименты, результат компиляции будет совершенно одинаков с PORTA=pwm[pwmstep++];
Сергей Борщ
Цитата(Огурцов @ Oct 9 2008, 09:49) *
На сколько я помню свои эксперименты, результат компиляции будет совершенно одинаков с PORTA=pwm[pwmstep++];
Не должен. *pIndex++ указателю один раз за 256 итераций присваивается значение адреса, и дальше вычислять смещение уже не нужно. Собственно проверить-то просто:
CODE
typedef struct
{
uint8_t a;
uint8_t b;
uint8_t c;
} pwm_point_t;

union
{
pwm_point_t point[256];
uint8_t raw[];
} PWM;
uint8_t *pIndex = PWM.raw;
uint16_t Index;
// PWM main interrupt
ISR(TIMER1_OVF_vect)
{
// Place your code here
uint8_t *pTmp = pIndex;
PORTD = *pTmp++;
PORTB = *pTmp++;
PORTC = *pTmp++;
if(++pTmp == (uint8_t *)(&PWM + 1))
{
pTmp = PWM.raw;
}
pIndex = pTmp;
}
ISR(TIMER0_OVF_vect)
{
// Place your code here
uint16_t Tmp = Index;
PORTD = PWM.raw[Tmp++];
PORTB = PWM.raw[Tmp++];
PORTC = PWM.raw[Tmp++];
if(++Tmp == sizeof(PWM.raw))
Tmp = 0;
Index = Tmp;
}

и листинг (WinAVR).
Первый вариант:
CODE
54 .section .text.__vector_9,"ax",@progbits
55 .global __vector_9
57 __vector_9:
58 .LFB25:
59 .LSM0:
60 /* prologue: frame size=0 */
61 0000 1F92 push __zero_reg__
62 0002 0F92 push __tmp_reg__
63 0004 0FB6 in __tmp_reg__,__SREG__
64 0006 0F92 push __tmp_reg__
65 0008 1124 clr __zero_reg__
GAS LISTING D:/Temp/ccreYbyY.s page 2


66 000a 8F93 push r24
67 000c AF93 push r26
68 000e BF93 push r27
69 0010 CF93 push r28
70 0012 DF93 push r29
71 0014 EF93 push r30
72 0016 FF93 push r31
73 /* prologue end (size=12) */
74 .LBB19:
75 .LSM1:
76 0018 A091 0000 lds r26,pIndex ; pTmp.68, pIndex
77 001c B091 0000 lds r27,(pIndex)+1 ; pTmp.68, pIndex
78 .LVL0:
79 .LSM2:
80 0020 FD01 movw r30,r26 ; pTmp.69, pTmp.68
81 .LVL1:
82 0022 8191 ld r24,Z+ ; D.2508,
83 0024 82BB out 50-0x20,r24 ; , D.2508
84 .LSM3:
85 0026 ED01 movw r28,r26 ; , pTmp.68
86 0028 8981 ldd r24,Y+1 ; temp.66,
87 002a 88BB out 56-0x20,r24 ; , temp.66
88 .LSM4:
89 002c 8181 ldd r24,Z+1 ; temp.67,
90 002e 85BB out 53-0x20,r24 ; , temp.67
91 .LSM5:
92 0030 1496 adiw r26,4 ; pTmp,
93 .LVL2:
94 0032 80E0 ldi r24,hi8(PWM+768) ; ,
95 0034 A030 cpi r26,lo8(PWM+768) ; pTmp,
96 0036 B807 cpc r27,r24 ; pTmp,
97 0038 01F4 brne .L2 ; ,
98 .LSM6:
99 003a A0E0 ldi r26,lo8(PWM) ; pTmp,
100 003c B0E0 ldi r27,hi8(PWM) ; pTmp,
101 .L2:
102 .LSM7:
103 003e B093 0000 sts (pIndex)+1,r27 ; pIndex, pTmp
104 0042 A093 0000 sts pIndex,r26 ; pIndex, pTmp
105 .LBE19:
106 /* epilogue: frame size=0 */
107 0046 FF91 pop r31
108 0048 EF91 pop r30
109 004a DF91 pop r29
110 004c CF91 pop r28
111 004e BF91 pop r27
112 0050 AF91 pop r26
113 0052 8F91 pop r24
114 0054 0F90 pop __tmp_reg__
115 0056 0FBE out __SREG__,__tmp_reg__
116 0058 0F90 pop __tmp_reg__
117 005a 1F90 pop __zero_reg__
118 005c 1895 reti
Второй вариант:
CODE
123 .section .text.__vector_8,"ax",@progbits
124 .global __vector_8
126 __vector_8:
127 .LFB26:
128 .LSM8:
129 /* prologue: frame size=0 */
130 0000 1F92 push __zero_reg__
131 0002 0F92 push __tmp_reg__
132 0004 0FB6 in __tmp_reg__,__SREG__
133 0006 0F92 push __tmp_reg__
134 0008 1124 clr __zero_reg__
135 000a 2F93 push r18
136 000c 4F93 push r20
137 000e 5F93 push r21
138 0010 8F93 push r24
139 0012 9F93 push r25
140 0014 AF93 push r26
141 0016 BF93 push r27
142 0018 EF93 push r30
143 001a FF93 push r31
144 /* prologue end (size=14) */
145 .LBB20:
146 .LSM9:
147 001c 4091 0000 lds r20,IndexRaw ; Tmp, IndexRaw
148 0020 5091 0000 lds r21,(IndexRaw)+1 ; Tmp, IndexRaw
149 .LVL3:
150 .LSM10:
151 0024 80E0 ldi r24,lo8(PWM) ; tmp47,
152 0026 90E0 ldi r25,hi8(PWM) ; tmp47,
153 0028 FA01 movw r30,r20 ; tmp48, Tmp
154 002a E80F add r30,r24 ; tmp48, tmp47
155 002c F91F adc r31,r25 ; tmp48, tmp47
156 002e 2081 ld r18,Z ; D.2520, PWM.raw
157 0030 22BB out 50-0x20,r18 ; , D.2520
158 0032 FA01 movw r30,r20 ; Tmp.97, Tmp
159 .LVL4:
160 0034 3196 adiw r30,1 ; Tmp.97,
161 .LSM11:
162 0036 DF01 movw r26,r30 ; tmp51, Tmp.97
163 0038 A80F add r26,r24 ; tmp51, tmp47
164 003a B91F adc r27,r25 ; tmp51, tmp47
165 003c 2C91 ld r18,X ; temp.100, PWM.raw
166 003e 28BB out 56-0x20,r18 ; , temp.100
167 .LSM12:
168 0040 FD01 movw r30,r26 ; Tmp.97, tmp51
169 0042 8181 ldd r24,Z+1 ; temp.101, PWM.raw
170 0044 85BB out 53-0x20,r24 ; , temp.101
171 .LSM13:
172 0046 4C5F subi r20,lo8(-(4)) ; Tmp,
173 0048 5F4F sbci r21,hi8(-(4)) ; Tmp,
174 004a 5093 0000 sts (IndexRaw)+1,r21 ; IndexRaw, Tmp
175 004e 4093 0000 sts IndexRaw,r20 ; IndexRaw, Tmp
176 .LBE20:
177 /* epilogue: frame size=0 */
178 0052 FF91 pop r31
179 0054 EF91 pop r30
180 0056 BF91 pop r27
181 0058 AF91 pop r26
182 005a 9F91 pop r25
183 005c 8F91 pop r24
184 005e 5F91 pop r21
185 0060 4F91 pop r20
186 0062 2F91 pop r18
187 0064 0F90 pop __tmp_reg__
188 0066 0FBE out __SREG__,__tmp_reg__
189 0068 0F90 pop __tmp_reg__
190 006a 1F90 pop __zero_reg__
191 006c 1895 reti
Третий вариант:
CODE
196 .section .text.__vector_4,"ax",@progbits
197 .global __vector_4
199 __vector_4:
200 .LFB27:
201 .LSM14:
202 /* prologue: frame size=0 */
203 0000 1F92 push __zero_reg__
204 0002 0F92 push __tmp_reg__
205 0004 0FB6 in __tmp_reg__,__SREG__
206 0006 0F92 push __tmp_reg__
207 0008 1124 clr __zero_reg__
208 000a 2F93 push r18
209 000c 8F93 push r24
210 000e 9F93 push r25
211 0010 EF93 push r30
212 0012 FF93 push r31
213 /* prologue end (size=10) */
214 .LBB21:
215 .LSM15:
216 0014 2091 0000 lds r18,Index ; Tmp, Index
217 .LVL5:
218 .LSM16:
219 0018 822F mov r24,r18 ; D.2529, Tmp
220 001a 9927 clr r25 ; D.2529
221 001c FC01 movw r30,r24 ; tmp50, D.2529
222 001e EE0F lsl r30 ; tmp50
223 0020 FF1F rol r31 ; tmp50
224 .LVL6:
225 0022 E80F add r30,r24 ; tmp50, D.2529
226 0024 F91F adc r31,r25 ; tmp50, D.2529
227 0026 E050 subi r30,lo8(-(PWM)) ; tmp50,
228 0028 F040 sbci r31,hi8(-(PWM)) ; tmp50,
229 002a 8081 ld r24,Z ; D.2530, <variable>.a
230 002c 82BB out 50-0x20,r24 ; , D.2530
231 .LSM17:
232 002e 8181 ldd r24,Z+1 ; D.2532, <variable>.b
233 0030 88BB out 56-0x20,r24 ; , D.2532
234 .LSM18:
235 0032 8281 ldd r24,Z+2 ; D.2534, <variable>.c
236 0034 85BB out 53-0x20,r24 ; , D.2534
237 .LBE21:
238 /* epilogue: frame size=0 */
239 0036 FF91 pop r31
240 0038 EF91 pop r30
GAS LISTING D:/Temp/ccreYbyY.s page 5


241 003a 9F91 pop r25
242 003c 8F91 pop r24
243 003e 2F91 pop r18
244 0040 0F90 pop __tmp_reg__
245 0042 0FBE out __SREG__,__tmp_reg__
246 0044 0F90 pop __tmp_reg__
247 0046 1F90 pop __zero_reg__
248 0048 1895 reti
Итого, победил sergeeff. Хотя другой компилятор может дать другие результаты. Совершенно непонятно, зачем компилятор в первом случае задействовал Y.
Огурцов
Цитата(Сергей Борщ @ Oct 9 2008, 07:42) *
Не должен.

Таки да, сэкономил полсотни байт. Видимо, куда-то не туда я смотрел. Там было копирование из флеша в массив vs загрузка массива константами. Но копирование по-прежнему побеждает, не смотря на то, что загрузка уменьшилась раза в два после замены индекса на указатель. Видимо, есть еще куда колдовать )
Огурцов
Однако, радует то, что я все же не сглючил.
Вот во что компилится инициализация массива с использованием индекса

Код
@000000D0: Get_serial_number
37:       {
+000000D0:   01FC        MOVW    R30,R24          Copy register pair
39:           aValue[0] = (unsigned char)(Device_serial_number_3 >> 24);
+000000D1:   ED83        LDI     R24,0xD3         Load immediate
+000000D2:   8380        STD     Z+0,R24          Store indirect with displacement
40:           aValue[1] = (unsigned char)(Device_serial_number_3 >> 16);
+000000D3:   E987        LDI     R24,0x97         Load immediate
+000000D4:   8381        STD     Z+1,R24          Store indirect with displacement
41:           aValue[2] = (unsigned char)(Device_serial_number_3 >> 8);
+000000D5:   E585        LDI     R24,0x55         Load immediate
+000000D6:   8382        STD     Z+2,R24          Store indirect with displacement
42:           aValue[3] = (unsigned char)(Device_serial_number_3 >> 0);
+000000D7:   E082        LDI     R24,0x02         Load immediate
+000000D8:   8383        STD     Z+3,R24          Store indirect with displacement
43:           aValue[4] = (unsigned char)(Device_serial_number_2 >> 24);
+000000D9:   E284        LDI     R24,0x24         Load immediate
+000000DA:   8384        STD     Z+4,R24          Store indirect with displacement


А это с использованием указателя

Код
+000000D0:   01FC        MOVW    R30,R24          Copy register pair
56:           *aValue++ = (unsigned char)(Device_serial_number_3 >> 24);
+000000D1:   ED83        LDI     R24,0xD3         Load immediate
+000000D2:   9381        ST      Z+,R24           Store indirect and postincrement
57:           *aValue++ = (unsigned char)(Device_serial_number_3 >> 16);
+000000D3:   E987        LDI     R24,0x97         Load immediate
+000000D4:   9381        ST      Z+,R24           Store indirect and postincrement
58:           *aValue++ = (unsigned char)(Device_serial_number_3 >> 8);
+000000D5:   E585        LDI     R24,0x55         Load immediate
+000000D6:   9381        ST      Z+,R24           Store indirect and postincrement
59:           *aValue++ = (unsigned char)(Device_serial_number_3 >> 0);
+000000D7:   E082        LDI     R24,0x02         Load immediate
+000000D8:   9381        ST      Z+,R24           Store indirect and postincrement
60:           *aValue++ = (unsigned char)(Device_serial_number_2 >> 24);
+000000D9:   E284        LDI     R24,0x24         Load immediate
+000000DA:   8380        STD     Z+0,R24          Store indirect with displacement


Т.е. разница, конечно, есть, но только не в размере и не в скорости выполнения. И такое сохранится до размера массива до 64 байт, т.е. пока будет хватать смещения (6 бит) в команде STD Z+disp, *. Для LDD могло бы быть так же.
Maik-vs
Цитата(SysRq @ Oct 8 2008, 22:30) *
Из трех массивов сделать один, расположив данные из них как [pwma0][pwmb0][pwmc0]...[pwmaN]


Так лучше. Тогда получается
Код
LD     Yh,high(pwmstep)
LD     Yl,low(pwmstep)        ; load pointer

LD     tmp,Y+
OUT   PORTA,tmp
LD     tmp,Y+
OUT   PORTB,tmp
LD     tmp,Y+
OUT   PORTC,tmp

ST     high(pwmstep),Yh
ST     low(pwmstep),Yl        ; save pointer


17 циклов.

Если unsigned char pwm [3][256], то нужно добавить inc Yh после каждого OUT - это дополнительно 3 цикла, плюс вычислить новый pwmstep это пахнет ещё 4-мя цмклами.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.