En éste post mostrare un par de ejemplos de como usar el bus i2c para escribir y leer datos en una memoria EEPROM serial (24C16).
La memoria 24C16 tiene una capacidad de 2048 bytes agrupados en 8 páginas de 256 bytes cada una.
Todos los esclavos del bus i2c tienen una dirección la cual les permite ser seleccionados; en el caso de estas memorias seriales la dirección es en parte configurable o fija, esto dependerá del fabricante. En el siguiente gráfico se muestra dos memorias de fabricantes distintos.
Programas
Programas
La primera es una memoria de ATMEL, la cual permite configurar parte de la dirección mediante los pines A2, A1 y A0; los bits B2B1B0 son usados para seleccionar la pagina de la dentro de la memoria.
La otra es una memoria de FAIRCHILD, ésta ya trae parte de dirección fija(1010), los bit A2A1A0 permiten seleccionar la pagina de la memoria a la cual se accederá.
La velocidad del reloj para esto dispositivos se indica en sus hojas de datos, en los ejemplos usaremos 100KHz. Para configurar dicha velocidad se usa la siguiente formula, la cual se puede encontrar en el manual de del uC que se usara, yo la obtuve del manual del ATmega8.
La forma de escribir datos es la siguiente:
Se inicia la transmisión con un “START”, luego se selecciona el esclavo “DEVICE ADDRESS” en modo de escritura “0”, después del “ACK” enviado por el esclavo se enviara la dirección donde se escribirá “WORD ADDRESS”, por último se envía el dato a escribir. Hay que cada ciclo de escritura tiene una duración, éste tiempo dependerá del dispositivo.
Se inicia la transmisión con un “START”, luego se selecciona el esclavo “DEVICE ADDRESS” en modo de escritura “0”, después del “ACK” enviado por el esclavo se enviara la dirección donde se leerá “WORD ADDRESS”, nuevamente se envía un “START” o también conocido como “RESTART”, por último se lee el dato.
Bueno, como ya es costumbre mostrare las macros que usare en estos ejemplos.
Ahora el un sencillo ejemplo se escritura y lectura de algunos datos en una EEPROM.
El ejemplo no hace otra cosa que escribir algunos datos a partir de la dirección 0x05 de la pagina 0, luego los leerá.
El circuito es el siguiente:
Con el uso de debuger i2c se puede ver la transferencia de datos:
El final la memoria debe quedar así:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
El segundo ejemplo consiste en enviarle al ATmega8, por el uart, un comando para que éste lea o escriba en la EEPROM.
‘W’+PAGINA+DIRECCIÓN+DATO se usara para escribir en la EEPROM.
‘R’+PAGINA+DIRECCIÓN se usara para leer en la EEPROM.
Por ejemplo si se envía por el uart ‘W’ 0x06 0x66 0x99 el uC escribirá en la dirección 0x66 de la pagina 6 el dato 0x99. Y si enviamos ‘R’ 0x03 0x79 estaremos leyendo el datos que esta guardado en la posición 0x79 de la pagina 3.
Agregaremos algunas rutinas al archivo RUTINAS_I2C.asm:
Las rutinas usadas en el uart son las siguientes:
El programa principal es mostrado a continuación.
Ahora les mostrare un vídeo con el funcionamiento del programa anterior.
En el vídeo se escribe 0x99 en la dirección 0x66 de la página 6 (dirección absoluta en la memoria es 6*0x100 + 0x66 = 0x666), luego éste dato es leído. También se escribe 0x58 en la posición 0x67 de la misma página.
Excelente, y tienes algun ejemplo para leer o escribir en memorias RAM?. Gracias!!!
ResponderEliminar¿Te refieres a RAM seriales?. Las únicas RAM que con las que he trabajado son las RAM spi de Microchip (23K256).
ResponderEliminarTambién las FRAM(RAM Ferromacticas) que usan el protocolo I2C, su funcionamiento es idéntico a las EEPROM I2C pero con un número mucho mayor de ciclos de lectura/escritura y sin tener retardos en la escritura.
Ahora no tengo ejemplos sobre eso, pero su funcionamiento es similar entre si. Envío de dirección del esclavo(I2C) ó selección del mismo(SPI), más el comando de escritura/lectura, luego envío de la dirección donde se escribirá/leerá y por ultimo enviar el dato(cuando se escribe) y esperar el dato(cuando se lee).
Para que sirve el retraso de 10ms en TX_BUS_I2C antes del retorno?
ResponderEliminaratte: Jahir
El tiempo de escritura en una EEPROM es muy lento, según las hojas de datos es de 10ms como máximo, es por ello que le pongo ese retardo.
ResponderEliminarTermine el programa pero no me funciono =( otra cosa que note esque no configuras ningun puerto porque? yo he usado el UART anteriormente pero siempre le configure el TX como salida.
ResponderEliminarDe necesitar config las i/o tengo que cambiar manualmente SDA si ocupo transmitir o reconocer?
Gracias de cualquier forma =)
atte:Jahir
Cuando habilitas algún periférico éste toma posesión de los pines que usa, es por ello que al habilitar la transmisión y la recepción ya no es necesario poner Tx como salida ó Rx como entrada.
ResponderEliminarDime cual de los dos ejemplos estas probando ?.. Dame un poco mas de información para poder ayudarte.
Bueno pues yo estoy usando nada mas el primero de I2C y los estoy mostrando con leds lo que tenga R16 al terminar cada RX_I2C_ pero ademas no estoy usando la memoria que tienes en el ejemplo sino un ADC el MCP3221(es de 12bits). El que tengo supuestamente me da el codigo 1001 101 asi que mando Tx la direccion y 0 de lectura ($9A) y luego un Rx ack seguido de un Rx nack y stop
ResponderEliminarLEER:
START_I2C
TX_I2C $9A ;Direccion del ADC
RX_I2C_ACK
OUT PORTB,R16
RX_I2C_NACK
OUT PORTD,R16
STOP_I2C
delay_ms(10)
RJMP LEER
mañana voy a buscar el AT24C16 para probarlo como en tu ejemplo y ver si lo que tengo mal es la direccion o falta de configuracion del adc o si copie mal el programa xD
Aqui dejo el programa
https://skydrive.live.com/redir.aspx?cid=0b35f0905045c622&resid=B35F0905045C622!333
atte:Jahir
Hola Jahir, el 99.9% de tu ejemplo esta bien, pero tienes que enviar 0x9B en lugar de 0x9A. No lo digo yo, el manual dice eso.
ResponderEliminarEsto es parte del manual.
When set to a ‘1’, a read operation is selected. When set to a ‘0’, a write operation is selected. There are no writable registers on the MCP3221. Therefore, this bit must be set to a ’1’ in order to initiate a conversion.
(facepalm) jaja estaba casi seguro de haber leido lo contrario, pero ya modificando el dato si funciono :D gracias por la ayuda todo esto me es muy util, casi diria que deberias hacer un libro ;) (yo lo compraria)
ResponderEliminaruhm y si quiero ponerlo como esclavo solo tengo que modificar los registros de config? o tambien tengo que hacer otras macros?
atte:Jahir
mmm.. nunca he usado un uC como esclavo, pero en este caso tienes que:
ResponderEliminar- Darle una dirección al uC.
- Tienes que testear(o habilitar su interrupción) el bit TWINT del registro TWCR.
- Cada vez que "TWINT=1" tienes que leer los bits de estado(TWS) del registro TWSR para determinar que es lo que ocurrió, en base a eso serán tus respuestas.
Hola,
ResponderEliminarDisculpa que salga un poco del tema. Soy de trujillo y quiero saber si en lima hay memorias ram seriales spi del tipo 23k256.
Saludos.
Muito bom artigo, continue.
ResponderEliminarAlvaroLuiz2@yahoo.com.br
São Paulo - Brasil
http:/alvieletronica.blogspot.com
Hola amigo, muy útil tu ejemplo. Un favor, crees que podria compartirnos tu codigo de la macro DELAY_MS . Gracias de antemano =)
ResponderEliminarEstimado. Hay un post con las rutinas del DELAY.
Eliminarhttp://avrperu.blogspot.com/2011/03/delaymsms-y-delayusus-para-cualquier.html