Example #1
0
/**
  Inititalise the I2C/TWI subsystem.

  \param address Address the system should listen to in slave mode, unused
                 when configured for master mode. In master mode, receiver
                 address is given to the send command.

  This also sets the I2C address. In slave mode it's the address we listen on.

  In master mode it's the communication target address. As master one can talk
  to different devices. Call again i2c_init() for changing the target address,
  then. Doing so won't interrupt ongoing transmissions and overhead is small.
*/
void i2c_init(uint8_t address) {

  // In case this is a re-inititalisation,
  // don't interrupt an ongoing transmission.
  while (i2c_state & I2C_MODE_BUSY) {
    delay_us(10);
  }

  i2c_address = address;

  #ifdef I2C_MASTER_MODE
    #ifdef I2C_ENABLE_PULLUPS
      SET_INPUT(SCL);
      PULLUP_ON(SCL);
      SET_INPUT(SDA);
      PULLUP_ON(SDA);
    #endif /* I2C_ENABLE_PULLUPS */

    /**
      TWI Bit Rate register
      SCL_freq = CPU_freq / (16 + 2 * TWBR)
      See: page 235 of atmega328 datasheet.
    */
    TWBR = ((F_CPU / I2C_BITRATE) - 16) / 2;

    /**
      TWI Status Register
      Lower two bits set the prescaler value.
      See: page 236 of atmega328 datasheet.
    */
    TWSR = 0x00;
  #endif /* I2C_MASTER_MODE */

  #ifdef I2C_SLAVE_MODE
    TWAR = i2c_address; // We listen to broadcasts if lowest bit is set.
    TWCR = (0<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(1<<TWEN)|(1<<TWIE);
  #endif
}
Example #2
0
uint8_t manchester_receive(data_t* data)  // Function call 4 clk, function overhead at start 5 clk
{
	// Grand total from the edge 15 us + 1.125 us = 16.125 us.
	uint8_t time_tmp;
	uint8_t remainder = CRC_INITIAL_REMAINDER; // 0 clk

	PULLUP_OFF();

	(*data).abcd = 0;  // 8 clk = 1 us.

	//if(pinstat)
	//	return 1;

	// Wait for high transition
	// Already consumed 17.125 us. For +13 us time window, it needs to come within (25+13) - 17.125 us = 20.875 us = 167 clk

	// Require two successive high readings.
	// LOOP: SBIS 2 + SBIC 2 + SUBI 1 + BRCC 2 = 7 clk /round.
	time_tmp = 24;	//167/7 would be 23.85, round to 24.

	while(time_tmp--)
	{
		if(pinstat && pinstat)
			goto OK1;

	}

	PULLUP_ON();
	return 2;

	OK1:

	// Now we are exactly aligned at first '1', which is discarded.

	_delay_us(10.125 + 1.5); // Compensation for CRC delay, see below.
	                         // +1.5 = measured correction.

	for(uint8_t i = 0; i < 32; i++)
	{
		(*data).abcd <<= 1;  // 20 clk = 2.5 us

		// Align at 35.0 us from previous data bit. 37.5 us is
		// halfway between the optional edge and the next data bit.
		// Sample the value between 35.0 us and 40.0 us.
		// The expected edge is at 50 us, but allow it some window
		// due to clock differences.

		del_us(35.0 - 2.5 - 10.125 - 2.5 + 1.0); // CRC calculation uses 10.125 us - see
		                             // below.
									 // -2.5 = measured correction.


		uint8_t n_low_readings = 0;
		for(uint8_t i = 8; i>0; --i)  // 5 clk per round (regardless of pin value.)
		{
			if(!pinstat)
				n_low_readings++;
		} // 40 clk = 5 us.


		// Num of zeroes: 0  1  2   3  4   5  6  7
		//                H I G H | ?  ? | L  O  W

		if(n_low_readings < 3) 
		{	// High -- expect low. 
			del_us(10-WINDOW_BEFORE);
			// time windows of +/-10 us = 20 us = 160 clock cycles starts here.
			// LOOP: SBIS 2 + SBIC 2 + SUBI 1 + BRCC 2 = 7 clk /round.
			time_tmp = 	((WINDOW_BEFORE+WINDOW_AFTER)*8)/7;
			while(time_tmp--)
			{ // Require two successive low readings.
				if((!pinstat) && (!pinstat))
					goto OK2;
			}
			PULLUP_ON();
			return 0x40+i;

			OK2:
			__asm__ __volatile__ ("nop");

		}
		else if(n_low_readings > 4) // low -- expect high
		{
			del_us(10-WINDOW_BEFORE);
			// time windows of +/-10 us = 20 us = 160 clock cycles starts here.
			// LOOP: SBIS 2 + SBIC 2 + SUBI 1 + BRCC 2 = 7 clk /round.
			time_tmp = 	((WINDOW_BEFORE+WINDOW_AFTER)*8)/7;
			while(time_tmp--)
			{ // Require two successive high readings.
				if(pinstat && pinstat)
					goto OK3;
			}
			PULLUP_ON();
			return 0x60+i;

			OK3:

			(*data).d |= 1; // 1 clk = 0.125 us

		}
		else
		{
			PULLUP_ON();
			return 0x20+i;
		}

		// Here, we are aligned perfectly again.


		// At the same time, calculate CRC8. Calculate every time 8 bits have been received,
		// but of course skip the last octet which is the CRC.

		// Consume a constant amount of time here, which can be then subtracted from
		// the delay at the beginning of the loop.

		if(i==7 || i==15 || i==23)  // 6 cycles used when not true, 3...7 if true.
		{
			// We have our latest full byte in data.d
			remainder ^= (*data).d;        // 3 cycles
			CALC_CRC(remainder);
			// Total 3+48+24 = 75 cycles = 9.375 us.
		}
		else
		{
			_delay_us(9.375);
		}
		// In total, 10.125 us was spent for the if + CRC.

	}

	PULLUP_ON();

	if(remainder != (*data).d)
		return CRC_ERROR;

	return COMM_SUCCESS;
}