Skip to content

Commit fc95b8f

Browse files
committed
Accelerometer: Wait for EC busy bit and validate sample ID
The EC has a busy bit and sample ID which tells us when it's currerntly updating samples and if the data is from the current or the previous sample. Without checking this we risk reading incomplete/invalid data. So now we're implementing the logic to report data only after the EC has finished updating and we're still reading the same sample. Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent 29f8963 commit fc95b8f

File tree

1 file changed

+86
-17
lines changed

1 file changed

+86
-17
lines changed

FrameworkSensors/AccelerometerClient.cpp

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -517,34 +517,102 @@ AccelerometerDevice::GetData(
517517

518518
SENSOR_FunctionEnter();
519519

520+
//
521+
// Read sensor data safely using the EC busy bit and sample ID protocol.
522+
// The EC sets the busy bit while updating sensor data and increments the
523+
// sample ID (lower 4 bits of ACC_STATUS) after each update. We must:
524+
// 1. Wait for the busy bit to clear
525+
// 2. Record the sample ID
526+
// 3. Read all sensor data
527+
// 4. Re-read ACC_STATUS and verify the busy bit is still clear
528+
// and the sample ID hasn't changed
529+
// This guarantees we didn't read partially-updated data.
530+
//
520531
UINT8 acc_status = 0;
521-
CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_STATUS, &acc_status);
522-
TraceInformation("Status: (%02x), Present: %d, Busy: %d\n",
523-
acc_status,
524-
(acc_status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT) > 0,
525-
(acc_status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) > 0);
532+
UINT8 samp_id = 0xFF;
533+
UINT8 status = 0;
534+
int attempts = 0;
535+
536+
#define quarter (0xFFFF/4)
537+
#define MAX_SENSOR_READ_ATTEMPTS 5
538+
#define MAX_BUSY_WAIT_ATTEMPTS 50
539+
#define BUSY_WAIT_SLEEP_INTERVAL 5
540+
#define BUSY_WAIT_SLEEP_MS 25
526541

527542
UINT8 lid_angle_bytes[2] = {0};
528-
CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_DATA + 0, &lid_angle_bytes[0]);
529-
CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_DATA + 1, &lid_angle_bytes[1]);
530-
UINT16 lid_angle = lid_angle_bytes[0] + (lid_angle_bytes[1] << 8);
543+
UINT16 lid_angle = 0;
544+
UINT SensorOffset = 6 * m_LidSensorIndex + EC_MEMMAP_ACC_DATA + 2;
545+
UINT8 Sensor1[6] = {0};
546+
547+
while ((status & (EC_MEMMAP_ACC_STATUS_BUSY_BIT |
548+
EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK)) != samp_id) {
549+
550+
if (attempts++ >= MAX_SENSOR_READ_ATTEMPTS) {
551+
TraceError("%!FUNC! Failed to get consistent sensor data after %d attempts", attempts);
552+
Status = STATUS_IO_DEVICE_ERROR;
553+
goto Exit;
554+
}
555+
556+
//
557+
// Poll ACC_STATUS until the EC is not busy
558+
//
559+
int busy_attempts = 0;
560+
CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_STATUS, &acc_status);
561+
562+
while (acc_status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) {
563+
if (busy_attempts++ >= MAX_BUSY_WAIT_ATTEMPTS) {
564+
TraceError("%!FUNC! EC busy bit stuck after %d attempts", busy_attempts);
565+
Status = STATUS_IO_DEVICE_ERROR;
566+
goto Exit;
567+
}
568+
569+
if (busy_attempts % BUSY_WAIT_SLEEP_INTERVAL == 0)
570+
Sleep(BUSY_WAIT_SLEEP_MS);
571+
572+
CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_STATUS, &acc_status);
573+
}
574+
575+
TraceInformation("Status: (%02x), Present: %d, Busy: %d\n",
576+
acc_status,
577+
(acc_status & EC_MEMMAP_ACC_STATUS_PRESENCE_BIT) > 0,
578+
(acc_status & EC_MEMMAP_ACC_STATUS_BUSY_BIT) > 0);
579+
580+
//
581+
// Record the current sample ID before reading data
582+
//
583+
samp_id = acc_status & EC_MEMMAP_ACC_STATUS_SAMPLE_ID_MASK;
584+
585+
//
586+
// Read all sensor data (unsafe - EC could update mid-read)
587+
//
588+
CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_DATA + 0, &lid_angle_bytes[0]);
589+
CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_DATA + 1, &lid_angle_bytes[1]);
590+
591+
CrosEcReadMemU8(Handle, SensorOffset + 0, &Sensor1[0]);
592+
CrosEcReadMemU8(Handle, SensorOffset + 1, &Sensor1[1]);
593+
CrosEcReadMemU8(Handle, SensorOffset + 2, &Sensor1[2]);
594+
CrosEcReadMemU8(Handle, SensorOffset + 3, &Sensor1[3]);
595+
CrosEcReadMemU8(Handle, SensorOffset + 4, &Sensor1[4]);
596+
CrosEcReadMemU8(Handle, SensorOffset + 5, &Sensor1[5]);
597+
598+
//
599+
// Re-read ACC_STATUS to verify data consistency
600+
//
601+
CrosEcReadMemU8(Handle, EC_MEMMAP_ACC_STATUS, &status);
602+
}
603+
604+
//
605+
// Data is now consistent - process it
606+
//
607+
lid_angle = lid_angle_bytes[0] + (lid_angle_bytes[1] << 8);
531608
TraceInformation("Lid Angle Status: %dDeg%s", lid_angle, lid_angle == 500 ? "(Unreliable)" : "");
532609

