Example #1
0
/*
 * initiate a slave read or write I2C operation (polled)
 */
int8_t i2c_sla_rw(uint8_t device, uint8_t op, uint8_t expected_status, 
                  uint8_t verbose)
{
  uint8_t sla_w;
  uint8_t status;

  ms_count = 0;

  /* slave address + read/write operation */
  sla_w = (device << 1) | op;
  TWDR  = sla_w;
  TWCR  = I2C_MASTER_TX;
  while (!(TWCR & _BV(TWINT)) && (ms_count < I2C_TIMEOUT))
    ;

  if (ms_count >= I2C_TIMEOUT) {
    if (verbose) {
      i2c_error(s_i2c_sla_w_error, TWCR, TWSR);
      i2c_error(s_i2c_timeout, TWCR, TWSR);
    }
    return -1;
  }

  status = TWSR;
  if ((status & 0xf8) != expected_status) {
    if (verbose) {
      i2c_error(s_i2c_sla_w_error, TWCR, status);
    }
    return -1;
  }

  return 0;
}
Example #2
0
/*
 * signal an I2C start condition in preparation for an I2C bus
 * transfer sequence (polled)
 */
int8_t i2c_start(uint8_t expected_status, uint8_t verbose)
{
  uint8_t status;

  ms_count = 0;

  /* send start condition to take control of the bus */
  TWCR = I2C_START;
  while (!(TWCR & _BV(TWINT)) && (ms_count < I2C_TIMEOUT))
    ;

  if (ms_count >= I2C_TIMEOUT) {
    if (verbose) {
      i2c_error(s_i2c_start_error, TWCR, TWSR);
      i2c_error(s_i2c_timeout, TWCR, TWSR);
    }
    return -1;
  }

  /* verify start condition */
  status = TWSR;
  if (status != expected_status) {
    if (verbose) {
      i2c_error(s_i2c_start_error, TWCR, status);
    }
    return -1;
  }

  return 0;
}
Example #3
0
/*
 * transmit a data byte onto the I2C bus (polled)
 */
int8_t i2c_data_tx(uint8_t data, uint8_t expected_status, uint8_t verbose)
{
  uint8_t status;

  ms_count = 0;

  /* send data byte */
  TWDR = data;
  TWCR = I2C_MASTER_TX;
  while (!(TWCR & _BV(TWINT)) && (ms_count < I2C_TIMEOUT))
    ;

  if (ms_count >= I2C_TIMEOUT) {
    if (verbose) {
      i2c_error(s_i2c_data_tx_error, TWCR, TWSR);
      i2c_error(s_i2c_timeout, TWCR, TWSR);
    }
    return -1;
  }

  status = TWSR;
  if ((status & 0xf8) != expected_status) {
    if (verbose) {
      i2c_error(s_i2c_data_tx_error, TWCR, status);
    }
    return -1;
  }

  return 0;
}
Example #4
0
/*
 * receive a data byte from the I2C bus (polled)
 */
