Velocizzare l'IO delle porte digitali

Come potrei compilare una piccola macro che faccia questo

if (bitRead(gr_PORT_C, 0) == 1) bitWrite(PORTC,0,comm01);

"gr_PORT_C" è un byte su eprom dove è scritto quali pin del registo C sono ENABLE alla commutazione
"comm01" è il bit 0 opure 1

per la prima parte l'ho fatto ma la scrittura come posso farla visto che il bit da scrivere può essere 1 o 0?

#define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))
if(bit_is_set(gr_PORT_C, 0)) bitWrite(PORTC,0,comm01);

se devo inserire un if per controllare il "comm01" allora allungo i tempi ....

leo72:
Ho preso l'Arduino ed ho compilato il seguente sketch:

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))

#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

void setup() {
    sbi(PORTD, 1);
}

void loop() {
}



468 byte di esegubile.
Alla riga 55, ecco l'istruzione in assembly:


a6: 9a 59      sbi $0b, 1



Confermato quanto da te detto.

OK. Andiamo avanti. Ho rifatto il test col seguente codice:


void setup() {
    PORTD |= (1<<1);
}

void loop() {
}



468 byte di eseguibile. Curioso... Disassemblo e alla riga 55 cosa mi appare?


a6: 9a 59      sbi $0b, 1



Il compilatore quindi ha ottimizzato ed in output ha dato lo stesso codice.

per fare queste prove hai usato l' ide ufficiale?

pablos:
Come potrei compilare una piccola macro che faccia questo

if (bitRead(gr_PORT_C, 0) == 1) bitWrite(PORTC,0,comm01);

"gr_PORT_C" è un byte su eprom dove è scritto quali pin del registo C sono ENABLE alla commutazione
"comm01" è il bit 0 opure 1

per la prima parte l'ho fatto ma la scrittura come posso farla visto che il bit da scrivere può essere 1 o 0?

#define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))

if(bit_is_set(gr_PORT_C, 0)) bitWrite(PORTC,0,comm01);



se devo inserire un if per controllare il "comm01" allora allungo i tempi ....

Non ho capito bene. Così ad intuito ti chiedi quello che tempo addietro mi sono chiesto io, cioè una unica macro o funzione che mi permetta di impostare
un solo bit di una variabile indifferentemente che lo voglia impostare a 0 o a 1, se si tratta di questo tempo addietro postai in merito e vennero fuori delle macro interessanti, ora il post è caduto nel dimenticatoio.

Comunque io uso questa funzione inline:

inline void __bit_set_to(uint8_t *d_ptr, uint8_t bit, uint8_t bit_value)
{
    *d_ptr ^= (-bit_value ^ *d_ptr) & (1 << bit);
}

E si usa così:

__bit_set_to(&PORTA, 7, 1) // Imposta il bit 7 ad 1
__bit_set_to(&PORTA, 7, 0) // Imposta il bit 7 ad 0

Per la funzione inline ho dovuto usare per forza il puntatore, mentre per la macro non è necessario.

La macro potrebbe essere qualcosa di simile:

#define bit_set_to(reg, bit, bitValue) d_ptr ^= (-bitValue ^ d_ptr) & (1 << bit)

Correzione della macro:

#define bit_set_to(reg, bit, bitValue) reg ^= (-bitValue ^ reg) & (1 << bit)

occhio che richiede ; alla fine

Fammi sapere se lavora.

Ciao.

andrea86:
per fare queste prove hai usato l' ide ufficiale?

L'IDE di Arduino con la toolchain Atmel 3.4.1 per Linux.

Così ad intuito ti chiedi quello che tempo addietro mi sono chiesto io, cioè una unica macro o funzione che mi permetta di impostare
un solo bit di una variabile indifferentemente che lo voglia impostare a 0 o a 1, se si tratta di questo tempo addietro postai in merito e vennero fuori delle macro interessanti, ora il post è caduto nel dimenticatoio.

Si hai capito bene, ho provato la macro, ma da errori di variabili indefinite. Sto cercando di capirla e correggerla, capire cosè questo "inline void", nel frattempo ho preso i tuoi 135 post e sono arrivato al n°98, se c'è tra i tuoi non mi scapperà :slight_smile:

ciao e grazie per ora

ecco trovato i pezzi e ricostruito la macro:

#define Bit_Set_to(reg, bit, bitvalue) (bitvalue ? ((reg) |= (1UL << (bit))) : ((reg) &= ~(1UL << (bit))))

bit da scrivere nel registro ? bit_set : bit_clear

Esempio d'uso
Bit_Set_to (PORTD,2,1);

Mi chiedo quale potrebbe essere il vantaggio rispetto all'uso di

bitWrite(PORTD,2,1);

Aggiornamento:
Come non detto ... riscrivere questa macro è del tutto inutile, sono già presenti nella lib Arduino.h:

Arduino.h

#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))

ciao

Ho corretto la macro, avevo dimenticato di cambiare "d_ptr" con "reg".
Quel codice lavora diversamente, cioè manca l'operatore "?" e in teoria dovrebbe essere più rapida, ma c'è una operazione matematica in più, quindi alla fine forse, l'una vale l'atra.

Per la funzione inline è necessario avere un header dove scrivere la funzione inline, quando richiamata nel codice il compilatore la riporta inline al codice, come un blocco di codice {}, ma senza overhead richiesto dal passagio di parametri.

Ciao.

