[英]STM32 - I2C Write Failure
I'm using STM32 with EEPROM 512KB, i inilized the project using STM32CubeMX我正在使用带有 512KB EEPROM 的 STM32,我使用 STM32CubeMX 初始化了项目
PB7 as I2C_SDA PB6 as I2C_SCL
PB7 作为 I2C_SDA PB6 作为 I2C_SCL
Generated Functions生成的函数
I2C_HandleTypeDef hi2c1;
/* I2C1 init function */
void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
_Error_Handler(__FILE__, __LINE__);
}
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = I2C_SCL_Pin|I2C_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* I2C1 clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspDeInit 0 */
/* USER CODE END I2C1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_I2C1_CLK_DISABLE();
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
HAL_GPIO_DeInit(GPIOB, I2C_SCL_Pin|I2C_SDA_Pin);
/* I2C1 interrupt Deinit */
HAL_NVIC_DisableIRQ(I2C1_EV_IRQn);
HAL_NVIC_DisableIRQ(I2C1_ER_IRQn);
/* USER CODE BEGIN I2C1_MspDeInit 1 */
/* USER CODE END I2C1_MspDeInit 1 */
}
}
In main i call MX_I2C1_Init()
then HAL_I2C_MspInit(&hi2c1)
, but when i call在主要我调用
MX_I2C1_Init()
然后HAL_I2C_MspInit(&hi2c1)
,但是当我调用
while(HAL_I2C_Mem_Write(hi2c,(uint16_t)DevAddress,(uint16_t)MemAddress,I2C_MEMADD_SIZE_8BIT,pData,(uint16_t)16-MemAddress,1000)!= HAL_OK && 1);
This while loop never returns HAL_OK, so i can not processed to read the written data to verify.这个while循环永远不会返回HAL_OK,所以我无法处理读取写入的数据进行验证。 My EEPROM is
我的 EEPROM 是
CAT24C512WI-GT3OSCT-ND and the A0->A2, WP are connected to ground
CAT24C512WI-GT3OSCT-ND和A0->A2,WP接地
Try this.尝试这个。 First call the device readiness check and make sure that the device is ready.
首先调用设备就绪检查并确保设备已就绪。
while(HAL_I2C_IsDeviceReady(&hi2c1, I2C_EEPROM_ADDRESS, 64, HAL_MAX_DELAY)!= HAL_OK);
and then进而
while(HAL_I2C_Mem_Write(&hi2c1, I2C_EEPROM_ADDRESS, eeStart, I2C_MEMADD_SIZE_8BIT, pRamStart, num, HAL_MAX_DELAY)!= HAL_OK);
64 in "HAL_I2C_IsDeviceReady" - the number of attempts. “HAL_I2C_IsDeviceReady”中的 64 - 尝试次数。 Sometimes one or more times is not enough.
有时一次或多次是不够的。 Check.
查看。 Need &hi2c1, not hi2c1
需要 &hi2c1,而不是 hi2c1
All right!好的! The first time will be "true", but after writing to the eeprom, you need to make sure that the recording is completed and the eeprom is ready for the next step.
第一次会是“true”,但是在写入 eeprom 之后,您需要确保录制完成并且 eeprom 已准备好进行下一步。 You have not been & before hi2c1 in the last line.
在最后一行的 hi2c1 之前,您没有去过 & 。 And, maybe for EEPROM 512kb you need to specify "I2C_MEMADD_SIZE_16BIT" and not "I2C_MEMADD_SIZE_8BIT"?
而且,也许对于 EEPROM 512kb,您需要指定“I2C_MEMADD_SIZE_16BIT”而不是“I2C_MEMADD_SIZE_8BIT”?
How do you determine that the recording, which requires considerable time, by the standards of the processor, is completed?您如何确定按照处理器的标准需要大量时间的录制已完成? To do this, there is this procedure HAL_I2C_IsDevitseReady.
为此,有此过程 HAL_I2C_IsDevitseReady。
Immediately after the call to HAL_I2C_MspInit(&hi2c1)
you need to check the state of the i2c whit在调用
HAL_I2C_MspInit(&hi2c1)
您需要立即检查 i2c whit 的状态
while(HAL_I2C_Mem_Write(
&hi2c1,
I2C_EEPROM_ADDRESS,
eeStart,
I2C_MEMADD_SIZE_8BIT,
pRamStart,
num,
HAL_MAX_DELAY) == HAL_BUSY);
if the program is stuck in the while loop always returning HAL_BUSY
its very likely that you are using a micro controller whit a hardware bug you can check the errata of the stm32f10xx8 in page 26, this happened to me whit the stm32f103c8t6 which is of the STM32F10xx8 family (if your device is not of this family you can still try the second solution listed below).如果程序卡在 while 循环中总是返回
HAL_BUSY
很可能您使用的是带有硬件错误的微控制器,您可以检查第 26 页中 stm32f10xx8 的勘误表,这发生在我身上,stm32f103c8t6 属于 STM32F10xx8系列(如果您的设备不属于该系列,您仍然可以尝试下面列出的第二种解决方案)。
the solution is listed in the errata and is this:解决方案列在勘误表中,是这样的:
Workaround The SCL and SDA analog filter output is updated after a transition occurs on the SCL and SDA line respectively.解决方法SCL 和 SDA 模拟滤波器输出分别在 SCL 和 SDA 线上发生转换后更新。 The SCL and SDA transition can be forced by software configuring the I2C I/Os in output mode.
SCL 和 SDA 转换可以通过软件在输出模式下配置 I2C I/O 来强制。 Then, once the analog filters are unlocked and output the SCL and SDA lines level, the BUSY flag can be reset with a software reset, and the I2C can enter master mode.
然后,一旦模拟滤波器解锁并输出 SCL 和 SDA 线电平,BUSY 标志可以通过软件复位来复位,I2C 可以进入主模式。 Therefore, the following sequence must be applied:
因此,必须应用以下顺序:
another solution is adding另一个解决方案是添加
__HAL_RCC_I2C1_FORCE_RESET();
HAL_Delay(2);
__HAL_RCC_I2C1_RELEASE_RESET();
to HAL_I2C_MspInit(...)
after __HAL_RCC_I2C1_CLK_ENABLE();
HAL_I2C_MspInit(...)
之后到HAL_I2C_MspInit(...)
__HAL_RCC_I2C1_CLK_ENABLE();
so that the final solution is所以最终的解决方案是
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(i2cHandle->Instance==I2C1)
{
/* USER CODE BEGIN I2C1_MspInit 0 */
/* USER CODE END I2C1_MspInit 0 */
/**I2C1 GPIO Configuration
PB6 ------> I2C1_SCL
PB7 ------> I2C1_SDA
*/
GPIO_InitStruct.Pin = I2C_SCL_Pin|I2C_SDA_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* I2C1 clock enable */
__HAL_RCC_I2C1_CLK_ENABLE();
//--------------added code :D -----------------------------------
__HAL_RCC_I2C1_FORCE_RESET();
HAL_Delay(2);
__HAL_RCC_I2C1_RELEASE_RESET();
//-------------end of added code---------------------------------
/* I2C1 interrupt Init */
HAL_NVIC_SetPriority(I2C1_EV_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C1_EV_IRQn);
HAL_NVIC_SetPriority(I2C1_ER_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(I2C1_ER_IRQn);
/* USER CODE BEGIN I2C1_MspInit 1 */
/* USER CODE END I2C1_MspInit 1 */
}
}
the second solution may or may not work whit you because its not the solution recommended by ST but in my case and many others works although i wouldn't trust this solution in a product, that depends on the model of your micro you can play whit the delay if 2 doesn't work it really depends on which micro controller you are using.第二种解决方案可能适用也可能不适用于您,因为它不是 ST 推荐的解决方案,但在我的情况下和许多其他解决方案有效,尽管我不相信产品中的此解决方案,这取决于您可以玩的微型模型如果 2 不起作用,则延迟实际上取决于您使用的微控制器。
I developed an EEPROM library, you can check it and use it for the project.我开发了一个 EEPROM 库,您可以检查它并将其用于项目。
Features:特征:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.