Molti di noi, in passato, con Arduino UNO R3 (ATmega328P, AVR) abbiamo utilizzato, per esigenze di velocità, l'accesso diretto ai pin di I/O con le istruzioni utilizzanti PIN e PORT ... anche con Arduino UNO R4 (Renesas RA4M1, ARM Cortex M4) la cosa è possibile, ma, data l'architettura differente, occorre seguire tutt'altra strada.
Per correttezza rammento che, l'utilizzo dell'accesso diretto ai pin di I/O, senza utilizzare il framework Arduino (quindi, senza utilizzare digitalRead() e digitalWrite()), rende il codice intrasportabile su altre piattaforme senza un discreto lavoro di adattamento e che quindi, salvo particolari esigenze, e del tutto da sconsigliare.
Comunque, studiando gli ottimi lavori di Susan Parker (TriodeGirl (Susan Parker) · GitHub) e i vari testi legati alla cosa ho messo a punto un piccolo modulo .h, che si può includere in un .ino mettendolo direttamente nella stessa cartella del progetto, e che rende banale l'accesso diretto in I/O sul singolo pin di Arduino UNO R4.
Per chi volesse approfondire c'è da studiarsi:
- Documentation – Arm Developer
- https://www.renesas.com/us/en/document/mah/renesas-ra4m1-group-users-manual-hardware
... che contengono tutte le informazioni necessarie.
In pratica, sul RA4M1, ogni singolo pin di I/O (e non solo) è mappato in memoria, per cui è possibile agire su di esso semplicemente leggendo o scrivendo una certa locazione.
Per semplificare la cosa ho fatto, come detto, un semplice .h che allego: portIO.h (4.3 KB) ... esso una volta incluso nel .ino permette banalmente di leggere/scrivere sul singolo pin di I/O di Arduino UNO R4.
Un paio di esempi per chiarire quanto la cosa sia semplice ...
- Il classico blink del LED che, anche su Arduino UNO R4, si trova sul pin 13:
#include "portIO.h"
bool ledStatus = false;
void setup() {
delay ( 500 );
Serial.begin ( 115200 );
while ( !Serial ) delay ( 100 );
Serial.println ( "Direct I/O LED blinking ... " );
}
void loop() {
if ( ledStatus ) {
IO_D13 = IO_OUT_LOW;
} else {
IO_D13 = IO_OUT_HIGH;
}
ledStatus = !ledStatus;
delay ( 1000 );
}
- la lettura di un pin in input (pull-up) (pin 7) e la sua visualizzazione sul LED (pin 13):
#include "portIO.h"
uint8_t pinStatus;
void setup() {
delay ( 500 );
Serial.begin ( 115200 );
while ( !Serial ) delay ( 100 );
Serial.println ( "Direct I/O test ... " );
IO_D7 = IO_INP | IO_INP_PULLUP; /* Enable INPUT PULL-UP) */
}
void loop() {
pinStatus = IO_D7 & IO_INP_MASK;
if ( pinStatus ) {
IO_D13 = IO_OUT_HIGH;
} else {
IO_D13 = IO_OUT_LOW;
}
}
Per semplificare la vita ho definito, nel .h, alcuni valori che si possono usare:
#define IO_OUT_LOW 0x04
#define IO_OUT_HIGH 0x05
#define IO_INP 0x00
#define IO_INP_MASK 0x02
#define IO_INP_PULLUP 0x10
... in pratica permettono di scrivere il valore LOW, il valore HIGH, di definire un pin come INPUT e, se occorre, attivare la pull-up interna ed infine di mascherare il uint8_t che si legge in input al fine di avere solo il valore logico del pin senza altri bit inutili.
Spero possa essere utile a chi avesse veramente la necessità di un accesso diretto senza l'utilizzo del framework Arduino (cosa che, ribadisco, senza una vera esigenza, è cosa da evitare).
Fatemi sapere ... ![]()
Guglielmo
P.S.: Solo una cosa, sul RA4M1, per questo tipo di accessi, occorre prestare molta attenzione all'allineamento di ciò che si va a leggere/scrivere ... ci sono indirizzi, come quelli usati da me nel .h, che sono per accesso a uint8_t, ce ne sono altri per accesso con uint16_t ed altri per accesso con uint32_t ... occhio quindi se toccate qualche cosa a studiarvi bene i documenti che ho indicato sopra ![]()
