Que pesadilla el Pibe y sus memorias SPI !!
Aqui les dejo un ejemplo sencillo y eficáz de usar la memoria serie más grande de microchip: La 25AA1024 o 25LC1024 con un PIC16f877A
El siguiente código fue probado en una protoboard y funciona 10 puntos.
Lo que hace es grabar 3 bytes consecutivos en modo burst y luego leerlos de la misma manera y mostrarlos por el PORTD
He optimizado el tiempo de grabación haciendo un WIP polling, que no es ni mas ni menos que la lectura del registro de estado de la memoria para saber si ha terminado de escribir y se pueden enviar/leer más datos, logrando así no tener que esperar un tiempo fijo de demora (generalmente en el peor de los casos es de 5ms) y que a la larga si escribimos muchos datos se agradece.
25AA1024
WP y HOLD con una R de 10k a positivo
CS a RC6 del micro
SO a SDI del micro
SI a SDO del micro
SCK a SCK del micro
No tiene mayores complicaciones a la hora de conectarla, como podrais ver. Pero no cometais la estupidéz que hice yo: Me tiré toda una mañana descifrando por qué no funcionaba. Mandaba datos, reloj, CS pero no grababa. Cuando me doy cuenta que me había olvidado de conectar el pin positivo de la eeprom
Bueno, gases del oficio.
Aquí va el código
LIST P=16F877A
; Port C pin descriptions
; SCK bit = 3
; SDI bit = 4
; SDO bit = 5
; CS bit =6
;
; 20MHz crystal is being used, thus each instruction cycle = 1600nS
;
;*******************RAM register definitions**********************
cblock 0x20
rxdata
txdata
addrL
loops
outbyte
temp1
temp2
PDel0
PDel1
PDel2
addrM
addrH
d1
d2
d3
endc
;*******************Bit definitions*******************************
CS equ 6
include "p16f877A.inc" ; this is the include file for a PIC16F877
errorlevel -302 ; suppress message 302 from list file
__CONFIG _CP_OFF & _WDT_OFF & _PWRTE_OFF & _HS_OSC
org 0x000 ; set the reset vector
goto start ; go to the beginning of main
start
bcf STATUS,RP0 ; set to bank 0
clrf PORTC ; initialize portc to 0
bsf STATUS,RP0 ; set to bank 1
movlw 0x10 ; all bits are outputs except SDI
movwf TRISC ; move the value to TRIS portc
clrw
movwf TRISD
bcf STATUS,RP0 ; set to bank0
bsf PORTC,CS ; make the chip select is high
clrf PIE1 ; disable peripheral interrupts
clrf INTCON ; disables all interrupts
bcf STATUS,RP0 ; set to bank 0
clrf SSPCON ; clear SSP control register
movlw 0x31 ; set up spi port, SPI master,
movwf SSPCON ; clk/16, ckp=1 (mode 1,1)
bsf STATUS,RP0 ; set to bank 1
clrf SSPSTAT ; clear SSP status register
movlw 0x80 ; set up spi port, SPI master,
movwf SSPSTAT ; cke = 0 (mode 1,1)
bcf STATUS,RP0 ; set to bank 0
;Dirección de inicio será 00 00 00h
movlw 0x00 ; put starting address 55 in
movwf addrL ; addr for later use
movwf addrM ; addr for later use
movwf addrH ; addr for later use
ini
;Datos a escribir serán d1= AA, d2= BB, d3= CC
movlw 0xaa
movwf d1
movlw 0xbb
movwf d2
movlw 0xcc
movwf d3
;Primero hacemos wren y escribimos el status para habilitar escrituras
bcf PORTC,CS ; clear the chip select (active)
movlw 0x06 ; load WREN sequence
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
bsf PORTC,CS ; set the chip select line
;Escribimos el registro status de la 1024
bcf PORTC,CS ; clear the chip select line
movlw 0x01 ; clear all status register
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movlw 0x00 ; load up zero to send
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
bsf PORTC,CS ; set the chip select line
call RDSR ; hacemos un WIP poll para ver si terminó de escribir
;Hacemos otro wren
bcf PORTC,CS ; clear the chip select (active)
movlw 0x06 ; load WREN sequence
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
bsf PORTC,CS ; set the chip select line
;Y enviamos el comando de escritura
bcf PORTC,CS ; clear the chip select line
movlw 0x02 ; load WRITE sequence
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
;Enviamos direcciónes empezando por el byte mas alto
movf addrH,W ; move the address into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movf addrM,W ; move the address into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movf addrL,W ; move the address into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
;Y grabamos la página con sólo 3 bytes: d1, d2, d3
movf d1,W ; load data AA into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movf d2,W ; load data AA into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movf d3,W ; load data AA into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
bsf PORTC,CS ; set the chip select line
call RDSR ; hacemos un WIP poll para ver si terminó de escribir
;Ahora leemos lo que escribimos en la misma dirección
bcf PORTC,CS ; clear the chip select line
movlw 0x03 ; load READ sequence
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movf addrH,W ; move the address into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movf addrM,W ; move the address into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movf addrL,W ; move the address into w
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
;Y vamos leyendo los bytes en forma sucesiva y los guardamos en la misma variable donde salieron
call output ; call output to read 1 byte
movf rxdata,w
movwf d1
call output ; call output to read 1 byte
movf rxdata,w
movwf d2
call output ; call output to read 1 byte
movf rxdata,w
movwf d3
bsf PORTC,CS ; set the chip select line
;Y luego los mostramos por el puerto D
movf d1,w
movwf PORTD
call DEMORA1s
clrf PORTD
call DEMORA1s
movf d2,w
movwf PORTD
call DEMORA1s
clrf PORTD
call DEMORA1s
movf d3,w
movwf PORTD
call DEMORA1s
clrf PORTD
call DEMORA1s
;Y volvemos
goto ini
;*******************SPI output subroutine***********************
output
movf outbyte,W ; move outbyte into w
movwf SSPBUF ; place data in send buffer
loop1
bsf STATUS,RP0 ; set to bank 1
btfss SSPSTAT,BF ; has data been received?
goto loop1 ; loop if not received yet
bcf STATUS,RP0 ; set to bank 0
movf SSPBUF,W ; empty the receive buffer
movwf rxdata ; put received byte into rxdata
retlw 0 ; return from subroutine
;Demora de 1 segundo
DEMORA1s movlw .22 ; 1 set numero de repeticion (C)
movwf PDel0 ; 1 |
PLoop0 movlw .134 ; 1 set numero de repeticion (B)
movwf PDel1 ; 1 |
PLoop1 movlw .211 ; 1 set numero de repeticion (A)
movwf PDel2 ; 1 |
PLoop2 clrwdt ; 1 clear watchdog
decfsz PDel2, 1 ; 1 + (1) es el tiempo 0 ? (A)
goto PLoop2 ; 2 no, loop
decfsz PDel1, 1 ; 1 + (1) es el tiempo 0 ? (B)
goto PLoop1 ; 2 no, loop
decfsz PDel0, 1 ; 1 + (1) es el tiempo 0 ? (C)
goto PLoop0 ; 2 no, loop
PDelL1 goto PDelL2 ; 2 ciclos delay
PDelL2 clrwdt ; 1 ciclo delay
return ; 2+2 Fin.
RDSR
;Perform data polling (RDSR bit 0)
bcf PORTC,CS ; clear the chip select line
movlw 0x05 ; load RDSR sequence
movwf outbyte ; store in RAM location outbyte
call output ; call the SPI output routine
movlw 0x10 ; give the spi device time to;
movwf loops ; set the WIP bit in the;
wait
decfsz loops,f ; status register before coming;
goto wait ; back and doing data polling;
polling
bcf PORTC,CS ; clear the chip select line
call output ; read the data in status reg.
call output ; read the data in status reg.
bsf PORTC,CS ; set the chip select line
btfsc rxdata,0 ; test the WIP bit in status reg.
goto polling ; WIP set, loop until WIP clear
bsf PORTC,CS ; set the chip select line
return
END