Velocizzare l'IO delle porte digitali

Stavo leggendo questo interessante articolo:

http://www.skpang.co.uk/blog/archives/323

in cui spiega come velocizzare l'IO delle porte digitali agendo direttamente a basso livello senza passare dai metodi di arduino.

In quell'articolo viene riportata anche la funzione digitalwrite per far vedere quante cose fa prima di impostare il pin.

Ora vedendo quel metodo noto che spegne, a volte, anche il pwm (if (timer != NOT_ON_TIMER) turnOffPWM(timer);)

Se io volessi lavorare con le porte a basso livello dovrei spegnerlo io il pwm a mano? Magari nel setup?
Ho provato a chiamare la turnOffPWM ma dice "Blink:16: error: ‘turnOffPWM’ was not declared in this scope"

Sbaglio qualcosa?

Grazie

erpomata:
Stavo leggendo questo interessante articolo:

http://www.skpang.co.uk/blog/archives/323

in cui spiega come velocizzare l'IO delle porte digitali agendo direttamente a basso livello senza passare dai metodi di arduino.

Puoi fare quel che ti pare con le porte del microcontrollore.

In quell'articolo viene riportata anche la funzione digitalwrite per far vedere quante cose fa prima di impostare il pin.

Il problema della manipolazione diretta delle porte è proprio questo, ossia capire/sapere cosa fa il core di Arduino. Il core di Arduino è molto complesso e dietro la semplificazione che offre all'utente c'è tutta una struttura di funzioni nascoste all'utente che permettono di utilizzare l'HW con semplici comandi.

Ora vedendo quel metodo noto che spegne, a volte, anche il pwm (if (timer != NOT_ON_TIMER) turnOffPWM(timer);)

Lo fa per evitare di trovarti un segnale PWM attivato da un analogWrite sullo stesso pin che poi vuoi usare come semplice uscita digitale.

Se io volessi lavorare con le porte a basso livello dovrei spegnerlo io il pwm a mano? Magari nel setup?
Ho provato a chiamare la turnOffPWM ma dice "Blink:16: error: ‘turnOffPWM’ was not declared in this scope"

Sbaglio qualcosa?

Grazie

Sì, a chiamare quella funzione dallo sketch, che è visibile solo all'interno del file wiring_digital.c
Potresti provare a prenderla e ricopiarla, magari togliendo i controlli che non riguardano l'Atmega328 (che ha solo 3 timer, mentre quella funzione ne controlla di più, tutti quelli disponibili anche sulla Mega, per esempio), direttamente nel tuo sketch.

Ho provato a copiare il codice ma dovrei importare mezza libreria di arduino.

Un'ultima domanda, disabilitare o meno pwm è dato solo dal fatto che se voglio ragionare a I/O digitali invece che analogici, cioè mi protegge.
Se io sono sicuro di non utilizzare mai la analogWrite me ne posso fregare?

erpomata:
Se io sono sicuro di non utilizzare mai la analogWrite me ne posso fregare?

Se non hai precedentemente utilizzato AnalogWrite su un pin, in realtà vale per una coppia, non devi disabilitare il PWM per utilizzare il pin in modo digitale, in caso contrario devi prima disabilitarlo.
C'è la proposta per una nuova funzione denominata noAnalogWrite() per disattivare il PWM, però non è ancora stata implementata, puoi comunque farlo da sketch con questa sequenza di istruzioni:

analogWrite(9, 128);
delay(1);
pinMode(9, OUTPUT);
digitalWrite(9, HIGH);

Trovi i riferimenti qui

erpomata:
Ho provato a copiare il codice ma dovrei importare mezza libreria di arduino.

Un'ultima domanda, disabilitare o meno pwm è dato solo dal fatto che se voglio ragionare a I/O digitali invece che analogici, cioè mi protegge.

