TODOPIC
Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: toxete en 06 de Noviembre de 2006, 19:54:15
-
Hola a todos de nuevo.
Vereis estoy utilizando un pic 18f6722 el cual dispone de dos UART's y dos MI2C compatible/SPI. Las dos comunicaciones UART las tengo ocupadas al igual que las dos SPI y tengo que utilizar la comunicacion I2C. Me gustaria saber si puedo utilizar el I2C por otros pines del PIC indicandolo en el CCS a la hora de compilarlo.
Gracias!!!
-
si se puede, simplemente tienes q cargar una libreria o un codigo q haga toda la gestion de una comunicacion I2C, por ejemplo sabes bien q el 16F84A no tiene modulos SPI ni I2C ni UART, pero hay programas en ASM q gestionan esos modulos, lo mismo sucede en el C, es cuestion de buscar y pegarlas o incluirlas a tu programa. exitos :-/, ah y puedes seleccionar cualquier pin del pic para usar.
-
Dentro de la carpeta de .h dentro del C18 hay una libreria llamada sw_i2c.h que te soluciona el problema. Está pensada para comunicar mediante i2c un pic y una e2prom, pero bueno, modificándola un poco te sirve para lo que quieras, y montas un i2c sin el módulo i2c.
Salud!!!!
-
Hola. La verdad que ayer hice mi primer programa de i2c y en base a esta consulta me puse a implementarlo en un 16f84 y no tuve que cambiar nada más que los pines y anda igual. (al menos en proteus)
#include <16f84A.H> /* tipo de PIC */
#use delay( clock = 4000000 ) /* reloj de 4 MHz */
#byte puerto_b = 06 /* dirección del puerto B */
#use I2C(master,sda=PIN_A1 ,scl=PIN_A0 ,NOFORCE_SW)
int r2,r1=0;
void main( void )
{
SET_TRIS_B( 0x00 );
puerto_b=0;
r2=0; r1=0;
// ############### BORRO LA MEMORIA (32 PAGINAS DE 8 BYTES)###############
while(r1!=32)
{
i2c_start(); // condición de inicio
i2c_write(0xa0); // dirección del dispositivo
i2c_write(8*(r1++)); // dirección del registro
for(r2=0;r2<8;r2++) i2c_write(0);
i2c_stop(); // condición de parada
delay_ms(5);
}
// ############### ESCRIBO UNA PAGINA #################################
i2c_start();
i2c_write(0xa0); // dirección del dispositivo
i2c_write(0x30); // dirección del registro
for(r1=1;r1<9;r1++) i2c_write(r1); // envío de datos al dispositivo
i2c_stop();
delay_ms(5);
// ############### LEO EL DATO DEL BYTE Nº 35 ############################
i2c_start();
i2c_write(0xa0); // dirección del dispositivo
i2c_write(0x35); // dirección del registro
i2c_start();
i2c_write(0xa1); // dirección del dispositivo + 1
r1=i2c_read();
i2c_stop();
delay_ms(5);
// ############### MUESTRO EL DATO POR EL PUERTO B #######################
puerto_b=r1;
}
-
No es de ortiva pero hay que agregar que cualquier periferico implementado por metodo de BIT-BANGING (por software y uso de pines de I/O) utilizan bastante tiempo de micro para el polling de las lineas que va en detrimento del rendimiento para la funcionalidad final del usuario.
Siempre es mejor usar todos los perifericos posibles antes de usar dicho metodo (aunque ande bien)
:-) :-)Saludos :-) :-)
-
Nada de ortiva. Es verdad y está bien que lo aclares. Esto, creo que es para determinados casos en que.
1º) No disponemos del hard i2c
2º) No se está "apretado" con la velocidad ni memoria del programa. Ya que sólo esto consume casi el 30% de la rom del 16f84.
Por ej. si quiero leer un dato, como ser una temperatura, e ir guardándolo en un dispositivo i2c cada minuto. Yo lo usaría.
Por el contrario si necesito velocidad si o si, o no tengo memoria para hacer esto. Tengo que conseguirme un pic mayor que tenga un i2c disponible.
Me parece, no sé que opinan, o si hay otra forma que no estoy considerando
-
Otra consideración que me olvidé es que por ahí alguien me comentó que es más simple el SPI; por lo que supongo que hacerlo por soft sería más simple tambien, pero yo nunca lo he usado.
De esa forma podrías liberar un puerto de tu pic para implementar i2c y para un SPI usas soft.
-
Opino que hacer por software lo que hace el hardware, siempre es más tedioso , requiere de métodos de polling de alguna forma y quitan recursos al pic.
Son recursos viables técnicamente y se debería analizar cada caso, para ver qué conviene en cada situación.
Coincido con que es más simple hacer una SPI por software
De todas formas acá hay algo que no me queda claro.
toxete ¿porque usas los 2 puertos spi ? ¿Porque no compartes directamente el data out de cada uno? ¿acaso alguno de los IC SPI que usas tiene salida de baja impedancia? sino, no veo razón por la cual no compartas los pines.
Es que ésta es una de las ventajas de usar precisamente el SPI, que solamente debes agregar un pin para CS de cada integrado, pero el resto de los pines (si se ponen en alta impedancia al no estar habilitado el IC) se reutilizan.
Saludos
-
Otra consideración que me olvidé es que por ahí alguien me comentó que es más simple el SPI; por lo que supongo que hacerlo por soft sería más simple tambien, pero yo nunca lo he usado.
De esa forma podrías liberar un puerto de tu pic para implementar i2c y para un SPI usas soft.
Te ayudo con esta, tanto los PIC16F como los PIC18F no tienen perifericos I2C realmente "nativos" son en realidad perifericos SPI "adaptados" para funcionar como I2C.
Vas a ver por ejemplo que tanto los 16 como los 18 tienen I2C esclavo pero el 18F solo tiene posibilidad de ser master.
Y si te fijas en un DSPIC vas a ver un I2C TOTALMENTE dedicado (no comparte registros ni nada con el SPI, esta hecho de cero)
Si vamos a los protocolos, tanto SPI como I2C son robustos, pero en un PIC 16F y 18F, de seguro no es lo mejor el I2C.
Otra cosa, el I2C anda en un estandar de 470Kbps mientras que el SPI lo podes llevar tranquilo al maximo en baudios posible.
-
Otra cosa, en un I2C trabajas con lineas PULL UP mientras que en SPI no.
Esto significa que la velocidad tambien depende de la polarizacion de las lineas (a menor resistencia mayor tiempo de crecimiento y mas velocidad pero tambien mas consumo)
Saludos
-
toxete ¿porque usas los 2 puertos spi ? ¿Porque no compartes directamente el data out de cada uno? ¿acaso alguno de los IC SPI que usas tiene salida de baja impedancia? sino, no veo razón por la cual no compartas los pines.
Es que ésta es una de las ventajas de usar precisamente el SPI, que solamente debes agregar un pin para CS de cada integrado, pero el resto de los pines (si se ponen en alta impedancia al no estar habilitado el IC) se reutilizan.
Saludos
Lo mismo opino, si no necesitas realizar trafico en paralelo para ambos dispositivos (o que los otros dispositivos sean los maestros), podes compartir las lineas y activar cada micro con el CS. De esa manera si no lo activas se pone en alta impedancia y compartis el canal
-
hola,
Si hay algún genio del I2C al otro lado del foro espero que me ayude:
Estoy realizando un proyecto con el I2C y he conseguido comunicar perfectamente un master y un slave. Es decir, el Master TRANSMITE y el Slave RECIBE.......o bien el Master RECIBE y el Slave TRANSMITE. Tambien un Master con dos expansores PCF8574, y también un Master y una EEPROM 24LC256 y un PCF8574. Los micros utilizados son pic16f876
De momento los programas están en ensamblador (.asm). Aqui os dejo las rutinas de enviar_I2C y recibir_I2C (funcionan a la perfección)
Mi problema se presenta cuando quiero establecer comunicacion entre tres microcontroladores pic 16f876, un Master y dos Slaves.
El programa es muy simple, el Master lee de un Slave1 (SLAVE TRANSMITE) su puerto B y el byte obtenido lo manda por el BUS al Slave2 (SLAVE RECIBE el byte del BUS) y escribe el resultado en el puerto B.
Después de la primera rutina de lectura (que funciona correctamente mas que probada) el Master al pasar por la rutina de escritura pierde definitivamente el control del BUS. El problema debe estar en la trama serie START, 1º ADDRESS, ACK, DATA, ACK, RESTART, 2º ADDRESS, ACK, DATA, ACK, ......en el cambio a la 2º ADDRESS se produce el error y el Master pierde definitivamente el control del BUS.
Aqui adjunto las rutinas que funcionan,
;**********************************************************************
;***SUBRUTINA PARA TRANSMITIR DATOS1 EN MODO MASTER DEL I2C
Envia_i2c
BCF STATUS,RP0 ; Restore Bank0 ................DEN BUS ÜBERNEHMEN
BCF PIR1,SSPIF ; Clear the interrupt flag before RX
BSF STATUS,RP0 ; SSPCON2: is in Bank1
BCF STATUS,RP1
BSF SSPCON2,SEN ; envia bit START
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; START finalizado?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF ; Clear the interrupt flag before RX
MOVF DIREC,W ;...............................DIE ADRESSE SENDEN
MOVWF SSPBUF ; carga direccion
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF ; Clear the interrupt flag before RX
MOVF Dato,W ; carga dato....................DIE DATEN SENDEN
MOVWF SSPBUF
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no espera
BCF PIR1,SSPIF
BSF STATUS,RP0 ; Restore Bank1................DEN BUS WIEDER FREIGEBEN
BCF STATUS,RP1
BSF SSPCON2,PEN ; Envia bit de stop
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; STOP finalizado?
GOTO $-1 ; no espera
BCF PIR1,SSPIF
RETURN
;************************************************************************
;SUBRUTINA PARA RECIBIR DATOS1 EN MODO MASTER DEL I2C
;************************************************************************
Recibe_i2c
BCF STATUS,RP0 ; Restore Bank0......... DEN BUS ÜBERNEHMEN
BCF PIR1,SSPIF
BSF STATUS,RP0 ; Restore Bank1
BCF STATUS,RP1
BSF SSPCON2,SEN ; envia bit START
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; START finalizado?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
movf DirSlave,W ;Dirección esclavo
iorlw b'00000001' ;con orden de lectura
; MOVF DIREC,W ; ........................DIE ADRESSE SENDEN
MOVWF SSPBUF ; carga direccion
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
BSF STATUS,RP0 ; Restore Bank1
BCF STATUS,RP1
BSF SSPCON2,RCEN ; activa modo receptor....DATEN EMPFANG EINSCHALTEN
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; ACK recibido?
GOTO $-1 ; no, espera
BCF PIR1,SSPIF
MOVF SSPBUF,W ; carga dato
MOVWF MensajeIn
; BSF STATUS,RP0 ; Restore Bank1...........EIN ANDERES BYTE SOLL GELESEN WERDEN
; BCF STATUS,RP1
; BSF SSPCON2,ACKEN ; Genera ACK
; BCF STATUS,RP0 ; Restore Bank0
BSF STATUS,RP0 ; Restore Bank1...........DEN BUS WIEDER FREIGEBEN
BCF STATUS,RP1
BSF SSPCON2,PEN ; Envia bit de stop
BCF STATUS,RP0 ; Restore Bank0
BTFSS PIR1,SSPIF ; STOP finalizado?
GOTO $-1 ; no espera
BCF PIR1,SSPIF
RETURN
Las direcciones empleadas para ambos Slaves son:
Slave ESCRITURA: b'01111000'
Slave LECTURA: b'01111100'
Espero que alguien me pueda ayudar,
saludos...
-
wallen no soy un genio del i2c pero por ahi te pueda echar una mano.
Si te fijas en la norma, el address para ESCRITURA y para LECTURA deben ser idénticos, solo diferir en el último bit (que será 0 en caso de escritura y 1 en caso de lectura).
Mäs allá de eso, tu pretendes chequear el ACKNOWLEDGE del esclavo mediante la verificación del flag SSPIF. EL flag simplemente te dirá si pudo o no tomar el bus, si pudo o no enviar el dato pero no te dirá si el esclavo lo recibió.
Para ello hay un bit que si mal no recuerdo se llama ACKSTAT donde puedes verificar el estado del acknowledge. Lo debes verificar al enviar el dato, es en ese registro donde queda almacenada esa información.
Otra pregunta , ¿estás seguro que el problema lo tienes del lado del master? ¿que hay del código de los esclavos?
-
No me pude poner a ver el codigo pero posteo un handler de I2C esclavo y despues el Master.
//Definicion de estados del I2C SMP|CKE|DA|STOP|START|RW|UA|BF
#define RISL0_STATE_WRITE_ADRESS 0B00001001
#define RISL0_STATE_READ_ADRESS 0B00001100
#define RISL0_STATE_READ_ADRESS_2 0B00001101
#define RISL0_STATE_WRITE_DATA 0B00101001
#define RISL0_STATE_READ_DATA 0B00101100
#define R_I2C_S_L0_STAT()\
{if (SSPIE&&SSPIF)\
{switch(SSPSTAT&RISL0_STATE_MASK)\
{case RISL0_STATE_WRITE_ADRESS: R_I2C_S_L0_VAR.DUMMY=SSPBUF;R_I2C_S_L0_VAR.ADRESS_DATA=1;R_I2C_S_L0_VAR.FREE=0;CKP=1;break;\
case RISL0_STATE_READ_ADRESS_2:R_I2C_S_L0_VAR.DUMMY=SSPBUF;\
case RISL0_STATE_READ_ADRESS:\
case RISL0_STATE_READ_DATA: R_I2C_S_L0_VAR.WATCHDOG=0;while(BF&&(R_I2C_S_L0_VAR.WATCHDOG++<RISL0_TOUT_MAX1));if (R_I2C_S_L0_VAR.WATCHDOG>=RISL0_TOUT_MAX1){SSPEN=0;R_I2C_S_L0_VAR.FREE=1;SSPEN=1;break;};\
R_I2C_S_L0_VAR.WATCHDOG=0;do{WCOL=0;SSPBUF=R_I2C_S_L0_VAR.MEM.DATA[R_I2C_S_L0_VAR.MEM.INDEX];}while(WCOL&&(R_I2C_S_L0_VAR.WATCHDOG++<RISL0_TOUT_MAX2));CKP=1;R_I2C_S_L0_VAR.MEM.INDEX++;break;\
case RISL0_STATE_WRITE_DATA: if(R_I2C_S_L0_VAR.ADRESS_DATA)\
{R_I2C_S_L0_VAR.MEM.INDEX=SSPBUF;R_I2C_S_L0_VAR.ADRESS_DATA=0;}\
else {R_I2C_S_L0_VAR.MEM.DATA[R_I2C_S_L0_VAR.MEM.INDEX++]=SSPBUF;R_I2C_S_L0_VAR.WRITE=1;}\
CKP=1;\
break;\
default: if (WCOL){WCOL=0;};if(SSPOV){SSPOV=0;};\
R_I2C_S_L0_VAR.DUMMY=SSPBUF;\
R_I2C_S_L0_VAR.FREE=1;R_I2C_S_L0_VAR.ALIVE++;\
if(R_I2C_S_L0_VAR.WRITE){R_I2C_S_L0_VAR.WRITE=0;OSSignalSem(R_I2C_S_L0_WRITE_E);}\
break;\
}\
if(R_I2C_S_L0_VAR.MEM.INDEX>(R_I2C_S_L0_VAR.MEM.SIZE-1)){R_I2C_S_L0_VAR.MEM.INDEX=R_I2C_S_L0_VAR.MEM.SIZE-1;}\
SSPIF=0;\
}\
}
La macro R_I2C_S_L0_STAT() se llama en interrupciones, tiene algunas cosas que son solo para la funcionalidad con el RTOS (eventos) y para que funcione como una memoria del tipo 24LCXX
-
Tiene algunas cositas mas que parecera que no tienen sentido como hacer "CKP=1" en donde supuestamente no se requiere liberar el clock, pero es para tener en cuenta los PIC18FXX20 que no funcionaban correctamente.
-
Aca un manejador de I2C MASTER por interrupciones:
//Valores para I2C
#define SSPMode(val) SSPCON1 &=0xF0; SSPCON1|=(val & 0xf)
#define MASTER_FIRM 0B1011
#define MASTER_CLK 0B1000
//Definiciones de tareas
#define T_IDLE 0
#define T_WRITE 1
#define T_READ 2
#define T_WRITE_R 3
#define T_READ_R 4
//Definiciones de pasos
#define S_IDLE 0
#define S_START 1
#define S_RESTART 2
#define S_STOP 3
#define S_WRITE_ADRESS_W 4
#define S_WRITE_ADRESS_R 5
#define S_WRITE_DEV_ADRE 6
#define S_WRITE_DATA 7
#define S_READ_DATA 8
#define S_ACK_MS 9
#define S_NACK_MS 10
#define S_DONE 11
#define S_ERROR 12
//Definiciones de errores
#define E_NO_ERROR 0
#define E_W_ADRESS_NACK 1
#define E_R_ADRESS_NACK 2
#define E_DATA_NACK 3
#define E_DEV_ADRESS_NACK 4
#define E_DEV_TIMEOUT 5
//Definicion de la I2C
#define SCL RC3
#define SDA RC4
#define SCL_TRIS TRISC3
#define SDA_TRIS TRISC4
//Variables de I2C
char I2C_TASK_TIMEOUT;
char I2C_TASK,I2C_TASK_STEP,I2C_TASK_ERROR;
char I2C_TASK_ADRESS,I2C_TASK_DEV_ADRESS,*I2C_TASK_DATA,I2C_TASK_NUM;
#define I2C_TASK_TIMEOUT_MAX 30 //tiempo de espera para que conteste
/******************************************************************************************/
// Rutinas I2C MASTER para dispositivos con HW I2C manejado por interrupciones
/******************************************************************************************/
void I2C_init (void);
void I2C_Interrupt (void);
void I2C_WRITE (char I2C_ADRESS,char *I2C_DATA,char I2C_NUM);
void I2C_READ (char I2C_ADRESS,char *I2C_DATA,char I2C_NUM);
void I2C_WRITE_ROM (char I2C_ADRESS,char I2C_DEV_ADRESS,char *I2C_DATA,char I2C_NUM);
void I2C_READ_ROM (char I2C_ADRESS,char I2C_DEV_ADRESS,char *I2C_DATA,char I2C_NUM);
/******************************************************************************************/
void I2C_WRITE (char I2C_ADRESS,char *I2C_DATA,char I2C_NUM)
{I2C_TASK_STEP=S_START; /*Posiciono en paso START*/;
I2C_TASK_TIMEOUT=I2C_TASK_TIMEOUT_MAX; /*Inicializo el TIMEOUT*/
I2C_TASK=T_WRITE;I2C_TASK_ADRESS=I2C_ADRESS;I2C_TASK_DATA=I2C_DATA;
I2C_TASK_NUM=I2C_NUM;SEN=1;/*Genero un Start*/;}
/******************************************************************************************/
void I2C_READ (char I2C_ADRESS,char *I2C_DATA,char I2C_NUM)
{I2C_TASK_STEP=S_START;/*Posiciono en paso START*/;
I2C_TASK_TIMEOUT=I2C_TASK_TIMEOUT_MAX; /*Inicializo el TIMEOUT*/
I2C_TASK=T_READ;I2C_TASK_ADRESS=I2C_ADRESS;I2C_TASK_DATA=I2C_DATA;
I2C_TASK_NUM=I2C_NUM;SEN=1;/*Genero un Start*/;}
/******************************************************************************************/
void I2C_WRITE_ROM (char I2C_ADRESS,char I2C_DEV_ADRESS,char *I2C_DATA,char I2C_NUM)
{I2C_TASK_STEP=S_START;/*Posiciono en paso START*/;
I2C_TASK_TIMEOUT=I2C_TASK_TIMEOUT_MAX; /*Inicializo el TIMEOUT*/
I2C_TASK=T_WRITE_R;I2C_TASK_ADRESS=I2C_ADRESS;I2C_TASK_DEV_ADRESS=I2C_DEV_ADRESS;
I2C_TASK_DATA=I2C_DATA;I2C_TASK_NUM=I2C_NUM;SEN=1;/*Genero un Start*/;}
/******************************************************************************************/
void I2C_READ_ROM (char I2C_ADRESS,char I2C_DEV_ADRESS,char *I2C_DATA,char I2C_NUM)
{I2C_TASK_STEP=S_START;/*Posiciono en paso START*/;
I2C_TASK_TIMEOUT=I2C_TASK_TIMEOUT_MAX; /*Inicializo el TIMEOUT*/
I2C_TASK=T_READ_R;I2C_TASK_ADRESS=I2C_ADRESS;I2C_TASK_DEV_ADRESS=I2C_DEV_ADRESS;
I2C_TASK_DATA=I2C_DATA;I2C_TASK_NUM=I2C_NUM;SEN=1;/*Genero un Start*/;}
/******************************************************************************************/
void I2C_Interrupt (void)
{I2C_TASK_TIMEOUT=I2C_TASK_TIMEOUT_MAX; /*Inicializo el TIMEOUT*/
switch(I2C_TASK_STEP)
{case S_START :I2C_TASK_ERROR=E_NO_ERROR;
if (I2C_TASK==T_READ)
{I2C_TASK_STEP=S_WRITE_ADRESS_R;SSPBUF=(I2C_TASK_ADRESS | 0x01);}
else{I2C_TASK_STEP=S_WRITE_ADRESS_W;SSPBUF=(I2C_TASK_ADRESS & 0xFE);};break;
case S_RESTART :I2C_TASK_STEP=S_WRITE_ADRESS_R;SSPBUF=(I2C_TASK_ADRESS | 0x01);break;
case S_WRITE_ADRESS_W:if (ACKSTAT) {I2C_TASK_ERROR=E_W_ADRESS_NACK;I2C_TASK_STEP=S_STOP;PEN=1;}
else {switch(I2C_TASK){case T_WRITE :I2C_TASK_STEP=S_WRITE_DATA;SSPBUF=*I2C_TASK_DATA;break;
case T_WRITE_R :I2C_TASK_STEP=S_WRITE_DEV_ADRE;SSPBUF=I2C_TASK_DEV_ADRESS;break;
case T_READ_R :I2C_TASK_STEP=S_WRITE_DEV_ADRE;SSPBUF=I2C_TASK_DEV_ADRESS;break;
};};break;
case S_WRITE_ADRESS_R:if (ACKSTAT) {I2C_TASK_ERROR=E_R_ADRESS_NACK;I2C_TASK_STEP=S_STOP;PEN=1;}
else{I2C_TASK_STEP=S_READ_DATA;RCEN=1;};break;
case S_WRITE_DEV_ADRE:if (ACKSTAT) {I2C_TASK_ERROR=E_DEV_ADRESS_NACK;I2C_TASK_STEP=S_STOP;PEN=1;}
else{switch(I2C_TASK){case T_WRITE_R:I2C_TASK_STEP=S_WRITE_DATA;SSPBUF=*I2C_TASK_DATA;break;
case T_READ_R :I2C_TASK_STEP=S_RESTART;RSEN=1;break;};}
break;
case S_WRITE_DATA :if (ACKSTAT) {I2C_TASK_ERROR=E_DATA_NACK;I2C_TASK_STEP=S_STOP;PEN=1;}
else if (I2C_TASK_NUM)
{I2C_TASK_NUM--;I2C_TASK_DATA++;I2C_TASK_STEP=S_WRITE_DATA;SSPBUF=*I2C_TASK_DATA;}
else {I2C_TASK_STEP=S_STOP;PEN=1;};
break;
case S_READ_DATA :*I2C_TASK_DATA=SSPBUF;
if (I2C_TASK_NUM) {ACKDT=0;I2C_TASK_NUM--;I2C_TASK_DATA++;I2C_TASK_STEP=S_ACK_MS;}
else {ACKDT=1;I2C_TASK_STEP=S_NACK_MS;};
ACKEN=1;break;
case S_ACK_MS :I2C_TASK_STEP=S_READ_DATA;RCEN=1;break;
case S_NACK_MS :I2C_TASK_STEP=S_STOP;PEN=1;break;
case S_STOP :if (I2C_TASK_ERROR==E_NO_ERROR)
{I2C_TASK_STEP=S_DONE;}else{I2C_TASK_STEP=S_ERROR;};break;
default :I2C_TASK_STEP=S_ERROR;break;
}
}
/******************************************************************************************/
void I2C_init (void)
{SCL_TRIS=SDA_TRIS=1; //Seteo SCL y SDA como entradas
SSPMode(MASTER_CLK); //SSP modo maestro con seteo de frec de I2C
SSPCON2=0;
#if XTAL_CON_PLL==1 //Velocidad de transferencia=fosc/(4*(SSPADD+1))=100K
SSPADD = 99;
#else
SSPADD = 24;
#endif
SSPEN = 1; //Habilito modulo I2C
CKP=SMP=1; //Control de Slew rate
I2C_TASK=T_IDLE;I2C_TASK_STEP=S_IDLE; //Inicializo flags
I2C_TASK_ERROR=E_NO_ERROR;
SSPIF=0;SSPIE=1; //Limpio flags de interrupcion y la inicio
}
Este manejador permite trabajar tanto con un dispositivo I2C clasico como con memorias 24LCXX de manera directa.
Falta un pequeño DAEMON de Timeout de I2C que va en la parte de relojeria pero es facil darse cuenta que va.
-
Que grande Darukur!!! :)
¿Habrá alguién que no entienda si no conoce el Salvo RTOS que estas utilizando? Por suerte encontré solo una señalización de semáforo:
OSSignalSem()
¿No sería mejor explicarlo?
Saludos.
Martín
PD: Cuando ingresas el código al post tenes un lista donde podes señalizar si queres que te lo coloree o resalte (la lista que dice GeSHi)
-
Darukur, he visto que para agregar algo a tus posts, haces un post nuevo.
Esto no es necesario, lo más práctico suele ser "modificar" el post , esto lo puedes hacer clickeando sobre tu post, en modificar y le agregas/quitas lo que te parezca.
:)
-
Err, tenes Razon Maunix.... Sorry.
Lo hice de vago nomas, lo sabia :mrgreen:
-
Err, tenes Razon Maunix.... Sorry.
Lo hice de vago nomas, lo sabia :mrgreen:
No problem, :)
Una pregunta, esa máquina de estados que haces en la rutina de i2c en el vector de interrupción, ¿no es algo lenta?
Es una pregunta, tengo dudas de cómo pueda funcionar semejante código en un vector de interrupción, mezclado con otras tareas que también requieran atención.
Si detallas para qué micro y frecuencia lo has usado, tal vez la duda quede disipada, ya que cuando hay velocidad... estas cosas pasan a un segundo plano ;)
-
Tanto para la rutina de interrupcion de I2C MASTER como la de SLAVE son Macros asi que esta optimizado el tiempo de entrada a la rutina.
El codigo puede parecer largo pero tene en cuenta que es un switch-case en donde se ejecuta una sola opcion.
Yo lo probe a 470Khz y 10Mhz de clock y anda eficientemente.
Entiendo perfectamente la necesidad de que las interrupciones sean lo mas breves posibles, pero realmente esto requiere hacerse en interrupciones.
Tengo casos muucho mas complicados, por ejemplo el manejo de un canal RS-485 half duplex con un protocolo tipo TCP-IP propietario y realmente ahi el codigo en interrupcion es grande.
Es que tiene que transmitir y escucharse (para detectar colision) y no hay otra manera de hacerlo tan rapido fuera de interrupciones.
Asi y todo ese micro gestiona el 485, el I2C master, relojes, contadores de pulsos y un monton de servicios juntos y anda perfecto.