앞서 언급한 내용처럼 ICM-20948은 Master모드를 지원해 자기 자신에 연결된 센서(auxiliary)의 데이터를 가져올 수 있습니다. 최대 5개의 주소를 지원하며, BANK 0의 EXT_SLV_SENS_DATA_XX 레지스터에 자동으로 저장되도록 설정할 수 있습니다.
즉, I2C Master모드를 사용해 AK09916 센서의 데이터를 읽는다면 0x28부터 주욱 읽으면 됩니다.
앞서 언급했듯이 DMA 활용을 위해 AK09916센서에 직접 통신하는것이 아닌, ICM20948을 I2C Master Mode로 설정해 이를 경유하여 읽는다고 하였습니다. 이때문에 AK09916의 레지스터에 접근하기 위해서는 추가적인 루틴이 필요한데요, 이를 위한 함수를 정의하였습니다.
src/hw/driver/icm20948.c
여기서 ICM-20948의 Auxiliary 센서 기능을 조금 알아두어야 합니다.
Auxiliary 센서에서 읽은 데이터는 BANK0의 EXT_SLV_SENS_DATA_00부터 SLV0~SLV4 순서로 차례로 저장되며, 각 센서 데이터의 시작점은 앞선 I2C_SLVx_CTRL 레지스터의 3:0 값의 합으로 정해집니다. 즉, 만약 첫 번째 센서가 5 len의 데이터를 읽는다면 두 번째 센서에서 읽힌 데이터는 5의 offset을 적용해 EXT_SLV_SENS_DATA_05부터 저장되는것이죠.
여기서는 하나의 Auxiliary 센서(내장 AK09916)만을 사용하기 때문에 I2C_SLV0_xx 레지스터만을 사용합니다.
대략적인 Aux 센서 제어 과정은 아래와 같습니다.
I2C_SLV0_ADDR 레지스터의 6:0에 AK09916의 주소값을 저장, 이때 7번 비트(MSB)에 R/W 비트를 지정
I2C_SLV0_REG 레지스터에 AK09916에서 읽거나 쓸 레지스터 주소를 저장
(데이터를 쓰는 경우) I2C_SLV0_DO 레지스터에 쓸 데이터를 저장
I2C_SLV0_CTRL 레지스터의 3:0에 읽거나 쓸 데이터 길이를, 7번 비트에 1을 저장하여 write
우선 레지스터를 읽을 때 사용할 버퍼를 하나 만들고 I2C 통신 함수의 처리결과를 저장할 변수를 선언하였습니다.
src/hw/driver/icm20948.c
그 후 BANK0의 WHO_AM_I 레지스터를 읽어 연결은 올바른지, 센서의 종류는 올바른지 확인하였습니다.
src/hw/driver/icm20948.c
센서가 정상인 것을 확인했다면 센서 세팅에 앞서 센서를 초기화합니다.
src/hw/driver/icm20948.c
클럭과 온도센서를 설정합니다.
CLKSEL[2:0]→0b001 : 클럭 소스 자동 설정 1
TEMP_DIS[3]→1 : 온도센서 끔
src/hw/driver/icm20948.c
ODR align을 켜주었습니다.
src/hw/driver/icm20948.c
자이로와 가속도 센서의 ODR을 설정하였습니다. 두 센서 모두 100 Hz로 설정하였습니다.
추가로 저역필터를 설정하였습니다.
src/hw/driver/icm20948.c
다음으로 I2C Master Mode를 설정합니다. 기능을 리셋해준 후 I2C Master Mode를 Enable하였습니다.
src/hw/driver/icm20948.c
I2C Slave Device의 ODR을 설정하였습니다. 글을 쓰면서 확인했는데, 만약 자이로 센서나 가속도 센서가 켜진 경우 자이로→가속도 순으로 ODR을 따라가기 때문에 I2C_MST_ODR_CONFIG를 따로 설정할 필요가 없다고 하네요.
src/hw/driver/icm20948.c
I2C Slave인 AK09916을 설정합니다. 우선 리셋해준 후 100 Hz 주기로 데이터를 자동으로 읽도록 하였습니다.
그 후 ICM-20948에게 AK09916의 레지스터 데이터를 읽어도록 요청해야하는데요, AK09916의 데이터시트에 따르면 Continuous measurement mode에서는 각 데이터를 읽은 후 ST2를 읽도록 강제하기 때문에 지자기 센서 데이터 레지스터인 HXL~HZH(6 bytes) 이외에도 ST2까지 추가로 2개의 바이트를 더 읽어야 했습니다.
따라서 HXL~ST2까지 총 8개의 바이트를 읽도록 설정하였습니다. (HZH와 ST2 사이에 더미 레지스터가 하나 끼여있습니다)
src/hw/driver/icm20948.c
마지막으로 인터럽트를 켜주었습니다. INT_PIN_CFG 레지스터의 4번 비트를 켜 인터럽트 상태를 초기화한 후 인터럽트를 enable하였습니다.
src/hw/driver/icm20948.c
여기까지 했으면 통신 결과를 확인하고 문제가 없다면 s_is_imu_init 을 true로 저장해둡니다.
센서로부터 데이터 준비 완료 인터럽트가 발생하면 DMA 컨트롤러에게 I2C 데이터를 읽어오도록 합니다. 이때 읽을 데이터의 길이는 ICM-20948의 데이터인 ACCEL_XOUT_H부터 TEMP_OUT_L까지 총 14바이트 + AK09916의 데이터인 6바이트 = 20바이트입니다.
💡 AK09916의 데이터 갱신을 위해 Master에게 추가적으로 읽도록 한 뒷쪽 2바이트는 읽지 않아도 무방합니다.