I2C-ATMEGA328p в качестве ведущего и 24LC256 в качестве ведомого

Итак, я пытаюсь установить соединение между ATMEGA328p в качестве мастера и чипом EEPROM 24LC256 с использованием протокола I2C.

  • Часы настроены на 100 кГц
  • Линии SDA и SCK подтянуты к Vcc с помощью резисторов 4,7 кОм,
  • Условие запуска работает нормально, я также получаю ACK в ответ,
  • ACK получен, когда отправлен правильный адрес,
  • Сбой при отправке MSB адреса в чипе!

Код:

#define FOSC         16000000UL
#define START        0x08
#define MT_SLA_ACK   0x18
#define MT_SLA_NACK  0x18
#define DEV_ADDR     0x50


typedef enum result_t{FAIL, SUCCESS}result;

void Debug_LED_ON()
{
   PORTD|=1<<PD4; //Turn on LED on PIN4 of PORTD
}

void set_clock(int freq_in_khz)
{
   TWCR = 1<<TWEN;     //Enable TWI module
   TWSR |=(1<<TWPS0); //Prescaler set to 4
   TWBR  = FOSC/freq_in_khz;
   TWBR -= 16;
   TWBR /= 8;  //2*Prescaler_value

}

void send_start()
{
   TWCR= ( (1<<TWINT) | (1<<TWEN) | (1<<TWSTA) ); //send START
   while( !(TWCR & (1<<TWINT)) ) ;                //wait for TWINT flag SET
}

void send_stop()
{
   TWCR= ( (1<<TWINT) | (1<<TWEN) | (1<<TWSTO) ); //send STOP
   //while( !(TWCR & (1<<TWINT)) ) ;                //wait for TWINT flag SET
}

result check_start_status()
{
   if ((TWSR & 0xF8) == START )
     return SUCCESS;
   else
     return FAIL;
}

void send_address(char addr_w)
{

   TWDR=addr_w; //7bit  address + W bit (write bit)
   TWCR = (1<<TWINT) | (1<<TWEN); //Clear TWINT bit to start transmission of address
   while (!(TWCR &(1<<TWINT)));  //wait for TWINT flag SET

}
result check_MT_slave_ack()
{
   if ((TWSR & 0xF8) == MT_SLA_ACK )
     return SUCCESS;
   else
     return FAIL;
}
result check_MT_slave_nack()
{
   if ((TWSR & 0xF8) == MT_SLA_NACK )
     return SUCCESS;
   else
     return FAIL;
}

void  transmit_data(char data)
{
   TWDR=data;
   TWCR = (1<<TWINT) | (1<<TWEN); //Clear TWINT bit to start transmission of Data on the bus
   while (!(TWCR &(1<<TWINT)));  //wait for TWINT flag SET

}

int main (void)
{
   DDRC=0xff;
   PORTC=0x30;   //Enable internal pullups on PORTC PINS  SDA(PC4) , SCL(PC5)
   DDRD=0xFF;   //Port D as output


   set_clock(100); //setting clock 100KHz
   send_start();

   if(check_start_status()==FAIL)
     Debug_LED_ON();


   send_address(DEV_ADDR << 1); 

   if(check_MT_slave_ack()==FAIL)
    Debug_LED_ON();

   transmit_data(0x00);  

   if(check_MT_slave_ack()==FAIL) //fails here!
    Debug_LED_ON();     

   return 0;
}

Думаю, что-то не так с кодом или с тем, как я отправляю адрес! Биты A2, A1, A0 24LC256 установлены на землю, поэтому адрес устройства 0x50 << 1.

Обновлять:

Адрес устройства теперь отправляется правильно, теперь, когда я отправляю MSB адреса на чип, куда я хочу записать данные, это не удается!

Настройка оборудования

Ответы (1)

Значение, которое вы устанавливаете в send_address()функции, смещено на один бит. Адрес чипа 0x50представляет собой 7-битное число, которое необходимо сдвинуть на 1 бит вверх при отправке по шине I2C (самый младший бит — флаг чтения/записи). Таким образом, вы должны использовать send_address(0xa0)(то есть 0x50<<1) в своем коде или выполнять send_address()функцию сдвига внутри.

Под «когда я отправляю адрес +/W, я не получаю ни ACK, ни NACK», вы имеете в виду, что ваш код зависает в while (!(TWCR &(1<<TWINT)));цикле внутри send_address()? Если да, то это другая проблема, не связанная с указанным выше адресом.

Спасибо! код не зависает в send_address(). Я отправлял адрес как 7-битный, 1010000, верхний полубайт 1010 исправлен, теперь я понял! Это работает до сих пор, т.е. я получаю ACK взамен :)