Hoi,
Ik heb een i2c driver geschreven die perfect werkt met verschillende device's zoals IOexpanders, eeproms, temperatuur sensoren etc.
Nu het probleem: Als ik een digitaal kompas (CMPS03) ook via de I2C uitlees dan gaat dit maar 1 van de 3x goed.
De eerste keer uitlezen gaat helemaal goed.
Bij de 2e keer reageert het kompas niet op de start conditie van de I2C en krijg ik een timeout.
Bij de 3e keer krijg ik geen ACK zodra ik het adres heb verstuurd. Na de 3e keer gaat het uitlezen wel weer goed.
Na de 2e en 3e keer word de I2C bus opnieuw geinitialiseerd (gebeurd zodra een error is gedetecteerd). Ook word er tussen het uitlezen 100ms gewacht.
Heeft iemand een idee waarom het kompas zo raar doet? En waar dit aan kan liggen?
Gebruikte microcontroller is een AVR ATMega8.
Grtn Zundapp
Roland van Leusden
It's the rule that you live by and die for It's the one thing you can't deny Even though you don't know what the price is. It is justified.
Post je code, gebruik je wel een "repeated start" zoals hier:
Ok bij deze de code:
(TWI = I2C bij AVR)
TWI.h
#ifndef _TWI_FUNCTIONS
#define _TWI_FUNCTIONS
#include "main.h"
/* Define */
#define TWI_PORTS 0x30 // Bit positions of SCL and SDA
#define TWI_TIMEOUT (CPU_SPEED / 1000) / 4
// Status code's
#define START_SEND 0x08 /* Start had been transmitted */
#define RSTART_SEND 0x10 /* Repeated start has been transmitted */
#define SLAW_ACK 0x18 /* SLA + W has been transmitted and ACK has been received */
#define SLAW_NACK 0x20 /* SLA + W has been transmitted and NO ACK has been received */
#define DATA_SEND_ACK 0x28 /* Data byte has been transmitted and ACK has been received */
#define DATA_SEND_NACK 0x30 /* Data byte has been transmitted and NO ACK has been received */
#define ARB_LOST 0x38 /* Arbitration lost in SLA+W, SLA+R or data bytes */
#define SLAR_ACK 0x40 /* SLA + R has been transmitted and ACK has been received */
#define SLAR_NACK 0x48 /* SLA + R has been transmitted and NO ACK has been received */
#define DATA_RECEIVED_ACK 0x50 /* Data byte has been received and ACK has been returned */
#define DATA_RECEIVED_NACK 0x58 /* Data byte has been reveived and NO ACK has been returned */
#define SLAW_ACK_RECEIVED 0x60 /* Own SLA + W has been received, ACK has been returned */
#define ARB_LOST_MASTER 0x68 /* Arbitration lost in SLA+R/W as Master */
#define GNRL_CALL_RECEIVED 0x70 /* General call recieved, ACK returned */
#define ARB_LOST_MASTER2 0x78 /* Aribtration loast in SLA+R/W as Master when General call has been received */
#define ADDRESS_FAULT1 0x80 /* Previously addressed with own SLA+W. Data has been received, ACK returned */
#define ADDRESS_FAULT2 0x88 /* Previously addressed with own SLA+W. Data has been received, NO ACK returned */
#define ADDRESS_FAULT3 0x90 /* Previously addressed with general call. Data has been received, ACK returned */
#define ADDRESS_FAULT4 0x98 /* Previously addressed with general call. Data has been received, NO ACK returned */
#define SLAVE_FAULT 0xA0 /* STOP or RSTART condition received while still addressed as Slave */
#define SLAR_ACK_RECEIVED 0xA8 /* Own SLA + R has been received, ACK has been returned */
#define ARB_LOST_MASTER3 0xB0 /* Arbitration lost in SLA+R/W as Master */
#define SLV_DATA_SEND_ACK 0xB8 /* Slave transmitter: Data byte from TWDR has been transmitted and ACK has been received */
#define SLV_DATA_SEND_NACK 0xC0 /* Slave transmitter: Data byte from TWDR has been transmitted and NO ACK has been received */
#define SLV_LAST_DATA 0xC8 /* Last data byte in TWDR has been transmitted, ACK has been received */
#define NO_STATE 0xF8 /* No status information available */
#define BUS_ERROR 0x00 /* BUS error due to illegal start or stop condition */
#define BUS_TIMEOUT 0xFF
/* Functie declaraties */
void TWI_Start(void);
void TWI_Write(unsigned char);
unsigned char TWI_Read(void);
void TWI_Stop(void);
void TWI_Wait(void);
void TWI_Init(void);
/* Variabelen */
extern bool twi_error;
extern bool twi_busy;
extern unsigned char twi_error_code;
#endif
TWI.c
#include "TWI.h"
/* Externe variabelen */
bool twi_busy = false;
bool twi_error = false;
unsigned char twi_error_code = 0;
/**********************************/
/* TWI_Start */
/**********************************/
void TWI_Start(void)
{
if (twi_busy == false)
{
twi_error = false; /* Reset error flag */
twi_error_code = 0;
}
twi_busy = true;
if (twi_error == false)
{
/* Verzend Start conditie */
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); /* Send start */
TWI_Wait();
if (!((TWSR == START_SEND) || (TWSR == RSTART_SEND) ))
{
if (twi_error == false) twi_error_code = TWSR;
twi_error = true;
}
}
}
/**********************************/
/* TWI_Write */
/**********************************/
void TWI_Write(unsigned char data)
{
if (twi_error == false)
{
TWDR = data; /* Schrijf adres van apparaat + write naar verzend register */
TWCR = (1 << TWINT) | (1 << TWEN); /* Clear TWINT bit en enable TWEN bit waardoor "TWDR" word verstuurd */
TWI_Wait();
if (!((TWSR == SLAW_ACK) || (TWSR == DATA_SEND_ACK) || (TWSR == SLAR_ACK) ))
{
if (twi_error == false) twi_error_code = TWSR;
twi_error = true;
}
}
}
/**********************************/
/* TWI_Read */
/**********************************/
unsigned char TWI_Read(void)
{
if (twi_error == false)
{
/* Geef signaal om data in te lezen */
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA); /* Clear TWINT bit en enable TWEN bit en TWEA bit waardoor "data" word ontvangen en WEL Ack word verstuurd */
TWI_Wait();
if (TWSR != DATA_RECEIVED_ACK)
{
if (twi_error == false) twi_error_code = TWSR;
twi_error = true;
}
}
if (twi_error == false) return(TWDR); /* De ontvangen data word teruggegeven aan de aanroepende functie */
else return(0);
}
/**********************************/
/* TWI_Stop */
/**********************************/
void TWI_Stop(void)
{
if (twi_error == false)
{
/* Verzend Stop conditie */
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); /* Send stop */
while (!(TWCR & (1 << TWSTO)));
}
twi_busy = false;
}
/**********************************/
/* TWI_Wait */
/**********************************/
void TWI_Wait(void)
{
unsigned long timeout = 0;
while ( (!(TWCR & (1 << TWINT))) && (timeout < TWI_TIMEOUT) ) /* Wacht totdat de TWINT bitje is geset, Dit betekend dat het commando is uitgevoerd */
{
timeout++;
}
if (timeout >= TWI_TIMEOUT)
{
/* Timeout error */
twi_error = true;
twi_error_code = BUS_TIMEOUT;
}
}
void TWI_Init(void)
{
twi_busy = true; /* Geen ander apparaat mag van de TWI gebruik maken */
/* Disable TWI */
DDRC &= ~TWI_PORTS; /* Poort C0 en C1 is input */
PORTC &= ~TWI_PORTS; /* Disable Pull-up */
TWBR = 0x00;
TWSR = 0x00;
TWDR = 0x00;
TWCR = 0x00;
Delay_MS(100);
/* TWI init */
PORTC |= TWI_PORTS; /* activeer Pull-up weerstand op C0 en C1 */
TWBR = 15; /* TWI Bit rate register = 10 bij prescaler 1 (formule in datasheet blz 173) */
TWSR = 0x00; /* TWI Status register: Prescaler = 1; */
TWDR = 0x00; /* TWI Data register */
TWCR = 0x00; /* TWI Control register , reset op 0x00 zodat twi niet vastloopt na sleepmode */
TWAR = 0x00; /* TWI (Slave) Adres register = Het indentificatie nummer van de atmega32 */
twi_busy = false; /* TWI mag door een ander apparaat gebruikt worden */
twi_error = false; /* Reset error flag */
twi_error_code = 0;
}
Kompas.c
#include "Kompas.h"
#include "TWI.h"
/**********************************/
/* Kompas_Read */
/**********************************/
unsigned int Kompas_Read()
{
unsigned char data[2] = {0};
int Value = 0;
unsigned char adres = 0xC0;
TWI_Start(); /* Zend start */
TWI_Write(adres); /* Verzend SlaveAdres + Write */
TWI_Write(0x02); /* Selecteer graden register */
TWI_Start(); /* Verzend Start conditie (Repeated Start) */
TWI_Write(adres + 1); /* Verzend SlaveAdres + Read */
/* Als het apparaat reageerd */
data[0] = TWI_Read(); /* Lees 1e waarde in */
data[1] = TWI_Read(); /* Lees 2e waarde in */
TWI_Stop(); /* Zend stop */
if (twi_error == true)
{
Handle_Error(twi_error_code);
TWI_Init();
}
else
{
Value = data[0] << 8;
Value += data[1];
}
return(Value);
} /* Temp_Sensor_Read */
main.c
/**********************************/
/* MAIN */
/**********************************/
void main(void)
{
int bearing = 0;
char array[20] = {0};
Init();
Uart_Init();
TWI_Init();
/* main loop */
while(1)
{
LED_ON;
bearing = Kompas_Read();
if (bearing != 0)
{
sprintf(array, "Bearing: %d ", bearing);
Uart_Send_String(array, sizeof(array));
}
LED_OFF;
Delay_MS(100);
}
} /* MAIN */