2016-08-26 8 views
2

Я пытаюсь получить базовое рукопожатие. Ниже приведен ISR для SMBus C8051F120 (шина управления системой). Я пытаюсь реализовать на нем устройство I2C (ads1115 7addr 0x48 для тех, кому интересно). Обратите внимание, что это в основном пример, представленный кремниевыми лабораториями для F120.SMBus (I2C) отправляет дополнительный ACK, а затем предназначенный

void SMBUS_ISR (void) interrupt 7 
{ 
    bit FAIL = 0;      // Used by the ISR to flag failed 
             // transfers 

    static unsigned char sent_byte_counter; 
    static unsigned char rec_byte_counter; 

    // Status code for the SMBus (SMB0STA register) 

    switch (SMB0STA) 
    { 
     // Master Transmitter/Receiver: START condition transmitted. 
     // Load SMB0DAT with slave device address. 
     case SMB_START: //0x08 

     // Master Transmitter/Receiver: repeated START condition transmitted. 
     // Load SMB0DAT with slave device address 
     case SMB_RP_START: //0x10 
     SMB0DAT = TARGET;    // Load address of the slave. 
     SMB0DAT &= 0xFE;    // Clear the LSB of the address for the 
             // R/W bit 
     SMB0DAT |= SMB_RW;   // Load R/W bit 
     STA = 0;      // Manually clear STA bit 

     rec_byte_counter = 1;   // Reset the counter 
     sent_byte_counter = 1;  // Reset the counter 

     break; 

     // Master Transmitter: Slave address + WRITE transmitted. ACK received. 
     // For a READ: N/A 
     // 
     // For a WRITE: Send the first data byte to the slave. 
     case SMB_MTADDACK: //0x18 

     SMB0DAT = SMB_DATA_OUT[sent_byte_counter-1]; 
     sent_byte_counter++; 

     break; 

     // Master Transmitter: Slave address + WRITE transmitted. NACK received. 
     // Restart the transfer. 
     case SMB_MTADDNACK: //0x20 
     STA = 1;      // Restart transfer 
     break; 

     // Master Transmitter: Data byte transmitted. ACK received. 
     // For a READ: N/A 
     // 
     // For a WRITE: Send all data. After the last data byte, send the stop 
     // bit. 
     case SMB_MTDBACK: //0x28 

     if (sent_byte_counter <= NUM_BYTES_WR) 
     { 
      // send data byte 
      SMB0DAT = SMB_DATA_OUT[sent_byte_counter-1]; 
      sent_byte_counter++; 
     } 
     else 
     { 
      STO = 1;     // Set STO to terminate transfer 
      SMB_BUSY = 0;    // And free SMBus interface 
     } 

     break; 

     // Master Transmitter: Data byte transmitted. NACK received. 
     // Restart the transfer. 
     case SMB_MTDBNACK: //0x30 
     STA = 1;      // Restart transfer 

     break; 

     // Master Receiver: Slave address + READ transmitted. ACK received. 
     // For a READ: check if this is a one-byte transfer. if so, set the 
     // NACK after the data byte is received to end the transfer. if not, 
     // set the ACK and receive the other data bytes. 
     // 
     // For a WRITE: N/A 
     case SMB_MRADDACK: //0x40 

     if (rec_byte_counter == NUM_BYTES_RD) 
     { 
      AA = 0;     // Only one byte in this transfer, 
             // send NACK after byte is received 
     } 
     else 
     { 
      AA = 1;     // More than one byte in this transfer, 
             // send ACK after byte is received 
     } 

     break; 

     // Master Receiver: Slave address + READ transmitted. NACK received. 
     // Restart the transfer. 
     case SMB_MRADDNACK: //0x48 
     STA = 1;      // Restart transfer 

     break; 

     // Master Receiver: Data byte received. ACK transmitted. 
     // For a READ: receive each byte from the slave. if this is the last 
     // byte, send a NACK and set the STOP bit. 
     // 
     // For a WRITE: N/A 
     case SMB_MRDBACK: //0x50 

     if (rec_byte_counter < NUM_BYTES_RD) 
     { 
      SMB_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received byte 
      AA = 1;     // Send ACK to indicate byte received 
      rec_byte_counter++;  // Increment the byte counter 
     } 
     else 
     { 
      AA = 0;     // Send NACK to indicate last byte 
             // of this transfer 
     } 

     break; 

     // Master Receiver: Data byte received. NACK transmitted. 
     // For a READ: Read operation has completed. Read data register and 
     // send STOP. 
     // 
     // For a WRITE: N/A 
     case SMB_MRDBNACK: //0x58 

     SMB_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received byte 
     STO = 1; 
     SMB_BUSY = 0; 
     AA = 1;      // Set AA for next transfer 

     break; 

     // Master Transmitter: Arbitration lost. 
     case SMB_MTARBLOST: //0x38 

     FAIL = 1;      // Indicate failed transfer 
             // and handle at end of ISR 

     break; 

     // All other status codes invalid. Reset communication. 
     default: 
     FAIL = 1; 

     break; 
    } 

    if (FAIL)       // If the transfer failed, 
    { 
     SMB0CN &= ~0x40;     // Reset communication 
     SMB0CN |= 0x40; 
     STA = 0; 
     STO = 0; 
     AA = 0; 

     SMB_BUSY = 0;     // Free SMBus 

     FAIL = 0; 
    } 

    SI = 0;        // Clear interrupt flag 
} 

//----------------------------------------------------------------------------- 
// Support Functions 
//----------------------------------------------------------------------------- 

