Browse Source

*** EFM32 branch ***
1. Change the usage of the second parameter of Read and Write functions in IIC driver
- to "Slave address" from (seldom used) "Offset"
2. Add a timer for IIC driver to prevent from forever waiting
3. Add digital (IIC) interface support for accelerometer driver (Freescale MMA7455L)

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@1678 bbd45198-f89e-11dd-88c7-29a3b14d5316

onelife.real 14 years ago
parent
commit
11488d143a
5 changed files with 924 additions and 183 deletions
  1. 714 85
      bsp/efm32/dev_accel.c
  2. 90 8
      bsp/efm32/dev_accel.h
  3. 90 76
      bsp/efm32/drv_iic.c
  4. 11 6
      bsp/efm32/drv_iic.h
  5. 19 8
      bsp/efm32/rtconfig.h

+ 714 - 85
bsp/efm32/dev_accel.c

@@ -13,6 +13,8 @@
  * Date			Author		Notes
  * 2011-07-13	onelife		Initial creation for using EFM32 ADC module to 
  *  interface the Freescale MMA7361L
+ * 2011-08-02	onelife		Add digital interface support of using EFM32 IIC 
+ *  module for the Freescale MMA7455L
  ******************************************************************************/
 
 /***************************************************************************//**
@@ -22,25 +24,37 @@
 
 /* Includes ------------------------------------------------------------------*/
 #include "board.h"
+
+#if defined(EFM32_USING_ACCEL)
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
 #include "drv_adc.h"
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+#include "drv_iic.h"
+#include "hdl_interrupt.h"
+#endif
 #include "dev_accel.h"
 
-#if defined(EFM32_USING_ACCEL)
 /* Private typedef -----------------------------------------------------------*/
 /* Private define ------------------------------------------------------------*/
 /* Private macro -------------------------------------------------------------*/
-#ifdef RT_ACCEL_DEBUG
+#ifdef EFM32_ACCEL_DEBUG
 #define accel_debug(format,args...) 		rt_kprintf(format, ##args)
 #else
 #define accel_debug(format,args...)
 #endif
 
 /* Private constants ---------------------------------------------------------*/
-static rt_device_t 					accel;
-static struct efm32_adc_control_t 	control = \
+static rt_device_t 						accel;
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
+static struct efm32_adc_control_t 		control = \
 	{ADC_MODE_SCAN, {3, ACCEL_USING_DMA}, {}};
-static struct efm32_accel_result_t 	accelOffset = {0};
-static rt_bool_t 					accelInTime = true;
+static struct efm32_accel_result_t 		accelOffset = {0};
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+static const struct efm32_iic_control_t	control = \
+	{IIC_STATE_MASTER, 0x0000};
+#endif
+static rt_bool_t 						accelInTime = true;
+static rt_uint32_t 						accelConfig = 0;
 
 /* Private variables ---------------------------------------------------------*/
 /* Private function prototypes -----------------------------------------------*/
@@ -56,26 +70,97 @@ static rt_bool_t 					accelInTime = true;
  * @param[out] data
  *	Pointer to output buffer
  *
+ * @param[in] lowResolution
+ *	Resolution selection
+ *
  * @return
  *	 Error code
  ******************************************************************************/
-rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data)
+rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data, 
+	rt_bool_t lowResolution)
 {
 	RT_ASSERT(accel != RT_NULL);
 
-	struct efm32_adc_result_t result;
+	rt_err_t ret;
 
 	if (data == RT_NULL)
 	{
 		return -RT_ERROR;
 	}
 
-	result.mode = control.mode;
-	result.buffer = (void *)data;
-	accel->control(accel, RT_DEVICE_CTRL_RESUME, &result);
-	accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, &result);
+	ret = RT_EOK;
+	do 
+	{
+		/* --------- ADC interface --------- */
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
+		struct efm32_adc_result_t result;
 
-	return RT_EOK;
+		result.mode = control.mode;
+		result.buffer = (void *)data;
+		if ((ret = accel->control(accel, RT_DEVICE_CTRL_RESUME, 
+			(void *)&result)) != RT_EOK)
+		{
+			break;
+		}
+		if ((ret = accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, \
+			(void *)&result)) != RT_EOK)
+		{
+			break;
+		}
+
+		data->x += accelOffset.x - 0x800;
+		data->y += accelOffset.y - 0x800;
+		data->z += accelOffset.z - 0x800;
+		if (lowResolution)
+		{
+			data->x >>= 4;
+			data->y >>= 4;
+			data->z >>= 4;
+		}
+
+		/* --------- IIC interface --------- */
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+		if (lowResolution || \
+			((accelConfig & ACCEL_MASK_RANGE) != MCTL_RANGE_8G))
+		{
+			rt_int8_t buf[3];
+
+			buf[0] = XOUT8;
+			if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, \
+				sizeof(buf)) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
+			data->x = buf[0];
+			data->y = buf[1];
+			data->z = buf[2];
+		}
+		else
+		{
+			rt_uint8_t buf[6];
+			rt_uint16_t *temp = (rt_uint16_t *)&buf;
+
+			buf[0] = XOUTL;
+			if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, \
+				sizeof(buf)) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
+			data->x = (*temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
+				((rt_uint32_t)*temp & 0x3FF);
+			data->y = (*++temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
+				((rt_uint32_t)*temp & 0x3FF);
+			data->z = (*++temp & 0x200) ? ((rt_uint32_t)*temp | ~0x3FF) : \
+				((rt_uint32_t)*temp & 0x3FF);
+		}
+#endif
+		return RT_EOK;
+	} while (0);
+
+	accel_debug("Accel err: Get data failed!\n");
+	return ret;
 }
 
 /***************************************************************************//**
@@ -94,84 +179,559 @@ static void efm_accel_timer(void* parameter)
 	accelInTime = false;
 }
 
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
 /***************************************************************************//**
  * @brief
- *   Accelerometer auto-zero calibration function
+ *	Accelerometer level and pulse detection interrupts handler
  *
  * @details
  *
  * @note
  *
- * @param[in] period
- *	Time period to perform auto-zero calibration
+ * @param[in] device
+ *	Pointer to device descriptor
+ ******************************************************************************/
+static void efm_accel_isr(rt_device_t device)
+{
+	rt_uint8_t buf[2];
+
+	if ((accelConfig & ACCEL_MASK_MODE) != ACCEL_MODE_MEASUREMENT)
+	{
+		/* Read detection source */
+		buf[0] = DETSRC;
+		if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 1) != 1)
+		{
+			accel_debug("Accel: read error\n");
+			return;
+		}
+		accel_debug("Accel: DETSRC %x\n", buf[0]);
+
+		/* Reset the interrupt flags: Part 1 */
+		buf[0] = INTRST;
+		buf[1] = INTRST_INT_1 | INTRST_INT_2;
+		accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2);
+
+		/* Read status to waste some time */
+		buf[0] = STATUS;
+		if (accel->read(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 1) != 1)
+		{
+			accel_debug("Accel: read error\n");
+			return;
+		}
+		accel_debug("Accel: STATUS %x\n", buf[0]);
+
+		/* Reset the interrupt flags: Part 2 */
+		buf[0] = INTRST;
+		buf[1] = 0x00;
+		accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2);
+	}
+}
+
+/***************************************************************************//**
+ * @brief
+ *	Accelerometer configuration function
+ *
+ * @details
+ *
+ * @note
+ *
+ * @param[in] config
+ *	Configuration options
+ *
+ * @param[in] level_threshold
+ *	Level detection threshold
+ *
+ * @param[in] pulse_threshold
+ *	Pulse detection threshold
+ *
+ * @param[in] pulse_duration
+ *	Time window for 1st pulse
+ *
+ * @param[in] pulse_latency
+ *	Pulse latency Time
+ *
+ * @param[in] pulse_duration2
+ *	Time window for 2nd pulse
  *
  * @return
  *	 Error code
  ******************************************************************************/
