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; 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_READ(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); // Read all bytes except last one for (count = 0; count < (length - 1); count++) { value = i2c_byte_read(obj, 0); data[count] = (char)value; } // If not repeated start, send stop. // Warning: must be done BEFORE the data is read. if (stop) { i2c_stop(obj); } // Read the last byte value = i2c_byte_read(obj, 1); data[count] = (char)value; return length; }
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; }
// 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; }
// 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; }