Velocità del loop Mega 2560

Nel 1° caso escludi il setup delle seriali, quindi escludi check sui buffer e interrupt.
Nel 2° caso togli solo i check per verificare se ci sono byte nei buffer, quindi il guadagno prestazionale è minore dato che hai le ISR a rallentare lo sketch.

(se ho capito bene a quali porzioni di codice ti stai riferendo)

leo72:
(se ho capito bene a quali porzioni di codice ti stai riferendo)

http://arduino.cc/forum/index.php/topic,141254.60.html Pag 5 #reply 70

leo72:
Nel 1° caso escludi il setup delle seriali, quindi escludi check sui buffer e interrupt.
Nel 2° caso togli solo i check per verificare se ci sono byte nei buffer, quindi il guadagno prestazionale è minore dato che hai le ISR a rallentare lo sketch.

(se ho capito bene a quali porzioni di codice ti stai riferendo)

Le ISR di ricezione seriale vengono eseguite solo quando arrivano dei byte. Il solo fatto che siano attive non consuma cicli di CPU.

Insomma concludiamo questo treadh

"Hai una Mega? Bene, te la tieni così, se vuoi andare più forte di compri una UNO o un ARM!!" :grin: :grin:

IMHO il 2° caso implica che il rallentamento indotto dalla creazione delle classi è minimo, quello che pesa molto è il check di serialEvent, sarebbe da capire quale istruzione o quale blocco di istruzioni rallenta così tanto e vedere se con il trucco dei buffer a null se non "beginnata" la serial può essere più veloce :smiley:

ho provato a modificare il codice copn la storia del buffer, compila ma non testato (sono a lavoro), qualche buon anima che lo testa? allego il file HardwareSerial.cpp

edit: arduino 1.0.2

HardwareSerial.cpp (14.1 KB)

Mmmmm da una barca di errori :slight_smile:
allego txt

errori.txt (5.74 KB)

usa la arduino IDE 1.0.2

il rallentamento indotto dalla creazione delle classi è minimo

No, è nullo.

Tuxduino, non avevo proprio guardato la main.cpp sei stato geniale :), però mi chiedevo ....
Adesso che le ISR di ricezione seriale vengono eseguite solo quando arrivano dei byte, cosa implica l'aver tolto quella linea? perchè se è stata messa un motivo c'era ... o no?
Tra l'altro hai reso più veloce anche la UNO, non ho provato ma dovrebbe essere così

ciao

tuxduino:

leo72:
Nel 1° caso escludi il setup delle seriali, quindi escludi check sui buffer e interrupt.
Nel 2° caso togli solo i check per verificare se ci sono byte nei buffer, quindi il guadagno prestazionale è minore dato che hai le ISR a rallentare lo sketch.

(se ho capito bene a quali porzioni di codice ti stai riferendo)

Le ISR di ricezione seriale vengono eseguite solo quando arrivano dei byte. Il solo fatto che siano attive non consuma cicli di CPU.

Vero anche questo....

Io non uso più il core Arduino da tanto, ne uso il C++, ma solo C e strutture usate a mò di oggetti. Poi uso una specie di pseudo tipo per raggruppare i registri da passare alle funzioni e altre cose che mi permettono di andare alla massima velocità.

Il codice seguente attiva la seriale 0 e scrive qualcosa:

#include <mio.h>
#include <uart.h>
#include <stdio.h>


FILE uart_str;
// seriale numero 0
// questa define si trova in ogni file header dipendente dalla MCU, header che viene incluso dal file "mio.h"
// vedi anche USART_T
// #define USART0 &UCSR0A, &UCSR0B, &UCSR0C, &UBRR0, TXEN0, RXEN0 

int
main(void) {
    usart_init(USART0, 230400, USART_CK_DOUBLE, &uart_str);
    while (1) {
        fprintf(&uart_str, "test uart");
        fprintf(&uart_str, "%d", UBRR0 );
    }
}

La funzione usart_init:

// USART_T è un pseudo tipo, ma è meglio dire che si tratta di un'accorpamente di dichiarazione di variabili
// che si trova nel file header dipendente dalla MCU.
// nel file atmega48.h c'è questa define:
// #define USART_T volatile uint8_t *ucsra, volatile uint8_t *ucsrb, volatile uint8_t *ucsrc,\
//                volatile uint16_t *ubrr, volatile uint8_t tx_en, volatile uint8_t rx_en
// pertanto i parametri passati a usart_init possono essere in numero deciso dall'header della MCU


void
usart_init(USART_T, uint32_t baud, const uint8_t ck_serial_mode, struct __file *strm);

void
usart_init(USART_T, uint32_t baud, const uint8_t ck_serial_mode, struct __file *strm)
{

    if (ck_serial_mode == USART_CK_DOUBLE) {
        /* Usart clock double */
        *ucsra _bit_set(UCSRA_U2X);
        *ubrr = USART_UBRR_2X(baud);
    } else {
        *ucsra _bit_unset(UCSRA_U2X);
        *ubrr = USART_UBRR_1X(baud);
    }
    *ucsrb = _BV(tx_en) | _BV(rx_en); /* tx/rx enable */


    fdev_setup_stream(strm, uart_putchar, uart_getchar, _FDEV_SETUP_WRITE);
}

Come si vede non scrivo molto, ma c'è un ma, per usare fprint per qualunque dato devo abilitare dei flag di compilazione che in arduino sono disabilitati, questo nel mio caso incrementa la dimensione dell'eseguibile.

