Exemplo n.º 1
0
int i2c_slave_receive(i2c_t *obj) {
    int retValue = NoData;

    if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == 1) {
        if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_ADDR) == 1) {
            if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TRA) == 1)
                retValue = ReadAddressed;
            else
                retValue = WriteAddressed;

            __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_ADDR);
        }
    }

    return (retValue);
}
Exemplo n.º 2
0
int i2c_slave_receive(i2c_t *obj) {
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int retValue = NoData;

    if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == 1) {
        if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_ADDR) == 1) {
            if (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_DIR) == 1)
                retValue = ReadAddressed;
            else
                retValue = WriteAddressed;
            __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_ADDR);
        }
    }

    return (retValue);
}
Exemplo n.º 3
0
void i2c_frequency(i2c_t *obj, int hz) {
    MBED_ASSERT((hz == 100000) || (hz == 400000) || (hz == 1000000));
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    // wait before init
    timeout = LONG_TIMEOUT;
    while ((__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY)) && (timeout-- != 0));

    // Common settings: I2C clock = 48 MHz, Analog filter = ON, Digital filter coefficient = 0
    switch (hz) {
        case 100000:
            I2cHandle.Init.Timing = 0x10805E89; // Standard mode with Rise Time = 400ns and Fall Time = 100ns
            break;
        case 400000:
            I2cHandle.Init.Timing = 0x00901850; // Fast mode with Rise Time = 250ns and Fall Time = 100ns
            break;
        case 1000000:
            I2cHandle.Init.Timing = 0x00700818; // Fast mode Plus with Rise Time = 60ns and Fall Time = 100ns
            break;
        default:
            break;
    }

    // I2C configuration
    I2cHandle.Init.AddressingMode   = I2C_ADDRESSINGMODE_7BIT;
    I2cHandle.Init.DualAddressMode  = I2C_DUALADDRESS_DISABLED;
    I2cHandle.Init.GeneralCallMode  = I2C_GENERALCALL_DISABLED;
    I2cHandle.Init.NoStretchMode    = I2C_NOSTRETCH_DISABLED;
    I2cHandle.Init.OwnAddress1      = 0;
    I2cHandle.Init.OwnAddress2      = 0;
    I2cHandle.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
    HAL_I2C_Init(&I2cHandle);
}
Exemplo n.º 4
0
void i2c_frequency(i2c_t *obj, int hz) {
    MBED_ASSERT((hz != 0) && (hz <= 400000));
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int timeout;
	
    // wait before init
    timeout = LONG_TIMEOUT;
    while((__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY)) && (timeout-- != 0));

    // I2C configuration
    I2cHandle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
    I2cHandle.Init.ClockSpeed      = hz;
    I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
    I2cHandle.Init.DutyCycle       = I2C_DUTYCYCLE_2;
    I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
    I2cHandle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLED;
    I2cHandle.Init.OwnAddress1     = 0;
    I2cHandle.Init.OwnAddress2     = 0;
    HAL_I2C_Init(&I2cHandle);
    if (obj->slave) {
        /* Enable Address Acknowledge */
        I2cHandle.Instance->CR1 |= I2C_CR1_ACK;
    }

}
Exemplo n.º 5
0
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int timeout;
    int count;
    int value;

    if (length == 0) return 0;

    /* update CR2 register */
    i2c->CR2 = (i2c->CR2 & (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP)))
               | (uint32_t)(((uint32_t)address & I2C_CR2_SADD) | (((uint32_t)length << 16) & I2C_CR2_NBYTES) | (uint32_t)I2C_SOFTEND_MODE | (uint32_t)I2C_GENERATE_START_READ);

    // Read all bytes
    for (count = 0; count < length; count++) {
        value = i2c_byte_read(obj, 0);
        data[count] = (char)value;
    }

    // Wait transfer complete
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TC) == RESET) {
        timeout--;
        if (timeout == 0) {
            return 0;
        }
    }

    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_TC);

    // If not repeated start, send stop.
    if (stop) {
        i2c_stop(obj);
        /* Wait until STOPF flag is set */
        timeout = FLAG_TIMEOUT;
        while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_STOPF) == RESET) {
            timeout--;
            if (timeout == 0) {
                return 0;
            }
        }
        /* Clear STOP Flag */
        __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_STOPF);
    }

    return length;
}
/**
  * @brief  This function handles I2C Communication Timeout for specific usage of RXNE flag.
  * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
  *                the configuration information for the specified I2C.
  * @param  Timeout Timeout duration
  * @param  Tickstart Tick start value
  * @retval HAL status
  */