533610
// Lid accelerometer is relevant for screen rotation
534611
// Base accelerometer is not used in this driver
535612
// It's only used for lid angle in the EC firmware
536-
UINT SensorOffset = 6 * m_LidSensorIndex + EC_MEMMAP_ACC_DATA + 2;
537-
UINT16 Sensor1[6] = {0};
538-
CrosEcReadMemU8(Handle, SensorOffset, (UINT8*)&Sensor1[0]);
539-
CrosEcReadMemU8(Handle, SensorOffset + 1, (UINT8*)&Sensor1[1]);
540-
CrosEcReadMemU8(Handle, SensorOffset + 2, (UINT8*)&Sensor1[2]);
541-
CrosEcReadMemU8(Handle, SensorOffset + 3, (UINT8*)&Sensor1[3]);
542-
CrosEcReadMemU8(Handle, SensorOffset + 4, (UINT8*)&Sensor1[4]);
543-
CrosEcReadMemU8(Handle, SensorOffset + 5, (UINT8*)&Sensor1[5]);
544613
m_CachedData.Axis.X = (float) (Sensor1[0] + (Sensor1[1] << 8));
545614
m_CachedData.Axis.Y = (float) (Sensor1[2] + (Sensor1[3] << 8));
546615
m_CachedData.Axis.Z = (float) (Sensor1[4] + (Sensor1[5] << 8));
547-
#define quarter (0xFFFF/4)
548616
m_CachedData.Axis.X = -((float) (INT16) m_CachedData.Axis.X) / quarter;
549617
m_CachedData.Axis.Y = -((float) (INT16) m_CachedData.Axis.Y) / quarter;
550618
m_CachedData.Axis.Z = -((float) (INT16) m_CachedData.Axis.Z) / quarter;
@@ -610,6 +678,7 @@ AccelerometerDevice::GetData(
610678
TraceInformation("COMBO %!FUNC! LAC Data did NOT meet the threshold");
611679
}
612680

681+
Exit:
613682
SENSOR_FunctionExit(Status);
614683
return Status;
615684
}

0 commit comments

Comments
 (0)