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.
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.