static HAL_StatusTypeDef I2C_WaitOnRXNEFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart, uint8_t prev_mode)
{
  while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_RXNE) == RESET)
  {
    /* Check if a NACK is detected */
    if (I2C_IsAcknowledgeFailed(hi2c, Timeout, Tickstart) != HAL_OK)
    {
      return HAL_NACK;
    }

    /*
     * FIXME: need to re-check if what is supposed to be a RESTART is not also
     * triggering a STOP along...
     */
    /* Check if a STOPF is detected */
    if (prev_mode != HAL_I2C_MODE_MASTER_SEL && __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == SET)
    {
      /* Clear STOP Flag */
      __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);

      /* Clear Configuration Register 2 */
      I2C_RESET_CR2(hi2c);

      hi2c->ErrorCode = HAL_I2C_ERROR_NONE;
      hi2c->State = HAL_I2C_STATE_READY;
      hi2c->Mode = HAL_I2C_MODE_NONE;

      /* Process Unlocked */
      __HAL_UNLOCK(hi2c);

      return HAL_ERROR;
    }

    /* Check for the Timeout */
    if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
    {
      hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
      hi2c->State = HAL_I2C_STATE_READY;

      /* Process Unlocked */
      __HAL_UNLOCK(hi2c);

      return HAL_TIMEOUT;
    }
  }
  return HAL_OK;
}
Exemplo n.º 7
0
// this function is based on STM code
STATIC bool I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c) {
    if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET) {
        /* Clear NACKF Flag */
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);
        return true;
    }
    return false;
}
Exemplo n.º 8
0
int i2c_byte_write(i2c_t *obj, int data) {
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    i2c->DR = (uint8_t)data;

    // Wait until the byte is transmitted
    timeout = FLAG_TIMEOUT;
    while ((__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TXE) == RESET) &&
            (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BTF) == RESET)) {
        if ((timeout--) == 0) {
            return 0;
        }
    }

    return 1;
}
Exemplo n.º 9
0
/**
  * @brief  This function handles Acknowledge failed detection during an I2C Communication.
  * @param  hi2c: Pointer to a I2C_HandleTypeDef structure that contains
  *               the configuration information for the specified I2C.
  * @param  Timeout: Timeout duration
  * @param  Tickstart: Tick start value
  * @retval HAL status
  */