-rt_err_t efm_accel_auto_zero(rt_tick_t period)
+rt_err_t efm_accel_config(rt_uint32_t config,
+	rt_uint8_t level_threshold,
+	rt_uint8_t pulse_threshold,
+	rt_uint8_t pulse_duration,
+	rt_uint8_t pulse_latency,
+	rt_uint8_t pulse_duration2)
 {
-	RT_ASSERT(accel != RT_NULL);
+	rt_err_t ret;
+	rt_uint8_t buf[2];
+	rt_uint8_t mode, mctl_reg, ctl1_reg, ctl2_reg;
 
-	rt_timer_t calTimer;
-	struct efm32_accel_result_t min = {0x7ff, 0x7ff, 0x7ff};
-	struct efm32_accel_result_t max = {0x7ff, 0x7ff, 0x7ff};
-	struct efm32_accel_result_t temp;
-	struct efm32_adc_result_t result;
-
-	if ((calTimer = rt_timer_create(
-		"cal_tmr",
-		efm_accel_timer,
-		RT_NULL,
-		period, 
-		RT_TIMER_FLAG_ONE_SHOT)) == RT_NULL)
+	ret = RT_EOK;
+	mctl_reg = 0;
+	ctl1_reg = 0;
+	ctl2_reg = 0;
+
+	/* Modify MCTL */
+	mode = config & ACCEL_MASK_MODE;
+	switch (mode)
 	{
-		accel_debug("Accel err: Create timer failed!\n");
+	case ACCEL_MODE_STANDBY:
+		mctl_reg |= MCTL_MODE_STANDBY;
+		break;
+	case ACCEL_MODE_MEASUREMENT:
+		mctl_reg |= MCTL_MODE_MEASUREMENT;
+		break;
+	case ACCEL_MODE_LEVEL:
+		mctl_reg |= MCTL_MODE_LEVEL;
+		break;
+	case ACCEL_MODE_PULSE:
+		mctl_reg |= MCTL_MODE_PULSE;
+		break;
+	default:
 		return -RT_ERROR;
 	}
 
-	result.mode = control.mode;
-	result.buffer = (void *)&temp;
-	accelInTime = true;
-	rt_timer_start(calTimer);
+	switch (config & ACCEL_MASK_RANGE)
+	{
+	case ACCEL_RANGE_8G:
+		mctl_reg |= MCTL_RANGE_8G;
+		break;
+	case ACCEL_RANGE_4G:
+		mctl_reg |= MCTL_RANGE_4G;
+		break;
+	case ACCEL_RANGE_2G:
+		mctl_reg |= MCTL_RANGE_2G;
+		break;
+	default:
+		return -RT_ERROR;
+	}
+
+	if ((mode == ACCEL_MODE_LEVEL) || (mode == ACCEL_MODE_PULSE))
+	{
+		mctl_reg |= MCTL_PIN_INT1;
+	}
+	
+	/* Modify CTL1 */
+	if (config & ACCEL_INTPIN_INVERSE)
+	{
+		ctl1_reg |= CTL1_INTPIN_INVERSE;
+	}
+
+	switch (config & ACCEL_MASK_INT)
+	{
+	case ACCEL_INT_LEVEL_PULSE:
+		ctl1_reg |= CTL1_INT_LEVEL_PULSE;
+		break;
+	case ACCEL_INT_PULSE_LEVEL:
+		ctl1_reg |= CTL1_INT_PULSE_LEVEL;
+		break;
+	case ACCEL_INT_SINGLE_DOUBLE:
+		ctl1_reg |= CTL1_INT_SINGLE_DOUBLE;
+		break;
+	default:
+		break;
+	}
+
+	switch (config & ACCEL_MASK_DISABLE)
+	{
+	case ACCEL_DISABLE_X:
+		ctl1_reg |= CTL1_X_DISABLE;
+		break;
+	case ACCEL_DISABLE_Y:
+		ctl1_reg |= CTL1_Y_DISABLE;
+		break;
+	case ACCEL_DISABLE_Z:
+		ctl1_reg |= CTL1_Z_DISABLE;
+		break;
+	default:
+		break;
+	}	
+
+	if (config & ACCEL_THRESHOLD_INTEGER)
+	{
+		ctl1_reg |= CTL1_THRESHOLD_INTEGER;
+	}
+
+	if (config & ACCEL_BANDWIDTH_125HZ)
+	{
+		ctl1_reg |= CTL1_BANDWIDTH_125HZ;
+	}
+
+	/* Modify CTL2 */
+	if (config & ACCEL_LEVEL_AND)
+	{
+		ctl2_reg |= CTL2_LEVEL_AND;
+	}
+	if (config & ACCEL_PULSE_AND)
+	{
+		ctl2_reg |= CTL2_PULSE_AND;
+	}
+	if (config & ACCEL_DRIVE_STRONG)
+	{
+		ctl2_reg |= CTL2_DRIVE_STRONG;
+	}
+
 	do
 	{
-		accel->control(accel, RT_DEVICE_CTRL_RESUME, &result);
-		accel->control(accel, RT_DEVICE_CTRL_ADC_RESULT, &result);
-		if (temp.x < min.x)
+		/* Write registers */
+		buf[0] = MCTL;
+		buf[1] = mctl_reg;
+		if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
+		{
+			ret = -RT_ERROR;
+			break;
+		}
+		accel_debug("Accel: MCTL %x\n", mctl_reg);
+
+		buf[0] = CTL1;
+		buf[1] = ctl1_reg;
+		if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
 		{
-			min.x = temp.x;
+			ret = -RT_ERROR;
+			break;
 		}
-		if (temp.y < min.y)
+		accel_debug("Accel: CTL1 %x\n", ctl1_reg);
+
+		buf[0] = CTL2;
+		buf[1] = ctl2_reg;
+		if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
 		{
-			min.y = temp.y;
+			ret = -RT_ERROR;
+			break;
 		}
-		if (temp.z < min.z)
+		accel_debug("Accel: CTL2 %x\n", ctl2_reg);
+		accelConfig = config;
+
+		if (mode == ACCEL_MODE_PULSE)
 		{
-			min.z = temp.z;
+			buf[0] = PDTH;
+			buf[1] = pulse_threshold;
+			if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
+			accel_debug("Accel: PDTH %x\n", buf[1]);
+
+			buf[0] = PW;
+			buf[1] = pulse_duration;
+			if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
+			accel_debug("Accel: PW %x\n", buf[1]);
+
+			buf[0] = LT;
+			buf[1] = pulse_latency;
+			if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
+			accel_debug("Accel: LT %x\n", buf[1]);
+
+			buf[0] = TW;
+			buf[1] = pulse_duration2;
+			if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
+			accel_debug("Accel: TW %x\n", buf[1]);
 		}
-		if (temp.x > max.x)
+
+		if ((mode == ACCEL_MODE_LEVEL) || (mode == ACCEL_MODE_PULSE))
 		{
-			max.x = temp.x;
+			efm32_irq_hook_init_t hook;
+
+			/* Reset the interrupt flags: Part 1 */
+			buf[0] = INTRST;
+			buf[1] = INTRST_INT_1 | INTRST_INT_2;
+			if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
+
+			/* Set level detection threshold */
+			buf[0] = LDTH;
+			if (config & ACCEL_THRESHOLD_INTEGER)
+			{
+				buf[1] = level_threshold;
+			}
+			else
+			{
+				buf[1] = level_threshold & 0x7f;
+			}
+			if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
+			accel_debug("Accel: LDTH %x\n", buf[1]);
+
+			/* Config interrupt */
+			hook.type		= efm32_irq_type_gpio;
+			hook.unit		= ACCEL_INT1_PIN;
+			hook.cbFunc 	= efm_accel_isr;
+			hook.userPtr	= RT_NULL;
+			efm32_irq_hook_register(&hook);
+			hook.unit		= ACCEL_INT2_PIN;
+			efm32_irq_hook_register(&hook);
+			/* Clear pending interrupt */
+			BITBAND_Peripheral(&(GPIO->IFC), ACCEL_INT1_PIN, 0x1UL);
+			BITBAND_Peripheral(&(GPIO->IFC), ACCEL_INT2_PIN, 0x1UL);
+			/* Set raising edge interrupt and clear/enable it */
+			GPIO_IntConfig(
+				ACCEL_INT1_PORT, 
+				ACCEL_INT1_PIN, 
+				true, 
+				false, 
+				true);
+			GPIO_IntConfig(
+				ACCEL_INT2_PORT, 
+				ACCEL_INT2_PIN, 
+				true, 
+				false, 
+				true);
+			if (((rt_uint8_t)ACCEL_INT1_PORT % 2) || \
+				((rt_uint8_t)ACCEL_INT2_PORT % 2))
+			{
+				NVIC_ClearPendingIRQ(GPIO_ODD_IRQn);
+				NVIC_SetPriority(GPIO_ODD_IRQn, EFM32_IRQ_PRI_DEFAULT);
+				NVIC_EnableIRQ(GPIO_ODD_IRQn);
+			}
+			if (!((rt_uint8_t)ACCEL_INT1_PORT % 2) || \
+				!((rt_uint8_t)ACCEL_INT2_PORT % 2))
+			{
+				NVIC_ClearPendingIRQ(GPIO_EVEN_IRQn);
+				NVIC_SetPriority(GPIO_EVEN_IRQn, EFM32_IRQ_PRI_DEFAULT);
+				NVIC_EnableIRQ(GPIO_EVEN_IRQn);
+			}
+
+			/* Reset the interrupt flags: Part 2 */
+			buf[0] = INTRST;
+			buf[1] = 0x00;
+			if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, (void *)buf, 2) == 0)
+			{
+				ret = -RT_ERROR;
+				break;
+			}
 		}