int8_t i2c_data_rx(uint8_t * data, uint8_t ack, uint8_t expected_status, 
                   uint8_t verbose)
{
  uint8_t status;
  uint8_t b;

  ms_count = 0;

  if (ack) {
    TWCR = _BV(TWINT)|_BV(TWEN)|_BV(TWEA);
  }
  else {
    TWCR = _BV(TWINT)|_BV(TWEN);
  }
  while (!(TWCR & _BV(TWINT)) && (ms_count < I2C_TIMEOUT))
    ;

  if (ms_count >= I2C_TIMEOUT) {
    if (verbose) {
      i2c_error(s_i2c_data_rx_error, TWCR, TWSR);
      i2c_error(s_i2c_timeout, TWCR, TWSR);
    }
    return -1;
  }

  status = TWSR;
  if ((status & 0xf8) != expected_status) {
    if (verbose) {
      i2c_error(s_i2c_data_rx_error, TWCR, status);
    }
    return -1;
  }

  b = TWDR;

  *data = b;

  return 0;
}
Example #5
0
void I2C_IRQ_err(i2c_bus *bus) {
  bool err = FALSE;
  bus->phy_error = 0;
  if (I2C_GetITStatus(I2C_HW(bus), I2C_IT_SMBALERT )) {
    DBG(D_I2C, D_WARN, "i2c_err: SMBus Alert\n");
    I2C_ClearITPendingBit(I2C_HW(bus), I2C_IT_SMBALERT );
    bus->phy_error |= 1 << I2C_ERR_PHY_SMBUS_ALERT;
    err = TRUE;
  }
  if (I2C_GetITStatus(I2C_HW(bus), I2C_IT_TIMEOUT )) {
    DBG(D_I2C, D_WARN, "i2c_err: Timeout or Tlow error\n");
    I2C_ClearITPendingBit(I2C_HW(bus), I2C_IT_TIMEOUT );
    bus->phy_error |= 1 << I2C_ERR_PHY_TIMEOUT;
    err = TRUE;
  }
  if (I2C_GetITStatus(I2C_HW(bus), I2C_IT_ARLO )) {
    DBG(D_I2C, D_WARN, "i2c_err: Arbitration lost\n");
    I2C_ClearITPendingBit(I2C_HW(bus), I2C_IT_ARLO );
    bus->phy_error |= 1 << I2C_ERR_PHY_ARBITRATION_LOST;
    err = TRUE;
  }
  if (I2C_GetITStatus(I2C_HW(bus), I2C_IT_PECERR )) {
    DBG(D_I2C, D_WARN, "i2c_err: PEC error\n");
    I2C_ClearITPendingBit(I2C_HW(bus), I2C_IT_PECERR );
    bus->phy_error |= 1 << I2C_ERR_PHY_PEC_ERR;
    err = TRUE;
  }
  if (I2C_GetITStatus(I2C_HW(bus), I2C_IT_OVR )) {
    DBG(D_I2C, D_WARN, "i2c_err: Overrun/Underrun flag\n");
    I2C_ClearITPendingBit(I2C_HW(bus), I2C_IT_OVR );
    bus->phy_error |= 1 << I2C_ERR_PHY_OVER_UNDERRUN;
    err = TRUE;
  }
  if (I2C_GetITStatus(I2C_HW(bus), I2C_IT_AF )) {
    DBG(D_I2C, D_WARN, "i2c_err: Acknowledge failure\n");
    I2C_ClearITPendingBit(I2C_HW(bus), I2C_IT_AF );
    bus->phy_error |= 1 << I2C_ERR_PHY_ACK_FAIL;
    err = TRUE;
  }
  if (I2C_GetITStatus(I2C_HW(bus), I2C_IT_BERR )) {
    DBG(D_I2C, D_WARN, "i2c_err: Bus error\n");
    I2C_ClearITPendingBit(I2C_HW(bus), I2C_IT_BERR );
    bus->phy_error |= 1 << I2C_ERR_PHY_BUS_ERR;
    err = TRUE;
  }

  if (err) {
    I2C_LOG_ERR(bus, bus->phy_error);
    i2c_error(bus, I2C_ERR_PHY, bus->phy_error & ((1 << I2C_ERR_PHY_BUS_ERR) | (1 << I2C_ERR_PHY_ARBITRATION_LOST)));
  }
}
Example #6
0
INLINE int read_reg(AccMMA *mma, uint8_t addr)
{
	i2c_start_w(mma->i2c, mma->dev_addr,  1, I2C_NOSTOP);
	i2c_putc(mma->i2c, addr);
	i2c_start_r(mma->i2c, mma->dev_addr, 1, I2C_STOP);

	uint8_t data = i2c_getc(mma->i2c);
	//LOG_INFO("%.2x\n", data);

	if (i2c_error(mma->i2c))
	{
		LOG_ERR("Errore!\n");
		return -1;
	}

	return data;
}
Example #7
0
INLINE int write_reg(AccMMA *mma, uint8_t addr, uint8_t data)
{
	i2c_start_w(mma->i2c, mma->dev_addr,  2, I2C_STOP);
	i2c_putc(mma->i2c, addr);
	i2c_putc(mma->i2c, data);

	LOG_INFO("Reg[%0x], Value[%0x]\n", addr, data);

	if (i2c_error(mma->i2c))
	{
		LOG_ERR("Errore!\n");
		return -1;
	}

	return data;

}
Example #8
0
int mma8451_readData(AccMMA *mma, AccData *data)
{
	ASSERT(data);
	memset(data, 0, sizeof(AccData));

	LOG_INFO("wait data\n");
	event_wait(&data_ready_ev);

	if (data_event_flag)
	{
		data_event_flag = false;
		data->data_status = read_reg(mma, MMA8451_REG_STATUS);
		i2c_start_w(mma->i2c, mma->dev_addr,  1, I2C_NOSTOP);
		i2c_putc(mma->i2c, MMA8451_REG_OUT_X_MSB);
		i2c_start_r(mma->i2c, mma->dev_addr, 6, I2C_STOP);

		memset(buf, 0, sizeof(buf));
		i2c_read(mma->i2c, buf, sizeof(buf));

		if (i2c_error(mma->i2c))
		{
			LOG_ERR("Errore!\n");
			return -1;
		}
		else
		{
			data->x = (int16_t)((buf[0] << 8) | buf[1]) >> 2;
			data->y = (int16_t)((buf[2] << 8) | buf[3]) >> 2;
			data->z = (int16_t)((buf[4] << 8) | buf[5]) >> 2;
		}
	}

	if (acc_event_flag)
	{
		acc_event_flag = false;
		data->ff_status = read_reg(mma,  MMA8451_REG_FF_MT_SRC);
		data->pl_status = read_reg(mma,  MMA8451_REG_PL_STATUS);
		data->tap_status = read_reg(mma, MMA8451_REG_PULSE_SRC);
	}

	return 0;
}
void send_cmd(uint8_t *cmd, size_t size) {
  i2c_master_transfer_t transfer;
  memset(&transfer, 0, sizeof(transfer));

  transfer.slaveAddress = max;
  transfer.direction = kI2C_Write;
  transfer.subaddress = 0;
  transfer.subaddressSize = 0;
  transfer.data = cmd;
  transfer.dataSize = size;
  transfer.flags = kI2C_TransferDefaultFlag;

  status_t status = I2C_MasterTransferBlocking(i2c_config_default.i2c, &transfer);
#ifndef NDEBUG
  if (status != kStatus_Success) {
    PRINTF("I2C write(%02d) <= %02x\r\n", 0, &cmd);
    i2c_error("write reg", status);
  }
#endif
}
Example #10
0
inline void LED_scan()
{
	// Latency measurement start
	Latency_start_time( ledLatencyResource );

	// Check for current change event
	if ( LED_currentEvent )
	{
		// Turn LEDs off in low power mode
		if ( LED_currentEvent < 150 )
		{
			LED_enable_current = 0;

			// Pause animations and clear display
			Pixel_setAnimationControl( AnimationControl_WipePause );
		}
		else
		{
			LED_enable_current = 1;

			// Start animations
			Pixel_setAnimationControl( AnimationControl_Forward );
		}

		LED_currentEvent = 0;
	}

	// Check if an LED_pause is set
	// Some ISSI operations need a clear buffer, but still have the chip running
	if ( LED_pause )
		goto led_finish_scan;

	// Check enable state
	if ( LED_enable && LED_enable_current )
	{
		// Disable Hardware shutdown of ISSI chips (pull high)
		GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveHigh, GPIO_Config_Pullup );
	}
	// Only write pages to I2C if chip is enabled (i.e. Hardware shutdown is disabled)
	else
	{
		// Enable hardware shutdown
		GPIO_Ctrl( hardware_shutdown_pin, GPIO_Type_DriveLow, GPIO_Config_Pullup );
		goto led_finish_scan;
	}

	// Check if any I2C buses have errored
	// Reset the buses and restart the Frame State
	if ( i2c_error() )
	{
		i2c_reset();
		Pixel_FrameState = FrameState_Update;
	}

	// Only start if we haven't already
	// And if we've finished updating the buffers
	if ( Pixel_FrameState == FrameState_Sending )
		goto led_finish_scan;

	// Only send frame to ISSI chip if buffers are ready
	if ( Pixel_FrameState != FrameState_Ready )
		goto led_finish_scan;

	// Adjust frame rate (i.e. delay and do something else for a bit)
	Time duration = Time_duration( LED_timePrev );
	if ( duration.ms < LED_framerate )
		goto led_finish_scan;

	// FPS Display
	if ( LED_displayFPS )
	{
		// Show frame calculation
		dbug_msg("1frame/");
		printInt32( Time_ms( duration ) );
		print("ms + ");
		printInt32( duration.ticks );
		print(" ticks");

		// Check if we're not meeting frame rate
		if ( duration.ms > LED_framerate )
		{
			print(" - Could not meet framerate: ");
			printInt32( LED_framerate );
		}

		print( NL );
	}

	// Emulated brightness control
	// Lower brightness by LED_brightness