static HAL_StatusTypeDef I2C_IsAcknowledgeFailed(I2C_HandleTypeDef *hi2c, uint32_t Timeout, uint32_t Tickstart)
{
  if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == SET)
  {
    /* Wait until STOP Flag is reset */
    /* AutoEnd should be initiate after AF */
    while(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) == RESET)
    {
      /* Check for the Timeout */
      if(Timeout != HAL_MAX_DELAY)
      {
      if((Timeout == 0)||((HAL_GetTick() - Tickstart) > Timeout))
        {
          hi2c->State= HAL_I2C_STATE_READY;
          hi2c->Mode = HAL_I2C_MODE_NONE;

          /* Process Unlocked */
          __HAL_UNLOCK(hi2c);
          return HAL_TIMEOUT;
        }
      }
    }

    /* Clear NACKF Flag */
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);

    /* Clear STOP Flag */
    __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);

    /* Flush TX register */
    I2C_Flush_TXDR(hi2c);

    /* Clear Configuration Register 2 */
    I2C_RESET_CR2(hi2c);

    hi2c->ErrorCode = HAL_I2C_ERROR_AF;
    hi2c->State= HAL_I2C_STATE_READY;
    hi2c->Mode = HAL_I2C_MODE_NONE;

    /* Process Unlocked */
    __HAL_UNLOCK(hi2c);

    return HAL_ERROR;
  }
  return HAL_OK;
}
Exemplo n.º 10
0
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int timeout;
    int count;

    if (length == 0) return 0;
    i2c_start(obj);

    // Wait until SB flag is set
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_SB) == RESET) {
        timeout--;
        if (timeout == 0) {
            return 0;
        }
    }

    i2c->DR = __HAL_I2C_7BIT_ADD_WRITE(address);


    // Wait address is acknowledged
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_ADDR) == RESET) {
        timeout--;
        if (timeout == 0) {
            return 0;
        }
    }
    __HAL_I2C_CLEAR_ADDRFLAG(&I2cHandle);

    for (count = 0; count < length; count++) {
        if (i2c_byte_write(obj, data[count]) != 1) {
            i2c_stop(obj);
            return 0;
        }
    }

    // If not repeated start, send stop.
    if (stop) {
        i2c_stop(obj);
    }

    return count;
}
Exemplo n.º 11
0
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
{
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);
    int timeout;
    int count;

    // Update CR2 register
    i2c->CR2 = (i2c->CR2 & (uint32_t)~((uint32_t)(I2C_CR2_SADD | I2C_CR2_NBYTES | I2C_CR2_RELOAD | I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | I2C_CR2_START | I2C_CR2_STOP)))
               | (uint32_t)(((uint32_t)address & I2C_CR2_SADD) | (((uint32_t)length << 16) & I2C_CR2_NBYTES) | (uint32_t)I2C_SOFTEND_MODE | (uint32_t)I2C_GENERATE_START_WRITE);

    for (count = 0; count < length; count++) {
        i2c_byte_write(obj, data[count]);
    }

    // Wait transfer complete
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TC) == RESET) {
        timeout--;
        if (timeout == 0) {
            return -1;
        }
    }
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_TC);

    // If not repeated start, send stop
    if (stop) {
        i2c_stop(obj);
        // Wait until STOPF flag is set
        timeout = FLAG_TIMEOUT;
        while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_STOPF) == RESET) {
            timeout--;
            if (timeout == 0) {
                return -1;
            }
        }
        // Clear STOP Flag
        __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_STOPF);
    }

    return count;
}
Exemplo n.º 12
0
// this function is based on STM code
STATIC bool I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart) {
    /* Wait until flag is set */
    while ((__HAL_I2C_GET_FLAG(hi2c, Flag) ? SET : RESET) == Status) {
        if (Timeout != HAL_MAX_DELAY) {
            if ((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout)) {
                return false;
            }
        }
    }
    return true;
}
Exemplo n.º 13
0
STATIC void i2c_reset_after_error(I2C_HandleTypeDef *i2c) {
    // wait for bus-busy flag to be cleared, with a timeout
    for (int timeout = 50; timeout > 0; --timeout) {
        if (!__HAL_I2C_GET_FLAG(i2c, I2C_FLAG_BUSY)) {
            // stop bit was generated and bus is back to normal
            return;
        }
        mp_hal_delay_ms(1);
    }
    // bus was/is busy, need to reset the peripheral to get it to work again
    i2c_deinit(i2c);
    i2c_init(i2c);
}
Exemplo n.º 14
0
int i2c_byte_read(i2c_t *obj, int last) {
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    // Wait until the byte is received
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_RXNE) == RESET) {
        if ((timeout--) == 0) {
            return 0;
        }
    }

    return (int)i2c->RXDR;
}
Exemplo n.º 15
0
int i2c_byte_write(i2c_t *obj, int data) {
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    // Wait until the previous byte is transmitted
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TXIS) == RESET) {
        if ((timeout--) == 0) {
            return 0;
        }
    }

    i2c->TXDR = (uint8_t)data;

    return 1;
}
Exemplo n.º 16
0
void i2c_reset(i2c_t *obj) {
    int timeout;
	
    // wait before reset
    timeout = LONG_TIMEOUT;
    while((__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY)) && (timeout-- != 0));

    if (obj->i2c == I2C_1) {
        __I2C1_FORCE_RESET();
        __I2C1_RELEASE_RESET();
    }
    if (obj->i2c == I2C_2) {
        __I2C2_FORCE_RESET();
        __I2C2_RELEASE_RESET();
    }
}
Exemplo n.º 17
0
/**
  * @brief  This function handles I2C Communication Timeout.
  * @param  hi2c: Pointer to a I2C_HandleTypeDef structure that contains
  *               the configuration information for the specified I2C.
  * @param  Flag: Specifies the I2C flag to check.
  * @param  Status: The new Flag status (SET or RESET).
  * @param  Timeout: Timeout duration
  * @param  Tickstart: Tick start value
  * @retval HAL status
  */
