ADXL345 Revisited Lab
References
- ADXL345.pdf
- GY-291-schematic.jpg
- MyI2CMasterSlave
Programming Library for ADXL345
-
ADXL345를 사용하는 함수들을 설계하고 구현한다.
-
이것들을 모아서 Library를 만든다.
-
Data
int16_t AccelX; /* -2g ~ +2g : -512 ~ 511
int16_t AccelY;
int16_t AccelZ;
- Methods
void ADXL345_WriteRegister(uint8_t reg, uint8_t value);
uint8_t ADXL345_ReadRegister(uint8_t reg);
bool ADXL345_Begin(void);
void ADXL345_GetXYZ_Polling(void);
Basic: ReadRegister() WriteRegister()
ADXL345_WriteRegister( )
는 다음과 같이 만들 수 있다.I2C_MASTER_Trasmit
method를 사용하여 2byte의 MasterDataTx를 전송한다.- 전송이 완료되기 전에 다시 이 함수가 호출되어 Over-run 이 발생되는 상황을 방지하기 위하여
SPI_MASTER_IsTxBusy( )
Method를 사용하여 Busy-wait 한다.
void ADXL345_WriteRegister(uint8_t reg, uint8_t value){
I2C_MasterDataTx[0] = reg;
I2C_MasterDataTx[1] = value;
while( I2C_MASTER_IsRxBusy(&dhI2C_MASTER) == true) { };
I2C_MASTER_Transmit(&dhI2C_MASTER, true, I2C_SlaveAddress, I2C_MasterDataTx, 2, true);
}
[Activity] ADXL345_ReadRegister( )
함수를 완성하여 보아라
-
Read Cycle을 수행하려면
I2C_MASTER_Transmit()
을 수행하여 해당 레지스터를 써준다.(주의 이때 STOP bit를 False 로 하여 전송 Cycle이 종료되는 것을 방지해 줘야 한다.) -
I2C_MASTER_Receive()
를 수행하여 해당 레지스터의 값을 읽어들여야 한다. -
각 명령이 실행되는 중에 Over-run이 발생되는 것을 방지하기 위하여 Busy-wait 한다.
uint8_t ADXL345_ReadRegister(uint8_t reg){
return(I2C_MasterDataRx[0]);
}
Set-Up: Begin()
-
ReadRegister(), WriteRegister() 함수를 사용하여 기본정보를 확인하고, 설정할 수 있다.
- DEVID: Device ID를 읽어서 그 값이 0xE5 인지 확인한다.
- BW_RATE: 현재 100KHz 의 전송속도를 고려하여 100Hz로 Conversion Rate를 설정한다.
- POWER_CTL: Measurement bit를 Set 하여 Conversion을 시작한다.
bool ADXL345_Begin(void){
uint8_t device_id;
/* Get & Check DEVID */
device_id = ADXL345_ReadRegister(ADXL345_DEVID);
if(device_id != 0xE5){
return false;
}
ADXL345_WriteRegister(ADXL345_BW_RATE, 0x0A); /* Set Conversion Rate 100Hz */
ADXL345_WriteRegister(ADXL345_POWER_CTL, 0x08); /* Enable measurements */
return(true);
}
Read Acceleration X, Y, Z
- DATAX0 와 DATAX1 레지스터를 읽어들여서 가속도 정보의 Lower byte와 Upper byte를 얻는다.
[Activity] Lower byte와 Upper byte 정보를 조합하여 AccelX 정보를 만들어 낸다.
void ADXL345_GetXYZ_Polling(void){
uint16_t upper, lower;
lower = ADXL345_ReadRegister(ADXL345_DATAX0);
upper = ADXL345_ReadRegister(ADXL345_DATAX1);
// Calculate AccelX using lower & upper
AccelX =
/* 이하 생략 */
}
Test
TestAdxl345()
함수는 100msec 마다 실행하도록 설정되어 있다.- 이 함수 내부에서 AccelX의 값에 따라서 LED1, LED2 의 밝기가 변화하도록 프로그래밍 되어 있다.
- 프로그램을 실행하고 ADXL345 센서를 X축 방향으로 기울여 가면서 LED1과 LED2의 변화를 관찰한다.
- 정확한 값의 변화를 확인하기 위하여 Debugger, 혹은 uC/Probe를 사용하여 AccelY와 AccelZ의 값을 살펴본다.
Optimization
- 현재 프로그램은 X, Y, Z 축의 Data를 읽어들이기 위하여 총 6회의 Single-Byte Read 싸이클을 수행해야 한다. Single-Byte Read 싸이클은 전송되는 데이터만 4byte (즉 32bit) 이상이 필요하게 된다. 그러므로 6축의 자료를 모두 읽어들이기 위해서는 24byte(약 200bit) 이상의 통신 시간이 필요하게 된다. 이를 100KHz를 기준으로 계산하면 2msec 라는 긴 시간이 필요하게 된다.
- 현재와 같이 단순한 작업을 진행하는 상황이라면 크게 문제되지 않지만, 해야하는 테스크가 늘어나거나, 신호처리의 주기가 짧아지는 상황이라면 최적화를 해야할 필요가 있다.
Multiple-Byte Read 싸이클 이용
- ADXL345의 DATAX0 ~ DATAZ1 Address는 0x32번 부터 6byte가 모두 붙어 있다. 그러므로 Multiple-Byte Read 싸이클을 이용한다면 통신 오버헤드를 줄일 수 있다. 오버헤드 3byte, 데이타 6byte 이므로 9byte(약 80 bit)의 정보를 연속적으로 읽어들일 수 있다. 이 방법을 사용하면 각각을 읽어들이는데 필요한 시간을 절반 이하로 줄일 수 있다. 그러나 이 방법도 100KHz 전송속도를 기준으로 약 1msec의 시간에 해당하므로 바람직한 방법은 아니다.
[Activity]
-
Multiple-Byte Read 방법을 사용하는 함수를 만들어 보자.
-
ADXL345_ReadRegister 참고
void ADXL345_GetXYZ_Multiple(void){
/* To Do */
}
Interrupt를 이용
- Interrupt를 사용하는 전송방식으로 프로그램을 개선한다면 이 대기 시간을 대폭적으로 줄일 수 있게 된다.
[Activity]
- Interrupt를 사용하여
ADXL345_GetXYZ(void)
Method를 새롭게 만들고, Data의 수신이 완료되면CB_MasterReceiveComplete( )
에서 AccelX, AccelY, AccelZ 값을 Update 하도록 개선해 보아라.
void CB_MasterReceiveComplete(){
}