#if ISSI_Chip_31FL3731_define == 1
	for ( uint8_t chip = 0; chip < ISSI_Chips_define; chip++ )
	{
		for ( uint8_t ch = 0; ch < LED_EnableBufferLength; ch++ )
		{
			LED_pageBuffer_brightness[ chip ].ledctrl[ ch ] = LED_pageBuffer[ chip ].ledctrl[ ch ];
		}

		for ( uint8_t ch = 0; ch < LED_BufferLength; ch++ )
		{
			// Don't modify is 0
			if ( LED_pageBuffer[ chip ].buffer[ ch ] == 0 || LED_brightness == 0 )
			{
				LED_pageBuffer_brightness[ chip ].buffer[ ch ] = 0;
				continue;
			}

			// XXX (HaaTa) Yes, this is a bit slow, but it's pretty accurate
			LED_pageBuffer_brightness[ chip ].buffer[ ch ] =
				(LED_pageBuffer[ chip ].buffer[ ch ] * LED_brightness) / 0xFF;
		}
	}
#endif

	// Update frame start time
	LED_timePrev = Time_now();

	// Set the page of all the ISSI chips
	// This way we can easily link the buffers to send the brightnesses in the background
	for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
	{
		uint8_t bus = LED_ChannelMapping[ ch ].bus;
		// Page Setup
		LED_setupPage(
			bus,
			LED_ChannelMapping[ ch ].addr,
			ISSI_LEDPwmPage
		);
	}

	// Send current set of buffers
	// Uses interrupts to send to all the ISSI chips
	// Pixel_FrameState will be updated when complete
	LED_chipSend = 0; // Start with chip 0
	LED_linkedSend();

