I2C communication with PIC18f4321 and wii nunchuck

71 views Asked by At

I'm a student and I'm attempting to read the joystick values from a wii nunchuck. The wii nunchuck works with i2c protocol but first I have to init two internal registers of the nunchuck before reading its data.

This is the link of how wii nunchuck works: wii nunchuck datasheet

Then, related to the PIC18F4321 microcontroller, i have to program it with assembler language, not with "c". But this is no problem. Here i offer my code and the datsheet of pic18f if someone can find a mistake in my code.

If you take a look at the following datsheet of pic18f, i'm using i2c master mode protocol in the serial comunication serial, from 17.4.6 point to 17.4.13.

Datasheet of PIC18F4321

This is my code in assembler language and i'm using MPLAB X ide to run and compile the program to the pic18f. In this code, i'm using an external Fosc XTALL of 10MHz and then i use the PLL that multiplies by 4 the external XTALL so i'm going at 40MHz freq and an instruction time of 100ns. But this doesn't affect, simply know that a 40MHz frequency and wii nunchuck works at 100KHz, and there's a table in the datasheet at 17-3 that tells the value of the SSPADD register to load and it's 0x63 in hexadecimal.

To summarize my problems. I think that the initialization of all SSP registers is great, and the protocol it's almost perfecte, but i don't know why the code read the wii nunchuck once and i get the same value (164 in decimal) for all the attributes of the nunchuck (attributes: joystick axis, accelerometers and buttons). Or maybe i'm not reading...

I'm connecting the wii nunchuck to the pic18f via an adaptor, and it works because i've test it with an arduino to check that this adaptor and the joystick work well and it did.

This is my code in assembler:

#include <p18f4321.inc>

    CONFIG OSC = HSPLL      ; De moment utilitzem XSTALL extern de 10MHz amb PLL per anar a 40MHz
    CONFIG MCLRE = ON       ; Tenim polsador de reset per si el PIC es queda penjat
    CONFIG PBADEN = DIG     ; Volem que el PORTB sigui DIGital
    CONFIG WDT = OFF        ; Posem a OFF el watch dog timer perque no l'utilitzarem
    
    ;Mapejem les @ de la FLASH
    ORG 0x0000
    GOTO main           ;Quan el pic es reseteja anem al main
    ORG 0x0008
    RETFIE FAST         ;declarem la interrupció del timer0 com a alta
    ORG 0x0018
    RETFIE FAST         ;posem retfie per si de cas, tot i que no saltarà mai

;variables del wii nunchuck    
JX EQU 0x00
JY EQU 0x01
AX EQU 0x02
AY EQU 0x03
AZ EQU 0x04
BT EQU 0x05 


main
    CLRF JX,0
    CLRF JY,0
    CLRF AX,0
    CLRF AY,0
    CLRF AZ,0
    CLRF BT,0
    
    CALL init_i2c
    CALL init_nunchuck
    
loop
    CLRF  SSPCON2,0     ; Tiene que estar en estado idle antes de poder usarlo
    
    CALL  i2c_start     ; Envía la señal de inicio
    MOVLW 0xA5          ; Dirección del dispositivo Nunchuk en modo de lectura
    CALL  i2c_write     ; Envía la dirección del dispositivo esclavo
    
    CALL  i2c_read      ; Lee el byte de datos
    MOVWF JX,0
    CALL  i2c_ack
    
    CALL  i2c_read      ; Lee el byte de datos
    MOVWF JY,0
    CALL  i2c_ack
    
    CALL  i2c_read      ; Lee el byte de datos
    MOVWF AX,0
    CALL  i2c_ack
    
    CALL  i2c_read      ; Lee el byte de datos
    MOVWF AY,0
    CALL  i2c_ack
    
    CALL  i2c_read      ; Lee el byte de datos
    MOVWF AZ,0
    CALL  i2c_ack
    
    CALL  i2c_read      ; Lee el byte de datos
    MOVWF BT,0
    CALL  i2c_nack
    CALL  i2c_stop      ; Envía la señal de parada
    
    GOTO  loop
    
