diff --git a/Makefile b/Makefile index 8fabffa..0a0b035 100644 --- a/Makefile +++ b/Makefile @@ -78,6 +78,11 @@ distclean: clean $(E) "[REM] $(BINDIR)" $(Q) $(RMR) $(BINDIR) +.PHONY: listen +listen: ./opt/tools/serial-listen.py + $(E) "[PY3] $<" + $(Q) ./$< + $(TMPDIRS): $(E) "[DIR] $@" $(Q) $(MKDIR) $@ diff --git a/docs/AHT20.pdf b/docs/AHT20.pdf index 166796f..382da12 100755 Binary files a/docs/AHT20.pdf and b/docs/AHT20.pdf differ diff --git a/src/bus/twi.c b/src/bus/twi.c index fb94790..910b738 100644 --- a/src/bus/twi.c +++ b/src/bus/twi.c @@ -77,6 +77,35 @@ int TWI_Write(unsigned char data) return 0; } +unsigned char TWI_Read_ACK(void) +{ + // Read data and acknowledge + + TWCR = (1 << TWEN) // Enable TWI + | (1 << TWINT) // Clear interrupt flag + | (1 << TWEA); // Send acknowledgment + + // Wait until data read + + while ((TWCR & (1 << TWINT)) == 0); + + return TWDR; +} + +unsigned char TWI_Read_NACK(void) +{ + // Read data, expect last byte + + TWCR = (1 << TWEN) // Enable TWI + | (1 << TWINT); // Clear interrupt flag + + // Wait until data read + + while ((TWCR & (1 << TWINT)) == 0); + + return TWDR; +} + int TWI_Wait_ACK(void) { unsigned int status; diff --git a/src/bus/twi.h b/src/bus/twi.h index a43a44b..c20ca9a 100644 --- a/src/bus/twi.h +++ b/src/bus/twi.h @@ -10,6 +10,8 @@ int TWI_Init(void); int TWI_Start(unsigned char addr, unsigned char mode); int TWI_SetChannel(int channel); int TWI_Write(unsigned char data); +unsigned char TWI_Read_ACK(void); +unsigned char TWI_Read_NACK(void); int TWI_Wait_ACK(void); int TWI_Stop(void); diff --git a/src/main.c b/src/main.c index 8d6ffb5..9689d00 100644 --- a/src/main.c +++ b/src/main.c @@ -6,6 +6,136 @@ #include +short TWI_ReadAHT20(void) +{ + unsigned char data, crc; + + // After the transmission is initiated, the first + // byte of the subsequent I2C transmission includes + // the 7-bit I2C device address 0x38 and a SDA + // direction bit. + + // Soft reset device. + + TWI_Start(0x38, 0); + TWI_Write(0xBA); + TWI_Wait_ACK(); + TWI_Stop(); + + // Wait 40ms after power-on. + + Sleep(40); + + // Before reading the temperature and humidity + // values, first check whether the calibration + // enable bit Bit [3] of the status word is 1 (you + // can get a byte of status word by sending 0x71). + + TWI_Start(0x38, 0); + TWI_Write(0x71); + TWI_Wait_ACK(); + + data = TWI_Read_NACK(); + TWI_Stop(); + + Info("Received calibration status %02X.", data); + + // If not 1, need to send 0xBE command (for + // initialization), this command parameter has two + // bytes, the first byte is 0x08, the second byte + // is 0x00, and then wait for 10ms. + + if (data & ~BIT(3)) { + Info("Requesting calibration..."); + + TWI_Start(0x38, 0); + TWI_Write(0xBE); + TWI_Wait_ACK(); + TWI_Write(0x08); + TWI_Wait_ACK(); + TWI_Write(0x00); + TWI_Wait_ACK(); + + Sleep(10); + data = TWI_Read_NACK(); + TWI_Stop(); + + if (data & ~BIT(3)) { + Info("Error: Calibration failed."); + return -1; + } + } + + // Send the 0xAC command directly (trigger + // measurement). The parameter of this command has + // two bytes, the first byte is 0x33 and the second + // byte is 0x00. + + Info("Triggering measurement..."); + + TWI_Start(0x38, 0); + TWI_Wait_ACK(); + TWI_Write(0xAC); + TWI_Wait_ACK(); + TWI_Write(0x33); + TWI_Wait_ACK(); + TWI_Write(0x00); + TWI_Wait_ACK(); + TWI_Stop(); + + // Wait for 80ms to wait for the measurement to be + // completed. If the read status word Bit [7] is 0, + // it indicates that the measurement is completed, + // and six bytes can be read in a row. Otherwise + // continue to wait. + + Info("Reading measurement..."); + + TWI_Start(0x38, 1); // Read + TWI_Wait_ACK(); + + do { + Sleep(80); + data = TWI_Read_ACK(); + } while (data & BIT(7)); + + data = TWI_Read_ACK(); + Info("Received data byte %02X.", data); + data = TWI_Read_ACK(); + Info("Received data byte %02X.", data); + data = TWI_Read_ACK(); + Info("Received data byte %02X.", data); + data = TWI_Read_ACK(); + Info("Received data byte %02X.", data); + data = TWI_Read_ACK(); + Info("Received data byte %02X.", data); + data = TWI_Read_ACK(); + Info("Received data byte %02X.", data); + + // After receiving six bytes, the next byte is the + // CRC check data, the user can read it as needed, + // if the receiving end needs CRC check, then send + // it after receiving the sixth byte ACK response, + // otherwise NACK is sent out, CRC initial value is + // 0xFF. The CRC8 check polynomial is: + // CRC[7:0]= 1 + (x^4) + (x^5) + (x^8) + + crc = TWI_Read_NACK(); + Info("Received CRC8 byte %02X.", crc); + + // Calculate the temperature and humidity values. + // Note: The calibration status check in the first + // step only needs to be checked at power-on. No + // operation is required during the normal + // acquisition process. + + // TODO: Calculate values + + TWI_Stop(); + + return 0; +} + int main(void) { USART_Init(); @@ -27,7 +157,14 @@ int main(void) // TODO: Set FAN03 timer frequency // TODO: Implement ADS1115 and AHT20 + // TEM01, TEM02, TEM03 + // HUM01, HUM02, HUM03 + + // TWI_GetValue(TEM03) + // TWI_GetValue(HUM03) + TWI_SetChannel(AHT01); // I2C Mux + TWI_ReadAHT20(); // TEMP and RH Info("Running idle loop...");