diff --git a/i2c.c b/i2c.c index ca561b7..c22d479 100644 --- a/i2c.c +++ b/i2c.c @@ -27,7 +27,9 @@ #include #include #include +#include "delay.h" #include "pinio.h" +#include "memory_barrier.h" #if defined I2C_MASTER_MODE && defined I2C_SLAVE_MODE @@ -66,11 +68,7 @@ // Address of the device that is communicated with. uint8_t i2c_address; // State of TWI component of MCU. -volatile uint8_t i2c_state; -// Index into the send/receive buffer. -uint8_t i2c_index; -// Count of bytes to be sent. -uint8_t i2c_byte_count; +volatile uint8_t i2c_state = I2C_MODE_FREE; #ifdef I2C_EEPROM_SUPPORT // For SAWSARP mode (see ENHA in i2c.h). @@ -84,10 +82,17 @@ uint8_t i2c_byte_count; #ifdef I2C_SLAVE_MODE uint8_t i2c_in_buffer[I2C_SLAVE_RX_BUFFER_SIZE]; uint8_t i2c_out_buffer[I2C_SLAVE_TX_BUFFER_SIZE]; -#else - uint8_t *i2c_buffer; #endif /* I2C_SLAVE_MODE */ +// Ringbuffer logic for buffer 'send'. +#define BUFSIZE I2C_BUFFER_SIZE + +volatile uint8_t sendhead = 0; +volatile uint8_t sendtail = 0; +volatile uint8_t sendbuf[BUFSIZE]; + +#include "ringbuffer.h" + /** Inititalise the I2C/TWI subsystem. @@ -129,21 +134,46 @@ void i2c_init(uint8_t address) { } /** - Send a data block to a slave device. + Send a byte to the I2C partner. + + \param address I2C address of the communications partner. + + \param data The byte to be buffered/sent. + + \param last_byte Wether this is the last byte of a transaction. + + Unlike many other protocols (serial, SPI), I2C has an explicite transmission + start and transmission end. Transmission start is detected automatically, + but end of the transmission has to be told by the invoking code. + + Data is buffered, so this returns quickly for small amounts of data. Large + amounts don't get lost, but this function has to wait until sufficient + previous data was sent. + + TODO: for now this function assumes that the buffer drains between distinct + transmissions. This means, last_byte is ignored and transmission is + ended as soon as the buffer drains. */ -void i2c_send(uint8_t address, uint8_t* block, uint8_t tx_len) { +void i2c_write(uint8_t address, uint8_t data, uint8_t last_byte) { - i2c_address = address; - i2c_buffer = block; - i2c_index = 0; - i2c_byte_count = tx_len; + if ( ! (i2c_state & I2C_MODE_BUSY)) { + // No transmission ongoing, start one. + i2c_address = address; - // Just send. - i2c_state = I2C_MODE_SAWP; + // Just send. + i2c_state = I2C_MODE_SAWP; - // Start transmission. - TWCR = (1<> 4) & 0x0F); - i2c_send(DISPLAY_I2C_ADDRESS, block, 4); - delay_ms(50); + i2c_write(DISPLAY_I2C_ADDRESS, 0x00 | (32 & 0x0F), 0); + i2c_write(DISPLAY_I2C_ADDRESS, 0x10 | ((32 >> 4) & 0x0F), 0); + delay_ms(100); - // Render text to bitmap. + // Render text to bitmap to display. + i2c_write(DISPLAY_I2C_ADDRESS, 0x40, 0); while (*message) { SYMBOL symbol = font_8x4[(uint8_t)*message - 0x20]; - memcpy(pointer, symbol.data, symbol.columns); - pointer += symbol.columns + FONT_SYMBOLS_SPACE; + + // Send the character bitmap. + for (i = 0; i < symbol.columns; i++) { + i2c_write(DISPLAY_I2C_ADDRESS, symbol.data[i], 0); + } + // Send space between characters. + for (i = 0; i < FONT_SYMBOLS_SPACE; i++) { + i2c_write(DISPLAY_I2C_ADDRESS, 0x00, 0); + } + message++; } - block[0] = 0x40; // Data marker. - i2c_send(DISPLAY_I2C_ADDRESS, block, pointer - block); } #endif /* I2C_TEST */