//----------------------------------------------------------------------------- 
// SMB_Write 
//----------------------------------------------------------------------------- 
// 
// Return Value : None 
// Parameters : None 
// 
// Writes a single byte to the slave with address specified by the <TARGET> 
// variable. 
// Calling sequence: 
// 1) Write target slave address to the <TARGET> variable 
// 2) Write outgoing data to the <SMB_DATA_OUT> array 
// 3) Call SMB_Write() 
// 
void SMB_Write (void) 
{ 
    char SFRPAGE_SAVE = SFRPAGE;  // Save Current SFR page 

    SFRPAGE = SMB0_PAGE; 

    while (SMB_BUSY);     // Wait for SMBus to be free. 
    SMB_BUSY = 1;      // Claim SMBus (set to busy) 
    SMB_RW = 0;       // Mark this transfer as a WRITE 
    STA = 1;       // Start transfer 

    SFRPAGE = SFRPAGE_SAVE;    // Restore SFR page detector 
} 

//----------------------------------------------------------------------------- 
// SMB_Read 
//----------------------------------------------------------------------------- 
// 
// Return Value : None 
// Parameters : None 
// 
// Reads a single byte from the slave with address specified by the <TARGET> 
// variable. 
// Calling sequence: 
// 1) Write target slave address to the <TARGET> variable 
// 2) Call SMB_Write() 
// 3) Read input data from <SMB_DATA_IN> array 
// 
void SMB_Read (void) 
{ 
    char SFRPAGE_SAVE = SFRPAGE;  // Save Current SFR page 

    SFRPAGE = SMB0_PAGE; 

    while (SMB_BUSY);     // Wait for bus to be free. 
    SMB_BUSY = 1;      // Claim SMBus (set to busy) 
    SMB_RW = 1;       // Mark this transfer as a READ 

    STA = 1;       // Start transfer 

    while (SMB_BUSY);     // Wait for transfer to complete 

    SFRPAGE = SFRPAGE_SAVE;    // Restore SFR page detector 
} 

Главное непрерывно выполняет следующие операции: отправляет 3 байта. Первый байт является указателем регистра устройства. Затем читает тот же регистр (поскольку указатель уже установлен). Он делает это.

while (1) 
    { 
     TARGET = SLAVE_ADDR;    // Target the Slave for next SMBus 
             // transfer 
     SMB_DATA_OUT[0] = 0x01;   // Device register 
     SMB_DATA_OUT[1] = 0x0A;   // Register MSByte 
     SMB_DATA_OUT[2] = 0x03;   // Register LSbyte 
     SMB_Write();      // Initiate SMBus write 

     // SMBus Read Sequence 
     TARGET = SLAVE_ADDR;    // Target the Slave for next SMBus 
             // transfer 
     SMB_Read(); 
    } 

А вот trace capture of transfer:

кажется мне, как хозяин получит посылает дополнительный ACK. Таким образом, мое главное внимание было сосредоточено на случаях:

SMB_MRADDACK: // 0x40

SMB_MRADDNACK: // 0x48

SMB_MRDBACK: // 0x50

Мой главный фокус больше так SMB_MRADDNACK: // 0x48 и количество раз, через которое выполняется это утверждение во время вызовов ISR. У меня небольшие проблемы, обертывая мою голову вокруг точной точки отказа. Итак, откуда этот дополнительный ACK? Я вернусь сюда в понедельник днем, если к тому времени я сам не пойму.

Вопрос с бонусом: Есть ли встроенный обмен стеками? Не видел ничего, что выделялось для меня в сообществах.

+0

Бонусный ответ: вы посетили форумы Cygnal/SiLabs (http://community.silabs.com/)? Это не формат SO, но он активен и населен некоторыми очень компетентными людьми. –

ответ

0
case SMB_MRDBACK: //0x50 

    SMB_DATA_IN[rec_byte_counter-1] = SMB0DAT; // Store received byte 
    rec_byte_counter++;  // Increment the byte counter 

    if (rec_byte_counter < NUM_BYTES_RD) 
    { 
     AA = 1;     // Send ACK to indicate byte received 
    } 
    else 
    { 
     AA = 0;     // Send NACK to indicate last byte 
            // of this transfer 
    } 

    break; 
1

Ваш след показывает (за исключением адресации) три байта и три байта. Я предполагаю, что вам нужно написать три байта, а затем читать только два байта. Если это правда, тогда проблема больше, чем просто ложный ACK, потому что ваш мастер продолжает синхронизировать третий байт.

Если вы хотите прочитать только два байта с примерами кода из Silabs 1, вам нужно определить NUM_BYTES_RD до 2 вместо прилагаемая 3. Это значение используется в SMB_MRADDACK и SMB_MRDBACK государств решить, следует ли ACK или Прекратите ,

На всякий случай (поскольку вы спрашиваете о ACK вместо дополнительных байтов), если ваш вопрос касается окончательного падения линии SDL на вашей трассе (после 0xff), потому что вы боитесь, что это дополнительный ACK, тогда беспокойство нет. Это STO (повышается при высоком SCL) и является правильным поведением для Master, заканчивающего передачу.

Редактировать: klamb верен в комментариях ниже, есть ошибка в состоянии SMB_MRDBACK. Сохранение SMB0DAT и приращение rec_byte_counter должно произойти до проверки rec_byte_counter против NUM_BYTES_RD. Подозреваю, что так вышло из SiLabs.

+0

Итак, мой NUM_BYTES_RD определяется как 2. Из моего понимания i2c мастер будет ACK, когда он ожидает другой байт, а затем NACK, когда он будет получать байты (и прекратить синхронизацию). Таким образом, это было ACKing дополнительное время (и отправка больше тактовых импульсов), чем я предполагал.Это было исправление: SMB_DATA_IN [rec_byte_counter-1] = SMB0DAT; rec_byte_counter ++; if (rec_byte_counter klamb

 Смежные вопросы

  • Нет связанных вопросов^_^