mi sembra un topic adatto per la mia curiosita'

se faccio:

DDRD=1<<PD6

in che file e' definito che PD6=6 ???

Testato:
mi sembra un topic adatto per la mia curiosita'

se faccio:

DDRD=1<<PD6

in che file e' definito che PD6=6 ???

Mi pare che nella cartella G:\Arduino\arduino-1.0.5\hardware\arduino\variants
Ci sono sottocartelle per le varie board e dentro c'e' pins_arduino.h per A0-Ax e MISO,etc.

Poi c'e in G:\Arduino\arduino-1.0.5\hardware\tools\avr\avr\include\avr
portpins.h ed anche io.h
dentro ad io.h in base alla board chiama un ioxxxx.h con registri e quant'altro del singolo MCU

ma quel PD6 non c'e'
Le istruzioni sono con i numeri del bit semplicemente

PORTD |= (1<<6);               // che poi è un PD6

La roba presente nelle cartelle avr credo sia materiale non arduinico, cioè sarebbero gli include della toolchain
Quindi la definizione di quanto vale PD6 è una scelta fatta dai programmatori del compilatore ? Da Atmel stessa ?

Esiste un tool di scrittura codice, o un ide, che cliccando su PD6 mi porta al punto in cui è definito ?
Credo sia comodobproprio per leggere il codice, anche a livello di funzioni, tipo sarebbe utile cliccare su delay ed andare indietro su dove è definita

Atmel studio + Visual Micro (un addin) permette di creare progetti per Arduino e se vai ad esempio sulla parola PORTD, mouse contestuale, voce "Goto Implementation" ti apre il file .h con la dichiarazione di PORTD (ed apre il file ioXXXX.h giusto a seconda della MCU scelta)

Se no si lavora con l'IDE, è necessario per usare i pin di I/O includere il file avr/io.h che a sua volta includerà altri file tra cui quello specifico per la famiglia dei micro con le definizioni dei pin e delle porte.
L'IDE semplifica la gestione perché stratifica su questi file altre definizione dei pin tramite i file pins_arduino.h.

Se si vuole lavorare direttamente con i pin e le porte è necessario conoscere le definizioni originali di queste.
Al posto di PD6, se incluso il corretto file, puoi anche scrivere PORTD6, che è un alias di quest'ultimo.

yes, ho visto che PORTD6 funziona, grazie della dritta, ma mi sono intestardito con PD6 :stuck_out_tongue_closed_eyes:
l'ho trovato in hardware\tools\avr\avr\include\avr\iomxx0_1.h
PD6 quindi funziona nativamente nell'ide, ma solo se si compila per Mega, non lo avevo specificato che stavo usando una Mega perche' non credevo ci fossero queste differenze, cioe' una volta assodato che PD6 e' sia sul 328 che sul 2560, perche' fare queste differenze :fearful:

Devi vedere le definizione nel file ioxxxxx.h specifico della famiglia dei micro. UNO e MEGA avendo due micro appartenenti a famiglie diverse xxx8 e xxx0 utilizzano due file ioxxx.h diversi con definizioni dei pin a volte diverse.
Perchè? Boh! Chiedilo all'Atmel.

PaoloP:
Perchè? Boh! Chiedilo all'Atmel.

:stuck_out_tongue_closed_eyes:

Sono file che fanno parte della toolchain e specificano le costanti predefinite per permettere all'utente di specificare PB6 al posto di un indirizzo di memoria per poter accedere al relativo pin. In fase di compilazione, il compilatore sostituirà quella costante con una serie di istruzioni di scrittura a particolari indirizzi di memoria SRAM in cui sono mappate le periferiche interne del microcontrollore, comprese le porte di I/O (difatti la SRAM inizia all'indirizzo $100, anche se l'utente non vede questa cosa, perché le prime locazioni sono riservate).
Ogni famiglia di integrati ha il proprio file delle definizioni perché ovviamente chip diversi hanno risorse diverse e quindi indirizzi diversi.

Yes, tutto chiaro, alla fine dove era definito il valore decimale 6 per PD6 l'ho trovato, resta inspiegabile il perché atmel tenga in disordine queste cose, almeno dal mio punto di vista.
Ripeto PD6 è presente sia sul 328 che sul 2560, capisco che sono micro diversi, ma se io Atmel mi prendo la briga di creare un define per PD6 nei file per 2560, perché non lo faccio anche per 328 e tutti gli altri micro che hanno un PD6 ?

Non è corretto, imho, perché questa scelta, che non è di arduino, deve rompere la portabilità del codice tra due micro che hanno entrambi un PD6

La toolchain non è di Atmel, è di Gnu. Atmel la patcha e la ridistribuisce.
Non so se su AvrStudio PD6 c'è oppure no.

Testato:
Yes, tutto chiaro, alla fine dove era definito il valore decimale 6 per PD6 l'ho trovato, resta inspiegabile il perché atmel tenga in disordine queste cose, almeno dal mio punto di vista.
Ripeto PD6 è presente sia sul 328 che sul 2560, capisco che sono micro diversi, ma se io Atmel mi prendo la briga di creare un define per PD6 nei file per 2560, perché non lo faccio anche per 328 e tutti gli altri micro che hanno un PD6 ?

Scusa, in quale file l'hai trovato per il 2560 ? Io non lo trovo.

il file è iomxx0_1.h che è incluso da iom2560.h che è incluso da io.h in base al modello di micro.