static HAL_StatusTypeDef I2C_WaitOnFlagUntilTimeout(I2C_HandleTypeDef *hi2c, uint32_t Flag, FlagStatus Status, uint32_t Timeout, uint32_t Tickstart)
{
  while((__HAL_I2C_GET_FLAG(hi2c, Flag) ? SET : RESET) == Status)
  {
    /* Check for the Timeout */
    if(Timeout != HAL_MAX_DELAY)
    {
      if((Timeout == 0)||((HAL_GetTick() - Tickstart ) > Timeout))
      {
        hi2c->State= HAL_I2C_STATE_READY;
        hi2c->Mode = HAL_I2C_MODE_NONE;

        /* Process Unlocked */
        __HAL_UNLOCK(hi2c);
        return HAL_TIMEOUT;
      }
    }
  }
  return HAL_OK;
}
Exemplo n.º 18
0
inline int i2c_start(i2c_t *obj) {
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);

    // Clear Acknowledge failure flag
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_AF);

    // Generate the START condition
    i2c->CR2 |= I2C_CR2_START;

    // Wait the START condition has been correctly sent
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == RESET) {
        if ((timeout--) == 0) {
            return 1;
        }
    }

    return 0;
}
Exemplo n.º 19
0
int i2c_byte_read(i2c_t *obj, int last) {
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    if (last) {
        // Don't acknowledge the last byte
        i2c->CR1 &= ~I2C_CR1_ACK;
    } else {
        // Acknowledge the byte
        i2c->CR1 |= I2C_CR1_ACK;
    }

    // Wait until the byte is received
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_RXNE) == RESET) {
        if ((timeout--) == 0) {
            return 0;
        }
    }

    return (int)i2c->DR;
}
Exemplo n.º 20
0
inline int i2c_start(i2c_t *obj)
{
    I2C_TypeDef *i2c = (I2C_TypeDef *)(obj->i2c);
    int timeout;

    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);

    // Clear Acknowledge failure flag
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_AF);

    // Generate the START condition and remove an eventual pending STOP bit
    i2c->CR1 = ((i2c->CR1 & ~I2C_CR1_STOP) | I2C_CR1_START);

    // Wait the START condition has been correctly sent
    timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_SB) == RESET) {
        if ((timeout--) == 0) {
            return 1;
        }
    }

    return 0;
}
Exemplo n.º 21
0
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
    uint32_t Timeout;
    int size = 0;
    if (length == 0) return 0;

    I2cHandle.Instance = (I2C_TypeDef *)(obj->i2c);

    while (length > 0) {
        /* Wait until TXE flag is set */
        Timeout = FLAG_TIMEOUT;
        while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_TXE) == RESET) {
            Timeout--;
            if (Timeout == 0) {
                return 0;
            }
        }


        /* Write data to DR */
        I2cHandle.Instance->DR = (*data++);
        length--;
        size++;

        if ((__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BTF) == SET) && (length != 0)) {
            /* Write data to DR */
            I2cHandle.Instance->DR = (*data++);
            length--;
            size++;
        }
    }

    /* Wait until AF flag is set */
    Timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_AF) == RESET) {
        Timeout--;
        if (Timeout == 0) {
            return 0;
        }
    }


    /* Clear AF flag */
    __HAL_I2C_CLEAR_FLAG(&I2cHandle, I2C_FLAG_AF);


    /* Wait until BUSY flag is reset */
    Timeout = FLAG_TIMEOUT;
    while (__HAL_I2C_GET_FLAG(&I2cHandle, I2C_FLAG_BUSY) == SET) {
        Timeout--;
        if (Timeout == 0) {
            return 0;
        }
    }

    I2cHandle.State = HAL_I2C_STATE_READY;

    /* Process Unlocked */
    __HAL_UNLOCK(&I2cHandle);

    return size;
}
Exemplo n.º 22
0
// this function is based on STM code
int machine_hard_i2c_writeto(mp_obj_base_t *self_in, uint16_t addr, const uint8_t *src, size_t len, bool stop) {
    machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in;
    I2C_HandleTypeDef *hi2c = self->pyb->i2c;
    uint32_t Timeout = *self->timeout;

    /* Init tickstart for timeout management*/
    uint32_t tickstart = HAL_GetTick();

#if 0
    // TODO: for multi-master, here we could wait for the bus to be free
    // we'd need a flag to tell if we were in the middle of a set of transactions
    // (ie didn't send a stop bit in the last call)
    /* Wait until BUSY flag is reset */
    if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) {
        return -MP_EBUSY;
    }