Anche se sono poche righe di codice, un principiante non saprebbe scriverle e arduino è vincente per questo. Io non ho trovato modo per coniugare
l'efficenza e semplicità di uso. Ho anche provato altre librerie C++ nelle quali si è fatto qualcosa di efficente, ma per salvare l'efficenza si è compromesso la semplicità di uso. Per questo considero la semplicità e l'efficenza le due facce della medaglia, cioè o l'una o l'altra ma mai entrambe.

Comunque anche la complicata iniziazializzazione che uso ha risvolti negativi, uno tra questi il numero elevato di argomenti di funzione.

L'unico modo che conosco per scrivere codice efficiente e quello di non usare librerie automatizzate e usare direttamente i registri.

Una funzione specifica di usart_init si avvantagerebbe dell'uso dei registri senza che queste debbano essere passati come argomento.

creare più funzioni di libreria con nome usart0_init, usart1_init ecc risolverebbe ma il programmatore non ha davanti sempre le stesse api.
Usare le strutture compilandole con gli indirizzi dei registri occupa memoria ram.

A proposito di ram, il compilatore dovrebbe fare pulizia se non c'è un riferimento ad una istanza, quindi anche l'array visto che non c'è codice che lo usa dovrebbe essere spazzato via e quindi non occupare memoria.

Ragazzi mi manca la volonta è il tempo per studiare asm, chi conosce bene asm può verificare cosa fa il compilatore tutti gli altri devono stare in fiducia.

Ciao.

se cerchi bene in giro puoi usare la printf senza bisogno di modificare nulla, l'ho usato personalmente ma non ho uppato il codice... ma l'avevo trovato facilmente con google.

lesto:
se cerchi bene in giro puoi usare la printf senza bisogno di modificare nulla, l'ho usato personalmente ma non ho uppato il codice... ma l'avevo trovato facilmente con google.

Esatto, la printf & company scrivono già nella prima seriale, cioè su USART0, ma il codice che ho postato vale anche per le altre seriali. Inoltro con lo stesso sistema scrivo sul display con fptrintf 20x4.

In genere qualunque funzionalità mi serva tendo ad usare cio che già offre la avr-libc, sempre che sia possibile.
Più in la dovrei riscrivere il codice per il display 64128 usando sempre lo stesso sistema, in questo modo riutilizzo più volte sempre lo stesso codice fornito dalla avr-libc
diversamente usando molte librerie il codice si gonfia rapidamente. Poi è quello che viene fatto anche nel core di Arduino, dove la print viene usata anche per altre cose, almeno così mi ricordo.

Ciao.

pablos:
Tuxduino, non avevo proprio guardato la main.cpp sei stato geniale :), però mi chiedevo ....

:slight_smile:

pablos:
Adesso che le ISR di ricezione seriale vengono eseguite solo quando arrivano dei byte, cosa implica l'aver tolto quella linea? perchè se è stata messa un motivo c'era ... o no?

Ho risposto qualche commento fa. Ripeto brevemente: serialEventRun fa sostanzialmente questo (pseudocodice per essere più chiari):

if (ci sono byte nel buffer di ricezione della seriale) then
chiama la funzione serialEvent
endif

Nel caso della UNO lo fa per la sola Serial, nel caso della Mega lo fa per Serial, 1, 2, 3. A prescindere dal fatto che all'utente servano o meno.
Commentando quella riga, l'utente non dovrà più implementare la funzione serialEvent() (una per ogni seriale che usa), ma dovrà esplicitamente scrivere:

if Serial.available() {
    fai qualcosa
}

per le seriali che usa.

pablos:
Tra l'altro hai reso più veloce anche la UNO, non ho provato ma dovrebbe essere così

ciao

Appunto, appena hai tempo e voglia fai una prova. :slight_smile:

fa sostanzialmente questo (pseudocodice per essere più chiari):

if (ci sono byte nel buffer di ricezione della seriale) then
chiama la funzione serialEvent
endif

Nel caso della UNO lo fa per la sola Serial, nel caso della Mega lo fa per Serial, 1, 2, 3. A prescindere dal fatto che all'utente servano o meno.
Commentando quella riga, l'utente non dovrà più implementare la funzione serialEvent() (una per ogni seriale che usa), ma dovrà esplicitamente scrivere:

Code:

if Serial.available() {
fai qualcosa
}

Ok, chiaro

Appunto, appena hai tempo e voglia fai una prova. smiley

Non ho provato perchè non ce l'ho io ahahahha (non avevo specificato), tu ce l'hai :grin:

riguardo a un appunto che hai fatto a pag 5 che mi era sfuggito

A proposito dell'influenza della seriale sulle prestazioni, vorrei sottolineare i risultati che ho ottenuto nel mio sketch di prova: tra baud rate di 9600 e 115200 c'è una differenza significativa.
Va ricordato però che nelle ultime versioni di Arduino anche la trasmissione seriale è fatta via interrupt, e diventa bloccante solo nel momento in cui il buffer di trasmissione è pieno, quindi in realtà se si trasmettono "pochi" (1) byte alla volta, l'impatto complessivo dovrebbe essere molto limitato.

ho rifatto i test prima con baud rate 9600 e 115200, non ho rilevato nessuna differenza

ciao

ho rifatto i test prima con baud rate 9600 e 115200, non ho rilevato nessuna differenza

Sì ma con quale codice ? Inviavi caratteri oppure era solo uno sketch vuoto con un argomento diverso passato alla begin() ?

inviavo caratteri, ma c'era un errore nello sketch :smiley: , confermo c'è un abisso tra i 2 baud rate.

x iscrizione

L'ultimo messaggio è di 6 mesi fa, credo che sia abbastanza "morta" come discussione :wink:

Si direi anche conclusa con un ottimizzazione dello speed sia della mega che della uno.