static void i2cs_send(char c) { I2C_WAIT(); while( TW_STATUS != TW_ST_SLA_ACK && TW_STATUS != TW_ST_DATA_ACK ) { I2C_ACK(); } I2C_SEND(c); }
// Send a n-byte data frame to an address void i2cm_send(uint8_t slave_addr, uint8_t n, const uint8_t* data) { int i; I2C_START(); // Slave address + Write bit (0) I2C_SEND(slave_addr<<1); // Data for( i=0; i<n; i++ ) { I2C_SEND(data[i]); } // Stop and wait I2C_STOP(); wait_4cyc(100); }
// Receive one data byte from an address, -1 on error int i2cm_rcv_single(uint8_t slave_addr) { 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 -1; } // First byte: is there something to transmit? I2C_ACK(); return TWDR; }
/* @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 }
// 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 Send data to an I2C slave. * * Parameters: * - I2C slave address (u8) * - data size (u16) * - data to send * * If the data size is 0 an empty frame is sent. * This can be used to synchronize the slave. * * @warning Since UART data is not bufferised, if slave is too long to UART * buffer overflows and the server will wait forever its input data. */ static void cmd_i2c_send(void) { const uint8_t addr = init_cmd_i2c(); if( addr == 0 ) { return; // reply sent by init_cmd_i2c() } // write frame uint16_t size = recv_u16(); // poll the slave do I2CM_START(); while( TW_STATUS != TW_START ); // slave address + Write bit (0) I2C_SEND(addr<<1); #ifndef DISABLE_STRICT_CHECKS uint8_t tw_status_copy = TW_STATUS; if( tw_status_copy == TW_MT_SLA_NACK ) { goto i2c_stop_slave_i2c_error; } if( tw_status_copy != TW_MT_SLA_ACK ) { goto slave_i2c_error; } #endif if( size != 0 ) { #ifndef DISABLE_STRICT_CHECKS tw_status_copy = TW_STATUS; if( tw_status_copy == TW_MT_SLA_NACK ) { goto i2c_stop_slave_i2c_error; } if( tw_status_copy != TW_MT_SLA_ACK ) { goto slave_i2c_error; } #endif // transfer data while( size-- != 1 ) { const uint8_t c = recv_u8(); I2C_SEND(c); #ifndef DISABLE_STRICT_CHECKS tw_status_copy = TW_STATUS; if( tw_status_copy != TW_MT_DATA_ACK ) { goto i2c_stop_slave_i2c_error; } #endif } const uint8_t c_last = recv_u8(); I2C_SEND_LAST(c_last); #ifndef DISABLE_STRICT_CHECKS tw_status_copy = TW_STATUS; if( tw_status_copy != TW_MT_DATA_ACK && tw_status_copy != TW_MT_DATA_NACK ) { goto i2c_stop_slave_i2c_error; } #endif } I2CM_STOP(); reply_success(0); return; #ifndef DISABLE_STRICT_CHECKS i2c_stop_slave_i2c_error: I2CM_STOP(); slave_i2c_error: reply_error(STATUS_I2C_ERROR); return; #endif }