init_i2c
    MOVLW 0x28          ; Configura el módulo I2C como maestro
    MOVWF SSPCON1,0     ; Configura el módulo I2C como maestro
    MOVLW 0x63          ; Configura el registro SSPADD para una velocidad de reloj de 100kHz
    MOVWF SSPADD,0      ; 100kHz = 40MHz/(4*(SSPADD +1)), SSPADD = 0x63
    MOVLW 0x80
    MOVWF SSPSTAT,0     ; Configura el registro SSPSTAT para una freq de 100kHz
    CLRF  SSPCON2,0     ; Tiene que estar en estado idle antes de poder usarlo
    RETURN

init_nunchuck
    ;protocolo para inicializar el registro 0x40 del nunchuk
    CALL  i2c_start     ; Envía la señal de inicio
    MOVLW 0xA4          ; Dirección del dispositivo Nunchuk en modo de escritura
    CALL  i2c_write     ; Envía la dirección del dispositivo esclavo
    MOVLW 0x40          ; Dirección del registro 0x40 del Nunchuk
    CALL  i2c_write     ; Envía la dirección del registro al dispositivo esclavo
    MOVLW 0x00          ; Envía el byte de datos 0x00 para inicializar el registro
    CALL  i2c_write     ; Escribe el byte de datos 0x00 para inicializar el registro
    CALL  i2c_stop      ; Envía la señal de parada
    
    ;protocolo para inicializar el registro 0x00 del nunchuk
    CALL  i2c_start     ; Envía la señal de inicio
    MOVLW 0xA4          ; Dirección del dispositivo Nunchuk en modo de escritura
    CALL  i2c_write     ; Envía la dirección del dispositivo esclavo
    MOVLW 0x00          ; Dirección del registro 0x00 del Nunchuk
    CALL  i2c_write     ; Envía la dirección del registro al dispositivo esclavo
    CALL  i2c_stop      ; Envía la señal de parada
    RETURN

i2c_start           
    BSF   SSPCON2, SEN,0    ; Envía la señal de inicio
    NOP
    BTFSC SSPCON2, SEN,0    ; Espera a que se complete la operación    
    GOTO  $-2               ; Salta a la instrucción anterior (espera)
    RETURN                  ; Retorna de la subrutina
    
i2c_stop
    BSF   SSPCON2, PEN,0    ; Envía la señal de parada
    NOP
    BTFSC SSPCON2, PEN,0    ; Espera a que se complete la operación
    GOTO  $-2               ; Salta a la instrucción anterior (espera)
    RETURN                  ; Retorna de la subrutina...

i2c_write                   ; Envía un byte de datos al dispositivo esclavo
    MOVWF SSPBUF,0          ; Escribe el byte de datos en el registro SSPBUF
    BSF   SSPCON2, ACKSTAT,0; Limpiamos el bit ack del esclavo antes de usarlo
    NOP             
    BTFSC SSPCON2, ACKSTAT,0; Espera a recibir el señal ACK
    GOTO  $-2
    RETURN                  ; Retorna de la subrutina

i2c_read                    ; Lee un byte de datos del dispositivo esclavo
    BSF   SSPCON2, RCEN,0   ; Habilita la recepción de datos
    NOP
    BTFSS SSPSTAT, BF,0     ; Espera a que se haya leido el byte entero
    GOTO  $-2               ; Salta a la instrucción anterior (espera)
    MOVF  SSPBUF,  W        ; Lee el byte de datos recibido
    RETURN

i2c_ack    
    BCF   SSPCON2, ACKDT,0  ; Configura el bit ACKDT para enviar un ack
    BSF   SSPCON2, ACKEN,0  ; Envía la señal de ACK
    NOP
    BTFSC SSPCON2, ACKEN,0  ; Espera a que se completa la señal de "acknowledge"
    GOTO  $-2
    RETURN                  ; Retorna de la subrutina
    
i2c_nack
    BSF   SSPCON2, ACKDT,0  ; Configura el bit ACKDT para enviar un no ack
    BSF   SSPCON2, ACKEN,0  ; Envía la señal de ACK
    NOP
    BTFSC SSPCON2, ACKEN,0  ; Espera a que se completa la señal de "no acknowledge"
    GOTO  $-2
    RETURN                  ; Retorna de la subrutina

    END    

My theory is that when i read from SSPBUF register, maybe i'm not reading well, i just read 164 decimal value at each data byte that joystick send to me.

0

There are 0 answers