Example #1
0
/**
  Prints a character at the current cursor position.

  \param data The character to be displayed.

  This code is identical for all display buses and display types, because it
  just queues up the character.

  In case the buffer is full already it waits for a millisecond to allow
  data to be sent to the display, then it tries again. If it still fails then,
  it drops the character. This way we're fairly protected against data loss,
  still we guarantee to not hang forever.
*/
void display_writechar(uint8_t data) {

  if ( ! buf_canwrite(display)) {
    delay_ms(1);
  }
  if (buf_canwrite(display)) {
    buf_push(display, data);
  }
}
Example #2
0
/**
  Send a byte to the I2C partner.

  \param data       The byte to be buffered/sent.

  \param last_byte  Wether this is the last byte of a transmission.

  This implementation assumes to talk to mostly one communications client. To
  set the target, or to change it between transmissions, call i2c_init().

  Unlike many other protocols (serial, SPI), I2C has an explicite transmission
  start and transmission end. Invoking code has to tell wether the given byte
  is the last byte of a transmission, so sending code can properly end it.

  This function has been tested to properly distinguish between individual
  transmissions separated by last_byte. Other than setting this flag, invoking
  code doesn't have to care about distinction, but may experience substantial
  delays (up to several milliseconds) if the bus is already busy with a
  distinct previous transmission.

  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.

  To avoid unexpected delays, invoking code can check for bus availability
  with i2c_busy().

  Note that calling code has to send bytes quickly enough to not drain the
  buffer. It looks like the I2C protocol doesn't, unlike e.g. SPI, allow
  to pause sending without dropping the transmission. Positive of this
  limitation is, one can end a transmisson by simply not writing for a while,
  until it's sure the buffer became empty.
*/
void i2c_write(uint8_t data, uint8_t last_byte) {

  // Drop characters until transmission end. Transmissions to the display
  // start with a command byte, so sending truncated transmissions is harmful.
  if (i2c_state & I2C_ERROR) {
    if (last_byte) {
      i2c_state &= ~I2C_ERROR;
    }
    return;
  }

  while (i2c_should_end || ! buf_canwrite(send)) {
    delay_us(10);
  }

  if ( ! (i2c_state & I2C_MODE_BUSY)) {
    // No transmission ongoing, start one.
    i2c_state = I2C_MODE_SAWP;
    TWCR = (1<<TWINT)|(0<<TWEA)|(1<<TWSTA)|(0<<TWSTO)|(1<<TWEN)|(1<<TWIE);
    i2c_state |= I2C_MODE_BUSY;
  }

  ATOMIC_START
    buf_push(send, data);
    i2c_should_end = last_byte;
  ATOMIC_END
}
Example #3
0
/// send one character
void serial_writechar(uint8_t data)
{
	// check if interrupts are enabled
	if (SREG & MASK(SREG_I)) {
		// if they are, we should be ok to block since the tx buffer is emptied from an interrupt
		for (;buf_canwrite(tx) == 0;);
		buf_push(tx, data);
	}
	else {
		// interrupts are disabled- maybe we're in one?
		// anyway, instead of blocking, only write if we have room
		if (buf_canwrite(tx))
			buf_push(tx, data);
	}
	// enable TX interrupt so we can send this character
	UCSR0B |= MASK(UDRIE0);
}