1

I'm trying to run a I2C device using the atmega328p (on a custom board ). I've read the data sheet , and wrote the code "exactly" as show in it: here's the code :

#define F_CPU 1000000
#define SCL_CLOCK 50000
#define BAUD 9600
#define MYUBRR    F_CPU/8/BAUD-1
#define TWIMUX  0x1C 


#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <util/twi.h>
#include <avr/interrupt.h>


// printf to debug 
static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE);
// initializing the UART 
void init_uart(unsigned short uValue  ){
    // setting the baud rate
    UBRR0H =(unsigned char)  ( uValue>> 8);  // 0x00
    UBRR0L =(unsigned char) uValue;  // 0x0C
    // enabling TX & RX
    UCSR0B = (1<<RXEN0)|(1<<TXEN0);
    UCSR0A = (1<<UDRE0)|(1<<U2X0);
    UCSR0C =  (1 << UCSZ01) | (1 << UCSZ00);    // Set frame: 8data, 1 stop

}

void init_i2c(void ) {
     uint8_t   twst;
     TWSR = 0;                         // no prescaler
     TWBR = ((F_CPU/SCL_CLOCK)-16)/2; 
     TWCR = (1<<(TWINT))|(1<<TWSTA )|(1<<TWEN);
     printf("TWCR 0x%x \n",TWCR);
     while(!(TWCR & (1<< TWINT)));
     printf(" Start condition has been transmitted \n");
     if( (TWSR&0xF8) != TW_START){
         printf(" Error \n");
     }
     // Setting Address 
     TWDR = 0x1C; 
     // cleating TWCR 
     TWCR = (1<<TWINT) |(1<<TWEN);
    if ((TWSR & 0xF8) != TW_MT_SLA_ACK){
         printf(" Error at TWSR   0x%x\n", TWSR);  // here is the problem !!!!!!!!!  TWSR value should be 0x18
         return; 
    }       
 }


static int uart_putchar(char c, FILE *stream)
{
    if (c == '\n')
    uart_putchar('\r', stream);
    while ( !( UCSR0A & (1<<UDRE0)) );
    UDR0 = c;
    return 0;
}
int main(void)
{
    unsigned short i = 0 ; 
    // UART init and printf 
    init_uart(MYUBRR);
    stdout = &mystdout;
    sei();
    init_i2c();


    while(1){

    }

    return 0;
}

output

As you can see in the output I have an error by the TWSR value ! first I tought that the frequency isn't set correctly , but I've measure it and it definitly 50khz. I've measured SDA and SCL and here is the scope pic : enter image description here

as far as I've learned, both wires should be on high ? I've plugged an arduino board on this chip and it did work fine! so the problem is definitely in the configuration,( my code ).

any idea how might solve this ?

thanks in advance !

Engine
  • 669
  • 2
  • 13
  • 29
  • Please add schematics of your custom board. Also make sure that you correctly send address, it looks like you could have made a mistake interpreting address in datasheet as 8bit though suppliers usually use 7bits – Artūras Jonkus Feb 09 '17 at 10:44
  • Have you external pull up resistors (10k) on your SDA and SCL lines? They are necessary. – auoa Feb 09 '17 at 11:44
  • I have a 4,7k and with the arduino it works fine ! – Engine Feb 09 '17 at 18:05

1 Answers1

1

After this line:

TWCR = (1<<TWINT) |(1<<TWEN);

You need to wait for the TWINT bit to set:

while (!(TWCR & (1<<TWINT)));

This on stage 4 in table on page 216 of the datasheet.

Without this line, your code is checking for the ACK at the start of transmit, not when it has completed.

In general, whenever you do anything that changes the state of the i2c bus (sending a start bit, sending an address, sending/receiving data), you should wait until the i2c hardware signals it has processed that change and is ready to continue.

jfowkes
  • 618
  • 3
  • 12