empezando con el I2C sdcc
2 participantes
Página 1 de 1.
empezando con el I2C sdcc
Hola de vuelta al foro, estoy interesado en realizar algunas aplicaciones con el protocolo I2C para lectura de memorias eeprom, sensores con ese protocolo, etc. Encontre una libreria que realizó Felixls que me pareció bastante buena. Pero para ser sinceros no se como ocupar este código al 100%.
Tengo dudas de como realizar la escritura y lectura a las memorias, en este caso tengo una 24LC22A de 2Kbits y un 24LC1025 de 1024Kbits.
Me gustaria saber como puedo guardar más de un solo dato en el programa principal. Este código más o menos me orienta pero no se con exactitud como implementarlo.
alguien me puede explicar esto:
addr&0xF0
addr&0x0F
Saludos cordiales!!!
- Código:
#include <pic/pic16f877a.h>
#define SDA RC4
#define SCL RC3
#define TSDA TRISC4
#define TSCL TRISC3
void i2c_delay(void)
{
delay_us(133);
}
void SDALow()
{
TSDA = 0;
SDA = 0;
}
void SDAHigh()
{
TSDA = 1;
}
void SCLLow()
{
TSCL = 0;
SCL = 0;
}
void SCLHigh()
{
TSCL = 1;
while(SCL==0);
}
void i2c_clock(void)
{
i2c_delay();
SCLHigh(); /* Start clock */
i2c_delay();
SCLLow(); /* Clear SCL */
i2c_delay();
}
void i2c_start(void)
{
if(SCL)
SCLLow(); /* Clear SCL */
SDAHigh(); /* Set SDA */
SCLHigh(); /* Set SCL */
i2c_delay();
SDALow(); /* Clear SDA */
i2c_delay();
SCLLow(); /* Clear SCL */
i2c_delay();
}
void i2c_stop(void)
{
if(SCL)
SCLLow(); /* Clear SCL */
SDALow(); /* Clear SDA */
SCLHigh(); /* Set SCL */
i2c_delay();
SDAHigh(); /* Set SDA */
i2c_delay();
}
unsigned char i2c_write(unsigned char dat)
{
unsigned char data_bit;
unsigned char i;
for(i=0;i<8;i++) /* For loop 8 time(send data 1 byte) */
{
data_bit = dat & 0x80; /* Filter MSB bit keep to data_bit */
if (data_bit==0)
SDALow(); /* Send data_bit to SDA */
else
SDAHigh();
dat = dat<<1;
SCLHigh();
i2c_delay();
SCLLow();
i2c_delay();
}
SDAHigh();
SCLHigh();
i2c_delay();
data_bit = SDA; /* Check acknowledge */
SCLLow(); /* Clear SCL */
i2c_delay();
return data_bit; /* If send_bit = 0 i2c is valid */
}
unsigned char i2c_read(void)
{
unsigned char i, dat;
dat = 0x00;
SDAHigh();
for(i=0;i<8;i++) /* For loop read data 1 byte */
{
SCLHigh(); /* Set SCL */
dat = dat<<1;
if (SDA)
dat = dat | 0x01; // if port pin = 1, set LSB (bit position)
else
dat = dat & 0xFE; // else port pin = ,clear LSB (bit position)
SCLLow();
i2c_delay();
}
return dat;
}
void i2c_ack()
{
SDALow(); /* Clear SDA */
i2c_delay();
i2c_clock(); /* Call for send data to i2c bus */
}
void i2c_noack()
{
SDAHigh(); /* Set SDA */
i2c_delay();
i2c_clock(); /* Call for send data to i2c bus */
}
Tengo dudas de como realizar la escritura y lectura a las memorias, en este caso tengo una 24LC22A de 2Kbits y un 24LC1025 de 1024Kbits.
Me gustaria saber como puedo guardar más de un solo dato en el programa principal. Este código más o menos me orienta pero no se con exactitud como implementarlo.
- Código:
http://memoria24xx256.c
unsigned char EEPROM_get(unsigned int addr)
{
unsigned char dat;
i2c_start(); /* Start i2c bus */
i2c_write(EEPROMS_ID); /* Connect to EEPROM */
i2c_write(addr&0xF0); /* Request RAM address (Hight byte) */
i2c_write(addr&0x0F); /* Request RAM address (Low byte) */
i2c_start(); /* Start i2c bus */
i2c_write(EEPROMS_ID+1);/* Connect to EEPROM for Read */
dat = i2c_read(); /* Receive data */
i2c_noack();
i2c_stop(); /* Stop i2c bus */
return dat;
}
void EEPROM_set(unsigned int addr, unsigned char val)
{
i2c_start();
i2c_write(EEPROMS_ID);/* Connect to EEPROM */
i2c_write(addr&0xF0); /* Request RAM address (Hight byte) */
i2c_write(addr&0x0F); /* Request RAM address (Low byte) */
i2c_write(val); /* Write sec on RAM specified address */
i2c_stop(); /* Stop i2c bus */
}
alguien me puede explicar esto:
addr&0xF0
addr&0x0F
Saludos cordiales!!!
tony8a87- Participante Activo
- Mensajes : 34
Fecha de inscripción : 10/08/2010
Re: empezando con el I2C sdcc
La addr en mi programa principal con que valor empieza y donde termina??
Empieza en 0 y termina según lo grande que sea la memoria, por ejemplo una memoria de 2k:
Decimal:0000 a 2048
Hexadecimal: 0x008 a 0x800
Binario: 000000000000 a 100000000000
(el conversor de base me ha sido util )
Aquí hay algo que no me cuadra, addr se supone que es un Int de 16 bits y debería de ser:alguien me puede explicar esto:
addr&0xF0
addr&0x0F
addr&0xFF00 ( y coger sólo byte alto )
addr&0x00FF
O no lo he entendido...
En cualquier caso:
addr&0xF0 pone a 0 los 4 bits bajos de addr
addr&0xF0 pone a 0 los 4 bits altos de addr
Por ejemplo si addr = 01101100
addr&0xF0
ahora addr = 01100000
Saludos.
Re: empezando con el I2C sdcc
Holo aun no he podido simular a la perfeción y creo que existe un problema en esta parte del codigo
Porque se recorre un bit, adjunte una imagen. Para ejemplificar envio en la dirección 0xF1=1111 0001 pero solo alcanza a enviar 0x78=0111 1000 el ultimo bit lo coloca en Nack y el bit que le corresponde a Nack lo coloca en otra palabra más.
Imagen:
http://www.mediafire.com/i/?6eff15nw6wp6d75
Espero contar con su ayuda para arreglar esto.
Saludos cordiales!!!
- Código:
unsigned char i2c_write(unsigned char dat)
{
unsigned char data_bit;
unsigned char i;
for(i=0;i<8;i++) /* For loop 8 time(send data 1 byte) */
{
data_bit = dat & 0x80; /* Filter MSB bit keep to data_bit */
if (data_bit==0)
SDALow(); /* Send data_bit to SDA */
else
SDAHigh();
dat = dat<<1;
SCLHigh();
i2c_delay();
SCLLow();
i2c_delay();
}
SDAHigh();
SCLHigh();
i2c_delay();
data_bit = SDA; /* Check acknowledge */
SCLLow(); /* Clear SCL */
i2c_delay();
return data_bit; /* If send_bit = 0 i2c is valid */
}
Porque se recorre un bit, adjunte una imagen. Para ejemplificar envio en la dirección 0xF1=1111 0001 pero solo alcanza a enviar 0x78=0111 1000 el ultimo bit lo coloca en Nack y el bit que le corresponde a Nack lo coloca en otra palabra más.
Imagen:
http://www.mediafire.com/i/?6eff15nw6wp6d75
Espero contar con su ayuda para arreglar esto.
Saludos cordiales!!!
tony8a87- Participante Activo
- Mensajes : 34
Fecha de inscripción : 10/08/2010
Re: empezando con el I2C sdcc
Hola no encontre solución con el anterior código, por lo cual segui buscando y viendo otros ejemplos con el uso de Master Synchronous Serial Port (MSSP) Module. La cual ya puedo leer y escribir en mi 24LC22A. Los códigos fueron obtenidos de los ejemplos de iearobotics.
- Código:
/* ----------------------------------------------------------------------- */
/* Template source file generated by piklab */
#include <pic16f877a.h>
#include <delay.h>
/* ----------------------------------------------------------------------- */
/* Configuration bits: adapt to your setup and needs */
typedef unsigned int word;
word at 0x2007 CONFIG = _XT_OSC & _WDT_ON & _PWRTE_OFF & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _DEBUG_OFF & _CP_OFF;
void i2c_SendAck();
void i2c_SendNack();
unsigned char i2c_CheckACK();
void i2c_SendStop();
void i2c_SendStart();
void i2c_WaitMSSP();
unsigned char i2c_MSSP_Status();
void i2c_SendRStart();
unsigned char i2c_ReadByte();
void i2c_SendByte(unsigned char dato);
void i2c_fail();
void i2c_configure();
unsigned char i2c_write_byte(unsigned char control_byte, unsigned char address, unsigned char dato);
unsigned char i2c_read_byte(unsigned char control_byte, unsigned char address, unsigned char *dato);
void main() {
unsigned char ret;
unsigned char dato;
PORTB=0;
TRISB=0;
while(1){
//-- Configurar el I2C como master
delay_ms(100);
i2c_configure();
delay_ms(10);
i2c_write_byte(0xA0, 0x7F, 0x0F);
delay_ms(10);
ret=i2c_read_byte(0xA0, 0x7F, &dato);
if (ret==1) {
PORTB = dato;
delay_ms(500);}
}
}
/****************************************
* FUNCIONES DE BAJO NIVEL DEL I2C *
****************************************/
// Envia Ack
// SDA = 0
void i2c_SendAck(){
ACKDT = 0; // Establece un ACK
ACKEN = 1; // Lo envia
}
// Envia Nack para finalizar la recepecion
// SDA = 1
void i2c_SendNack(){
ACKDT = 1; // Establece un NACK
ACKEN = 1; // Lo envia
}
// verifica ACK
// Mira si en el 9 pulso de reloj (SCL en estado a 1) la señal SDA está a 0
unsigned char i2c_CheckACK(){
if ( ACKSTAT == 0 ) {
return 0; // correcto (lo he recibido )
} else {
return 1; // incorrecto (no lo he recibido)
}
}
// Envia la condicion de STOP
// Libera el BUS I2C, SDA y SCL a nivel alto
// SDA=1 cuando SCL=1.
void i2c_SendStop(){
PEN = 1; // send stop bit
}
// Envia la condicion de START
// Inicializa el Bus I2C, SCL y SDA a nivel bajo
// Estando SCL=1 pone SDA=0, luego pone SCL=0
void i2c_SendStart(){
SEN = 1; // send start bit
}
// Espera a que el I2C reciba algun evento
void i2c_WaitMSSP(){
while (SSPIF == 0); // Espera evento
SSPIF=0; // Limpia FLAG
}
// Espera a que el I2C reciba algun evento
unsigned char i2c_MSSP_Status(){
return SSPIF;
}
// Repeated start from master
// Queremos transmitir más datos pero sin dejar el BUS, es decir
// sin mandar previamente un STOP. O por ejemplo si queremos mandar un STOP y seguidamente un
// START para que ningún otro dispositivo ocupe la línea usaremos esto.
void i2c_SendRStart(){
RSEN=1;
}
// Leer Byte por el I2C
// Devuelve byte leido
unsigned char i2c_ReadByte(){
RCEN=1; // Activar el RCEN
i2c_WaitMSSP();
return SSPBUF;
}
// Envia un Dato por el Bus I2C
// Entrada el dato a enviar
void i2c_SendByte(unsigned char dato){
SSPBUF=dato;
}
// Fallo en el I2C
void i2c_fail(){
i2c_SendStop();
i2c_WaitMSSP();
}
/**************************************
* FUNCIONES DE ALTO NIVEL del I2C *
**************************************/
/* Configurar I2C
Configuramos el I2C como Master
y a una velocidad de 1Mhz */
void i2c_configure(){
// configuramos SCL y SDA como pines de entrada
TRISC=TRISC | 0x18; // 1 entrada / 0 salida
SSPSTAT=0x0;
SSPSTAT=SSPSTAT | 0x80; // SMP=1 Slew rate disable for 100Kh @@@
// CKE=0 (modo maestro I2C) y UA=0 (7 bits
SSPCON=0x08; // I2C master mode (uso la formula del reloj con SSPAD)
SSPCON=SSPCON | 0x20; // enable I2C SSPEN=1
SSPCON2=0x00; // no se usa por ahora
// velocidad = FOSC / ( 4 * (sspad + 1) )
// Fosc=20Mhz
SSPADD=49; // 49->100Khz @@@
//SSPADD=24; // 24 -> 400khz @@@
// Limpia Flags de eventos
SSPIF=0; //Limpia flag de eventos SSP
}
// manda un byte al dispositivo i2c
unsigned char i2c_write_byte(unsigned char control_byte, unsigned char address, unsigned char dato){
// 1º Envia Bit de Start
i2c_SendStart();
i2c_WaitMSSP();
// 2º Envio la direccion del modulo
i2c_SendByte(control_byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 3º mando el registro sobre el que voy a actuar
i2c_SendByte(address);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 4º mando el dato
i2c_SendByte(dato);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 6º termino el envio
i2c_SendStop();
i2c_WaitMSSP();
return 1; // Byte mandado correctamente
}
// Lee 1 byte1 del dispositivo i2c
// El dato leido lo devuelve por el parametro dato
unsigned char i2c_read_byte(unsigned char control_byte, unsigned char address, unsigned char *dato){
// 1º Envia Bit de Start
i2c_SendStart();
i2c_WaitMSSP();
// 2º Envio la direccion del modulo
i2c_SendByte(control_byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 3º mando el registro sobre el que voy a actuar
i2c_SendByte(address);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 4º Repeated start
i2c_SendRStart();
i2c_WaitMSSP();
// 4º mando direccion indicando lectura
i2c_SendByte(control_byte | 1);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 5º leo el byte
*dato=i2c_ReadByte();
// 6º Mando NACK
i2c_SendNack();
i2c_WaitMSSP();
// Mando el Stop
i2c_SendStop();
i2c_WaitMSSP();
return 1; // Lectura correcta
}
tony8a87- Participante Activo
- Mensajes : 34
Fecha de inscripción : 10/08/2010
Re: empezando con el I2C sdcc
Ya pude grabar y leer en el 24LC1025 pero tengo un ligero inconveniente. El 24LC1025 tiene dos bloques uno va de 0x0000-0xFFFF y el otro va de 0x10000-0x1FFFF, no hay problemas con el primer bloque, para el segundo bloque debo modificar mi direción de control por 0xA8 si fuera un solo chip y poner el pin 3 en 5Vcc, si programo esto por separado no hay problema, pero si quiero grabar y leer en cada bloque en la dirección 0x0000 a 0x1FFFF el problema es que no lee el segundo bloque, solo lee el primer bloque.
modifique en estos códigos para enviar la dirección de 16bits
Favor de apoyarme a solucionar este problema, me es complicado simular esto porque proteus no tiene el 24LC1025 y basarme en el I2C que tiene es complicado, pero en la realidad si veo sus resultados.
Saludos cordiales!!
- Código:
void main() {
unsigned char ret;
unsigned char dato;
PORTB=0;
TRISB=0;
while(1){
//-- Configurar el I2C como master
delay_ms(100);
i2c_configure();
delay_ms(10);
i2c_write_byte(0xA0, 0xFFFF, 0x55);
delay_ms(10);
ret=i2c_read_byte(0xA0, 0xFFFF, &dato);
if (ret==1) {
PORTB = dato;
delay_ms(200);}
PORTB =0;
delay_ms(10);
i2c_write_byte(0xA8, 0xFFFF, 0x50);
delay_ms(10);
ret=i2c_read_byte(0xA8, 0xFFFF, &dato);
if (ret==1) {
PORTB = dato;
delay_ms(100);}
}
}
modifique en estos códigos para enviar la dirección de 16bits
- Código:
unsigned char i2c_write_byte(unsigned char control_byte, unsigned int address, unsigned char dato){
unsigned char High_Byte=0;
unsigned char Low_Byte=0;
// 1º Envia Bit de Start
i2c_SendStart();
i2c_WaitMSSP();
// 2º Envio la direccion del modulo
i2c_SendByte(control_byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
High_Byte=(address&0xFF00)>>8;
Low_Byte=address&0x00FF;
// 3º mando el registro sobre el que voy a actuar
i2c_SendByte(High_Byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
///////////
i2c_SendByte(Low_Byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 4º mando el dato
i2c_SendByte(dato);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 6º termino el envio
i2c_SendStop();
i2c_WaitMSSP();
return 1; // Byte mandado correctamente
}
// Lee 1 byte1 del dispositivo i2c
// El dato leido lo devuelve por el parametro dato
unsigned char i2c_read_byte(unsigned char control_byte, unsigned int address, unsigned char *dato){
unsigned char High_Byte=0;
unsigned char Low_Byte=0;
// 1º Envia Bit de Start
i2c_SendStart();
i2c_WaitMSSP();
// 2º Envio la direccion del modulo
i2c_SendByte(control_byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
High_Byte=(address&0xFF00)>>8;
Low_Byte=address&0x00FF;
// 3º mando el registro sobre el que voy a actuar
i2c_SendByte(High_Byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
////////////////
i2c_SendByte(Low_Byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 4º Repeated start
i2c_SendRStart();
i2c_WaitMSSP();
// 4º mando direccion indicando lectura
i2c_SendByte(control_byte | 1);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 5º leo el byte
*dato=i2c_ReadByte();
// 6º Mando NACK
i2c_SendNack();
i2c_WaitMSSP();
// Mando el Stop
i2c_SendStop();
i2c_WaitMSSP();
return 1; // Lectura correcta
}
Favor de apoyarme a solucionar este problema, me es complicado simular esto porque proteus no tiene el 24LC1025 y basarme en el I2C que tiene es complicado, pero en la realidad si veo sus resultados.
Saludos cordiales!!
tony8a87- Participante Activo
- Mensajes : 34
Fecha de inscripción : 10/08/2010
Re: empezando con el I2C sdcc
Hola Tony8a87, gracias por ir compartiendo tus avances.
No entiendo bien a que problema te refieres, según lo veo ya lo tienes funcionando, para leer/escribir en el bloque bajo pones a 0 el bit 3 de control_byte (0xA0) y para seleccionar el bloque alto lo pones a 1 (0xA8).
Puedes poner un caso práctico o un ejemplo de donde tendrías el problema??
Saludos.
No entiendo bien a que problema te refieres, según lo veo ya lo tienes funcionando, para leer/escribir en el bloque bajo pones a 0 el bit 3 de control_byte (0xA0) y para seleccionar el bloque alto lo pones a 1 (0xA8).
Puedes poner un caso práctico o un ejemplo de donde tendrías el problema??
Saludos.
Re: empezando con el I2C sdcc
Estimados compañeros he solucionado para el 24LC1025 este es mi código como realiza un barrido a todos los regristros tanto bloque 1 y 2, no puedo asegurar que funciono al 100% pues llege a ver hasta el dato 5000. Lo que proseguire es relizar un pequeño teclador y poder teclear el valor, el registro y si es bloque 1 o 2. Espero me puedan ofrecer algunos comentarios.
Saludos cordiales!!
- Código:
/* ----------------------------------------------------------------------- */
/* Template source file generated by piklab */
#include <pic16f877a.h>
#include <delay.h>
#include <i2c.h>
//***************LCD Definiciones*****
#define RS RD0
#define RW RD1
#define EN RD2
#define lcdPortD
#include <pic/lcd4.h>
/* ----------------------------------------------------------------------- */
/* Configuration bits: adapt to your setup and needs */
typedef unsigned int word;
word at 0x2007 CONFIG = _XT_OSC & _WDT_OFF & _PWRTE_OFF & _BODEN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _DEBUG_OFF & _CP_OFF;
#define NUMBER_OF_DIGITS 16 /* space for NUMBER_OF_DIGITS + '\0' */
void uitoa(unsigned long value, char* string, int radix){
unsigned char index, i;
index = NUMBER_OF_DIGITS;
i = 0;
do {
string[--index] = '0' + (value % radix);
if ( string[index] > '9') string[index] += 'A' - ':'; // continue with A, B,..
value /= radix;
} while (value != 0);
do {
string[i++] = string[index++];
} while ( index < NUMBER_OF_DIGITS );
string[i] = 0; // string terminator
}
void itoa(long value, char* string, int radix){
if (value < 0 && radix == 10) {
*string++ = '-';
uitoa(-value, string, radix);
}
else {
uitoa(value, string, radix);
}
}
unsigned char i2c_write_byte(unsigned char control_byte, unsigned int address, unsigned char dato);
unsigned char i2c_read_byte(unsigned char control_byte, unsigned int address, unsigned char *dato);
void main() {
unsigned char ret;
unsigned char dato;
unsigned long i=0;
unsigned char bloque_1=0xA0;
unsigned char bloque_2=0xA8;
char direccion[20]="";
PORTB=0;
TRISB=0;
PORTD=0;
TRISD=0;
lcd_iniciar();
lcd_posicion(1,1);
lcd_imprimir("INICIAR LCD");
delay_ms(100);
lcd_posicion(1,2);
lcd_imprimir("***COMPLETADA***");
delay_ms(100);
lcd_borrar();
i2c_configure();
lcd_posicion(1,1);
lcd_imprimir("CONFIGURAR I2C");
delay_ms(100);
lcd_posicion(1,2);
lcd_imprimir("***COMPLETADA***");
delay_ms(100);
lcd_borrar();
while(1){
for(i=0;i<=131071;i++){
itoa(i,direccion,10); //conversión de int a string
if(i<=65535){
i2c_write_byte(bloque_1, i, 0x3);
delay_ms(10);
ret=i2c_read_byte(bloque_1, i, &dato);
if (ret==1) {
PORTB = dato;
lcd_comando(linea1); //iniciar LCD en posición 1,1
lcd_imprimir(direccion); //imprimir en el LCD
lcd_posicion(1,2); //dirección en 1,2
lcd_imprimir("BLOQUE 1");
delay_ms(50);
PORTB =0;}
}
else{
RB7=1;
i2c_write_byte(bloque_2, (i-65536), 0x2);
delay_ms(10);
ret=i2c_read_byte(bloque_2, (i-65536), &dato);
if (ret==1) {
PORTB = dato;
lcd_comando(linea1); //iniciar LCD en posición 1,1
lcd_imprimir(direccion); //imprimir en el LCD
lcd_posicion(1,2); //dirección en 1,2
lcd_imprimir("BLOQUE 2");
delay_ms(50);
PORTB =0;}
}
}
RB7=0;
lcd_borrar();
}
}
// manda un byte al dispositivo i2c
unsigned char i2c_write_byte(unsigned char control_byte, unsigned int address, unsigned char dato){
unsigned char High_Byte=0;
unsigned char Low_Byte=0;
// 1º Envia Bit de Start
i2c_SendStart();
i2c_WaitMSSP();
// 2º Envio la direccion del modulo
i2c_SendByte(control_byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
High_Byte=(address&0xFF00)>>8;
Low_Byte=address&0x00FF;
// 3º mando el registro sobre el que voy a actuar
i2c_SendByte(High_Byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
///////////
i2c_SendByte(Low_Byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 4º mando el dato
i2c_SendByte(dato);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 6º termino el envio
i2c_SendStop();
i2c_WaitMSSP();
return 1; // Byte mandado correctamente
}
// Lee 1 byte1 del dispositivo i2c
// El dato leido lo devuelve por el parametro dato
unsigned char i2c_read_byte(unsigned char control_byte, unsigned int address, unsigned char *dato){
unsigned char High_Byte=0;
unsigned char Low_Byte=0;
// 1º Envia Bit de Start
i2c_SendStart();
i2c_WaitMSSP();
// 2º Envio la direccion del modulo
i2c_SendByte(control_byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
High_Byte=(address&0xFF00)>>8;
Low_Byte=address&0x00FF;
// 3º mando el registro sobre el que voy a actuar
i2c_SendByte(High_Byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
////////////////
i2c_SendByte(Low_Byte);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 4º Repeated start
i2c_SendRStart();
i2c_WaitMSSP();
// 4º mando direccion indicando lectura
i2c_SendByte(control_byte | 1);
i2c_WaitMSSP();
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
// 5º leo el byte
*dato=i2c_ReadByte();
// 6º Mando NACK
i2c_SendNack();
i2c_WaitMSSP();
// Mando el Stop
i2c_SendStop();
i2c_WaitMSSP();
return 1; // Lectura correcta
}
Saludos cordiales!!
tony8a87- Participante Activo
- Mensajes : 34
Fecha de inscripción : 10/08/2010
Re: empezando con el I2C sdcc
Hola de nuevo.
Creo que ya entiendo a lo que te referías en el post anterior.
Una solución para el tema de direccionar los bloques podría ser usar un long para almacenar la dirección y pasar el bit 16 al bit 3 de control_byte:
Hace tiempo que no uso SDCC y no estoy seguro de que la sintaxis sea correcta, pero la idea es esa.
Creo que ya entiendo a lo que te referías en el post anterior.
Una solución para el tema de direccionar los bloques podría ser usar un long para almacenar la dirección y pasar el bit 16 al bit 3 de control_byte:
- Código:
// manda un byte al dispositivo i2c
unsigned char i2c_write_byte( unsigned long address, unsigned char dato )
{
unsigned char control_byte = 0xA0;
control_byte |= address,16<<3;
// Resto del codigo
}
Hace tiempo que no uso SDCC y no estoy seguro de que la sintaxis sea correcta, pero la idea es esa.
Re: empezando con el I2C sdcc
Hola no entendi del todo la explicación pero lo que si me di cuenta es que el protocolo solicita realizar envios de 8bits y colocar Acknowledge entre cada uno. Adjunto una impresión de pantalla.
http://www.mediafire.com/i/?vezm4db0x0b5x8z
http://www.mediafire.com/i/?vezm4db0x0b5x8z
tony8a87- Participante Activo
- Mensajes : 34
Fecha de inscripción : 10/08/2010
Re: empezando con el I2C sdcc
Lo que te proponía es simplificar el direccionamiento:
Tu eeprom tiene 128 KBytes, para direccionar todas esas posiciones de memoria necesitas direcciones de 17 bits: 2^17 = 131072 bytes = 128 KBytes.
Pero el protocolo usa 2 bytes para la dirección, osea 16 bits, con lo que se pueden direccionar 64 KBytes.
Para solucionar el acceso al resto de la memoria y no tener que usar otro byte sólo para enviar el 17º bit, lo que hace es poner ese bit en la palabra de control. Digamos que la dirección está dividida en 2 partes: los 16 primeros bits (bits 0 : 15) que se ponen en un unsigned int y el bit 16 que se pone en control byte.
Cómo necesitas 17 bits para una dirección completa, lo que te proponía es usar un unsigned long (32 bits):
unsigned char i2c_write_byte( unsigned long address, unsigned char dato )
y luego poner el bit 16 de address en el bit 3 de config_word:
unsigned char control_byte = 0xA0;
control_byte |= address,16<<3;
De manera que cuando el bit 16 de address está a 0 (address<65535) entonces control_byte=0xA0, y cuando está a 1 entonces control_byte=0xA8.
Entonces ahora puedes hacer esto:
Para leer tendrías que poner a 1 el bit 0 de control_byte:
Si quieres dejarlo preparado para conectar 4 eeprom de esas y usarlo como si fuera un espacio continuo de 512 KB, tendrías que hacer lo mismo con los bits 17 y 18 de la dirección y pasarlos a los bits 1 y 2 de control_byte:
Respecto al ACK, este lo envía el dispositivo esclavo, en este caso la eeprom para confirmar que ha recibido el dato:
Tu eeprom tiene 128 KBytes, para direccionar todas esas posiciones de memoria necesitas direcciones de 17 bits: 2^17 = 131072 bytes = 128 KBytes.
Pero el protocolo usa 2 bytes para la dirección, osea 16 bits, con lo que se pueden direccionar 64 KBytes.
Para solucionar el acceso al resto de la memoria y no tener que usar otro byte sólo para enviar el 17º bit, lo que hace es poner ese bit en la palabra de control. Digamos que la dirección está dividida en 2 partes: los 16 primeros bits (bits 0 : 15) que se ponen en un unsigned int y el bit 16 que se pone en control byte.
Cómo necesitas 17 bits para una dirección completa, lo que te proponía es usar un unsigned long (32 bits):
unsigned char i2c_write_byte( unsigned long address, unsigned char dato )
y luego poner el bit 16 de address en el bit 3 de config_word:
unsigned char control_byte = 0xA0;
control_byte |= address,16<<3;
De manera que cuando el bit 16 de address está a 0 (address<65535) entonces control_byte=0xA0, y cuando está a 1 entonces control_byte=0xA8.
Entonces ahora puedes hacer esto:
- Código:
unsigned long i = 0;
for(i=0;i<=131071;i++){
i2c_write_byte(i, 0x3);
}
Para leer tendrías que poner a 1 el bit 0 de control_byte:
- Código:
// Lee un byte del dispositivo i2c
unsigned char i2c_read_byte( unsigned long address, unsigned char *dato )
{
unsigned char control_byte = 0xA1;
control_byte |= address,16<<3;
// Resto del codigo
}
Si quieres dejarlo preparado para conectar 4 eeprom de esas y usarlo como si fuera un espacio continuo de 512 KB, tendrías que hacer lo mismo con los bits 17 y 18 de la dirección y pasarlos a los bits 1 y 2 de control_byte:
- Código:
// manda un byte del dispositivo i2c
unsigned char i2c_write_byte( unsigned long address, unsigned char dato )
{
unsigned char control_byte = 0xA0;
control_byte |= address,16<<3;
control_byte |= address,18<<2;
control_byte |= address,17<<1;
// Resto del codigo
}
Respecto al ACK, este lo envía el dispositivo esclavo, en este caso la eeprom para confirmar que ha recibido el dato:
- Código:
if (i2c_CheckACK()!=0) {
i2c_fail();
return 0; // Ha habido un error, salgo de la rutina
}
Última edición por Pikitin el Dom 9 Oct 2011 - 20:23, editado 1 vez
Re: empezando con el I2C sdcc
Tenía un error en el código de los bits 17 y 18 de address, ya he editado el mensaje, pero sería así:
control_byte |= address,18<<2;
control_byte |= address,17<<1;
Otra cosa es que el pin A2 de la eeprom lo tienes que poner a Vcc (+5V) para activar el chip, en la imagen que pusiste hace un tiempo de la simulación en proteus, lo tienes a masa, con lo que creo que estaría desactivado.
control_byte |= address,18<<2;
control_byte |= address,17<<1;
Otra cosa es que el pin A2 de la eeprom lo tienes que poner a Vcc (+5V) para activar el chip, en la imagen que pusiste hace un tiempo de la simulación en proteus, lo tienes a masa, con lo que creo que estaría desactivado.
Re: empezando con el I2C sdcc
Si pues, me di a la tarea de seguir investigando más sobre esta memoria, tienes razón me deje llevar por deducciones mias y como esta el diagrama de escritura y lectura del datasheet.
1.- El pin A2 se conecta a 5Vcc
2.- Es posible enviar una cadena donde incluya los 16bits.
3.- El maximo número de memorias es 4 (00,01,10,11).
Muchas gracias, realizare estos cambios y comentare mis resultados.
1.- El pin A2 se conecta a 5Vcc
2.- Es posible enviar una cadena donde incluya los 16bits.
3.- El maximo número de memorias es 4 (00,01,10,11).
Muchas gracias, realizare estos cambios y comentare mis resultados.
tony8a87- Participante Activo
- Mensajes : 34
Fecha de inscripción : 10/08/2010
Temas similares
» SDCC - NF....
» SDCC USB libreria
» Uso de punteros en SDCC
» Equivalencias CCS a SDCC
» SDCC PIC16F84A
» SDCC USB libreria
» Uso de punteros en SDCC
» Equivalencias CCS a SDCC
» SDCC PIC16F84A
Página 1 de 1.
Permisos de este foro:
No puedes responder a temas en este foro.