#endif

    /* Check if the I2C is already enabled */
    if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) {
        /* Enable I2C peripheral */
        __HAL_I2C_ENABLE(hi2c);
    }

    /* Disable Pos */
    hi2c->Instance->CR1 &= ~I2C_CR1_POS;

    /* Send Slave Address */
    int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_WRITE(addr << 1), Timeout, tickstart);
    if (ret != 0) {
        return ret;
    }

    /* Clear ADDR flag */
    __HAL_I2C_CLEAR_ADDRFLAG(hi2c);

    int num_acks = 0;

    while (len > 0U) {
        /* Wait until TXE flag is set */
        while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET) {
            /* Check if a NACK is detected */
            if (I2C_IsAcknowledgeFailed(hi2c)) {
                goto nack;
            }

            /* Check for the Timeout */
            if (Timeout != HAL_MAX_DELAY) {
                if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) {
                    goto timeout;
                }
            }
        }

        /* Write data to DR */
        hi2c->Instance->DR = *src++;
        len--;

        /* Wait until BTF flag is set */
        while (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == RESET) {
            /* Check if a NACK is detected */
            if (I2C_IsAcknowledgeFailed(hi2c)) {
                goto nack;
            }

            /* Check for the Timeout */
            if (Timeout != HAL_MAX_DELAY) {
                if ((Timeout == 0U) || ((HAL_GetTick()-tickstart) > Timeout)) {
                    goto timeout;
                }
            }
        }
        ++num_acks;
    }
nack:

    /* Generate Stop */
    if (stop) {
        hi2c->Instance->CR1 |= I2C_CR1_STOP;
    }

    return num_acks;

timeout:
    // timeout, release the bus cleanly
    hi2c->Instance->CR1 |= I2C_CR1_STOP;
    return -MP_ETIMEDOUT;
}
Exemplo n.º 23
0
// this function is based on STM code
int machine_hard_i2c_readfrom(mp_obj_base_t *self_in, uint16_t addr, uint8_t *dest, size_t len, bool stop) {
    machine_hard_i2c_obj_t *self = (machine_hard_i2c_obj_t*)self_in;
    I2C_HandleTypeDef *hi2c = self->pyb->i2c;
    uint32_t Timeout = *self->timeout;

    /* Init tickstart for timeout management*/
    uint32_t tickstart = HAL_GetTick();

#if 0
    // TODO: for multi-master, here we could wait for the bus to be free
    // we'd need a flag to tell if we were in the middle of a set of transactions
    // (ie didn't send a stop bit in the last call)
    /* Wait until BUSY flag is reset */
    if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart)) {
        return -MP_EBUSY;
    }
