Interfacciarsi con il Nunchuck della Nintendo – Appunti

La Nintendo WII utilizza un curioso controller di gioco chiamato Nunchuck (il cui nome deriva da Nunchaku, la famosa arma giapponese costituita da due mazze di legno unite da una catena o da una piccola fune o catena). Tale controller è molto interessante per noi smanettoni per tutta una serie di motivi che ora vi elenco:

  • All’interno ha un accelerometro a 10bit
  • Ha un joystick analogico a due assi
  • Ci sono due pulsanti
  • E’ possibile acquistare un Nunchuck non originale ad un prezzo ≤ €10 (quello originale si trova a 20)
  • Comunica utilizzando un protocollo I2C standard

Il primo punto unito agli ultimi due mi ha fatto subito correre a procurarmi un Nunchuck (non originale) nonostante  io non possegga una Nintendo WII:

Un accelerometro e un joystick analogico in un case così accattivante, per di più in I2C, a solo 10 euro?!

Il nunchuck non originale di discosta di poco da quello della Nintendo, mancano gli inserti ergonomici laterali, è leggermente diverso l’incavo dello stick e probabilmente è diversa anche la plastica, ma non è che mi importa più di tanto. Non voglio aggiungere che l’elettronica sia leggermente diversa perchè questo penso sia ovvio (se no come fa a costare 10 euro di meno, non è certo la plastica che fa tutta la differenza!) ma prima di affermarlo con certezza sto aspettando che mi arrivi un cacciavite tri-wings per poterlo smontare e darci un occhio all’interno:

A me questo controller sta simpatico

Pinout

Bando alle ciance. Incominciamo a vedere dove mettere le mani. Partiamo dal connettore:

Notiamo innanzitutto che, come era logico aspettarsi, il connettore non è standard. Il pin n°5 a me non è presente, probabilmente sul Nuchuck originale c’è, comunque sia non serve a nulla perchè non è connesso. Il pinout è il seguente:

Pinout Nintendo Nunchuck, verificato. Diffidate dalle imitazioni!

Attenzione che su alcuni documenti è riportato un pinout in cui il pin di presenza è indicato come +3V e il pin 3 come non connesso: questo pinout è sbagliato ma funziona comunque e il perchè lo capirete tra poco. Su altri schemi in rete il pin che io ho chiamato presenza è indicato come ATT. Come vedete il Nunchuck funziona a 3.3V, per cui per alimentarlo dobbiamo procurarci una sorgente di alimentazione adatta. I pin 1 e 4 sono rispettivamente il canale dati del bus I2C e il clock. Il nunchuck funziona come dispositivo I2C Slave a 400KHz. Il pin n°2 serve alla WII per capire quando il controller è collegato o meno (internamente al Nunchuck i pin 2 e 3 sono collegati insieme, in pratica la WII “legge” 3.3V sul pin2 quando il Nunchuck è attaccato alla console: ecco perchè quei pinout sbagliati funzionano lo stesso).

Realizziamo un adattatore per il Nunchuck

Non mi piaceva assolutamente l’idea di spezzare il cavo e tirare fuori i fili: sarebbe un atto di cannibalizzazione troppo estremo e io odio la violenza! In giro esistono tante soluzioni per potersi collegare al cavo del Nunchuck, come questa ad esempio, ma andavo un po’ di fretta per cui ho pensato di realizzarmi da me un adattatore, un po’ spartano ma efficace. La distanza tra le due file di pin del connettore del Nunchuck è uguale a quella dei normali PCB, la distanza tra i pin, però, non è quella classica da 0.1″ ma leggermente inferiore, nonostante questo, trattandosi di solo 3 pin (3 sopra e 3 sotto), utilizzare un classico PCB con connettore a pettine da 0.1″ non causa nessun problema.

Ho quindi pensato bene di dare miglior utilizzo ad una vecchia scheda PCI per computer tagliando un pezzetto del connettore inferiore:

Usando un po’ di forza bruta (leggasi: minitrapano dotato di disco diamantato, una limetta e un po’ di cartavetrata):

Si riesce ad ottenere una cosa abbastanza decente e funzionale:

Qualche cavetto, un paio di punti di saldatura, un pezzetto di termorestringente e uno strip maschio da 5 poli completano l’opera:

Interfacciarsi a livello elettrico