Giusto per precisione, un'uscita PWM non è un'uscita analogica.
Comunque il concetto è che siccome il core di Arduino non sa se hai attivato un segnale PWM su un pin (non tiene traccia della cosa), e non fa neanche un controllo sui registri per motivi di snellezza del codice, semplifica la cosa e disattiva il PWM sui pin con tale capacità a prescindere.

Se io sono sicuro di non utilizzare mai la analogWrite me ne posso fregare?

:wink:

C'è anche questo topic sull'argomento --> http://arduino.cc/forum/index.php/topic,117356.0.html

Grazie a tutti.
Superlativi come al solito

leo72:
...
Arduino Reference - Arduino Reference
Puoi fare quel che ti pare con le porte del microcontrollore.
...

Li è scritto dettagliatamente come funzionano le porte del micro. Se vuoi avere un'infarinatura generale puoi leggere questo mio vecchio post:

Grazie tante.
Ottima spiegazione ma anche il link che ho trovato io è molto chiaro.

Scusate, riprendo l'argomento per chiedere se è possibile, ed eventualmente come faccio, ad impostare 2 o 3 pin contemporaneamente.

Queste guide parlano sempre di un pin alla volta.

Guarda questa discussione --> http://arduino.cc/forum/index.php?topic=124080.0

Comunque settando la porta puoi settare più pin contemporaneamente.

PORTD |= B10101000; // sets digital pins 7,5,3 HIGH

Si quel metodo mi è chiaro.
Non sono stato chiaro io.
Intendevo con la notazione tipo:

PORTD |= 1<<2; // Set bit 2 high

erpomata:
Si quel metodo mi è chiaro.
Non sono stato chiaro io.
Intendevo con la notazione tipo:

PORTD |= 1<<2; // Set bit 2 high

--> chiarimento su PORTD = B10101000; - #5 by leo72 - Software - Arduino Forum

PORTD |= ((1<<3) | (1<<5));

Caspita che hai l'indirce del forum in testa?

Grazie per la dritta.

Comunque, mi pare di aver capito che è impossibile settare per una stessa porta un pin HIGH e l'altro LOW.
Devono essere 2 operazioni differenti.

Sbaglio?

erpomata:
Comunque, mi pare di aver capito che è impossibile settare per una stessa porta un pin HIGH e l'altro LOW.
Devono essere 2 operazioni differenti.

Sbaglio?

Sì.
0=LOW
1=HIGH
Quindi se riprendiamo la porta dell'esempio precedente, PORTD, e facciamo questa assegnazione:

PORTD = 0b10101010;

Hai impostato le porte collegate ai bit dispari su LOW (1-3-5-7) e quelle collegate ai bit pari su HIGH (0-2-4-6).

Si ma se io volessi impostare, ad esempio i bit 0 e 1 rispettivamente a HIGH ed a LOW ma preservando gli altri bit della porta non lo posso fare.

In quella maniera sovrascrivo tutte le impostazioni precedentemente date agli altri pin.

Allora vuol dire che non hai letto il mio post quotato da PaoloP :stuck_out_tongue:

erpomata:
Si ma se io volessi impostare, ad esempio i bit 0 e 1 rispettivamente a HIGH ed a LOW ma preservando gli altri bit della porta non lo posso fare.

Per settare i singoli bit di un port, o un registro, puoi usare le macro SBI(reg,bit) e CBI(reg,bit), usano le omonime istruzioni assembly e richiedo solo due cicli macchina per l'esecuzione.

SBI = Set Bit in I/O Register
CBI = Clear Bit in I/O Register

//SBI e CBI
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

leo72:
Allora vuol dire che non hai letto il mio post quotato da PaoloP :stuck_out_tongue:
chiarimento su PORTD = B10101000; - #5 by leo72 - Software - Arduino Forum

Certo che l'ho letto ma se per settare a HIGH devo usare una OR e per metterla a LOW devo usare una AND come faccio a combinare la cosa su pin diversi, mantenendo lo stato degli altri pin della porta e facendo l'operazione contemporaneamente su tutta la porta.
Non mi pare di vedere ciò che mi serve in quel post.