#endif

    /* Check if the I2C is already enabled */
    if ((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE) {
        /* Enable I2C peripheral */
        __HAL_I2C_ENABLE(hi2c);
    }

    /* Disable Pos */
    hi2c->Instance->CR1 &= ~I2C_CR1_POS;

    /* Enable Acknowledge */
    hi2c->Instance->CR1 |= I2C_CR1_ACK;

    /* Send Slave Address */
    int ret = send_addr_byte(hi2c, I2C_7BIT_ADD_READ(addr << 1), Timeout, tickstart);
    if (ret != 0) {
        return ret;
    }

    if (len == 0U) {
        /* Clear ADDR flag */
        __HAL_I2C_CLEAR_ADDRFLAG(hi2c);

        /* Generate Stop */
        if (stop) {
            hi2c->Instance->CR1 |= I2C_CR1_STOP;
        }
    } else if (len == 1U) {
        /* Disable Acknowledge */
        hi2c->Instance->CR1 &= ~I2C_CR1_ACK;

        /* Clear ADDR flag */
        __HAL_I2C_CLEAR_ADDRFLAG(hi2c);

        /* Generate Stop */
        if (stop) {
            hi2c->Instance->CR1 |= I2C_CR1_STOP;
        }
    } else if (len == 2U) {
        /* Disable Acknowledge */
        hi2c->Instance->CR1 &= ~I2C_CR1_ACK;

        /* Enable Pos */
        hi2c->Instance->CR1 |= I2C_CR1_POS;

        /* Clear ADDR flag */
        __HAL_I2C_CLEAR_ADDRFLAG(hi2c);
    } else {
        /* Enable Acknowledge */
        hi2c->Instance->CR1 |= I2C_CR1_ACK;

        /* Clear ADDR flag */
        __HAL_I2C_CLEAR_ADDRFLAG(hi2c);
    }

    while (len > 0U) {
        if (len <= 3U) {
            if (len == 1U) {
                /* Wait until RXNE flag is set */
                int ret = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart);
                if (ret != 0) {
                    return ret;
                }

                /* Read data from DR */
                *dest++ = hi2c->Instance->DR;
                len--;
            } else if (len == 2U) {
                /* Wait until BTF flag is set */
                if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) {
                  return -MP_ETIMEDOUT;
                }

                /* Generate Stop */
                if (stop) {
                    hi2c->Instance->CR1 |= I2C_CR1_STOP;
                }

                /* Read data from DR */
                *dest++ = hi2c->Instance->DR;
                len--;

                /* Read data from DR */
                *dest++ = hi2c->Instance->DR;
                len--;
            } else {
                /* Wait until BTF flag is set */
                if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) {
                  return -MP_ETIMEDOUT;
                }

                /* Disable Acknowledge */
                hi2c->Instance->CR1 &= ~I2C_CR1_ACK;

                /* Read data from DR */
                *dest++ = hi2c->Instance->DR;
                len--;

                /* Wait until BTF flag is set */
                if (!I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)) {
                    return -MP_ETIMEDOUT;
                }

                /* Generate Stop */
                if (stop) {
                    hi2c->Instance->CR1 |= I2C_CR1_STOP;
                }

                /* Read data from DR */
                *dest++ = hi2c->Instance->DR;
                len--;

                /* Read data from DR */
                *dest++ = hi2c->Instance->DR;
                len--;
            }
        } else {
            /* Wait until RXNE flag is set */
            int ret = I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart);
            if (ret != 0) {
                return ret;
            }

            /* Read data from DR */
            *dest++ = hi2c->Instance->DR;
            len--;

            if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) {
                /* Read data from DR */
                *dest++ = hi2c->Instance->DR;
                len--;
            }
        }
    }

    return 0;
}