-		if (temp.y > max.y)
+	} while (0);
+
+	return ret;
+}
+
+#endif
+
+/***************************************************************************//**
+ * @brief
+ *   Accelerometer auto-zero calibration function
+ *
+ * @details
+ *
+ * @note
+ *
+ * @param[in] mode
+ *	0, simple mode (assuming the device is placed on flat surface)
+ *	1, interaction method
+ *
+ * @param[in] period
+ *	Time period to perform auto-zero calibration
+ *
+ * @return
+ *	 Error code
+ ******************************************************************************/
+rt_err_t efm_accel_auto_zero(rt_uint8_t mode, rt_tick_t period)
+{
+	RT_ASSERT(accel != RT_NULL);
+
+	rt_timer_t calTimer;
+	struct efm32_accel_result_t min = {0, 0, 0};
+	struct efm32_accel_result_t max = {0, 0, 0};
+	struct efm32_accel_result_t temp, sum;
+	rt_int32_t simpleOffset[] = ACCEL_CAL_1G_VALUE;
+	rt_uint8_t cmd[7] = {0};
+	rt_uint8_t i, j;
+
+	/* Reset offset */
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
+	accelOffset.x = 0;
+	accelOffset.y = 0;
+	accelOffset.z = 0;
+
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+	cmd[0] = XOFFL;
+	if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
+	{
+		return -RT_ERROR;
+	}
+#endif
+
+	if (mode == ACCEL_CAL_SIMPLE)
+	{
+		/* Simple mode */
+		for (j = 0; j < ACCEL_CAL_ROUND; j++)
 		{
-			max.y = temp.y;
+			sum.x = 0x0;
+			sum.y = 0x0;
+			sum.z = 0x0;
+
+			for (i = 0; i < ACCEL_CAL_SAMPLES; i++)
+			{
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+				/* Waiting for data ready */
+				while(!GPIO_PinInGet(ACCEL_INT1_PORT, ACCEL_INT1_PIN));
+#endif
+				if (efm_accel_get_data(&temp, false) != RT_EOK)
+				{
+					return -RT_ERROR;
+				}
+				sum.x += temp.x;
+				sum.y += temp.y;
+				sum.z += temp.z;
+			}
+
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
+			temp.x = sum.x / ACCEL_CAL_SAMPLES;
+			temp.y = sum.y / ACCEL_CAL_SAMPLES;
+			temp.z = sum.z / ACCEL_CAL_SAMPLES - simpleOffset[ACCEL_G_SELECT];
+			if ((temp.x == 0) && (temp.y == 0) && \
+				(temp.z == 0))
+			{
+				accel_debug("Accel: Offset %+d %+d %+d\n", 
+					accelOffset.x, accelOffset.y, accelOffset.z);
+				break;
+			}
+			accelOffset.x -= temp.x;
+			accelOffset.y -= temp.y;
+			accelOffset.z -= temp.z;
+
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+			temp.x = sum.x / (ACCEL_CAL_SAMPLES >> 1);
+			temp.y = sum.y / (ACCEL_CAL_SAMPLES >> 1);
+			temp.z = sum.z / (ACCEL_CAL_SAMPLES >> 1) \
+				- (simpleOffset[ACCEL_G_SELECT] << 1);
+			if ((temp.x == 0) && (temp.y == 0) && \
+				(temp.z == 0))
+			{
+				break;
+			}
+			
+			/* Set offset drift registers */
+			max.x -= temp.x;
+			max.y -= temp.y;
+			max.z -= temp.z;
+			*(rt_int16_t *)&cmd[1] = (rt_int16_t)max.x;
+			*(rt_int16_t *)&cmd[3] = (rt_int16_t)max.y;
+			*(rt_int16_t *)&cmd[5] = (rt_int16_t)max.z;
+			if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
+			{
+				return -RT_ERROR;
+			}
+			accel_debug("Accel: Offset %+d %+d %+d\n", *(rt_int16_t *)&cmd[1], \
+				*(rt_int16_t *)&cmd[3], *(rt_int16_t *)&cmd[5]);
+#endif
+			rt_thread_sleep(1);
 		}
-		if (temp.z > max.z)
+	}
+	else
+	{
+		/* Interact mode */
+		if ((calTimer = rt_timer_create(
+			"cal_tmr",
+			efm_accel_timer,
+			RT_NULL,
+			period, 
+			RT_TIMER_FLAG_ONE_SHOT)) == RT_NULL)
 		{
-			max.z = temp.z;
+			accel_debug("Accel err: Create timer failed!\n");
+			return -RT_ERROR;
 		}
-		rt_thread_sleep(1);
-	} while (accelInTime);
-
-	accelOffset.x = (min.x + max.x) >> 1;
-	accelOffset.y = (min.y + max.y) >> 1;
-	accelOffset.z = (min.z + max.z) >> 1;
-	accel_debug("Accel: Min %x %x %x, max %x %x %x, Offset %x %x %x\n", 
-		min.x, min.y, min.z, max.x,	max.y, max.z, 
+
+		accelInTime = true;
+		rt_timer_start(calTimer);
+		do
+		{
+			sum.x = 0x0;
+			sum.y = 0x0;
+			sum.z = 0x0;
+
+			for (i = 0; i < ACCEL_CAL_SAMPLES; i++)
+			{
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+				/* Waiting for data ready */
+				while(!GPIO_PinInGet(ACCEL_INT1_PORT, ACCEL_INT1_PIN));
+#endif
+				if (efm_accel_get_data(&temp, false) != RT_EOK)
+				{
+					return -RT_ERROR;
+				}
+				sum.x += temp.x;
+				sum.y += temp.y;
+				sum.z += temp.z;
+			}
+			sum.x /= ACCEL_CAL_SAMPLES;
+			sum.y /= ACCEL_CAL_SAMPLES;
+			sum.z /= ACCEL_CAL_SAMPLES;

+			if (sum.x < min.x)
+			{
+				min.x = sum.x;
+			}
+			if (sum.y < min.y)
+			{
+				min.y = sum.y;
+			}
+			if (sum.z < min.z)
+			{
+				min.z = sum.z;
+			}
+			if (sum.x > max.x)
+			{
+				max.x = sum.x;
+			}
+			if (sum.y > max.y)
+			{
+				max.y = sum.y;
+			}
+			if (sum.z > max.z)
+			{
+				max.z = sum.z;
+			}
+			rt_thread_sleep(1);
+		} while (accelInTime);
+
+		accel_debug("Accel: Min %+d %+d %+d, max %+d %+d %+d\n", 
+			min.x, min.y, min.z, max.x, max.y, max.z);
+
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
+		accelOffset.x = -((min.x + max.x) >> 1);
+		accelOffset.y = -((min.y + max.y) >> 1);
+		accelOffset.z = -((min.z + max.z) >> 1);
+
+	accel_debug("Accel: Offset %+d %+d %+d\n", 
 		accelOffset.x, accelOffset.y, accelOffset.z);
 
-	rt_timer_delete(calTimer);
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+		/* Set offset drift registers */
+		*(rt_int16_t *)&cmd[1] = (rt_int16_t)-(min.x + max.x);
+		*(rt_int16_t *)&cmd[3] = (rt_int16_t)-(min.y + max.y);
+		*(rt_int16_t *)&cmd[5] = (rt_int16_t)-(min.z + max.z);
+		if (accel->write(accel, ACCEL_IIC_SLAVE_ADDRESS, cmd, sizeof(cmd)) == 0)
+		{
+			return -RT_ERROR;
+		}
+
+	accel_debug("Accel: Offset %+d %+d %+d\n", 
+		*(rt_int16_t *)&cmd[1], *(rt_int16_t *)&cmd[3], *(rt_int16_t *)&cmd[5]);
+#endif
+
+		rt_timer_delete(calTimer);
+	}
+
 	return RT_EOK;
 }
 
