i have problem with i2c.
after this line: " i2cTransmit(ADXL345, POWER_CTL, 0)"
the communication stop and program don’t perform in while(1) loop. usart works great.
what am I doing wrong?
#define F_CPU 20000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <util/twi.h>
#define BAUD 19200
#define MYUBRR F_CPU/16/BAUD-1
#define VREF 5
#define ADXL345 0x53
#define POWER_CTL 0x2D
#define DATAX0 0x32
#define DATAX1 0x33
#define DATAY0 0x34
#define DATAY1 0x35
#define DATAZ0 0x36
#define DATAZ1 0x37
void USART_Init(unsigned int ubrr);
void USART_Tx(unsigned char data);
void USART_TS(const char *s);
void USART_RS(void);
unsigned char USART_Rx(void);
void USART_Flush(void);
void PWM_Init(void);
void set_motors(int L_motor, int P_motor);
void ADC_Init(void);
void i2cInit(unsigned long scl_freq);
char i2cTransmit(char sla, char reg_addr, char value);
char i2cReceive(char sla, char reg_addr, char * value);
void i2cReset(void);
unsigned char buff[32];
int x;
int y;
int z;
char temp;
char value;
char c;
float vbat;
static volatile uint8_t adc_flag;
static volatile uint8_t rx_flag;
static volatile uint8_t tx_flag;
int main(void)
{
DDRC |= _BV(1)|_BV(2)|_BV(3); //diody led
DDRD |= _BV(4)|_BV(5)|_BV(6)|_BV(7); //L298
DDRB |= _BV(1)|_BV(2); //pwmy
DDRC |= _BV(4)|_BV(5); //SDA i SCL
PWM_Init();
ADC_Init();
//sei();
cli();
i2cInit(50000);
USART_Init(MYUBRR);
i2cReset();
i2cTransmit(ADXL345, POWER_CTL, 0); //reset
//i2cReset();
//i2cTransmit(ADXL345, POWER_CTL, 16); //standby
//i2cReset();
//i2cTransmit(ADXL345, POWER_CTL, 8); //measure
i2cReset();
_delay_ms(100);
while(1)
{
/*
i2cReceive(ADXL345, DATAX0, &value);
temp = value;
i2cReceive(ADXL345, DATAX1, &value);
x = (value<<8)|temp;
i2cReceive(ADXL345, DATAY0, &value);
temp = value;
i2cReceive(ADXL345, DATAY1, &value);
y = (value<<8)|temp;
i2cReceive(ADXL345, DATAZ0, &value);
temp = value;
i2cReceive(ADXL345, DATAZ1, &value);
z = (value<<8)|temp;
*/
sprintf(buff, "%d %d %d\r\n", x,y,z);
USART_TS(buff);
USART_TS("wynik: \r\n");
_delay_ms(1000);
}
}
void USART_Init(unsigned int ubrr)
{
UBRR0H = (unsigned char)(ubrr>>8); // Set baud rate
UBRR0L = (unsigned char)ubrr;
UCSR0B |= (1<<RXEN0)|(1<<TXEN0); // Enable receiver and transmitter
//UCSR0B |= (1<<RXCIE0)|(1<<TXCIE0); // przerwania
UCSR0C = (1<<UCSZ00)|(1<<UCSZ01); // 8 bitów danych, 1 bit stopu, brak parzystości
}
void USART_Tx(unsigned char data)
{
while (!( UCSR0A & (1<<UDRE0))); // Wait for empty transmit buffer
UDR0 = data; // Put data into buffer, sends the data
}
void USART_TS(const char *s)
{
while (*s)
USART_Tx(*s++);
}
void USART_RS(void)
{
unsigned char i=0;
do
{
if((buff[i] = USART_Rx()) == '\n') break;
i++;
}while(i < 32); //zeby nie przepelnic bufora
}
unsigned char USART_Rx(void)
{
while (!(UCSR0A & (1<<RXC0))); /* Wait for data to be received */
return UDR0; /* Get and return received data from buffer */
}
void USART_Flush(void) /* opróżnianie bufora odbioru */
{
unsigned char dummy;
while (UCSR0A & (1<<RXC0)) dummy = UDR0;
}
void PWM_Init(void)
{
//8bit PWM, phase correct
//MCU clock / 8
OCR1A = 0;
OCR1B = 0;
TCCR1A = (1<<COM1A1)|
(1<<COM1B1)|
(1<<WGM10);
TCCR1B = (1<<CS11)|
(1<<WGM12)|
(1<<CS10);
}
void set_motors(int L_motor, int P_motor)
{
if(L_motor<0){
ENABLE_B = (-1)*L_motor;
INPUT3_PORT &= ~INPUT3;
INPUT4_PORT |= INPUT4;}
else if(L_motor>0){
ENABLE_B = L_motor;
INPUT3_PORT |= INPUT3;
INPUT4_PORT &= ~INPUT4;}
else if(L_motor==0){
ENABLE_B = 0;}
else if(L_motor==-1){
INPUT3_PORT |= INPUT3;
INPUT4_PORT |= INPUT4;}
if(P_motor<0){
ENABLE_A = (-1)*P_motor;
INPUT1_PORT &= ~INPUT1;
INPUT2_PORT |= INPUT2;}
else if(P_motor>0){
ENABLE_A = P_motor;
INPUT1_PORT |= INPUT1;
INPUT2_PORT &= ~INPUT2;}
else if(P_motor==0){
ENABLE_A = 0;}
else if(P_motor==-1){
INPUT1_PORT |= INPUT1;
INPUT2_PORT |= INPUT2;}
}
void ADC_Init(void)
{
ADMUX |= (1 << REFS0); // Set ADC reference to AVCC
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Set ADC prescalar to 128
ADCSRA |= (1 << ADIE); // przerwania
ADCSRA |= (1 << ADEN)|(1<<ADATE); // Enable ADC + auto triger
ADCSRA |= (1 << ADSC); // Start A2D Conversions (ADEN musi byc wlaczony)
}
void i2cInit(unsigned long scl_freq)
{
//Set the TWI Prescaler to 1
//(Actually this is default setting...)
//Set up the TWI Bit Rate
TWBR = F_CPU/(2*(long)scl_freq)-8; //(SCL_FREQ = F_CPU/(16+2*TWBR) *According to datasheet
}
//Puts the ATmega in Master Transmitter mode and sends a value to a register
//pre: sla - i2c address of slave
// reg_addr - the register to address
// value - the value to write in the register location
//returns: 1-Success
// TWSR - Failure (The TWI failure code)
char i2cTransmit(char sla, char reg_addr, char value)
{
//Send the start condition
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Clear int bit(by writing a 1), enable twi and send start
while (!(TWCR & (1<<TWINT))); //Wait for the interrupte bit to get set
if(TW_STATUS != TW_START)return TWSR;
//No matter what we start with a write to the slave
TWDR = sla | TW_WRITE; //Put the slave address in the twi data register
TWCR = (1<<TWINT)|(1<<TWEN); //Send the address to the slave
while (!(TWCR & (1<<TWINT))); //Wait for the operatation to complete
if (TW_STATUS != TW_MT_SLA_ACK)return TWSR; //Make sure we received an ack from the slave.
//Load the register into the slave device that we want to alter
TWDR = reg_addr;
TWCR = (1<<TWINT)|(1<<TWEN); //Send the register address through the twi interface
while (!(TWCR & (1<<TWINT))); //Wait for operation to complete
if (TW_STATUS != TW_MT_DATA_ACK)return TWSR;//Make sure we received an ack from the slave
//Now send the actual register data to the slave
TWDR = value;
TWCR = (1<<TWINT)|(1<<TWEN); //Send the register value through the twi interface
while (!(TWCR & (1<<TWINT))); //Wait for operation to complete
if (TW_STATUS != TW_MT_DATA_ACK)return TWSR;//Make sure we received an ack from the slave
//We're finished. Send a stop.
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
return 1;
}
//Reads a value from a specified register
//pre: sla - i2c address of slave
// reg_addr - The address of the register to read from
// value - a pointer to a character
//post: value is assigned the value read from the register
//returns: 1 - Success
// TWSR - Failur
char i2cReceive(char sla, char reg_addr, char * value)
{
//Send the start condition
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Clear int bit(by writing a 1), enable twi and send start
while (!(TWCR & (1<<TWINT))); //Wait for the interrupte bit to get set
if (TW_STATUS != TW_START)return TWSR; //Check the TWI status, return if bad status.
//Start Condition has been transmitted
//Send SLA+W to TWDR
TWDR = sla|TW_WRITE; //Put the slave address in the twi data register
TWCR = (1<<TWINT)|(1<<TWEN); //Send the address to the slave
while (!(TWCR & (1<<TWINT))); //Wait for the operatation to complete
if(TW_STATUS != TW_MT_SLA_ACK)return TWSR;
//SLA+W has been transmitted, Ack has been received
//Load the register into the slave device that we want to read
TWDR = reg_addr;
TWCR = (1<<TWINT)|(1<<TWEN); //Send the register address through the twi interface
while (!(TWCR & (1<<TWINT))); //Wait for operation to complete
if(TW_STATUS != TW_MT_DATA_ACK)return TWSR;
//Data byte has been transmitted, Ack has been received
//Now send a 'repeated start' to switch to master receiver mode
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); //Clear int bit(by writing a 1), enable twi and send start
while (!(TWCR & (1<<TWINT))); //Wait for the interrupte bit to get set
if (TW_STATUS != TW_REP_START)return TWSR;
//A Repeated Start condition has been received
//Send the SLA+R
TWDR = sla | TW_READ; //Load the slave address and the read bit into the data register
TWCR = (1<<TWINT)|(1<<TWEN); //Send the address+R to the slave
while(!(TWCR & (1<<TWINT))); //Wait for the operation to complete
if (TW_STATUS != TW_MR_SLA_ACK)return TWSR; //Make sure we got the right ack.
//SLA+R has been transmitted, Ack has been received
//Get the value from the pre-configured register on the slave
TWCR = (1<<TWINT)|(1<<TWEN); //Tell the slave to send the next value and send NACK afterwards
while(!(TWCR & (1<<TWINT))); //Wait for the operation to complete
if (TW_STATUS != TW_MR_DATA_NACK)return 5; //Make sure we got the right ack.
//Data byte has been received, Nack has been returned
//Send a stop
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
*value = TWDR;
return 1; //Return the value we got from the register
}
void i2cReset(void)
{
TWCR = 0;
}