; ------------------------------------------------------------------------------------------------------------- ; EEPROM 93C66 (256x16) Spinelli - 23/06/2010 ; ; SUBROTINAS DE CONTROLE DE LEITURA E GRAVACAO DE MEMORIAS EEPROM 93C66 EM MODO 16 BITS. ; ; A memoria EEPROM 93C66 consiste de um array de 256x16 bits, isto e, comporta 512 bytes de 8 bits porem ; a leitura e escrita se faz em palavras de dois bytes (16 bits), assim, o endereco mais alto da ; memoria e 0xFF (255). ; A rotina EP_put grava sequencialmente ate 255 bytes na EEPROM em cada chamada, enquanto a rotina EP_READ le ; apenas uma palavra de 16 bits (2 bytes) em cada chamada. ; ; ------------------------------------------------------------------------------------------------------------- ; REQUISITOS DE HARDWARE: ; As rotinas foram testadas com frequencias de clock de processador de 4MHz e 20MHz, de onde se deduz que ; qualquer frequencia entre esses dois valores devem ser bem aceitas. Portanto nao ha requisitos especiais ; de hardware. ; ------------------------------------------------------------------------------------------------------------- ; ; DEFINIR NO PROGRAMA OS REGISTRADORES E SIMBOLOS: ; ; Os registradores abaixo sao para uso exclusivo das rotinas de controle da EEPROM e nao devem ser usados ; pelo programador para qualquer finalidade a nao ser aquela especificada nas descricoes das rotinas. ; EP_ADDRESS RES 1 ; endereco corrente na EPROM ; EP_DATA RES 2 ; 16 bits de dados ; EP_ILC RES 1 ; tamanho da instrucao ; EP_ICACHE RES 4 ; cache de instrucao da EPROM ; EP_TMP1 RES 1 ; temp EP_READ, EP_rotate, EP_wait ; EP_TMP2 RES 1 ; temp EP_READ ; EP_TMP3 RES 1 ; temp EP_READ, EP_put ; ; Os simbolos que seguem definem as portas e bits de I/O que serao usados pelas rotinas para controlar ; a memoria EEPROM. Os bits podem ser escolhidos a vontade contanto que pertencam a mesma porta. ; Os valores atribuidos aos simbolos abaixo sao apenas exemplos. ; #define EP_TRIS TRISx ; I/O da EPROM ; #define EP_PORT PORTx ; porta da EPROM ; EP_CS equ 3 ; pino CS da EPROM Chip Select ---> PIC output ; EP_SK equ 2 ; pino SK da EPROM Clock ---> PIC output ; EP_DI equ 1 ; pino DI da EPROM Input ---> PIC output ; EP_DO equ 4 ; pino DO da EPROM Output ---> PIC input ; EP_STABLE equ .200 ; tempo para estabilizar a EEPROM no Chip Select (micro segundos) ; ; ; Pode-se, opcionalmente, acender um LED indicador de estado da EEPROM durante as instrucoes de gravacao. ; Para acender o LED incicador, reserve um bit de uma porta qualquer, definindo-os no programa com os ; simbolos abaixo e conecte o LED nesse pino. Se nao desejar o LED indicador, nao defina os simbolos abaixo ; e automaticamente a rotina nao vai gerar instrucoes para mostrar o status da EPPROM com o LED. ; #define EP_LED PORTy ; porta para o LED de Wait da gravacao (OPCIONAL) ; EP_LEDBIT equ n ; pino para o LED de Wait da gravacao (OPCIONAL) ; ------------------------------------------------------------------------------------------------------------- ; ; DESCRICAO DAS ROTINA ; -------------------- ; ; EP_WEN.......................... Habilita a gravacao na EEPROM ; ENTRADA: nao ha ; SAIDA : EEPROM habilitada para gravacao ; CHAMADA: call EP_WEN ; ; EP_WDS.......................... Desabilita a gravacao na EEPROM ; ENTRADA: nao ha ; SAIDA : EEPROM desabilitada para gravacao ; CHAMADA: call EP_WDS ; ; EP_WRALL........................ Grava um unico valor (16 bits) em toda a EEPROM. ; ENTRADA: EP_DATA deve conter os 16 bits de dados ; SAIDA : toda a EEPROM gravada com o dado especificado ; CHAMADA: movlw "A" ; movwf EP_DATA+0 ; movlw "X" ; movwf EP_DATA+1 ; call EP_WRALL ; ; EP_WRITE........................ Grava um dado (16 bits) num endereco da EEPROM ; ENTRADA: EP_ADDRESS deve conter um endereco (0x00 a 0xFF) ; EP_DATA deve conter os 16 bits de dados ; SAIDA : dado em EP_DATA (16 bits) gravado no endereco EP_ADDRESS ; CHAMADA: movlw 0x20 ; movwf EP_ADDRESS ; movlw "A" ; movwf EP_DATA+0 ; movlw "X" ; movwf EP_DATA+1 ; call EP_WRITE; ; ; EP_READ......................... Le um dado (16 bits) de um endereco da EEPROM ; ENTRADA: EP_ADDRESS deve conter um endereco (0x00 a 0xFF) ; SAIDA : EP_DATA (16 bits) contera o dado lido ; CHAMADA: movlw 0x20 ; movwf EP_ADDRESS ; call EP_READ; ; ; EP_ERAL......................... Apaga todos os dados da EPPROM gravando 0xFF ; ENTRADA: nao ha ; SAIDA : toda a EPPROM apagada (gravada com 0xFF) ; CHAMADA: call EP_ERAL ; ; ; EP_ERASE........................ Apaga um endereco da EEPROM gravando 0xFF ; ENTRADA: EP_ADDRESS deve conter um endereco (0x00 a 0xFF) ; SAIDA : endereco especificado apagado (gravado com 0xFF) ; CHAMADA: movlw 0x20 ; movwf EP_ADDRESS ; call EP_ERASE; ; ; ; EP_PUT.......................... Move bytes da memoria de dados do processador para a EEPROM ; ENTRADA: W.............. contem o numero de bytes a serem movidos ; FSR............ contem o endereco de origem do dado na memoria do processador ; EP_ADDRESSS.... contem o endereco destino do dado na memoria EEPROM ; SAIDA : endereco EP_ADDRESS da EEPROM com o dado movido do processador ; CHAMADA: movlw dado ; endereco do dado na memoria de dados do processador ; movwf FSR ; carrega indexador ; movlw 0x50 ; endereco destino na EEPROM ; movwf EP_ADDRESS ; carrega destino ; movlw n ; numero de bytes a mover ; call EP_PUT ; chama a rotina de movimentacao ; ; ; ------------------------------------------------------------------------------------------------------------- ; ---------------------------------------------------------------------------------- ; EEPROM - Write All ; ; Grava um dado de 16 bits em toda a memoria. ; ; Cod Oper.......... b'10001' ; Instrucao......... 10001xxxxxxDDDDDDDDDDDDDDDD ; Tamanho........... 27 bits ; ENTRADA........... EP_DATA+0 e EP_DATA+1 devem conter o dado de 16 bits ; SAIDA............. toda a EEPROM sera gravada com o dado fornecido ; ---------------------------------------------------------------------------------- EP_OPWRALL equ b'10001000' ; codigo de operacao da instrucao WRITE ENABLE EP_WRALL call EP_clcache ; limpa o cache de instrucao movlw EP_OPWRALL ; CACHE+0 CACHE+1 CACHE+2 CACHE+3 movwf EP_ICACHE+1 ; 00000000 10001eee eeexxxxx xxxxxxxx movlw .3 ; deslocamento call EP_rotate ; no final teremos: ; 00000100 01eeeeee xxxxxxxx xxxxxxxx movf EP_DATA+0,w ; movwf EP_ICACHE+2 ; 00000100 01eeeeee DDDDDDDD xxxxxxxx movf EP_DATA+1,w ; movwf EP_ICACHE+3 ; 00000100 01eeeeee DDDDDDDD DDDDDDDD movlw .5 ; deslocamento para alinhar start bit no MSB de CACHE+0 call EP_rotate ; no final teremos: ; 10001eee eeeDDDDD DDDDDDDD DDDxxxxx movlw .27 ; tamanho da instrucao movwf EP_ILC ; estabelece o tamanho da instrucao call EP_EXEC ; executa a instrucao call EP_wait ; aguarda a EPROM responder "ready" return ; ---------------------------------------------------------------------------------- ; EEPROM - Write Disable Instruction ; ; Desabilita gravacao na EEPROM. ; ; Cod Oper.......... b'10000' ; Instrucao......... 10000XXXXXX ; Tamanho........... 11 bits ; ENTRADA........... Nao ha ; SAIDA............. desabilita gravacao na EEPROM ; ---------------------------------------------------------------------------------- EP_OPWDS equ b'10000000' ; codigo de operacao da instrucao EP_WDS movlw EP_OPWDS ; carrega codigo da operacao call EP_BUILD ; constroi e executa a instrucao return ; ---------------------------------------------------------------------------------- ; EEPROM - ERASE ALL ; ; Limpa toda a memoria EEPROM. ; ; Cod Oper.......... b'10010' ; Instrucao......... 10010XXXXXX ; Tamanho........... 11 bits ; ENTRADA........... Nao ha ; SAIDA............. limpa toda a memoria EEPROM ; ---------------------------------------------------------------------------------- EP_OPERAL equ b'10010000' ; codigo de operacao da instrucao EP_ERAL movlw EP_OPERAL ; carrega codigo da operacao call EP_BUILD ; constroi e executa a instrucao return ; ---------------------------------------------------------------------------------- ; EEPROM - Write Enable Instruction ; ; Habilita gravacao na EEPROM. ; ; Cod Oper.......... b'10011' ; Instrucao......... 10011XXXXXX ; Tamanho........... 11 bits ; ENTRADA........... Nao ha ; SAIDA............. habilita gravacao na EEPROM ; ---------------------------------------------------------------------------------- EP_OPWEN equ b'10011000' ; codigo de operacao da instrucao EP_WEN movlw EP_OPWEN ; carrega codigo da operacao (WEN) call EP_BUILD ; constroi e executa a instrucao return ; ---------------------------------------------------------------------------------- ; CONSTROI E EXECUTA UMA DAS INSTRUCOES DE 11 BITS: ; WEN, WDS e ERAL ; ---------------------------------------------------------------------------------- EP_BUILD call EP_clcache ; limpa o cache de instrucao movwf EP_ICACHE+0 ; ICACHE=10011000 00000000 00000000 00000000 movlw .11 ; tamanho da instrucao movwf EP_ILC ; estabelece o tamanho da instrucao call EP_EXEC ; executa a instrucao call EP_wait ; aguarda a EPROM responder "ready" return ; ---------------------------------------------------------------------------------- ; EPROM - Erase ; ; Apaga uma localizacao da memoria gravando 0xFF. ; ; Cod Oper.......... b'111' ; Instrucao......... 111eeeeeeee ; Tamanho........... 11 bits ; ENTRADA........... EP_ADDRESS deve conter o endereco a ser apagado ; SAIDA............. Endereco EP_ADDRESS apagado ; ---------------------------------------------------------------------------------- EP_OPERASE equ b'00000111' ; codigo de operacao da instrucao ; CACHE+0 CACHE+1 CACHE+2 CACHE+3 EP_ERASE call EP_clcache ; 00000000 00000000 00000000 00000000 movlw EP_OPERASE ; movwf EP_ICACHE+0 ; 00000111 00000000 00000000 00000000 movf EP_ADDRESS,w ; movwf EP_ICACHE+1 ; 00000111 eeeeeeee 00000000 00000000 movlw .5 ; deslocamento call EP_rotate ; alinha instrucao em CACHE+0 ; 111eeeee eee00000 00000000 00000000 movlw .11 ; tamanho da instrucao movwf EP_ILC ; estabelece tamanho da instrucao call EP_EXEC ; executa a instrucao call EP_wait ; aguarda a EPROM responder "ready" return ; ---------------------------------------------------------------------------------- ; EPROM - Write Instruction ; ; Grava 16 bits de dados na EPROM no endereco especificado em EP_ADDRESS. ; Antes de executar esta instrucao deve-se executar a instrucao WRITE ENABLE. ; ; Cod Oper.......... b'101" ; Instrucao......... 101EEEEE.EEEDDDDD.DDDDxxxx ; Tamanho........... 27 bits ; ENTRADA........... EP_ADDRESS deve conter o endereco ; EP_DATA+0 e EP_DATA+1 devm conter os 16 bits de dados ; SAIDA............. 16 bits gravados na EEPROM ; ---------------------------------------------------------------------------------- EP_OPWRITE equ b'00000101' ; codigo de operacao da instrucao WRITE ; CACHE+0 CACHE+1 CACHE+2 CACHE+3 EP_WRITE call EP_clcache ; 00000000 00000000 00000000 00000000 movlw EP_OPWRITE ; W = 00000101 movwf EP_ICACHE+0 ; 00000101 00000000 00000000 00000000 movf EP_ADDRESS,w ; obtem o endereco movwf EP_ICACHE+1 ; 00000101 EEEEEEEE 00000000 00000000 movf EP_DATA+0,w ; primeiros 8 bits dos dados movwf EP_ICACHE+2 ; 00000101 EEEEEEEE DDDDDDDD 00000000 movf EP_DATA+1,w ; proximos 8 bits dos dados movwf EP_ICACHE+3 ; 00000101 EEEEEEEE DDDDDDDD DDDDDDDD movlw .5 ; mover 5 bits para alinhar a instrucao em EP_ICACHE+0 call EP_rotate ; ao final temos: ; 101EEEEE EEEDDDDD DDDDDDDD DDDxxxxx ( 27 bits ) movlw .27 ; tamanho da instrucao movwf EP_ILC ; estabelece tamanho da instrucao call EP_EXEC ; executa a instrucao call EP_wait ; aguarda a EPROM responder "ready" return ; ---------------------------------------------------------------------------------- ; EEPROM - READ Instruction ; ; Le 16 bits de dados num dado endereco. ; ; Cod Oper.......... b'110' ; Instrucao......... b'110EEEEEEEE' ; Tamanho........... 11 bits ; ; ENTRADA........... EP_ADDRESS deve conter o endereco entre 0x00 e 0xFF ; SAIDA............. EP_DATA+0 e EP_DATA+1 conterao os 16 bits lidos ; ---------------------------------------------------------------------------------- EP_OPREAD equ b'00000110' ; codigo de operacao b'110' EP_READ call EP_reset ; CS=SK=DI=0 call EP_clcache ; limpa o cache movlw EP_OPREAD ; CACHE+0 CACHE+1 CACHE+2 CACHE+3 movwf EP_ICACHE+0 ; xxxxx1l0 xxxxxxxx xxxxxxxx xxxxxxxx movf EP_ADDRESS,w ; obtem o endereco movwf EP_ICACHE+1 ; xxxxxl10 EEEEEEEE xxxxxxxx xxxxxxxx movlw .5 ; desloca 5 bits para alinhar em ICACHE+0 call EP_rotate ; ao final temos: ; 110EEEEE EEExxxxx xxxxxxxx xxxxxxxx ; LEITURA DOS DADOS movlw .11 ; tamanho da instrucao movwf EP_ILC ; estabelece tamanho da instrucao call EP_EXEC ; envia a instrucao ; movlw .16 ; numero de bits a serem lidos movwf EP_TMP1 ; salva no contador de bits EP_READ2 goto $+1 ; espera estabilizar goto $+1 ; espera estabilizar bsf EP_PORT,EP_SK ; levanta o clock goto $+1 ; espera estabilizar goto $+1 ; espera estabilizar movf EP_PORT,w ; le a porta movwf EP_TMP2 ; salva em tmp2 movlw EP_DO ; numero do bit de dado addlw .1 ; soma 1 para deslocar ate cair no Carry movwf EP_TMP3 ; salva em tmp3 bcf EP_PORT,EP_SK ; abaixa o clock EP_READ3 rrf EP_TMP2,f ; EP_TMP2[LSB] -> Carry decfsz EP_TMP3,f ; conta bits goto EP_READ3 ; na ainda nao caiu no Carry, continua deslocando rlf EP_DATA+1,f ; Carry -> EP_DATA+1(LSB) EP_DATA+1(MSB) -> Carry rlf EP_DATA+0,f ; Carry -> EP_DATA+0(LSB) EP_DATA+0(MSB) -> Carry(lixo) decfsz EP_TMP1,f ; contabiliza goto EP_READ2 ; loop ate o ultimo bit bcf EP_PORT,EP_CS ; abaixa o Chip Select return ; ---------------------------------------------------------------------------------- ; EP_put - move bytes da memoria de dados do processador para a EEPROM ; ; ENTRADA: W contem o numero de bytes a serem movidos ; FSR contem o endereco de origem do dado na memoria do processador ; EP_ADDRESSS contem o endereco destino do dado na memoria EEPROM ; ; SAIDA : endereco EP_ADDRESS da EEPROM com o dado movido do processador ; ; CHAMADA: movlw dado ; endereco do dado na memoria de dados do processador ; movwf FSR ; carrega indexador ; movlw 0x50 ; endereco destino na EEPROM ; movwf EP_ADDRESS ; carrega destino ; movlw n ; numero de bytes a mover ; call EP_put ; chama a rotina de movimentacao ; ; ; ---------------------------------------------------------------------------------- EP_put ; simbolo mantido somente para compatibilidade EP_PUT movwf EP_TMP3 ; salva tamanho do dado EP_put_1 movf INDF,w ; pega o dado na memoria do processador movwf EP_DATA+0 ; move dado para registrado de saida movlw 0x00 ; 0x00 movwf EP_DATA+1 ; move para registrador decfsz EP_TMP3,f ; verifica se terminou goto EP_put_2 ; se nao terminou, pega o proximo dado goto EP_put_3 ; senao vai gravar o ultimo EP_put_2 incf FSR,f ; proximo byte na memoria do processador movf INDF,w ; pega o dado movwf EP_DATA+1 ; move dado para registrado de saida call EP_WRITE ; grava dado no enredeco EP_ADDRESS incf EP_ADDRESS,f ; proximo endereco na EEPROM incf FSR,f ; proximo endereco na memoria do processador decfsz EP_TMP3,f goto EP_put_1 ; continua gravando... return EP_put_3 call EP_WRITE ; grava a ultima palavra na EEPROM return ; fim ; ---------------------------------------------------------------------------------- ; EPROM - SUB-ROTINA INTERNA *** (nao deve ser usada pelo programador) ; Executa uma instrucao na EPROM ; Move, para a EPROM, o numero de bits especificados em EP_ILC da instrucao ; que se encontra em EP_ICACHE. ; Ao entrar nesta rotina os pino CS, DI e SK serao levados a zero. ; ---------------------------------------------------------------------------------- EP_EXEC call EP_reset ; coloca EPROM no estado inicial bsf EP_PORT,EP_CS ; levanta o chip select movlw EP_STABLE ; tempo de estabilizacao call delay_us ; aguarda... EP_EXEC_1 bcf EP_PORT,EP_DI ; move zero para o bit de dado movlw .1 ; deslocamento call EP_rotate ; roda bits do cache - EP_ICACHE+0[MSB] -> Carry btfsc STATUS,C ; se Carry == 0, entao EP_DI = 0, senao bsf EP_PORT,EP_DI ; EP_DI = 1 bsf EP_PORT,EP_SK ; levanta i sinal de clock goto $+1 ; espera estabilizar goto $+1 ; espera estabilizar bcf EP_PORT,EP_SK ; abaixa o sinal de clock decfsz EP_ILC,f ; contabiliza bits da instrucao ja enviados goto EP_EXEC_1 ; vai mover o proximo bit da instrucao return ; ---------------------------------------------------------------------------------- ; EPROM - SUB-ROTINA INTERNA *** (nao deve ser usada pelo programador) ; Aguarda a EPROM responder "ready", ou seja, Do = 1. ; Apos a instrucao ser enviada para a EPROM, ela abaixa pino DO enquanto ; a instrucao esta sendo executada e somente apos a conclusao da instrucao ; o pino DO sera colocado em 1. O tempo Tcs deve ser no minimo 1uS segundo ; o datasheet do chip 93C66. ; ---------------------------------------------------------------------------------- EP_wait ifdef EP_LED bcf EP_LED,EP_LEDBIT ; apaga o LED de ocupado endif goto $+1 ; espera estabilizar goto $+1 ; espera estabilizar bcf EP_PORT,EP_CS ; abaixa o chip select apos enviar instrucao goto $+1 ; espera estabilizar goto $+1 ; espera estabilizar bsf EP_PORT,EP_CS ; levanta o chip select para testar status goto $+1 ; espera estabilizar goto $+1 ; espera estabilizar ; if __FAMILIA == 16 bsf STATUS,RP0 bsf EP_TRIS,EP_DO bcf STATUS,RP0 endif if __FAMILIA == 18 bsf EP_TRIS,EP_DO endif EP_wait0 movf EP_PORT,w ; le a porta movwf EP_TMP1 ; salva em TMP1 btfsc EP_TMP1,EP_DO ; testa o status da EPROM goto EP_wait1 ; se liberou sai desta rotina, senao, ifdef EP_LED bsf EP_LED,EP_LEDBIT ; se ocupado, acende LED de chip ocupado endif goto EP_wait0 ; continua testando o status EP_wait1 bcf EP_PORT,EP_CS ; abaixa o chip select - fim do ciclo ifdef EP_LED bcf EP_LED,EP_LEDBIT ; apaga o LED de ocupado endif return ; ---------------------------------------------------------------------------------- ; EPROM - SUB-ROTINA INTERNA *** (nao deve ser usada pelo programador) ; Rotaciona bits do cache para formacao da instrucao ; ---------------------------------------------------------------------------------- EP_rotate movwf EP_TMP1 rlf EP_ICACHE+3,f rlf EP_ICACHE+2,f rlf EP_ICACHE+1,f rlf EP_ICACHE+0,f decfsz EP_TMP1,f goto $-5 return ; ---------------------------------------------------------------------------------- ; EPROM - SUB-ROTINA INTERNA *** (nao deve ser usada pelo programador) ; Limpeza do cache de instrucao ; ---------------------------------------------------------------------------------- EP_clcache clrf EP_ICACHE+0 clrf EP_ICACHE+1 clrf EP_ICACHE+2 clrf EP_ICACHE+3 return ; ---------------------------------------------------------------------------------- ; EPROM - SUB-ROTINA INTERNA *** (nao deve ser usada pelo programador) ; Os pino CS, DI e SK serao levados ao nivel baixo e mantidos assim ; por 100uS. ; ---------------------------------------------------------------------------------- EP_reset bcf EP_PORT,EP_CS ; abaixa o CS bcf EP_PORT,EP_SK ; abaixa o SK bcf EP_PORT,EP_DI ; abaixa o DI movlw EP_STABLE ; tempo de estabilizacao call delay_us ; aguarda uns micro segundos com CS e SK abaixados return