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

Помогите оптимизировать

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

 

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++];

}

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


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

Можно попробовать так (компилятора нет под рукой для 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;
}

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


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

Я идею подам, остальные результативно поругают :rolleyes:

Из трех массивов сделать один, расположив данные из них как [pwma0][pwmb0][pwmc0]...[pwmaN][pwmbN][pwmcN], и:

PORTA = thatArray[pwmstep];
PORTB = thatArray[pwmstep + 1];
PORTC = thatArray[pwmstep + 2];
pwmstep += 3;

 

Но ручками переписать на asm'е было бы самое то (он для того и нужен - оптимизировать).

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


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

Тогда уж так:

PORTA = thatArray[pwmstep++];

PORTB = thatArray[pwmstep ++];

PORTC = thatArray[pwmstep ++];

 

Скорее всего именно так будет самое короткое.

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


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

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

 

Если считаются по ходу времени, то лучше иметь 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;

}

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


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

Можно попробовать так (компилятора нет под рукой для 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] использовать для заполнения массива. По ним тоже можно шагать указателем.

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


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

PORTA = *pIndex++;

На сколько я помню свои эксперименты, результат компиляции будет совершенно одинаков с PORTA=pwm[pwmstep++];

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


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

На сколько я помню свои эксперименты, результат компиляции будет совершенно одинаков с PORTA=pwm[pwmstep++];
Не должен. *pIndex++ указателю один раз за 256 итераций присваивается значение адреса, и дальше вычислять смещение уже не нужно. Собственно проверить-то просто:

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).

Первый вариант:

  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

Второй вариант:

 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

Третий вариант:

 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.

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


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

Не должен.

Таки да, сэкономил полсотни байт. Видимо, куда-то не туда я смотрел. Там было копирование из флеша в массив 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 могло бы быть так же.

Изменено пользователем Огурцов

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


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

Из трех массивов сделать один, расположив данные из них как [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-мя цмклами.

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


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

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

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

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

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

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

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

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

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

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