changeset 328:4fe5400567e7 I2C_Improvment

Set I2C speed to 88kHz, use digital filter only and reworked idle clock recovery The errata describes a possible problem in operation between 88kHz and 100kHz => Set speed as recommended as work around. Based on reference implementation only one filter should be use. Choice was digital because only drawback is lag of wakeup functionality which is not used I2C communication may be randomly interrupted e.g. by a RTE reset or firmware update => reworked recovery function to get I2C devices in idle state again (Clk and SDA HIGH)
author ideenmodellierer
date Wed, 17 Jul 2019 22:42:15 +0200
parents abec171c2c4b
children da5b91b1e20e
files Small_CPU/Src/i2c.c
diffstat 1 files changed, 30 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/Small_CPU/Src/i2c.c	Wed Jul 17 22:41:31 2019 +0200
+++ b/Small_CPU/Src/i2c.c	Wed Jul 17 22:42:15 2019 +0200
@@ -31,39 +31,51 @@
 void HAL_I2C_Send_One_CLOCK(void)
 {
 	HAL_GPIO_WritePin(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN, GPIO_PIN_RESET);
-	HAL_Delay(10);
+	HAL_Delay(1); 
 	HAL_GPIO_WritePin(I2Cx_SCL_GPIO_PORT, I2Cx_SCL_PIN, GPIO_PIN_SET);
-	HAL_Delay(10);
+	HAL_Delay(1);
 }
 
 GPIO_PinState MX_I2C1_TestAndClear(void)
 {
+	GPIO_PinState retval;
+	uint8_t repeatcnt = 3;
+
 	I2C_DeInit();
 	HAL_I2C_ManualControl_MspInit();
-	for(int i=0; i<9;i++)
+	
+/* The SDA line is expected to be HIGH if no com is pending => send dummy clock signals if that is not the case */
+	do
 	{
-		if(HAL_I2C_Read_Data_PIN() == GPIO_PIN_RESET)
-			HAL_I2C_Send_One_CLOCK();
-		else
-			break;
-	}
-	return HAL_I2C_Read_Data_PIN();
+		for(int i=0; i<20;i++)
+		{
+			if(HAL_I2C_Read_Data_PIN() == GPIO_PIN_RESET)
+				HAL_I2C_Send_One_CLOCK();
+			else
+				break;
+		}
+		retval = HAL_I2C_Read_Data_PIN();
+	}while ((repeatcnt-- > 0) && (retval != GPIO_PIN_SET));
+
+	return retval;
 }
 
 HAL_StatusTypeDef MX_I2C1_Init(void)
 {
-	I2cHandle.Instance             = I2Cx;
+  I2cHandle.Instance             = I2Cx;
   I2cHandle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
-  I2cHandle.Init.ClockSpeed      = 100000;//400000; REDUCED for compatibility with  HMC5583L + MMA8452Q
-  I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
-  I2cHandle.Init.DutyCycle       = I2C_DUTYCYCLE_2;
+  I2cHandle.Init.ClockSpeed      = 88000; /* Reduced to avoid behavior described in errata: Mismatch on the “Setup time for a repeated Start condition” */
+  I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
+  I2cHandle.Init.DutyCycle       = I2C_DUTYCYCLE_2;				/* don't care if not in fast mode */
   I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
   I2cHandle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLED;
-  I2cHandle.Init.OwnAddress1     = 0x01;
+  I2cHandle.Init.OwnAddress1     = 0x01;						/* don't care because of master mode */
+
+/* According to documentation setting filters before I2C initialization is recommended */
+	/* HAL_I2CEx_AnalogFilter_Config(&I2cHandle, I2C_ANALOGFILTER_ENABLED); */
+	HAL_I2CEx_ConfigDigitalFilter(&I2cHandle,0x0F);
 
 	global.I2C_SystemStatus = HAL_I2C_Init(&I2cHandle);
-	HAL_I2CEx_AnalogFilter_Config(&I2cHandle, I2C_ANALOGFILTER_ENABLED);
-	HAL_I2CEx_ConfigDigitalFilter(&I2cHandle,0x0F);
 
 	if(global.dataSendToSlavePending)
 	{
@@ -85,12 +97,13 @@
 	i2c_errors++;
 }
 
+
 HAL_StatusTypeDef I2C_Master_Transmit(  uint16_t DevAddress, uint8_t *pData, uint16_t Size)
 {
 	if(global.I2C_SystemStatus != HAL_OK)
 		return global.I2C_SystemStatus;
 
-	global.I2C_SystemStatus = HAL_I2C_Master_Transmit(&I2cHandle, DevAddress,  pData, Size, 2);
+	global.I2C_SystemStatus = HAL_I2C_Master_Transmit(&I2cHandle, DevAddress,  pData, Size, 10);
 	if(global.I2C_SystemStatus != HAL_OK)
 	{
 		I2C_Error_count();