Newsgroup: it.hobby.elettronica.digitale
Titolo: uC & moltiplicatore HW

salve
premessa: uC=PIC Fclk=10MHz linguaggio=MikroC
in un uC (PIC16Fxxxx) dovendo eseguire delle moltiplicazioni
di una variabile ,tipo long, per un altra ,sempre di tipo long,
il uC richiede un notevole tempo di esecuzione per fare ciò.
E questo non mi sta bene, dovrei ridurre il tempo di calcolo!
Passando alla famiglia superiore (PIC18Fxxxx) che possiede
al suo interno un moltiplicatore HW 8x8, è possibile eseguire
la suddetta moltiplicazione (long x long)?
e di quale ordine è il miglioramento, che si ottiene,come tempi
di esecuzione?
grazie,emi

 di esecuzione?
Se passi ad un PIC18 con pll interno, mantenendo lo stesso quarzo da 10MHz 
puoi lavorare a 40MHz.
Quindi il medesimo codice sarebbe eseguito 4 volte + rapidamente.
Se il tuo compilatore ï¿œ in grado di generare il codice per sfruttare la 
moltiplicazione hw, questa sarï¿œ eseguita in un singolo ciclo.
Nella tua domanda scrivi perï¿œ "(long x long)".
Non so come hai definito le direttive di compilazione, ma di solito per i 
micro 'piccoli' (quali i pic16 e i pic18), long significa un intero a 16bit.
Il moltiplicatore hw ï¿œ quindi 'parzialmente' utilizzato e le operazioni 
MULLW  e MULWF in un singolo ciclo non sono possibili.
Con il CCS una motliplicazione ui32= ui16 * ui16 ï¿œ eseguita in 40 
istruzioni, mentre una ui16 = ui8 * ui8 ï¿œ eseguita in 23 istruzioni.
Ritengo sempre valido il consiglio di valutare gli operatori a priori: una 
moltiplicazione o una divisione per un numero multiplo di 2 puï¿œ essere 
notevolemnte 'ridotta' in termini di tempo e di complessitï¿œ, sfruttando le 
istruzioni di bit shifting sx o a dx. 

 di esecuzione?
Nella mia esperienza, sono veramente rare le volte in cui le perfomance 
richieste sono tali da richiedere soluzioni di questo tipo.
Di solito ï¿œ sufficiente valutare meglio il problema per accorgersi che 
magari ci sono soluzioni meno dispendiose.
Potresti dettagliare un po' di piï¿œ, magari fornendo anche il pezzo di 
codice incriminato?
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org/

 sfruttando le istruzioni di bit shifting sx o a dx.
....devo fare il quadrato del valore che mi legge l'ADC; quindi
niente rotazioni!
emi

 
praticamente devo fare la conversione AC->DC rms, che deve essere
indipendente dalla forma d'onda d'ingresso.
quindi devo fare la radice quadrata della sommatoria dei quadrati di
1000 campioni letti dall'ADC. Quindi se voglio salire di freq. del
segnale di IN, devo fare questo calcolo il + veloce possibile.
la parte di codice interessata al post ï¿œ:
DATA=0;
         for (i=0 ;i<N_CAMPIONI; ++i){ 		//acqui. n adc
              ADCON0.GO=1;                    	//start ADC
              while (ADCON0.GO);              	//end conversion?
              VALORE=(ADRESL | (ADRESH << 8));      			
         DATA +=(long)VALORE*(long)VALORE; 	//esegui il quadrato
        		}
         DATA=sqrt(DATA/N_CAMPIONI);      	//estrai RMS
nb:ho omesso tutte le definizioni e funzioni.
emi

 potrei guadagnare?
Non conosco il tuo ambiente di sviluppo, ma in genere è possibile impostare 
il sistema di debug in emulazione.
Una volta che stai emulando il tuo sw (compilato x il micro che desideri 
utilizzare ed impostata la frequenza di lavoro effettiva), imposti un paio 
di breakpoint e tramite lo stopwatch vai a vedere quanti us impiega la parte 
di codice 'incriminata'.
 

         DATA=sqrt(DATA/N_CAMPIONI);          //estrai RMS
Mi vengono in mente diverse cose:
- Che risoluzione necessiti? Sei sicuro che i dati dell'ADC siano a 16 
bit? Forse ne puoi usare meno velocizzando l'operazione.
- Di che frequenze stiamo parlando? Sei sicuro che la moltiplicazione 
sia lenta? A 10MHz un PIC esegue un ciclo di clock in circa 500nS, se 
tutta la moltiplicazione durasse 500 cicli (ma credo duri meno) 
potresti andare a 4kS/s.
In ogni caso potresti fare in diversi modi:
1- Fare la moltiplicazione *prima* di attendere la fine della 
conversione, in questo modo usi il tempo che perdi aspettando l'ADC.
2- Salvare tutti gli N_CAMPIONI in RAM  e ritardare l'elaborazione a 
dopo che li hai acquisiti tutti.


 dopo che li hai acquisiti tutti.
