diff --git a/bsp/efm32/dev_accel.c b/bsp/efm32/dev_accel.c index b0423e227c2d3319f93094bb0f92160f969856c8..989e49827915f36c410984af839259c9571b0b62 100644 --- a/bsp/efm32/dev_accel.c +++ b/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 -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 diff --git a/bsp/efm32/dev_accel.h b/bsp/efm32/dev_accel.h index 2950ce354dd23018058b973365487d4d6f232ae2..9e2ba2ec18178d5938c230133193e5758e727ac2 100644 --- a/bsp/efm32/dev_accel.h +++ b/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__ */ diff --git a/bsp/efm32/drv_iic.c b/bsp/efm32/drv_iic.c index 081871ca6aae6914408b01ed95710ccbd5783091..aefe41d327ea2e6e19a3c65bb9d002ccd1713f6d 100644 --- a/bsp/efm32/drv_iic.c +++ b/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"); diff --git a/bsp/efm32/drv_iic.h b/bsp/efm32/drv_iic.h index 8199c56eb6ec7c8880756842d31ab603040f7e04..53df7b42e43327e0ed1811327845218d9c8e81a5 100644 --- a/bsp/efm32/drv_iic.h +++ b/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); diff --git a/bsp/efm32/rtconfig.h b/bsp/efm32/rtconfig.h index 4db20604aba0a0bf8fff49071fa373b724dce6cd..ec9579a998514e337c7bc37d88ae6e51187eb69c 100644 --- a/bsp/efm32/rtconfig.h +++ b/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