Ho detto che il Nunchuck funziona come dispositivo I2C Slave alla frequenza di 400KHz, ovviamente questo non basta perchè dobbiamo tener conto di due fattori importanti:

  1. Il Nunchuck funziona a 3.3Volts. Siamo abituati con le logiche a 5V, ma alimentare il nunchuck con una tensione inferiore non dovrebbe essere un problema. Possiamo riccorere anche ad un regolatore lineare come l’LM1117-3.3 o altri simili.
  2. Funzionando a 3.3Volts, è necessario anche adattare i livelli logici. L’adattamento può essere eseguito nel miglior modo utilizzando appositi circuitini come questo oppure porte logiche o ancora più semplicemente un partitore di tensione come già ho illustrato in questo articolo (paragrafo Adattare i livelli logici): a 400KHz anche il partitore dovrebbe funzionare correttamente senza falsare i segnali. Dovremo ovviamente ricordarci che il livello va adattato sia sulla linea dei dati che su quella del clock.

Ho visto un po’ dappertutto che in realtà nessuno si cura della questione dei 3.3V e fanno funzionare il Nunchuck a 5V senza problemi. A me non va di fare questa prova e non ho nemmeno la possibilità di verificare se la Nintendo WII fornisce davvero 3.3V o ne fornisce 5.

Il protocollo di comunicazione

Abbiamo imparato che un dispositivo I2C ha comunemente un indirizzo a 7 bit più un ottavo bit (il bit 0) che specifica la modalità di accesso alla periferica: 0=in scrittura 1=in lettura. Il Nunchuck ha l’indirizzo 0x52 (a 7 bit), aggiungendo il bit di lettura/scrittura gli indirizzi I2C completi del Nunchuck sono quindi:

  • 0xA4 (scrittura)
  • 0xA5 (lettura)

In questa pagina c’è un esempio di interfacciamento con Arduino: http://www.windmeadow.com/node/42

Il Nunchuck va inizializzato, una sola volta all’accensione, scrivendo il valore 0x00 nella locazione 0x40. La sequenza di inizializzazione del Nunchuck è quindi questa:

[I2C Start] 0xA4 0x40 0x00 [I2C Stop]

Ricordiamo che la sequenza di scrittura I2C è: Start – Indirizzo periferica in scrittura (0xA4) – Locazione di memoria in cui scrivere (0x40) – Valore da scrivere (0x00) – Stop.

Alcuni Nunchuck non originali (come il mio, ad esempio, marcato Shiro o alcuni marcati DealExtreme) utilizzano una sequenza di inizializzazione  differente:

[I2C Start] 0xA4 0xF0 0x55 [I2C Stop]

Dopo aver eseguito l’inizializzazione, si comunica al Nunchuck di voler leggere lo stato dei sensori (Accelerometro, Stick e pulsanti). Lo si fa con la sequenza:

[Start] 0xA4 0x00 [Start Ripetuto] 0xA5 [Lettura bulk di 6 bytes] [Stop]

Ricordo che la sequenza di lettura di un dispositivo I2C è la seguente: Start – Indirizzo periferica in scrittura (0xA4)- indirizzo locazione dalla quale iniziare a leggere (0x00) – Start ripetuto – Indirizzo periferica in lettura (0xA5) – Lettura dei bytes restituiti dalla periferica – Stop.

Per eseguire la lettura Bulk (sequenziale) basta dare un ACK dopo ogni byte ricevuto: in questo modo la periferica Slave fornisce il contenuto dei registri successivi a quello di partenza fino a che il master non da un NACK seguito da STOP per terminare la comunicazione. Questa modalità è piu vantaggiosa perchè richiede meno tempo e i bytes vengono restituiti tutti di fila. Se volete eseguire la lettura classica di un byte singolo basta che partite col fornire l’indirizzo 0x00 e leggere singolarmente tutte le locazioni fino ad arrivare alla 0x05.

Questa sequenza di lettura è uguale sia per il Nunchuck originale che non.

Il nunchuck restituirà quindi un pacchetto composto da 6 bytes:

C’è da dire una cosa: un po’ dappertutto c’è scritto che i bytes ricevuti vanno “decodificati”. Su ogni byte ricevuto si deve eseguire un XOR con il valore 0x17 e quindi al risultato sommare ancora il valore 0x17 ma personalmente ho ancora qualche perplessità su questa questione e capirete perchè. Analizziamo il contenuto dei bytes ricevuti:

Byte 0 : posizione dello stick analogico sull’asse X (0=tutto a sinistra, 255=tutto a destra). A questo punto la questione della decodifica mi pare piuttosto strana. Eseguendo la decodifica sui valori estremi 0 e 255 non c’è nessun problema perchè ottengo sempre 0 e 255. Il dubbio ce l’ho sui valori di mezzo. Avendo un valore di stick analogico che varia tra 0 e 255 è logico pensare che con lo stick fermo in posizione centrale io ottenga il valore 0x80 (128), e difatti così ottengo SENZA decodifica, se invece eseguo la decodifica sul valore ricevuto (0x80) ottengo:

(0x80 XOR 0x17) + 0x17 = 0xAE (174)

che non mi odora proprio di valore centrale… Per cui… fate voi delle prove con i vostri Nunchuck e fatemi sapere…

Byte 1 : posizione dello stick analogico sull’asse Y (0=tutto giù, 255=tutto su)

Byte 2 : 8 bit alti del valore a 10 bit relativo all’asse X dell’accelerometro. La variazione dell’asse X la si ha quando si trasla il controller in senso laterale. Quando il controller è fermo il valore a 10bit è intorno a 512, muovendosi verso sinistra il valore diminuisce, muovendosi verso destra il valore aumenta:

Questa immagine e le seguenti due sono prelevate dal manuale del “ZX-Nunchuck – WII Nunchuck interface Board” scaricato dal sito robotshop.com (http://www.robotshop.com/content/PDF/inex-zx-nunchuck-datasheet.pdf)

I valori restituiti dall’accelerometro hanno una variazione proporzionale alla velocità del movimento (uno spostamento molto veloce fa variare il valore in misura più alta), quando il movimento è terminato i valori si riportano al centro. In condizioni di stasi, quindi, i 3 valori restituiti dall’accelerometro dovrebbero trovarsi più o meno intorno a 512, in realtà io mi ritrovo valori tra 400 e 700 (sia con che senza decodifica).

Ricordo che un accelerometro misura l’accelerazione e non va confuso con un giroscopio che misura l’inclinazione.

Byte 3 : 8 bit alti del valore a 10 bit relativo all’asse Y dell’accelerometro. La variazione dell’asse Y si ha quando il controller viene traslato in senso longitudinale. Muovendo il controller in avanti il valore aumenta, tirandolo verso sè il valore diminuisce.

Byte 4 : 8 bit alti del valore a 10 bit relativo all’asse Z dell’accelerometro. La variazione dell’asse Z si ha quando il controller viene traslato verso il soffitto o verso il pavimento (maccheronicamente parlando!). Traslando in alto il valore aumenta, traslando verso il basso il valore diminuisce:

Byte 5 : in questo byte è contenuto un po’ di tutto:

  • Bits 7 e 6 : corrispondono ai 2 bit bassi (rispettivamente 1 e 0) del valore a 10 bit dell’asse Z dell’accelerometro
  • Bits 5 e 4 : corrispondono ai 2 bit bassi (rispettivamente 1 e 0) del valore a 10 bit dell’asse Y dell’accelerometro
  • Bits 3 e 2 : corrispondono ai 2 bit bassi (rispettivamente 1 e 0) del valore a 10 bit dell’asse X dell’accelerometro
  • Bit 1 : pulsante C (quello più piccolo posto in alto). Tale bit vale zero quando il pulsante è premuto
  • Bit 0 : pulsante Z (quello più grande posto in basso). Tale bit vale zero quando il pulsante è premuto

Come avete capito, quindi, l’interfacciamento di questo simpatico dispositivo può essere eseguito sfruttando le periferiche di comunicazione I2C ed eseguendo delle semplici operazioni. Se non si vuole ottenere la piena risoluzione a 10 bit dell’accelerometro è anche possibile utilizzare i soli 8 bit alti evitando di eseguire bitshift e maschere sul 5°byte ricevuto. In questo momento sto facendo delle prove di collegamento con il Bus Pirate giusto per capirne perfettamente il funzionamento prima di passare a cose più complicate, quindi non escludo che tra poco piazzo qualche appunto su questo argomento.

Troubleshooting

Come fare a capire che  la comunicazione non vi funziona? Semplice: o il dispositivo vi restituisce sempre NACK dopo ogni byte ricevuto, oppure quando andate ad eseguire la lettura vi vengono restituiti tutti 0xFF. Se a voi il nunchuck non comunica controllate in sequenza:

  1. L’adattatore che avete costruito fa bene contatto?
  2. La tensione di alimentazione arriva al Nunchuck?
  3. Provate a comunicare utilizzando la prima sequenza di inizializzazione, che fa riferimento al Nunchuck originale Nintendo e alla maggioranza dei Nunchuck non originali.
  4. Se l’inizializzazione “originale” non funziona, provate a comunicare utilizzando la seconda sequenza.

Ringrazio l’utente Fiacca per le correzioni

Links

Se questo articolo ti è piaciuto, condividilo su un social:
Se l'articolo ti è piaciuto o ti è stato utile, potresti dedicare un minuto a leggere questa pagina, dove ho elencato alcune cose che potrebbero farmi contento? Grazie :)