/* BMP280_CQ_BB.c */ // Use Adafruit "BMP280 I2C or SPI Barometric Pressure & Altitude Sensor" // with all the pins broken out to standard headers and added voltage regulator and level shifting // so allow you to use it with (either 3.3V or) 5V systems such as Arduino Uno // Warning! 5V logic levels direct to the sensor will kill it (use level shifting)! // This simple program checks if the pressure sensor BMP280 is connected to the SPI bus // and answers with the chip ID 0x58 ? // Program uses BitBanging on the SPI-pins, but other pins could be used for this as well. // Note! The SPI-unit is not used at all. // Arduino UNO R3 // AVR_ATmega328P #define F_CPU 16000000UL #include // AVR register names/addresses and bit names/numbers #include // for the nop instruction #include void _delay_ms ( double ); void _delay_us ( double ); void init_uart( void ); unsigned char getchar_uart( void ); void putchar_uart( unsigned char ); void string_out_uart( char * ); // uses strings stored in RAM // Happens to use the SPI-pins, but any other pin could be redefined instead. #define CS_pin PINB2 #define CS_DDR DDRB #define CS_PIN PINB #define CS_PORT PORTB #define MOSI_pin PINB3 #define MOSI_DDR DDRB #define MOSI_PIN PINB #define MOSI_PORT PORTB #define MISO_pin PINB4 #define MISO_DDR DDRB #define MISO_PIN PINB #define MISO_PORT PORTB #define SCK_pin PINB5 #define SCK_DDR DDRB #define SCK_PIN PINB #define SCK_PORT PORTB void SPI_init_BB( void); void SPI_masterTransmitByte_BB( unsigned char data ); unsigned char SPI_masterReceive_BB(); void check_BMP280_exist_BB( void); int main(void) { SPI_init_BB(); _delay_ms(5); init_uart( ); _delay_ms(3000); // delay output - please open the serial monitor // Read the chip ID check_BMP280_exist_BB( ); while(1) { _NOP(); } } /* *********************************** */ /* FUNCTIONS */ /* *********************************** */ void SPI_init_BB() { // Mode 00 clock idle state = 0 // data is sampled on rising edge and shifted on falling edge // set CS, MOSI and SCK to output CS_DDR |= (1 << CS_pin); MOSI_DDR |= (1 << MOSI_pin); SCK_DDR |= (1 << SCK_pin); // set MISO to input MISO_DDR &= (~( 1 << MISO_pin )); CS_PORT &= (~( 1 << CS_pin )); // CS = 0 at startup for BMP280 to use SPI and not I2C _delay_ms(5); CS_PORT |= ( 1 << CS_pin ); // CS = 1 release the SPI bus // set clock state idle SCK = 0 SCK_PORT &= (~( 1 << SCK_pin )); } void SPI_masterTransmitByte_BB( unsigned char data ) { unsigned char i; for (i = 0; i < 8; i++) { // first set data bit if (data & 0x80) MOSI_PORT |= ( 1 << MOSI_pin ); // MOSI = 1 else MOSI_PORT &= (~( 1 << MOSI_pin )); // MOSI = 0 _delay_us(10); // clock idle SCK_PORT |= ( 1 << SCK_pin ); // SCK = 1 data is sampled on this edge _delay_us(10); SCK_PORT &= (~( 1 << SCK_pin )); // SCK = 0 shift on this edge data <<= 1 ; } } unsigned char SPI_masterReceive_BB() { unsigned char data = 0; unsigned char i; for (i = 0; i < 8; i++) { _delay_us(10); // clock idle SCK_PORT |= ( 1 << SCK_pin ); // SCK = 1 data is sampled on this edge if( MISO_PIN & ( 1 << MISO_pin )) data |= ( 0x80 >> i ); // read data bit _delay_us(10); SCK_PORT &= (~( 1 << SCK_pin )); // SCK = 0 data shifted on this edge } _delay_us(10); // clock idle return data; } 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 check_BMP280_exist_BB( void) { // Read the chip ID unsigned char chipID; CS_PORT &= (~( 1 << CS_pin )); // CS = 0 enable BMP280 SPI_masterTransmitByte_BB( 0xD0 ); // Chip ID register: 0xD0 (1)1010000 read chipID = SPI_masterReceive_BB(); // should return 0x60 for BMP280 chip CS_PORT |= ( 1 << CS_pin ); // CS = 1 disable BMP280, release the SPI bus if ( chipID == 0x58 ) string_out_uart( "Found BMP280 on SPI bus\r\n" ); else string_out_uart( "No one is there!\r\n" ); } /* *********************************** */ /* HARDWARE */ /* *********************************** */ /* Chip ATMega328 Arduino Uno R3 stackable header _______ Digital: _____/ \__ Analog: ______________ ______________ txd ->-|D00 >RXD A5|- | \/ | rxd -<-|D01 -(D00)-|02 PD0/RXD SDA/PC4 27|-(A4)- -|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)->- SCK CSB -<-|D10~ +3.3V|- -(D05)-|11 PD5/PWM MISO/PB4 18|-(D12)-<- SDO SDI -<-|D11~ Res|- -(D06)-|12 PD6/PWM PWM/MOSI/PB3 17|-(D11)->- SDI SDO ->-|D12 IOREF|- -(D07)-|13 PD7 PWM/SS'/PB2 16|-(D10)->- CSB SCK -<-|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 | SCK ->-| SCK | MISO -<-| SDO | MOSI ->-| SDI | SS' ->-| CSB' | |__________| BMP280 Registers (Byte size): // Control and Status registers (R/-) 0xD0/- : id Chip identification (=0x58) (-/W) -/0x60 : reset (Write data = 0xB6 to reset) (R/-) 0xF3/- : status "---measuring---updating" (R/W) 0xF4/0x74 : ctrl_meas "osrs_t2 osrs_t1 osrs_t0 osrs_p2 osrs_p1 osrs_p0 mode1 mode0" (R/W) 0xF5/0x75 : config "t_sb2 tsb_1 tsb0 filter2 filter1 filter0 - spi3w" // Temperature and Pressure values from the AD-converter (R/-) 0xF7/- : press_msb (R/-) 0xF8/- : press_lsb (R/-) 0xF9/- : press_xlsb (R/-) 0xFA/- : temp_msb (R/-) 0xFB/- : temp_lsb (R/-) 0xFC/- : temp_xlsb // Indvidual Calibration Constants stored in chip (R/-) 0x88/- : calib00, dig_T1 LSB (R/-) 0x89/- : calib01, dig_T1 MSB (R/-) 0x8A/- : calib02, dig_T2 LSB (R/-) 0x8B/- : calib03, dig_T2 MSB (R/-) 0x8C/- : calib04, dig_T3 LSB (R/-) 0x8D/- : calib05, dig_T3 MSB (R/-) 0x8E/- : calib06, dig_P1 LSB (R/-) 0x8F/- : calib07, dig_P1 MSB (R/-) 0x90/- : calib08, dig_P2 LSB (R/-) 0x91/- : calib09, dig_P2 MSB (R/-) 0x92/- : calib10, dig_P3 LSB (R/-) 0x93/- : calib11, dig_P3 MSB (R/-) 0x94/- : calib12, dig_P4 LSB (R/-) 0x95/- : calib13, dig_P4 MSB (R/-) 0x96/- : calib14, dig_P5 LSB (R/-) 0x97/- : calib15, dig_P5 MSB (R/-) 0x98/- : calib16, dig_P6 LSB (R/-) 0x99/- : calib17, dig_P6 MSB (R/-) 0x9A/- : calib18, dig_P7 LSB (R/-) 0x9B/- : calib19, dig_P7 MSB (R/-) 0x9C/- : calib20, dig_P8 LSB (R/-) 0x9D/- : calib21, dig_P8 MSB (R/-) 0x9E/- : calib22, dig_P9 LSB (R/-) 0x9F/- : calib23, dig_P9 MSB */