summaryrefslogtreecommitdiff
path: root/common/motion_sense.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/motion_sense.c')
-rw-r--r--common/motion_sense.c157
1 files changed, 85 insertions, 72 deletions
diff --git a/common/motion_sense.c b/common/motion_sense.c
index 1023409f99..353e54030b 100644
--- a/common/motion_sense.c
+++ b/common/motion_sense.c
@@ -45,13 +45,8 @@ const intv3_t orientation_modes[] = {
};
#endif
-/*
- * Sampling interval for measuring acceleration and calculating lid angle.
- */
-test_export_static unsigned int motion_interval;
-
/* Delay between FIFO interruption. */
-static unsigned int motion_int_interval;
+static unsigned int ap_event_interval;
/* Minimum time in between running motion sense task loop. */
unsigned int motion_min_interval = CONFIG_MOTION_MIN_SENSE_WAIT_TIME * MSEC;
@@ -208,22 +203,19 @@ static inline int motion_sensor_in_forced_mode(
#endif
}
-
-
/* Minimal amount of time since last collection before triggering a new one */
static inline int motion_sensor_time_to_read(const timestamp_t *ts,
const struct motion_sensor_t *sensor)
{
- int rate_mhz = sensor->drv->get_data_rate(sensor);
-
- if (rate_mhz == 0)
+ if (sensor->collection_rate == 0)
return 0;
+
/*
- * converting from mHz to us.
- * If within 95% of the time, check sensor.
+ * If the time is within the min motion interval (3 ms) go ahead and
+ * read from the sensor
*/
return time_after(ts->le.lo,
- sensor->last_collection + SECOND * 950 / rate_mhz);
+ sensor->next_collection - motion_min_interval);
}
static enum sensor_config motion_sense_get_ec_config(void)
@@ -296,7 +288,9 @@ int motion_sense_set_data_rate(struct motion_sensor_t *sensor)
* Reset last collection: the last collection may be so much in the past
* it may appear to be in the future.
*/
- sensor->last_collection = ts.le.lo;
+ odr = sensor->drv->get_data_rate(sensor);
+ sensor->collection_rate = odr > 0 ? SECOND * 1000 / odr : 0;
+ sensor->next_collection = ts.le.lo + sensor->collection_rate;
sensor->oversampling = 0;
mutex_unlock(&g_sensor_mutex);
return 0;
@@ -402,9 +396,9 @@ static int motion_sense_ec_rate(struct motion_sensor_t *sensor)
*
* Note: Not static to be tested.
*/
-static int motion_sense_set_motion_intervals(void)
+static void motion_sense_set_motion_intervals(void)
{
- int i, sensor_ec_rate, ec_rate = 0, ec_int_rate = 0;
+ int i, sensor_ec_rate, ec_int_rate = 0;
struct motion_sensor_t *sensor;
for (i = 0; i < motion_sensor_count; ++i) {
sensor = &motion_sensors[i];
@@ -415,28 +409,20 @@ static int motion_sense_set_motion_intervals(void)
(sensor->drv->get_data_rate(sensor) == 0))
continue;
- sensor_ec_rate = motion_sense_ec_rate(sensor);
- if (sensor_ec_rate == 0)
- continue;
- if (ec_rate == 0 || sensor_ec_rate < ec_rate)
- ec_rate = sensor_ec_rate;
-
sensor_ec_rate = motion_sense_select_ec_rate(
sensor, SENSOR_CONFIG_AP, 1);
if (ec_int_rate == 0 ||
(sensor_ec_rate && sensor_ec_rate < ec_int_rate))
ec_int_rate = sensor_ec_rate;
}
- motion_interval = ec_rate;
- motion_int_interval =
+ ap_event_interval =
MAX(0, ec_int_rate - MOTION_SENSOR_INT_ADJUSTMENT_US);
/*
* Wake up the motion sense task: we want to sensor task to take
* in account the new period right away.
*/
task_wake(TASK_ID_MOTIONSENSE);
- return motion_interval;
}
static inline int motion_sense_init(struct motion_sensor_t *sensor)
@@ -692,11 +678,8 @@ static inline void update_sense_data(uint8_t *lpc_status, int *psample_id)
static int motion_sense_read(struct motion_sensor_t *sensor)
{
- if (sensor->state != SENSOR_INITIALIZED)
- return EC_ERROR_UNKNOWN;
-
- if (sensor->drv->get_data_rate(sensor) == 0)
- return EC_ERROR_NOT_POWERED;
+ ASSERT(sensor->state == SENSOR_INITIALIZED);
+ ASSERT(sensor->drv->get_data_rate(sensor) != 0);
#ifdef CONFIG_ACCEL_SPOOF_MODE
/*
@@ -711,6 +694,30 @@ static int motion_sense_read(struct motion_sensor_t *sensor)
return sensor->drv->read(sensor, sensor->raw_xyz);
}
+
+static inline void increment_sensor_collection(struct motion_sensor_t *sensor,
+ const timestamp_t *ts)
+{
+ sensor->next_collection += sensor->collection_rate;
+
+ if (time_after(ts->le.lo, sensor->next_collection)) {
+ /*
+ * If we get here it means that we completely missed a sensor
+ * collection time and we attempt to recover by scheduling as
+ * soon as possible. This should not happen and if it does it
+ * means that the ec cannot handle the requested data rate.
+ */
+ int missed_events =
+ time_until(sensor->next_collection, ts->le.lo) /
+ sensor->collection_rate;
+
+ CPRINTS("%s Missed %d data collections at %u - rate: %d",
+ sensor->name, missed_events, sensor->next_collection,
+ sensor->collection_rate);
+ sensor->next_collection = ts->le.lo + motion_min_interval;
+ }
+}
+
static int motion_sense_process(struct motion_sensor_t *sensor,
uint32_t *event,
const timestamp_t *ts)
@@ -729,6 +736,13 @@ static int motion_sense_process(struct motion_sensor_t *sensor,
struct ec_response_motion_sensor_data vector;
int *v = sensor->raw_xyz;
+ /*
+ * Since motion_sense_read can sleep, other task may be
+ * scheduled. In particular if suspend is called by
+ * HOOKS task, it may set colleciton_rate to 0 and we
+ * would crash in increment_sensor_collection.
+ */
+ increment_sensor_collection(sensor, ts);
ret = motion_sense_read(sensor);
if (ret == EC_SUCCESS) {
vector.flags = 0;
@@ -743,7 +757,6 @@ static int motion_sense_process(struct motion_sensor_t *sensor,
motion_sense_fifo_add_data(&vector, sensor, 3,
__hw_clock_source_read());
}
- sensor->last_collection = ts->le.lo;
} else {
ret = EC_ERROR_BUSY;
}
@@ -760,8 +773,14 @@ static int motion_sense_process(struct motion_sensor_t *sensor,
if (motion_sensor_in_forced_mode(sensor)) {
if (motion_sensor_time_to_read(ts, sensor)) {
/* Get latest data for local calculation */
+ /*
+ * Since motion_sense_read can sleep, other task may be
+ * scheduled. In particular if suspend is called by
+ * HOOKS task, it may set colleciton_rate to 0 and we
+ * would crash in increment_sensor_collection.
+ */
+ increment_sensor_collection(sensor, ts);
ret = motion_sense_read(sensor);
- sensor->last_collection = ts->le.lo;
} else {
ret = EC_ERROR_BUSY;
}
@@ -897,6 +916,7 @@ void motion_sense_task(void *u)
{
int i, ret, wait_us;
timestamp_t ts_begin_task, ts_end_task;
+ int32_t time_diff;
uint32_t event = 0;
uint16_t ready_status;
struct motion_sensor_t *sensor;
@@ -970,7 +990,6 @@ void motion_sense_task(void *u)
update_sense_data(lpc_status, &sample_id);
#endif
- ts_end_task = get_time();
#ifdef CONFIG_ACCEL_FIFO
/*
* Ask the host to flush the queue if
@@ -981,14 +1000,14 @@ void motion_sense_task(void *u)
if (fifo_flush_needed || wake_up_needed ||
event & TASK_EVENT_MOTION_ODR_CHANGE ||
queue_space(&motion_sense_fifo) < CONFIG_ACCEL_FIFO_THRES ||
- (motion_int_interval > 0 &&
- time_after(ts_end_task.le.lo,
- ts_last_int.le.lo + motion_int_interval))) {
+ (ap_event_interval > 0 &&
+ time_after(ts_begin_task.le.lo,
+ ts_last_int.le.lo + ap_event_interval))) {
if (!fifo_flush_needed)
motion_sense_insert_timestamp(
__hw_clock_source_read());
fifo_flush_needed = 0;
- ts_last_int = ts_end_task;
+ ts_last_int = ts_begin_task;
/*
* Count the number of event the AP is allowed to
* collect.
@@ -1012,25 +1031,36 @@ void motion_sense_task(void *u)
#endif
}
#endif
- if (motion_interval > 0) {
- /*
- * Delay appropriately to keep sampling time
- * consistent.
- */
- wait_us = motion_interval -
- (ts_end_task.val - ts_begin_task.val);
- /* and it cannnot be negative */
- wait_us = MAX(wait_us, 0);
+ ts_end_task = get_time();
+ wait_us = -1;
+
+ for (i = 0; i < motion_sensor_count; i++) {
+ struct motion_sensor_t *sensor = &motion_sensors[i];
+
+ if (!motion_sensor_in_forced_mode(sensor) ||
+ sensor->collection_rate == 0)
+ continue;
+
+ time_diff = time_until(ts_end_task.le.lo,
+ sensor->next_collection);
+
+ /* We missed our collection time so wake soon */
+ if (time_diff <= 0) {
+ wait_us = 0;
+ break;
+ }
+
+ if (wait_us == -1 || wait_us > time_diff)
+ wait_us = time_diff;
+ }
+ if (wait_us >= 0 && wait_us < motion_min_interval) {
/*
- * Guarantee some minimum delay to allow other lower
- * priority tasks to run.
- */
- if (wait_us < motion_min_interval)
- wait_us = motion_min_interval;
- } else {
- wait_us = -1;
+ * Guarantee some minimum delay to allow other lower
+ * priority tasks to run.
+ */
+ wait_us = motion_min_interval;
}
event = task_wait_event(wait_us);
@@ -1633,8 +1663,7 @@ static int command_accel_data_rate(int argc, char **argv)
sensor->drv->get_data_rate(sensor));
ccprintf("EC rate for sensor %d: %d\n", id,
motion_sense_ec_rate(sensor));
- ccprintf("Current EC rate: %d\n", motion_interval);
- ccprintf("Current Interrupt rate: %d\n", motion_int_interval);
+ ccprintf("Current Interrupt rate: %d\n", ap_event_interval);
}
return EC_SUCCESS;
@@ -1710,7 +1739,6 @@ DECLARE_CONSOLE_COMMAND(accelinit, command_accel_init,
#ifdef CONFIG_CMD_ACCEL_INFO
static int command_display_accel_info(int argc, char **argv)
{
- char *e;
int val;
if (argc > 3)
@@ -1724,21 +1752,6 @@ static int command_display_accel_info(int argc, char **argv)
accel_disp = val;
}
- /*
- * Second arg changes the accel task time interval. Note accel
- * sampling interval will be clobbered when chipset suspends or
- * resumes.
- */
- if (argc > 2) {
- val = strtoi(argv[2], &e, 0);
- if (*e)
- return EC_ERROR_PARAM2;
-
- motion_interval = val * MSEC;
- task_wake(TASK_ID_MOTIONSENSE);
-
- }
-
return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(accelinfo, command_display_accel_info,