led_finish_scan:
	// Latency measurement end
	Latency_end_time( ledLatencyResource );
}
static inline void i2c_irq(struct i2c_periph *periph)
{

  /*
	There are 7 possible reasons to get here:

	If IT_EV_FEN
	-------------------------

	We are always interested in all IT_EV_FEV: all are required.

	1) SB		// Start Condition Success in Master mode
	2) ADDR		// Address sent received Acknoledge
	[3 ADDR10]	// -- 10bit address stuff
	[4 STOPF]	// -- only for slaves: master has no stop interrupt
	5) BTF		// I2C has stopped working (it is waiting for new data, all buffers are tx_empty/rx_full)

	// Beware: using the buffered I2C has some interesting properties:
	  -in master receive mode: BTF only occurs after the 2nd received byte: after the first byte is received it is
           in RD but the I2C can still receive a second byte. Only when the 2nd byte is received while the RxNE is 1
	   then a BTF occurs (I2C can not continue receiving bytes or they will get lost). During BTF I2C is halted (SCL held low)
	  -in master transmitmode: when writing a byte to WD, you instantly get a new TxE interrupt while the first is not
	   transmitted yet. The byte was pushed to the I2C shift register and the buffer is ready for more. You can already
	   fill new data in the buffer while the first is still being transmitted for max performance transmission.

        // Beware: besides data buffering you can/must plan several consecutive actions. You can send 2 bytes to the buffer, ask for a stop and
           a new start in one go.

          -thanks to / because of this buffering and event sheduling there is not 1 interrupt per start / byte / stop
           This also means you must think more in advance and a transaction could be popped from the stack even before it is
           actually completely transmitted. But then you would not know the result yet so you have to keep it until the result
           is known.

	// Beware: the order in which Status is read determines how flags are cleared. You should not just read SR1 & SR2 every time

	If IT_EV_FEN AND IT_EV_BUF
	--------------------------

	Buffer event are not always wanted and are tipically switched on during longer data transfers. Make sure to turn off in time.

	6) RxNE
	7) TxE

	--------------------------------------------------------------------------------------------------
	// This driver uses only a subset of the pprz_i2c_states for several reasons:
	// -we have less interrupts than the I2CStatus states (for efficiency)
	// -STM32 has such a powerfull I2C engine with plenty of status register flags that
            only little extra status information needs to be stored.

       // Status is re-used (abused) to remember the last COMMAND THAT WAS SENT to the STM I2C hardware.

// TODO: check which are used
	enum I2CStatus {
	  I2CIdle,			// No more last command

	  I2CStartRequested,		// Last command was start
	  I2CRestartRequested,		// Last command was restart
	  I2CStopRequested,		// Very important to not send double stop conditions

	  I2CSendingByte,		// Some address/data operation

	  // Following are not used
	  I2CReadingByte,
	  I2CAddrWrSent,
	  I2CAddrRdSent,
	  I2CSendingLastByte,
	  I2CReadingLastByte,
	  I2CComplete,
	  I2CFailed
	};

	---------

	The STM waits indefinately (holding SCL low) for user interaction:
	a) after a master-start (waiting for address)
	b) after an address (waiting for data)
	   not during data sending when using buffered
	c) after the last byte is transmitted (waiting for either stop or restart)
	   not during data receiving when using buffered
	   not after the last byte is received

	-The STM I2C stalls indefinately when a stop condition was attempted that
	did not succeed. The BUSY flag remains on.
        -There is no STOP interrupt: use needs another way to finish.

   */


  ///////////////////////////////////////////////////////////////////////////////////
  // Reading the status:
  // - Caution: this clears several flags and can start transmissions etc...
  // - Certain flags like STOP / (N)ACK need to be guaranteed to be set before
  //   the transmission of the byte is finished. At higher clock rates that can be
  //   quite fast: so we allow no other interrupt to be triggered in between
  //   reading the status and setting all needed flags

  // Direct Access to the I2C Registers
  // Do not read SR2 as it might start the reading while an (n)ack bit might be needed first
  I2C_TypeDef *regs = (I2C_TypeDef *) periph->reg_addr;

#ifdef I2C_DEBUG_LED
  LED1_ON();
  LED1_OFF();
#endif


  ///////////////////////////////////////////////////////////////////////////////////////////////////////
  ///////////////////////////////////////////////////////////////////////////////////////////////////////
  //
  //	TRANSACTION HANDLER

  enum STMI2CSubTransactionStatus ret = 0;

  ///////////////////////
  // Nothing Left To Do
  if (periph->trans_extract_idx == periph->trans_insert_idx)
  {
#ifdef I2C_DEBUG_LED
        LED2_ON();
        LED1_ON();
	LED2_OFF();
	LED1_OFF();

    // no transaction and also an error?
    LED_SHOW_ACTIVE_BITS(regs);
#endif

    // If we still get an interrupt but there are no more things to do
    // (which can happen if an event was sheduled just before a bus error occurs)
    // then its easy: just stop: clear all interrupt generating bits

    // Count The Errors
    i2c_error(periph);

    // Clear Running Events
    stmi2c_clear_pending_interrupts(regs);

    // Mark this as a special error
    periph->errors->unexpected_event_cnt++;

    periph->status = I2CIdle;

    // There are no transactions anymore:
    // furtheron we need a transaction pointer: so we are not allowed to continue
    return;
  }

  struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx];

  ///////////////////////////
  // If there was an error:
  if (( regs->SR1 & I2C_SR1_BITS_ERR ) != 0x0000)
  {

#ifdef I2C_DEBUG_LED
        LED1_ON();
        LED2_ON();
	LED1_OFF();
	LED2_OFF();

        LED_SHOW_ACTIVE_BITS(regs);
#endif

    // Set result in transaction
    trans->status = I2CTransFailed;

    // Prepare for next
    ret = STMI2C_SubTra_Ready;

    // Make sure a TxRx does not Restart
    trans->type = I2CTransRx;

/*
    // There are 2 types of errors: some need a STOP, some better do without: Following will not get an extra stop
    if (
           // Lost Arbitration
           (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ERR_ARLO, regs->SR1 ) )
           // Buss Error When Master Only
        || ((BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ERR_BUS,  regs->SR1 ) )  &&  (!BIT_X_IS_SET_IN_REG( I2C_SR2_BIT_MSL,  regs->SR2 ) ))
        || (BIT_X_IS_SET_IN_REG( I2C_SR1_BIT_ERR_OVR,  regs->SR1 ) )
       )
    {
      ret = STMI2C_SubTra_Error;
    }
*/

    // Count The Errors
    i2c_error(periph);

    // Clear Running Events
    stmi2c_clear_pending_interrupts(regs);

  }


  ///////////////////////////
  // Normal Event:
  else
  {

    if (trans->type == I2CTransRx) // TxRx are converted to Rx after the Tx Part
    {
      switch (trans->len_r)
      {
        case 1:
          ret = stmi2c_read1(regs,trans);
          break;
        case 2:
          ret = stmi2c_read2(regs,trans);
          break;
        default:
          ret = stmi2c_readmany(regs,periph, trans);
          break;
      }
    }
    else // TxRx or Tx
    {
      ret = stmi2c_send(regs,periph,trans);
    }
  }

  /////////////////////////////////
  // Sub-transaction has finished
  if (ret != STMI2C_SubTra_Busy)
  {
    // If a restart is not needed
    if (trans->type != I2CTransTxRx)
    {
      // Ready, no stop condition set yet
      if (ret == STMI2C_SubTra_Ready)
      {

        // Program a stop
        PPRZ_I2C_SEND_STOP(regs);

        // Silent any BTF that would occur before STOP is executed
        regs->DR = 0x00;
      }

      // In case of unexpected condition: e.g. not slave, no event
      if (ret == STMI2C_SubTra_Error)
      {

        trans->status = I2CTransFailed;

    // Error
#ifdef I2C_DEBUG_LED
        LED2_ON();
        LED1_ON();
	LED2_OFF();
	LED1_OFF();
#endif

        LED_SHOW_ACTIVE_BITS(regs);

        // Clear Running Events
        stmi2c_clear_pending_interrupts(regs);

      }


      // Jump to the next transaction
      periph->trans_extract_idx++;
      if (periph->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
        periph->trans_extract_idx = 0;

      // Tell everyone we are ready
      periph->status = I2CIdle;


      // if we have no more transaction to process, stop here
      if (periph->trans_extract_idx == periph->trans_insert_idx)
      {

#ifdef I2C_DEBUG_LED
        LED2_ON();
        LED1_ON();
	LED1_OFF();
        LED1_ON();
	LED1_OFF();
	LED2_OFF();
#endif
      }
      // if not, start next transaction
      else
      {
        // Restart transaction doing the Rx part now
// --- moved to idle function
        PPRZ_I2C_SEND_START(periph);
// ------
     }

    }
    // RxTx -> Restart and do Rx part
    else
    {
      trans->type = I2CTransRx;
      periph->status = I2CStartRequested;
      regs->CR1 |= I2C_CR1_BIT_START;

      // Silent any BTF that would occur before SB
      regs->DR = 0x00;
    }
  }

  return;
}
Example #12
0
static inline void i2c_irq(struct i2c_periph *periph)
{

  /*
    There are 7 possible event reasons to get here + all errors

    If IT_EV_FEN
    -------------------------

    We are always interested in all IT_EV_FEV: all are required.

    1) SB		// Start Condition Success in Master mode
    2) ADDR		// Address sent received Acknoledge
    [ADDR10]	// -- 10bit address stuff: not used
    [STOPF]		// -- only for slaves: master has no stop interrupt: not used
    3) BTF		// I2C has stopped working (it is waiting for new data, all buffers are tx_empty/rx_full)

    // Beware: using the buffered I2C has some interesting properties:
    - in master receive mode: BTF only occurs after the 2nd received byte: after the first byte is received it is
      in RD but the I2C can still receive a second byte. Only when the 2nd byte is received while the RxNE is 1
      then a BTF occurs (I2C can not continue receiving bytes or they will get lost). During BTF I2C is halted (SCL held low)
    - in master transmit mode: when writing a byte to WD, you instantly get a new TxE interrupt while the first is not
      transmitted yet. The byte was pushed to the I2C shift register and the buffer is ready for more. You can already
      fill new data in the buffer while the first is still being transmitted for max performance transmission.

    // Beware: besides data buffering you can/must plan several consecutive actions. You can send 2 bytes to the buffer, ask for a stop and
    a new start in one go.

    - thanks to / because of this buffering and event sheduling there is not 1 interrupt per start / byte / stop
      This also means you must think more in advance and a transaction could be popped from the transaction stack even before it's
      stop condition is actually generated.

    // Beware: the order in which Status (and other register) is read determines how flags are cleared.
    You should NOT simply read SR1 & SR2 every time

    If IT_EV_FEN AND IT_EV_BUF
    --------------------------

    Buffer event are not always wanted and are typically switched on during longer data transfers. Make sure to turn off in time.

    4) RxNE
    5) TxE

    --------------------------------------------------------------------------------------------------

    The STM waits indefinately (holding SCL low) for user interaction:
    a) after a master-start (waiting for address)
    b) after an address (waiting for data)
       not during data sending when using buffered
    c) after the last byte is transmitted (waiting for either stop or restart)
       not during data receiving when using buffered
       not after the last byte is received

    - The STM I2C stalls indefinately when a stop condition was attempted that
      did not succeed. The BUSY flag remains on.
    - There is no STOP interrupt.

    Caution Reading the status:
    - Caution: this clears several flags and can start transmissions etc...
    - Certain flags like STOP / (N)ACK need to be guaranteed to be set before
      the transmission of the byte is finished. At higher clock rates that can be
      quite fast: so we allow no other interrupt to be triggered in between
      reading the status and setting all needed flags

  */

  // Here we go ...

  // Apparently we got an I2C interrupt: EVT BUF or ERR

#ifdef I2C_DEBUG_LED
  // Notify ISR is triggered
  LED1_ON();
  LED1_OFF();
#endif

  // Save Some Direct Access to the I2C Registers ...
  uint32_t i2c = (uint32_t) periph->reg_addr;

  /////////////////////////////
  // Check if we were ready ...
  if (periph->trans_extract_idx == periph->trans_insert_idx)
  {
    // Nothing Left To Do

#ifdef I2C_DEBUG_LED
    LED2_ON();
    LED1_ON();
    LED2_OFF();
    LED1_OFF();

    // no transaction and also an error?
    LED_SHOW_ACTIVE_BITS(regs);
#endif

    // If we still get an interrupt but there are no more things to do
    // (which can happen if an event was sheduled just before a bus error occurs)
    // (or can happen if both error and event interrupts were called together [the 2nd will then get this error])

    // since there is nothing more to do: its easy: just stop: clear all interrupt generating bits

    // Count The Errors
    i2c_error(periph);

    // Clear Running Events
    stmi2c_clear_pending_interrupts(i2c);

    // Mark this as a special error
    periph->errors->last_unexpected_event++;

    // Document the current Status
    periph->status = I2CIdle;

    // There are no transactions anymore: return
    // further-on in this routine we need a transaction pointer: so we are not allowed to continue
    return;
  }

  // get the I2C transaction we were working on ...

  enum STMI2CSubTransactionStatus ret = 0;
  struct i2c_transaction* trans = periph->trans[periph->trans_extract_idx];

  ///////////////////////////
  // If there was an error:
  if (( I2C_SR1(i2c) & I2C_SR1_ERR_MASK ) != 0x0000)
  {

#ifdef I2C_DEBUG_LED
    LED1_ON();
    LED2_ON();
    LED1_OFF();
    LED2_OFF();

    LED_SHOW_ACTIVE_BITS(regs);
#endif

    // Notify everyone about the error ...

    // Set result in transaction
    trans->status = I2CTransFailed;

    // Document the current Status
    periph->status = I2CFailed;

    // Make sure a TxRx does not Restart
    trans->type = I2CTransRx;

    // Count The Errors
    i2c_error(periph);

    // Clear Running Events
    stmi2c_clear_pending_interrupts(i2c);

    // Now continue as if everything was normal from now on
    ret = STMI2C_SubTra_Ready;

  }

  ///////////////////////////
  // Normal Event:
  else
  {

    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////////////////////////////////////////////
    //
    //	SUB-TRANSACTION HANDLER

    if (trans->type == I2CTransRx) // TxRx are converted to Rx after the Tx Part
    {
      switch (trans->len_r)
      {
      case 1:
        ret = stmi2c_read1(i2c,periph,trans);
        break;
      case 2:
        ret = stmi2c_read2(i2c,periph,trans);
        break;
      default:
        ret = stmi2c_readmany(i2c,periph,trans);
        break;
      }
    }
    else // TxRx or Tx
    {
      ret = stmi2c_send(i2c,periph,trans);
    }
  }

  /////////////////////////////////
  // Sub-transaction has finished
  if (ret != STMI2C_SubTra_Busy)
  {
    // Ready or SubTraError
    // -ready: with or without stop already asked

    // In case of unexpected event condition during subtransaction handling:
    if (ret == STMI2C_SubTra_Error)
    {
      // Tell everyone about the subtransaction error:
      // this is the previously called SPURRIOUS INTERRUPT
      periph->status = I2CFailed;
      trans->type = I2CTransRx;		// Avoid possible restart
      trans->status = I2CTransFailed;	// Notify Ready
      periph->errors->unexpected_event_cnt++;

      // Error
#ifdef I2C_DEBUG_LED
      LED2_ON();
      LED1_ON();
      LED2_OFF();
      LED1_OFF();

      LED_SHOW_ACTIVE_BITS(regs);
#endif

      // Clear Running Events
      stmi2c_clear_pending_interrupts(i2c);
    }

    // RxTx -> Restart and do Rx part
    if (trans->type == I2CTransTxRx)
    {
      trans->type = I2CTransRx;
      periph->status = I2CStartRequested;
      i2c_send_start(i2c);

      // Silent any BTF that would occur before SB
      i2c_send_data(i2c, 0x00);
    }
    // If a restart is not needed: Rx part or Tx-only
    else
    {
      // Ready, no stop condition set yet
      if (ret == STMI2C_SubTra_Ready)
      {

        // Program a stop
        PPRZ_I2C_SEND_STOP(i2c);

        // Silent any BTF that would occur before STOP is executed
        i2c_send_data(i2c, 0x00);
      }

      // Jump to the next transaction
      periph->trans_extract_idx++;
      if (periph->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
        periph->trans_extract_idx = 0;

      // Tell everyone we are ready
      periph->status = I2CIdle;


      // if we have no more transaction to process, stop here
      if (periph->trans_extract_idx == periph->trans_insert_idx)
      {

        periph->watchdog = -1; // stop watchdog
#ifdef I2C_DEBUG_LED
        LED2_ON();
        LED1_ON();
        LED1_OFF();
        LED1_ON();
        LED1_OFF();
        LED2_OFF();
#endif
      }
      // if not, start next transaction
      else
      {
        // Restart transaction doing the Rx part now
        // --- moved to idle function
        PPRZ_I2C_SEND_START(periph);
        // ------
      }
    }
  }

  return;
}
Example #13
0
void I2C_IRQ_ev(i2c_bus *bus) {
  if (bus->state == I2C_S_IDLE) {
//    u32_t ev = I2C_GetLastEvent(I2C_HW(bus));
//    I2C_LOG_UNKNOWN_EV(bus, ev);
//    (void)ev;
//    i2c_error(bus, I2C_ERR_UNKNOWN_STATE, TRUE);
    return;
  }


  u32_t sr1 = I2C_HW(bus)->SR1;
  DBG(D_I2C, D_DEBUG, "I2C irq ev %02x\n", sr1);

  if (bus->op == I2C_OP_RX) {

    // ==== RX ====

    if ((sr1 & I2C_IT_SB) && bus->state == I2C_S_GEN_START) {
      // send address | 0x01 for rx
      I2C_HW_DBG("rx it sb\n");
      I2C_LOG_EV(bus, sr1);
      I2C_HW(bus)->DR = bus->addr | 0x01;
    } // if IT_SB
    else if ((sr1 & I2C_IT_ADDR) && bus->state == I2C_S_GEN_START) {
      // address sent and acknowledged
      // IT_ADDR bit cleared by reading SR1 & SR2
      (void)I2C_HW(bus)->SR2;
      I2C_LOG_EV(bus, sr1);
      bus->state = I2C_S_RX;
      if (bus->len == 2) {
        I2C_HW_DBG("rx it addr, len = 2\n");
        // RM0008 26.3.3 case len = 2
        I2C_ITConfig(I2C_HW(bus), I2C_IT_BUF, DISABLE); // kill RXNE interrupt, rely on BTF interrupt
        // POS=1 indicates that the ACK bit indicates ack or nack of next byte coming in the shift reg
        I2C_HW(bus)->CR1 |= I2C_CR1_POS;
        I2C_AcknowledgeConfig(I2C_HW(bus), DISABLE);
      }
      else if (bus->len <= 1) {
        // RM0008 26.3.3 case len = 1
        I2C_HW_DBG("rx it addr, len < 2\n");
        I2C_AcknowledgeConfig(I2C_HW(bus), DISABLE);
        if (bus->gen_stop) {
          I2C_LOG_STOP(bus);
          I2C_GenerateSTOP(I2C_HW(bus), ENABLE);
        } else {
          // the restart condition must be set before receiving last byte
          I2C_LOG_START(bus);
          I2C_GenerateSTART(I2C_HW(bus), ENABLE);
          bus->restart_generated = TRUE;
        }
      }
      else { // bus->len > 2
        // do naught, rely on RXNE interrupt
        I2C_HW_DBG("rx it addr, len > 2\n");
      }
    } // if IT_ADDR
    else if ((sr1 & I2C_IT_BTF) && bus->state == I2C_S_RX) {
      // data register full, shift register full, clock is now stretched
      I2C_LOG_EV(bus, sr1);
      if (bus->len == 2) {
        I2C_HW_DBG("rx it btf, len = 2\n");
        // these are the two last bytes to receive
        if (bus->gen_stop) {
          I2C_LOG_STOP(bus);
          I2C_GenerateSTOP(I2C_HW(bus), ENABLE);
        } else {
          // the restart condition must be set before receiving last byte
          I2C_LOG_START(bus);
          I2C_GenerateSTART(I2C_HW(bus), ENABLE);
          bus->restart_generated = TRUE;
        }
        *bus->buf++ = I2C_HW(bus)->DR;
        *bus->buf++ = I2C_HW(bus)->DR;
        bus->len -= 2;

        // clear POS
        I2C_HW(bus)->CR1 &= ~I2C_CR1_POS;

        i2c_finalize(bus);
        if (bus->i2c_bus_callback) {
          I2C_LOG_CB(bus);
          bus->i2c_bus_callback(bus, I2C_RX_OK);
        }
      }
      else if (bus->len == 3) {
        I2C_HW_DBG("rx it btf, len = 3\n");
        I2C_ITConfig(I2C_HW(bus), I2C_IT_BUF, DISABLE); // kill RXNE interrupts now, rely on BTF
        I2C_AcknowledgeConfig(I2C_HW(bus), DISABLE);
        // read N-2, await IT_BTF for the final 2 bytes
        *bus->buf++ = I2C_HW(bus)->DR;
        bus->len--;
      }
      else { // bus->len > 3
        I2C_HW_DBG("rx it btf, len > 3\n");
        *bus->buf++ = I2C_HW(bus)->DR;
        bus->len--;
      }
    } // if IT_BTF
    else if (sr1 & I2C_IT_RXNE) {
      I2C_LOG_EV(bus, sr1);
      ASSERT(bus->len != 2); // this should never happen as RXNE interrupts for 2 bytes are disabled
      if (bus->len == 3) {
        I2C_HW_DBG("rx it rxne, len = 3\n");
        I2C_ITConfig(I2C_HW(bus), I2C_IT_BUF, DISABLE); // kill RXNE interrupts now, rely on BTF
      }
      else {
        // bus->len > 3 || bus->len == 1
        I2C_HW_DBG("rx it rxne, len > 3\n");
        *bus->buf++ = I2C_HW(bus)->DR;
        bus->len--;
        if (bus->len == 0) {
          if (bus->gen_stop) {
            I2C_LOG_STOP(bus);
            I2C_GenerateSTOP(I2C_HW(bus), ENABLE);
          } else {
            // the restart condition must be set before receiving last byte
            I2C_LOG_START(bus);
            I2C_GenerateSTART(I2C_HW(bus), ENABLE);
            bus->restart_generated = TRUE;
          }
          bool gen_cb = bus->state == I2C_S_RX;
          i2c_finalize(bus);
          if (bus->i2c_bus_callback && gen_cb) {
            I2C_LOG_CB(bus);
            bus->i2c_bus_callback(bus, I2C_RX_OK);
          }
        }
      }
    } // if IT_RXNE
    else {
      // do not read SR2 here, this might clear IT_ADDR or IT_SB
      I2C_HW_DBG("rx it bad\n");
      I2C_LOG_UNKNOWN_EV(bus, sr1);
      bus->bad_ev_counter++;
    } // if any other interrupt

  } // if RX
  else {

    // ==== TX or QUERY ====

    I2C_LOG_EV(bus, sr1);
    if (sr1 & I2C_IT_SB) {
      // from send start condition
      I2C_HW_DBG("tx it sb\n");
      I2C_HW(bus)->DR = bus->addr & ~0x01;
    }
    else if (sr1 & I2C_IT_ADDR) {
      // from send 7 bit address tx
      // IT_ADDR bit cleared by reading SR1 & SR2
      (void)I2C_HW(bus)->SR2;
      if (bus->len > 0 && bus->op == I2C_OP_TX) {
        I2C_HW_DBG("tx it addr\n");
        bus->state = I2C_S_TX;
        I2C_HW(bus)->DR = *bus->buf++;
        bus->len--;
        if (bus->len == 0) {
          I2C_ITConfig(I2C_HW(bus), I2C_IT_BUF, DISABLE); // kill TXE interrupts now, rely on BTF
        }
      } else {
        // for address query
        I2C_HW_DBG("tx query it addr\n");
        I2C_LOG_STOP(bus);
        I2C_GenerateSTOP(I2C_HW(bus), ENABLE);
        i2c_finalize(bus);
        if (bus->i2c_bus_callback) {
          I2C_LOG_CB(bus);
          bus->i2c_bus_callback(bus, I2C_OK);
        }
      }
    }
    else if ((sr1 & I2C_IT_TXE) || (sr1 & I2C_IT_BTF)) {
      // transmitted or transmitting
      I2C_HW_DBG("tx it txed txing TXE:%i BTF:%i len:%i\n", (sr1 & I2C_IT_TXE) != 0, (sr1 & I2C_IT_BTF) != 0, bus->len);
      if (bus->len > 0) {
        I2C_HW(bus)->DR = *bus->buf++;
        bus->len--;
        if (bus->len == 0) {
          I2C_ITConfig(I2C_HW(bus), I2C_IT_BUF, DISABLE); // kill TXE interrupts now, rely on BTF
        }
      }
      else if (bus->state == I2C_S_TX && (sr1 & I2C_IT_BTF)) {
        // must check for tx here, at low speeds there might come spurios tx events
        if (bus->len == 0) {
          if (bus->gen_stop) {
            I2C_LOG_STOP(bus);
            I2C_GenerateSTOP(I2C_HW(bus), ENABLE);
          } else {
            I2C_LOG_START(bus);
            I2C_GenerateSTART(I2C_HW(bus), ENABLE);
            bus->restart_generated = TRUE;
          }
          bool gen_cb = bus->state == I2C_S_TX;
          i2c_finalize(bus);
          if (bus->i2c_bus_callback && gen_cb) {
            I2C_LOG_CB(bus);
            bus->i2c_bus_callback(bus, I2C_TX_OK);
          }
        }
      }
    }
    else {
      // bad event
      DBG(D_I2C, D_WARN, "i2c_err: bad event %02x\n", sr1);
      bus->bad_ev_counter ++;
      I2C_LOG_UNKNOWN_EV(bus, sr1);
    } // switch ev
  }
  if (bus->bad_ev_counter > 16) {
    i2c_error(bus, I2C_ERR_UNKNOWN_STATE, TRUE);
  }
}