/* BMP280_calibration_I2C.c */ // Uses I2C unit over I2C-bus // Program retrieves the individual calibration values that are stored in the chip // Cut and paste as constants in programs that use this BMP280 sensor chip // Arduino UNO R3 // AVR_ATmega328P #define F_CPU 16000000UL #include // register names/addresses and bit names/numbers #include // for the nop instruction #include void _delay_ms ( double ); void _delay_us ( double ); /* UART function prototypes */ void init_uart( void ); unsigned char getchar_uart( void ); void putchar_uart( unsigned char ); void string_out_uart( char * ); // uses strings stored in RAM void constant_out_uart( unsigned int, unsigned char ); /* I2C function prototypes */ void I2C_Init( void ); void I2C_Start( void ); void I2C_Stop( void ); void I2C_Write( unsigned char ); unsigned char I2C_ReadACK( void ); unsigned char I2C_ReadNACK( void ); // BMP280 7-bit device address is 0x77 (with SDO = 1 default by pullup) #define BMP280_WR_ADDRESS 0xEE // 8-bit write address #define BMP280_RD_ADDRESS 0xEF // 8-bit read address // BMP280 alternative 7-bit device address is 0x76 (with SDO = 0, GND) // #define BMP280_WR_ADDRESS 0xEC // 8-bit write address // #define BMP280_RD_ADDRESS 0xED // 8-bit read address void I2C_print_stored_calibration(void); int main(void) { I2C_init(); init_uart( ); _delay_ms(3000); // delay output - please open the serial monitor I2C_print_stored_calibration(); while(1) { _NOP(); } } /* *********************************** */ /* FUNCTIONS */ /* *********************************** */ void I2C_init(void) { //set SCL frequency to < 100kHz the max freq of DS1307 // Bits in TWSR register: "TWS7 TWS6 TWS5 TWS4 TWS3 - TWPS1 TWPS0" TWSR = 0x00; // "xxxxx-00" prescaler set to divide by one // TWBR register: frequency division byte TWBR = 73; // SCLfreq = CPUfreq / (16+2*TWBR*Presc) = 16*10^6 / (16+2*73*1) = 99 kHz //enable TWI // Bits in TWCR register: "TWINT TWEA TWSTA TWSTO TWWC TWEN - TWIE" TWCR = (1 << TWEN); // "-----1--" } // send start signal void I2C_Start( void ) { // Bits in TWCR register: "TWINT TWEA TWSTA TWSTO TWWC TWEN - TWIE" TWCR = (1 << TWINT)|(1 << TWSTA)|(1 << TWEN); // "1-1--1--" while ((TWCR & (1 << TWINT)) == 0); // "?-------" wait for done } // send stop signal void I2C_Stop( void ) { // Bits in TWCR register: "TWINT TWEA TWSTA TWSTO TWWC TWEN - TWIE" TWCR = (1 << TWINT)|(1 << TWSTO)|(1 << TWEN); // "1--1-1--" } void I2C_Write( unsigned char data) { TWDR = data; // Bits in TWCR register: "TWINT TWEA TWSTA TWSTO TWWC TWEN - TWIE" TWCR = (1 << TWINT)|(1 << TWEN); // "1----1--" while ((TWCR & (1 << TWINT)) == 0); // "?-------" wait for done } // read byte with ACK, use for consecutive Bytes read unsigned char I2C_ReadACK(void) { // Bits in TWCR register: "TWINT TWEA TWSTA TWSTO TWWC TWEN - TWIE" // with ACK set TWCR = (1 << TWINT)|(1 << TWEN)|(1 << TWEA); // "11---1--" while ((TWCR & (1 << TWINT)) == 0); // "?-------" wait for done return TWDR; } // read byte with NACK, use with last Byte read unsigned char I2C_ReadNACK( void ) { // Bits in TWCR register: "TWINT TWEA TWSTA TWSTO TWWC TWEN - TWIE" // no acknowledge bit set, NOT ACK TWCR = (1 << TWINT)|(1 << TWEN); // "1----1--" while ((TWCR & (1 << TWINT)) == 0); // "?-------" wait for done return TWDR; } void init_uart( void ) { // Bits in UCSR0B register: "RXCIE0 TXCIE0 UDRIE0 RXEN0 TXEN0 UCSZ02 RXB80 TXB80" UCSR0B |= (1<<(RXEN0)) | (1<<(TXEN0)); // "----1---" // Bits in UCSR0C register: "UMSEL01 UMSEL00 UPM01 UPM00 USBS0 UCSZ01/UCPHA0 UCSZ01/UCPHA0 UCPOL0" UCSR0C |= (1<<(UCSZ01)) | (1<<(UCSZ00)); // "-----11-" UBRR0 = 103; // Baud prescaler 103 -> 9600 Baud } void putchar_uart( unsigned char ch ) { // Bits in UCSR0A register: "RXC0 TXC0 UDRE0 FE0 DOR0 UPE0 U2X0 MPCM0" // wait until the port is ready to be written to while( ( UCSR0A & ( 1<<(UDRE0) ) ) == 0 ){} // write the byte to the serial port UDR0 = ch; } void string_out_uart( char * string ) // use for strings in RAM { while (* string != '\0') putchar_uart(*string ++ ); } void constant_out_uart(unsigned int dig_ , unsigned char signum) { unsigned int divisor = 10000; unsigned char i; unsigned char s[10]; if ( signum == 1 ) // should be treated as signed number { if ( (signed int)dig_ < 0 ) { dig_ = - dig_ ; putchar_uart( '-' );} } for ( i=0; i<5; i++ ) // populate array with 5 decimal digits { s[i]= (unsigned char)(dig_ /divisor) + '0'; dig_ %= divisor; divisor /= 10; } // find the leading zeros to skip i = 0; while ( s[i] == '0' ) i++ ; // print decimal integer for(i; i<5; i++) putchar_uart(s[i]); } void I2C_print_stored_calibration(void) { // Burst read from the 24 registers with the stored calibration data // to print out the 12 calibration constants // (could then be copied and pasted to future program code with same chip sample) signed int dig_ ; // dig_T1 I2C_Start(); I2C_Write( BMP280_WR_ADDRESS ); // BMP280 write address I2C_Write( 0x88 ); // dummy write "calib00 register" to set address pointer I2C_Start(); // repeat start I2C_Write( BMP280_RD_ADDRESS ); // BMP280 read address dig_ = (unsigned int)I2C_ReadACK(); // LSB dig_ += ( ( (unsigned int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const unsigned int dig_T1 = "); constant_out_uart( dig_ , 0 ); string_out_uart(";\r\n"); // dig_T2 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_T2 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_T3 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_T3 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_P1 dig_ = (unsigned int)I2C_ReadACK(); // LSB dig_ += ( ( (unsigned int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const unsigned int dig_P1 = "); constant_out_uart( dig_ , 0 ); string_out_uart(";\r\n"); // dig_P2 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_P2 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_P3 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_P3 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_P4 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_P4 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_P5 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_P5 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_P6 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_P6 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_P7 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_P7 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_P8 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadACK() )<<8 ); // MSB string_out_uart("const signed int dig_P8 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); // dig_P9 dig_ = (signed int)I2C_ReadACK(); // LSB dig_ += ( ( (signed int)I2C_ReadNACK() )<<8 ); // MSB last byte to read (NACK) string_out_uart("const signed int dig_P9 = "); constant_out_uart( dig_ , 1 ); string_out_uart(";\r\n"); I2C_Stop(); } /* *********************************** */ /* HARDWARE */ /* *********************************** */ /* Chip ATMega328 Arduino Uno R3 stackable header _______ Digital: _____/ \__ Analog: ______________ ______________ txd ->-|D00 >RXD A5|->-- SCK | \/ | rxd -<-|D01 - SDI Res---|01 PC6/RES' ATM328 SCL/PC5 28|-(A5)->-- SCK -|D02 A3|- txd ->-(D00)-|02 PD0/RXD SDA/PC4 27|-(A4)-<>- SDI -|D03~ A2|- rxd -<-(D01)-|03 PD1/TXD PC3 26|-(A3)- -|D04 A1|- -(D02)-|04 PD2/INT0 PC2 25|-(A2)- -|D05~ A0|- -(D03)-|05 PD3/INT1/PWM PC1 24|-(A1)- -|D06~ | Power: -(D04)-|06 PD4 PC0 23|-(A0)- -|D07 Vin|- +5V ---|07 VCC GND 22|--- Gnd | GND|--- GND Gnd ---|08 GND AREF 21|--- Vin -|D08 GND|- Xtal |X|--|09 PB6/OSC1 AVCC 20|--- +5V -|D09~ +5V|--- +5V 16MHz |X|--|10 PB7/OSC2 SCK/PB5 19|-(D13)- -|D10~ +3.3V|- -(D05)-|11 PD5/PWM MISO/PB4 18|-(D12)- -|D11~ Res|- -(D06)-|12 PD6/PWM PWM/MOSI/PB3 17|-(D11)- -|D12 IOREF|- -(D07)-|13 PD7 PWM/SS'/PB2 16|-(D10)- -|D13 LED --- | -(D08)-|14 PB0 PWM/PB1 15|-(D09)- -|GND | |______________________________| -|AREF | -|SCL | -|SDA | |________________| */ /* Bosch Barometer chip Adafruit BMP280 with 5/3 V level translators included __________ | BMP280 | | | +5V ---| 5V | -| 3V3 | GND --| GND | SCL -->-| SCK | -| SDO | SDA -<>-| SDI | -| CSB' | |__________| BMP280 Registers (Byte size): // Control and Status registers 0xD0 : id Chip identification (=0x58) 0xE0 : reset (Write data = 0xB6 to reset) 0xF3 : status "---measuring---updating" 0xF4 : ctrl_meas "osrs_t2 osrs_t1 osrs_t0 osrs_p2 osrs_p1 osrs_p0 mode1 mode0" 0xF5 : config "t_sb2 tsb_1 tsb0 filter2 filter1 filter0 - spi3w" // Temperature and Pressure values from the AD-converter 0xF7 : press_msb 0xF8 : press_lsb 0xF9 : press_xlsb 0xFA : temp_msb 0xFB : temp_lsb 0xFC : temp_xlsb // Indvidual Calibration Constants stored in chip 0x88 : calib00, dig_T1 LSB 0x89 : calib01, dig_T1 MSB 0x8A : calib02, dig_T2 LSB 0x8B : calib03, dig_T2 MSB 0x8C : calib04, dig_T3 LSB 0x8D : calib05, dig_T3 MSB 0x8E : calib06, dig_P1 LSB 0x8F : calib07, dig_P1 MSB 0x90 : calib08, dig_P2 LSB 0x91 : calib09, dig_P2 MSB 0x92 : calib10, dig_P3 LSB 0x93 : calib11, dig_P3 MSB 0x94 : calib12, dig_P4 LSB 0x95 : calib13, dig_P4 MSB 0x96 : calib14, dig_P5 LSB 0x97 : calib15, dig_P5 MSB 0x98 : calib16, dig_P6 LSB 0x99 : calib17, dig_P6 MSB 0x9A : calib18, dig_P7 LSB 0x9B : calib19, dig_P7 MSB 0x9C : calib20, dig_P8 LSB 0x9D : calib21, dig_P8 MSB 0x9E : calib22, dig_P9 LSB 0x9F : calib23, dig_P9 MSB */