// Receive a frame from an address // Slave must respect the i2c_ryder protocol : first byte tells if there are // data to transmit or not // Return number of read bytes uint8_t i2cm_rcv(uint8_t slave_addr, uint8_t n, uint8_t* data) { int i; I2C_START(); // Slave address + Read bit (1) I2C_SEND((slave_addr<<1)+1); // No ACK, no data if( TW_STATUS != TW_MR_SLA_ACK ) { I2C_STOP(); wait_4cyc(100); return 0; } // First byte: is there something to transmit? I2C_ACK(); if( TWDR == 0 ) { I2C_NACK(); I2C_STOP(); wait_4cyc(100); return 0; } // Read all data for( i=0; i<n; i++ ) { I2C_ACK(); data[i] = TWDR; } I2C_NACK(); I2C_STOP(); wait_4cyc(100); return 1; }
/* @brief Receive data from an I2C slave. * * Parameters for the '>' command: * - I2C slave address (u8) * - data size (u8) or 0 * * If the data size is 0, the value is read from the first data byte and is the * number of bytes to read after this first one. This is used to read protocol * replies from the slave. */ static void cmd_i2c_recv(void) { const uint8_t addr = init_cmd_i2c(); if( addr == 0 ) { return; // reply sent by init_cmd_i2c() } uint8_t size = recv_u8(); // poll the slave do I2CM_START(); while( TW_STATUS != TW_START ); // slave address + Read bit (1) I2C_SEND((addr<<1)+1); #ifndef DISABLE_STRICT_CHECKS if( TW_STATUS != TW_MR_SLA_ACK && TW_STATUS != TW_MR_SLA_NACK ) { I2CM_STOP(); goto slave_i2c_error; } #endif if( size == 0 ) { // read the size in the first byte I2C_ACK(); size = TWDR; reply_success(size+1); send_u8(size); } else { reply_success(size); } while( size-- != 1 ) { I2C_ACK(); const uint8_t c = TWDR; send_u8(c); } I2C_NACK(); send_u8( TWDR ); I2CM_STOP(); return; #ifndef DISABLE_STRICT_CHECKS slave_i2c_error: reply_error(STATUS_I2C_ERROR); return; #endif }
int DS1672_GetNextByte(void) { int t; I2C_Init(100,1000000); I2C_Start(); t=I2C_TX(DS1672_READ_ADDRESS); if(t!=0) { Log_Error((FARROM*)"DS1672: GetNextByte Error sending Address\r\n"); return -1; } t=I2C_RX(); if(t==-1) { Log_Error((FARROM*)"DS1672: GetNextByte Error receiving byte\r\n"); return -1; } I2C_NACK(); I2C_Stop(); return t; }
unsigned long DS1672_Value(void) { unsigned long value; int t; unsigned long v; I2C_Init(100,1000000); I2C_Start(); t=I2C_TX(0xD1); if(t!=0) return 0xffffffff; t=I2C_RX(); if(t==-1) return 0xffffffff; value=t; I2C_ACK(); t=I2C_RX(); if(t==-1) return 0xffffffff; v = t; value+=v<<8; I2C_ACK(); t=I2C_RX(); if(t==-1) return 0xffffffff; v = t; value+=v<<16; I2C_ACK(); t=I2C_RX(); if(t==-1) return 0xffffffff; v = t; value+=v<<24; I2C_NACK(); I2C_Stop(); return value; }
inline void i2c_handle_sda_irq(int controller) { volatile struct i2c_status *p_status = i2c_stsobjs + controller; /* 1 Issue Start is successful ie. write address byte */ if (p_status->oper_state == SMB_MASTER_START || p_status->oper_state == SMB_REPEAT_START) { uint8_t addr = p_status->slave_addr; /* Prepare address byte */ if (p_status->sz_txbuf == 0) {/* Receive mode */ p_status->oper_state = SMB_READ_OPER; /* * Receiving one byte only - set nack just * before writing address byte */ if (p_status->sz_rxbuf == 1) I2C_NACK(controller); /* Write the address to the bus R bit*/ I2C_WRITE_BYTE(controller, (addr | 0x1)); CPRINTS("-ARR-0x%02x", addr); } else {/* Transmit mode */ p_status->oper_state = SMB_WRITE_OPER; /* Write the address to the bus W bit*/ I2C_WRITE_BYTE(controller, addr); CPRINTS("-ARW-0x%02x", addr); } /* Completed handling START condition */ return; } /* 2 Handle master write operation */ else if (p_status->oper_state == SMB_WRITE_OPER) { /* all bytes have been written, in a pure write operation */ if (p_status->idx_buf == p_status->sz_txbuf) { /* no more message */ if (p_status->sz_rxbuf == 0) { /* need to STOP or not */ if (p_status->flags & I2C_XFER_STOP) { /* Issue a STOP condition on the bus */ I2C_STOP(controller); CPUTS("-SP"); /* Clear SDAST by writing dummy byte */ I2C_WRITE_BYTE(controller, 0xFF); } /* Set error code */ p_status->err_code = SMB_OK; /* Set SMB status if we need stall bus */ p_status->oper_state = (p_status->flags & I2C_XFER_STOP) ? SMB_IDLE : SMB_WRITE_SUSPEND; /* * Disable interrupt for i2c master stall SCL * and forbid SDAST generate interrupt * until common layer start other transactions */ if (p_status->oper_state == SMB_WRITE_SUSPEND) i2c_interrupt(controller, 0); /* Notify upper layer */ task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0); CPUTS("-END"); } /* need to restart & send slave address immediately */ else { uint8_t addr_byte = p_status->slave_addr; /* * Prepare address byte * and start to receive bytes */ p_status->oper_state = SMB_READ_OPER; /* Reset index of buffer */ p_status->idx_buf = 0; /* * Generate (Repeated) Start * upon next write to SDA */ I2C_START(controller); CPUTS("-RST"); /* * Receiving one byte only - set nack just * before writing address byte */ if (p_status->sz_rxbuf == 1) { I2C_NACK(controller); CPUTS("-GNA"); } /* Write the address to the bus R bit*/ I2C_WRITE_BYTE(controller, (addr_byte | 0x1)); CPUTS("-ARR"); } } /* write next byte (not last byte and not slave address */ else { I2C_WRITE_BYTE(controller, p_status->tx_buf[p_status->idx_buf++]); CPRINTS("-W(%02x)", p_status->tx_buf[p_status->idx_buf-1]); } } /* 3 Handle master read operation (read or after a write operation) */ else if (p_status->oper_state == SMB_READ_OPER) { uint8_t data; /* last byte is about to be read - end of transaction */ if (p_status->idx_buf == (p_status->sz_rxbuf - 1)) { /* need to STOP or not */ if (p_status->flags & I2C_XFER_STOP) { /* Stop should set before reading last byte */ I2C_STOP(controller); CPUTS("-SP"); } } /* Check if byte-before-last is about to be read */ else if (p_status->idx_buf == (p_status->sz_rxbuf - 2)) { /* * Set nack before reading byte-before-last, * so that nack will be generated after receive * of last byte */ if (p_status->flags & I2C_XFER_STOP) { I2C_NACK(controller); CPUTS("-GNA"); } } /* Read last byte but flag don't include I2C_XFER_STOP */ if (p_status->idx_buf == p_status->sz_rxbuf-1) { /* * Disable interrupt before i2c master read SDA reg * (stall SCL) and forbid SDAST generate interrupt * until common layer start other transactions */ if (!(p_status->flags & I2C_XFER_STOP)) i2c_interrupt(controller, 0); } /* Read data for SMBSDA */ I2C_READ_BYTE(controller, data); CPRINTS("-R(%02x)", data); /* Read to buffer */ p_status->rx_buf[p_status->idx_buf++] = data; /* last byte is read - end of transaction */ if (p_status->idx_buf == p_status->sz_rxbuf) { /* Set current status */ p_status->oper_state = (p_status->flags & I2C_XFER_STOP) ? SMB_IDLE : SMB_READ_SUSPEND; /* Set error code */ p_status->err_code = SMB_OK; /* Notify upper layer of missing data */ task_set_event(p_status->task_waiting, TASK_EVENT_I2C_IDLE, 0); CPUTS("-END"); } } }
static void I2C_SEND_LAST(uint8_t d) { TWDR = (d); I2C_NACK(); }