Mi è partito il messaggio prima di scrivere il 3:
3- Scrivere la moltiplicazione ottimizzata per il tuo caso, in assembly


 dopo che li hai acquisiti tutti.
ma il tempo totale non cambia, anzi mi ci vuole in + quello per salvare
i dati in ram, e ricaricarli.
per quanto riguarda l'assemby del PIC, lo conosco pochissimo.
hai mai usato un uC con moltiplicatore HW?
emi

 hai mai usato un uC con moltiplicatore HW?
Sì, ma non sui PIC. Ho anche scritto routine ottimizzate di 
moltiplicazione in assembly. In genere però quando l'istruzione è 
disponibile, il compilatore la usa da solo in autonomia.


 
quindi non sai il miglioramento che ci puo essere tra l'avero a
livello HW e no.
emi

 livello HW e no.
Come ti ho già accennato nell'altro post, la moltiplicazione 8x8 con 
l'istruzione interna al micro, è eseguita in un singolo ciclo di clock.
Il compilatore utilizza questa istruzione anche per eseguire parte della 
moltiplicazione 16x16, quindi il tutto è eseguito il pochissime istruzioni.
Ho fatto una simulazione in mplab e ccs, con un pic18 e pll4x abilitato 
(quindi clock interno 40MHz/4=10MHz effettivi), la moltiplicazione 
ui32=ui16*ui16 è eseguita in 5,2us, comprese le istruzioni di assegnamento 
delle variabili.
A mio parere il tuo codice potrebbe essere migliorato impostando abilitando 
l'interrupt sull'adc ed facendo in modo che l'acquisizione avvenga ad 
intervalli di campionamento fissi e rimepiendo un buffer.
Nel tempo che intercorre fra le letture esegui i calcoli.
Ovvio che però, che per fare questo, ti serve un micro con sufficiente ram 
per tenere tutto il buffer... 

 al secondo (questo non l'avevo specificato ,perchè mi sembrava implicito)
Immagino tu abbia fatto già il conto però per sicurezza te lo chiedo, 
con i dati che hai fornito viene aggiornato circa 4 volte al secondo, 
non è sufficiente?
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org/

 grazie,emi
mi intrometto anche io, giusto per fornre uno spunto oltre ai post già
pervenuti.
se X è espresso a 10 bit , poi sempre pensarlo composto da una
variabile a 8 bit + una a 10 bit che ha pari a zero gli 8 LSB.
X = X8 + X10
Esempio:
X= 0000 0010 0101 0110
X8 =              0101 0110
X10 =        10 000 000
Supponiamo di dover moltiplicare X per Y
X x Y = (X8+X10) x (Y8 + Y10)
         = (X8 x Y8) + (X8 x Y10) + (X10 x Y8) + (X10 x Y10)
Il primo termine rappresenta una molt. 8x8 e quindi richiede un solo
ciclo se hai un molt. hw
Bene, i bit significativi di X10 e Y10 sono solo 2. Quindi il secondo
e terzo termine sono ottimizzabili ad una molt. 8x2. Il quarto è un
2x2.
In ogni caso, con una minima formattazione dei campi, potresti
ricondurti a 4 moltiplicazioni 8x8 hw e poi una somma.
Direi che, anche senza scrivere in assembler, per stimare il guadagno
di prestazioni con un PIC18 potresti partire da qui.
saluti,
simone.bern

         = (X8 x Y8) + (X8 x Y10) + (X10 x Y8) + (X10 x Y10)
Sei sicuro che possa essere corretto ?
Mi sa che se rappresenti  X10 e Y10 con soli 2 bit, devi poi riportarli in 
scala moltiplicando opportunamente x 256.
Una cosa tipo:
X x Y = (X8+X10) x (Y8 + Y10)
          = (X8 x Y8) + (X8 x Y10 x 256) + (X10 x Y8 x 256) + (X10 x Y10 x 
256 x 256)

 scala moltiplicando opportunamente x 256.
si, certo, era quello che intendevo dire con "con una minima
formattazione dei campi". Come suggerivi tu, si tratta di semplici
shift.
saluti,
simone.bern

 
con clk a 10MHz ,il calcolo dell'rms, per 1000 campioni impiega circa
300msec ,per i 50Hz sono buoni (c'è molto spazio per lavorare con
altro codice per fare le altre cose che ci devo mettere dentro),ma
se volessi portare i campioni a 2000 o +, mi troverei un po alle
strette.
grazie a tutti per i suggerimenti, emi