@@ -188,15 +748,9 @@ rt_err_t efm_accel_auto_zero(rt_tick_t period)
  ******************************************************************************/
 rt_err_t efm_accel_init(void)
 {
-	ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;
-
-#if defined(EFM32_G290_DK)
-	/* Enable accelerometer */
-	DVK_enablePeripheral(DVK_ACCEL);
-	/* Select low g-range */
-	DVK_disablePeripheral(DVK_ACCEL_GSEL);
-#endif
+	rt_err_t ret;
 
+	ret = RT_EOK;
 	do
 	{
 		/* Find ADC device */
@@ -204,16 +758,65 @@ rt_err_t efm_accel_init(void)
 		if (accel == RT_NULL)
 		{
 			accel_debug("Accel err: Can't find device: %s!\n", ACCEL_USING_DEVICE_NAME);
+			ret = -RT_ERROR;
 			break;
 		}
 		accel_debug("Accel: Find device %s\n", ACCEL_USING_DEVICE_NAME);
 
+		/* --------- ADC interface --------- */
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
+		ADC_InitScan_TypeDef scanInit = ADC_INITSCAN_DEFAULT;
+
+ #if defined(EFM32_G290_DK)
+		/* Enable accelerometer */
+		DVK_enablePeripheral(DVK_ACCEL);
+			/* Select g-range */
+  #if (ACCEL_G_SELECT == 0)
+		DVK_disablePeripheral(DVK_ACCEL_GSEL);
+  #elif (ACCEL_G_SELECT == 1)
+		DVK_enablePeripheral(DVK_ACCEL_GSEL);
+  #else
+  #error "Wrong value for ACCEL_G_SELECT"
+  #endif
+ #endif
 		/* Init ADC for scan mode */
 		scanInit.reference = adcRefVDD;
 		scanInit.input = ACCEL_X_ADC_CH | ACCEL_Y_ADC_CH | ACCEL_Z_ADC_CH;
 
 		control.scan.init = &scanInit;
-		accel->control(accel, RT_DEVICE_CTRL_ADC_MODE, &control);
+		if ((ret = accel->control(accel, RT_DEVICE_CTRL_ADC_MODE, \
+			(void *)&control)) != RT_EOK)
+		{
+			break;
+		}
+
+		/* --------- IIC interface --------- */
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+		rt_uint8_t cmd[2];
+
+		/* Initialize */
+		if ((ret = accel->control(accel, RT_DEVICE_CTRL_IIC_SETTING, \
+			(void *)&control)) != RT_EOK)
+		{
+			break;
+		}
+
+		if (efm_accel_config(
+			ACCEL_MODE_MEASUREMENT | ACCEL_RANGE_2G, 
+			EFM32_NO_DATA, 
+			EFM32_NO_DATA, 
+			EFM32_NO_DATA, 
+			EFM32_NO_DATA, 
+			EFM32_NO_DATA) != RT_EOK)
+		{
+			break;
+		}
+
+		/* Config interrupt pin1 */
+		GPIO_PinModeSet(ACCEL_INT1_PORT, ACCEL_INT1_PIN, gpioModeInput, 0);
+		/* Config interrupt pin2 */
+		GPIO_PinModeSet(ACCEL_INT2_PORT, ACCEL_INT2_PIN, gpioModeInput, 0);
+#endif
 
 		accel_debug("Accel: Init OK\n");
 		return RT_EOK;
@@ -229,35 +832,61 @@ rt_err_t efm_accel_init(void)
 #ifdef RT_USING_FINSH
 #include <finsh.h>
 
-void accel_cal(rt_uint32_t second)
+void accel_cal(rt_uint8_t mode, rt_uint32_t second)
 {
-	efm_accel_auto_zero(RT_TICK_PER_SECOND * second);
+	if (efm_accel_auto_zero(mode, RT_TICK_PER_SECOND * second) != RT_EOK)
+	{
+		rt_kprintf("Error occurred.");
+		return;
+	}
 
-	rt_kprintf("Calibration done. Offset: 0x%03x, 0x%03x, 0x%03x\n", 
-		accelOffset.x, accelOffset.y, accelOffset.z);
+	rt_kprintf("Calibration done.\n");
 }
 FINSH_FUNCTION_EXPORT(accel_cal, auto-zero calibration.)
 
 void list_accel(void)
 {
-	struct efm32_accel_result_t temp;
-	rt_int32_t x, y, z;
+	struct efm32_accel_result_t data;
+
+	efm_accel_get_data(&data, false);
+	rt_kprintf("X: %d, Y: %d, Z: %d\n", data.x, data.y, data.z);
+}
+FINSH_FUNCTION_EXPORT(list_accel, list accelerometer info.)
 
-	if ((accelOffset.x == 0) && \
-		(accelOffset.y == 0) && \
-		(accelOffset.z == 0))
+void test_accel(rt_uint8_t mode)
+{
+	if (mode == 0)
 	{
-		rt_kprintf("Please calibrate the device first!\n");
-		return;
+		if (efm_accel_config(
+			ACCEL_MODE_LEVEL | ACCEL_RANGE_8G | ACCEL_INT_LEVEL_PULSE | \
+			ACCEL_SOURCE_LEVEL_X | ACCEL_SOURCE_LEVEL_Y, 
+			0x1f, 
+			EFM32_NO_DATA, 
+			EFM32_NO_DATA, 
+			EFM32_NO_DATA, 
+			EFM32_NO_DATA) != RT_EOK)
+		{
+			rt_kprintf("efm_accel_config(): error\n");
+			return;
+		}
+	}
+	else
+	{
+		if (efm_accel_config(
+			ACCEL_MODE_PULSE | ACCEL_RANGE_8G | ACCEL_INT_SINGLE_DOUBLE | \
+			ACCEL_SOURCE_PULSE_X | ACCEL_SOURCE_PULSE_Y, 
+			0x1f, 
+			0x1f, 
+			200, 
+			255, 
+			255) != RT_EOK)
+		{
+			rt_kprintf("efm_accel_config(): error\n");
+			return;
+		}
 	}
-	efm_accel_get_data(&temp);
-	x = temp.x - accelOffset.x;
-	y = temp.y - accelOffset.y;
-	z = temp.z - accelOffset.z;
-	
-	rt_kprintf("X: %d, Y: %d, Z: %d\n", x, y, z);
 }
-FINSH_FUNCTION_EXPORT(list_accel, list accelerometer info.)
+FINSH_FUNCTION_EXPORT(test_accel, list accelerometer info.)
 #endif
 
 #endif

+ 90 - 8
bsp/efm32/dev_accel.h

@@ -13,28 +13,110 @@
  * Date			Author		Notes
  * 2011-07-13	onelife		Initial creation for using EFM32 ADC module to 
  *  interface the Freescale MMA7361L
+ * 2011-08-02	onelife		Add digital interface support of using EFM32 IIC 
+ *  module for the Freescale MMA7455L
  ******************************************************************************/
 #ifndef __DEV_ACCEL_H__
 #define __DEV_ACCEL_H__
 
 /* Includes ------------------------------------------------------------------*/
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+#include "mma7455l.h"
+#endif
+
 /* Exported types ------------------------------------------------------------*/
 struct efm32_accel_result_t
 {
-	rt_uint32_t 			x;
-	rt_uint32_t 			y;
-	rt_uint32_t 			z;
+	rt_int32_t 				x;
+	rt_int32_t 				y;
+	rt_int32_t 				z;
 };
 
 /* Exported constants --------------------------------------------------------*/
 /* Exported macro ------------------------------------------------------------*/
-#define ACCEL_X_ADC_CH 		ADC_SCANCTRL_INPUTMASK_CH2
-#define ACCEL_Y_ADC_CH 		ADC_SCANCTRL_INPUTMASK_CH3
-#define ACCEL_Z_ADC_CH 		ADC_SCANCTRL_INPUTMASK_CH4
+/* 	MMA7361LC 
+ 	g-Select 	g-Range 	Sensitivity
+ 	0 			1.5 g 		800 mV/g
+ 	1 			6 g 		206 mV/g
+
+ 	MMA7455L
+ 	g-Select 	g-Range 	Sensitivity
+ 	0 			2 g 		64 LSB/g
+ 	1 			4 g 		32 LSB/g
+	2			8 g 		16 LSB/g
+*/
+#define ACCEL_G_SELECT 			(0)
+
+#define ACCEL_CAL_SAMPLES 		(4) 	/* Must be multiple of 2 */
+#define ACCEL_CAL_ROUND 		(50)
+#define ACCEL_CAL_SIMPLE 		(0)
+#define ACCEL_CAL_INTERACT 		(1)
+
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
+/* Reading_at_1g = Sensitivity * Max_reading / Refference_voltage */
+#define ACCEL_CAL_1G_VALUE 		{993, 256}
+
+#define ACCEL_X_ADC_CH 			ADC_SCANCTRL_INPUTMASK_CH2
+#define ACCEL_Y_ADC_CH 			ADC_SCANCTRL_INPUTMASK_CH3
+#define ACCEL_Z_ADC_CH 			ADC_SCANCTRL_INPUTMASK_CH4
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+#define ACCEL_CAL_1G_VALUE 		{0x3f, 0x1f, 0x0f}
+#define ACCEL_IIC_SLAVE_ADDRESS (0x1d)
+
+#define ACCEL_INT1_PORT			(gpioPortD)
+#define ACCEL_INT1_PIN			(13)
+#define ACCEL_INT2_PORT 		(gpioPortD)
+#define ACCEL_INT2_PIN 			(12)
+
+#define ACCEL_MODE_STANDBY 		(1 << 0)
+#define ACCEL_MODE_MEASUREMENT	(1 << 1)
+#define ACCEL_MODE_LEVEL		(1 << 2)
+#define ACCEL_MODE_PULSE 		(1 << 3)
+#define ACCEL_RANGE_8G 			(1 << 4)
+#define ACCEL_RANGE_4G 			(1 << 5)
+#define ACCEL_RANGE_2G 			(1 << 6)
+#define ACCEL_INTPIN_INVERSE 	(1 << 7)
+#define ACCEL_INT_LEVEL_PULSE 	(1 << 8)
+#define ACCEL_INT_PULSE_LEVEL 	(1 << 9)
+#define ACCEL_INT_SINGLE_DOUBLE	(1 << 10)
+#define ACCEL_DISABLE_X 		(1 << 11)
+#define ACCEL_DISABLE_Y 		(1 << 12)
+#define ACCEL_DISABLE_Z 		(1 << 13)
+#define ACCEL_THRESHOLD_INTEGER	(1 << 14) 	/* For level detection only */
+#define ACCEL_BANDWIDTH_125HZ	(1 << 15)
+#define ACCEL_LEVEL_AND			(1 << 16)
+#define ACCEL_PULSE_AND			(1 << 17)
+#define ACCEL_DRIVE_STRONG		(1 << 18)
+#define ACCEL_SOURCE_LEVEL_X 	(1 << 19)
+#define ACCEL_SOURCE_LEVEL_Y 	(1 << 20)
+#define ACCEL_SOURCE_LEVEL_Z 	(1 << 21)
+#define ACCEL_SOURCE_PULSE_X 	(1 << 22)
+#define ACCEL_SOURCE_PULSE_Y 	(1 << 23)
+#define ACCEL_SOURCE_PULSE_Z 	(1 << 24)
+
+#define ACCEL_SHIFT_MODE 		(0)
+#define ACCEL_SHIFT_RANGE 		(4)
+#define ACCEL_SHIFT_INT 		(8)
+#define ACCEL_SHIFT_DISABLE		(11)
+#define ACCEL_SHIFT_SOURCE		(19)
+
+#define ACCEL_MASK_MODE 		(0X0000000f << ACCEL_SHIFT_MODE)
+#define ACCEL_MASK_RANGE 		(0X00000007 << ACCEL_SHIFT_RANGE)
+#define ACCEL_MASK_INT 			(0X00000007 << ACCEL_SHIFT_INT)
+#define ACCEL_MASK_DISABLE 		(0X00000007 << ACCEL_SHIFT_DISABLE)
+#define ACCEL_MASK_SOURCE 		(0X0000003f << ACCEL_SHIFT_SOURCE)
+#endif
 
 /* Exported functions ------------------------------------------------------- */
-rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data);
-rt_err_t efm_accel_auto_zero(rt_tick_t period);
+rt_err_t efm_accel_get_data(struct efm32_accel_result_t *data, 
+	rt_bool_t lowResolution);
+rt_err_t efm_accel_config(rt_uint32_t config,
+	rt_uint8_t level_threshold,
+	rt_uint8_t pulse_threshold,
+	rt_uint8_t pulse_duration,
+	rt_uint8_t pulse_latency,
+	rt_uint8_t pulse_duration2);
+rt_err_t efm_accel_auto_zero(rt_uint8_t mode, rt_tick_t period);
 rt_err_t efm_accel_init(void);
 
 #endif /*__DEV_ACCEL_H__ */

+ 90 - 76
bsp/efm32/drv_iic.c

@@ -15,6 +15,9 @@
  * 2011-06-17	onelife		Modify init function for efm32lib v2 upgrading
  * 2011-07-11	onelife		Add lock (semaphore) to prevent simultaneously 
  *  access
+ * 2011-08-04	onelife		Change the usage of the second parameter of Read 
+ *  and Write functions from (seldom used) "Offset" to "Slave address"
+ * 2011-08-04	onelife		Add a timer to prevent from forever waiting
  ******************************************************************************/
 
 /***************************************************************************//**
@@ -29,6 +32,13 @@
 
 #if (defined(RT_USING_IIC0) || defined(RT_USING_IIC1))
 /* Private typedef -----------------------------------------------------------*/
+struct efm32_iic_block
+{
+	struct rt_device 			device;
+	struct rt_semaphore			lock;
+	struct rt_timer 			timer;
+};
+
 /* Private define ------------------------------------------------------------*/
 /* Private macro -------------------------------------------------------------*/
 #ifdef RT_IIC_DEBUG
@@ -39,19 +49,17 @@
 
 /* Private variables ---------------------------------------------------------*/
 #ifdef RT_USING_IIC0
-#if (RT_USING_IIC0 > 3)
-	#error "The location number range of IIC is 0~3"
-#endif
-	struct rt_device 			iic0_device;
-	static struct rt_semaphore	iic0_lock;
+ #if (RT_USING_IIC0 > 3)
+ #error "The location number range of IIC is 0~3"
+ #endif
+static struct efm32_iic_block 	iic0;
 #endif
 
 #ifdef RT_USING_IIC1
-#if (RT_USING_IIC1 > 3)
-	#error "The location number range of IIC is 0~3"
-#endif
-	struct rt_device 			iic1_device;
-	static struct rt_semaphore	iic1_lock;
+ #if (RT_USING_IIC1 > 3)
+ #error "The location number range of IIC is 0~3"
+ #endif
+static struct efm32_iic_block 	iic1;
 #endif
 
 /* Private function prototypes -----------------------------------------------*/
@@ -161,7 +169,7 @@ static rt_err_t rt_iic_close(rt_device_t dev)
  *   Pointer to device descriptor
  *
  * @param[in] pos
- *   Offset
+ *   Slave address
  *
  * @param[in] buffer
  *   Poniter to the buffer
@@ -183,7 +191,6 @@ static rt_size_t rt_iic_read (
 	struct efm32_iic_device_t* 	iic;
 	I2C_TransferSeq_TypeDef 	seq;
 	I2C_TransferReturn_TypeDef 	ret;
-	rt_uint8_t 					data[1];
 
 	if (!size)
 	{
@@ -193,7 +200,6 @@ static rt_size_t rt_iic_read (
 	err_code = RT_EOK;
 	read_size = 0;
 	iic = (struct efm32_iic_device_t*)dev->user_data;
-	data[0] = (rt_uint8_t)(pos & 0x000000FF);
 
 	/* Lock device */
 	if (rt_hw_interrupt_check())
@@ -211,36 +217,39 @@ static rt_size_t rt_iic_read (
 
 	if (iic->state & IIC_STATE_MASTER)
 	{
-		seq.addr = iic->slave_address;
+		seq.addr = (rt_uint16_t)pos << 1;
 		seq.flags = I2C_FLAG_WRITE_READ;
-		/* Select register to be read */
-		seq.buf[0].data = data;
+		/* Set register to be read */
+		seq.buf[0].data = (rt_uint8_t *)buffer;
 		seq.buf[0].len = 1;
-		/* Select location/length of data to be read */
+		/* Set read buffer pointer and size */
 		seq.buf[1].data = (rt_uint8_t *)buffer;
 		seq.buf[1].len = size;
 
 		/* Do a polled transfer */
+		iic->timeout = false;
+		rt_timer_stop(iic->timer);
+		rt_timer_start(iic->timer);
 		ret = I2C_TransferInit(iic->iic_device, &seq);
-		while (ret == i2cTransferInProgress)
+		while ((ret == i2cTransferInProgress) && !iic->timeout)
 		{
 		  ret = I2C_Transfer(iic->iic_device);
 		}
 	
 		if (ret != i2cTransferDone)
 		{
-			iic_debug("IIC0 read error: %x\n", ret);
-			iic_debug("IIC0 read address: %x\n", seq.addr);
-			iic_debug("IIC0 read data0: %x -> %x\n", seq.buf[0].data, *seq.buf[0].data);
-			iic_debug("IIC0 read len0: %x\n", seq.buf[0].len);
-			iic_debug("IIC0 read data1: %x -> %x\n", seq.buf[1].data, *seq.buf[1].data);
-			iic_debug("IIC0 read len1: %x\n", seq.buf[1].len);
+			iic_debug("IIC read error: %x\n", ret);
+			iic_debug("IIC read address: %x\n", seq.addr);
+			iic_debug("IIC read data0: %x -> %x\n", seq.buf[0].data, *seq.buf[0].data);
+			iic_debug("IIC read len0: %x\n", seq.buf[0].len);
+			iic_debug("IIC read data1: %x -> %x\n", seq.buf[1].data, *seq.buf[1].data);
+			iic_debug("IIC read len1: %x\n", seq.buf[1].len);
 			err_code = (rt_err_t)ret;
 		}
 		else
 		{
 			read_size = size;
-			iic_debug("IIC0 read size: %d\n", read_size);
+			iic_debug("IIC read size: %d\n", read_size);
 		}
 	}
 	else
@@ -288,7 +297,7 @@ static rt_size_t rt_iic_read (
 		}
 
 		read_size = (rt_uint32_t)ptr - (rt_uint32_t)buffer;
-		iic_debug("IIC0 slave read size: %d\n", read_size);
+		iic_debug("IIC slave read size: %d\n", read_size);
 	}
 
 	/* Unlock device */
@@ -311,7 +320,7 @@ static rt_size_t rt_iic_read (
  *   Pointer to device descriptor
  *
  * @param[in] pos
- *   Offset
+ *   Slave address
  *
  * @param[in] buffer
  *   Poniter to the buffer
@@ -359,24 +368,11 @@ static rt_size_t rt_iic_write (
 
 	if (iic->state & IIC_STATE_MASTER)
 	{
-		seq.addr = iic->slave_address;
-		if (pos != (rt_off_t)(-1))
-		{
-			seq.flags = I2C_FLAG_WRITE_WRITE;
-			/* Select register to be write */
-			seq.buf[0].data = (rt_uint8_t *)(pos & 0x000000FF);
-			seq.buf[0].len = 1;
-			/* Select location/length of data to be write */
-			seq.buf[1].data = (rt_uint8_t *)buffer;
-			seq.buf[1].len = size;
-		}
-		else
-		{
-			seq.flags = I2C_FLAG_WRITE;
-			/* Select location/length of data to be write */
-			seq.buf[0].data = (rt_uint8_t *)buffer;
-			seq.buf[0].len = size;
-		}
+		seq.addr = (rt_uint16_t)pos << 1;
+		seq.flags = I2C_FLAG_WRITE;
+		/* Set write buffer pointer and size */
+		seq.buf[0].data = (rt_uint8_t *)buffer;
+		seq.buf[0].len = size;
 	}
 	else
 	{
@@ -384,10 +380,13 @@ static rt_size_t rt_iic_write (
 	}
 
 	/* Do a polled transfer */
+	iic->timeout = false;
+	rt_timer_stop(iic->timer);
+	rt_timer_start(iic->timer);
 	ret = I2C_TransferInit(iic->iic_device, &seq);
-	while (ret == i2cTransferInProgress)
+	while ((ret == i2cTransferInProgress) && !iic->timeout)
 	{
-	  ret = I2C_Transfer(iic->iic_device);
+		ret = I2C_Transfer(iic->iic_device);
 	}
 	
 	if (ret != i2cTransferDone)
@@ -474,8 +473,7 @@ static rt_err_t rt_iic_control (
 
 			control = (struct efm32_iic_control_t *)args;
 			iic->state = control->config & (IIC_STATE_MASTER | IIC_STATE_BROADCAST);
-			iic->master_address = control->master_address << 1;
-			iic->slave_address = control->slave_address << 1;
+			iic->address = control->address << 1;
 
 			if (!(iic->state & IIC_STATE_MASTER))
 			{
@@ -503,7 +501,7 @@ static rt_err_t rt_iic_control (
 				}
 			
 				/* Enable slave mode */
-				I2C_SlaveAddressSet(iic->iic_device, iic->slave_address);
+				I2C_SlaveAddressSet(iic->iic_device, iic->address);
 				I2C_SlaveAddressMaskSet(iic->iic_device, 0xFF);
 				iic->iic_device->CTRL |= I2C_CTRL_SLAVE | I2C_CTRL_AUTOACK | I2C_CTRL_AUTOSN;
 
@@ -513,7 +511,7 @@ static rt_err_t rt_iic_control (
 				
 				/* Enable I2Cn interrupt vector in NVIC */
 #ifdef RT_USING_IIC0
-				if (dev == &iic0_device)
+				if (dev == &iic0.device)
 				{
 					NVIC_ClearPendingIRQ(I2C0_IRQn);
 					NVIC_SetPriority(I2C0_IRQn, EFM32_IRQ_PRI_DEFAULT);
@@ -521,7 +519,7 @@ static rt_err_t rt_iic_control (
 				}
 #endif
 #ifdef RT_USING_IIC1
-				if (dev == &iic1_device)
+				if (dev == &iic1.device)
 				{
 					NVIC_ClearPendingIRQ(I2C1_IRQn);
 					NVIC_SetPriority(I2C1_IRQn, EFM32_IRQ_PRI_DEFAULT);
@@ -539,6 +537,22 @@ static rt_err_t rt_iic_control (
 	return RT_EOK;
 }
 
+/***************************************************************************//**
+ * @brief
+ *   IIC timeout interrupt handler
+ *
+ * @details
+ *
+ * @note
+ *
+ * @param[in] parameter
+ *	Parameter
+ ******************************************************************************/
+static void rt_iic_timer(void *timeout)
+{
+	*(rt_bool_t *)timeout = true;
+}
+
 /***************************************************************************//**
  * @brief
  *	Register IIC device
@@ -683,14 +697,15 @@ static void rt_hw_iic_slave_isr(rt_device_t dev)
  *	Pin location number 
  ******************************************************************************/
 static struct efm32_iic_device_t *rt_hw_iic_unit_init(
-	rt_device_t device,
-	rt_uint8_t 	unitNumber, 
-	rt_uint8_t 	location)
+	struct efm32_iic_block 	*block,
+	rt_uint8_t 				unitNumber, 
+	rt_uint8_t 				location)
 {
 	struct efm32_iic_device_t 	*iic;
 	CMU_Clock_TypeDef			iicClock;
 	I2C_Init_TypeDef			init = I2C_INIT_DEFAULT;
 	efm32_irq_hook_init_t		hook;
+	rt_uint8_t 					name[RT_NAME_MAX];
 
 	do
 	{
@@ -702,9 +717,10 @@ static struct efm32_iic_device_t *rt_hw_iic_unit_init(
 			break;
 		}
 		iic->counter 		= 0;
+		iic->timer 			= &block->timer;
+		iic->timeout 		= false;
 		iic->state 			|= IIC_STATE_MASTER;
-		iic->master_address	= 0x0000;
-		iic->slave_address 	= 0x0000;
+		iic->address		= 0x0000;
 		iic->rx_buffer 		= RT_NULL;
 
 		/* Initialization */
@@ -729,6 +745,7 @@ static struct efm32_iic_device_t *rt_hw_iic_unit_init(
 		default:
 			break;
 		}
+		rt_sprintf(name, "iic%d", unitNumber);
 
 		/* Enabling clock */
 		CMU_ClockEnable(iicClock, true);  
@@ -751,7 +768,7 @@ static struct efm32_iic_device_t *rt_hw_iic_unit_init(
 		hook.type		= efm32_irq_type_iic;
 		hook.unit		= unitNumber;
 		hook.cbFunc 	= rt_hw_iic_slave_isr;
-		hook.userPtr	= device;
+		hook.userPtr	= (void *)&block->device;
 		efm32_irq_hook_register(&hook);
 
 		/* Enable SDZ and SCL pins and set location */
@@ -765,6 +782,17 @@ static struct efm32_iic_device_t *rt_hw_iic_unit_init(
 		/* Abort current TX data and clear TX buffers */
 		iic->iic_device->CMD = I2C_CMD_ABORT | I2C_CMD_CLEARPC | I2C_CMD_CLEARTX;
 
+		/* Initialize lock */
+		iic->lock = &block->lock;
+		if (rt_sem_init(iic->lock, name, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
+		{
+			break;
+		}
+
+		/* Initialize timer */
+		rt_timer_init(iic->timer, name, rt_iic_timer, &iic->timeout, 
+			IIC_TIMEOUT_PERIOD, RT_TIMER_FLAG_ONE_SHOT);
+
 		return iic;
 	} while(0);
 
@@ -795,40 +823,26 @@ void rt_hw_iic_init(void)
 		flag = RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX;
 #ifdef RT_USING_IIC0
 		/* Initialize and register iic0 */
-		if ((iic = rt_hw_iic_unit_init(&iic0_device, 0, RT_USING_IIC0)) != RT_NULL)
+		if ((iic = rt_hw_iic_unit_init(&iic0, 0, RT_USING_IIC0)) != RT_NULL)
 		{
-			rt_hw_iic_register(&iic0_device, RT_IIC0_NAME, flag, iic);
+			rt_hw_iic_register(&iic0.device, RT_IIC0_NAME, flag, iic);
 		}
 		else
 		{
 			break;
 		}
-
-		/* Initialize lock for iic0 */
-		iic->lock = &iic0_lock;
-		if (rt_sem_init(iic->lock, RT_IIC0_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
-		{
-			break;
-		}
 #endif
 
 #ifdef RT_USING_IIC1
 		/* Initialize and register iic1 */
-		if ((iic = rt_hw_iic_unit_init(&iic1_device, 1, RT_USING_IIC1)) != RT_NULL)
+		if ((iic = rt_hw_iic_unit_init(&iic1, 1, RT_USING_IIC1)) != RT_NULL)
 		{
-			rt_hw_iic_register(&iic1_device, RT_IIC1_NAME, flag, iic);
+			rt_hw_iic_register(&iic1.device, RT_IIC1_NAME, flag, iic);
 		}
 		else
 		{
 			break;
 		}
-
-		/* Initialize lock for iic1 */
-		iic->lock = &iic1_lock;
-		if (rt_sem_init(iic->lock, RT_IIC1_NAME, 1, RT_IPC_FLAG_FIFO) != RT_EOK)
-		{
-			break;
-		}
 #endif
 
 		iic_debug("IIC: H/W init OK!\n");

+ 11 - 6
bsp/efm32/drv_iic.h

@@ -14,6 +14,9 @@
  * 2011-01-07	onelife		Initial creation for EFM32
  * 2011-07-11	onelife		Add lock (semaphore) to prevent simultaneously 
  *  access
+ * 2011-08-04	onelife		Change the usage of the second parameter of Read 
+ *  and Write functions from (seldom used) "Offset" to "Slave address"
+ * 2011-08-04	onelife		Add a timer to prevent from forever waiting
  ******************************************************************************/
 #ifndef __DRV_IIC_H__
 #define __DRV_IIC_H__
@@ -33,14 +36,16 @@ struct efm32_iic_device_t
 	rt_uint32_t 				counter;
 	/* Lock */
 	struct rt_semaphore 		*lock;
+	/* Pointer to timer */
+	rt_timer_t 					timer;
+	/* Timeout flag */
+	volatile rt_bool_t 			timeout;
 	/* State */
 	rt_uint8_t 					state;
 	/*  Pointer to IIC device structure */
 	I2C_TypeDef 				*iic_device;
-	/*  Master address */
-	rt_uint16_t					master_address;
-	/*  Slave address */
-	rt_uint16_t					slave_address;
+	/*  Self address */
+	rt_uint16_t					address;
 	/* RX structure */
 	struct efm32_iic_int_mode_t	*rx_buffer;
 };
@@ -48,8 +53,7 @@ struct efm32_iic_device_t
 struct efm32_iic_control_t
 {
 	rt_uint8_t 		config;
-	rt_uint16_t		master_address;
-	rt_uint16_t		slave_address;
+	rt_uint16_t		address;
 };
 
 /* Exported constants --------------------------------------------------------*/
@@ -58,6 +62,7 @@ struct efm32_iic_control_t
 #define IIC_STATE_BROADCAST (1 << 1)
 //#define IIC_STATE_TX_BUSY 	(1 << 2)
 #define IIC_STATE_RX_BUSY 	(1 << 3)
+#define IIC_TIMEOUT_PERIOD 	(RT_TICK_PER_SECOND)
 
 /* Exported functions --------------------------------------------------------*/
 void rt_hw_iic_init(void);

+ 19 - 8
bsp/efm32/rtconfig.h

@@ -49,7 +49,7 @@
 //#define RT_RTC_DEBUG
 
 #define EFM32_DEBUG
-#define RT_ACCEL_DEBUG
+#define EFM32_ACCEL_DEBUG
 #define EFM32_SFLASH_DEBUG
 //#define EFM32_SDCARD_DEBUG
 //#define EFM32_ETHERNET_DEBUG
@@ -119,7 +119,7 @@
 #endif
 
 /* SECTION: IIC options */
-//#define RT_USING_IIC0				0x1UL
+#define RT_USING_IIC0				0x3UL
 #define RT_IIC0_NAME				"iic0"
 
 /* SECTION: ACMP options */
@@ -162,23 +162,34 @@
 #define FINSH_USING_DESCRIPTION
 
 /* SECTION: Peripheral devices */
+#define EFM32_INTERFACE_ADC 		(0)
+#define EFM32_INTERFACE_IIC 		(1)
+#define EFM32_INTERFACE_SPI 		(2)
 #if defined(EFM32_G290_DK)
-//#define EFM32_USING_ACCEL 			/* Three axis accelerometer */
-//#define EFM32_USING_SFLASH 		/* SPI Flash */
-//#define EFM32_USING_SPISD 			/* MicroSD card */
-#define EFM32_USING_ETHERNET 		/* Ethernet controller */
+#define EFM32_USING_ACCEL 			EFM32_INTERFACE_IIC	/* Three axis accelerometer */
+//#define EFM32_USING_SFLASH 							/* SPI Flash */
+//#define EFM32_USING_SPISD 								/* MicroSD card */
+//#define EFM32_USING_ETHERNET 							/* Ethernet controller */
 #endif
+
 #if defined(EFM32_USING_ACCEL)
+#if (EFM32_USING_ACCEL == EFM32_INTERFACE_ADC)
 #define ACCEL_USING_DEVICE_NAME 	RT_ADC0_NAME
-#define ACCEL_USING_DMA				(0x3UL)
+#define ACCEL_USING_DMA				(0x3UL) 			/* For multiple channels scan mode */
+#elif (EFM32_USING_ACCEL == EFM32_INTERFACE_IIC)
+#define ACCEL_USING_DEVICE_NAME 	RT_IIC0_NAME
+#endif
 #endif
+
 #if defined(EFM32_USING_SFLASH)
 #define SFLASH_USING_DEVICE_NAME 	RT_USART0_NAME
 #endif
+
 #if defined(EFM32_USING_SPISD)
 #define SPISD_USING_DEVICE_NAME 	RT_USART0_NAME
 #define SPISD_DEVICE_NAME 			"spiSd"
 #endif
+
 #if defined(EFM32_USING_ETHERNET)
 #define ETH_USING_DEVICE_NAME 		RT_USART2_NAME
 #define ETH_DEVICE_NAME 			"spiEth"
@@ -205,7 +216,7 @@
 //#define hostName 					"onelife.dyndns.org"
 //#define userPwdB64 					"dXNlcjpwYXNzd2Q="
 
-#define RT_USING_LWIP
+///#define RT_USING_LWIP
 //#define RT_USING_NETUTILS
 /* LwIP uses RT-Thread Memory Management */
 #define RT_LWIP_USING_RT_MEM