gwdeveloper 275 Posted June 6, 2011 Share Posted June 6, 2011 Hey guys, I managed to get the BMP085 running on the new MSP-EXP430F5529 dev board. Still putting the final touches on the application but it will initially be a basic weather station. Getting the BMP085 was one of the tougher parts of the programming. The display is showing temperature, pressure and time. Eventually, it will look like a weather station plot like http://www.srh.noaa.gov/jetstream/synoptic/wxmaps.htm Since the USCI was used, I'm pretty sure that all of this code, with minor modifications, would run on a MSP430G2553. I may attempt that later on today but the RC truck is screaming for attention (and it's in a thousand pieces on the dining table). Begin BMP085.c /****************************************************************/ /* Greg Whitmore */ /* greg@gwdeveloper.net */ /* gwdevprojects.blogspot.com */ /****************************************************************/ /* released under the "Use at your own risk" license */ /* use it how you want, where you want and have fun */ /* debugging the code. */ /* MSP-EXP430F5529 */ /****************************************************************/ // currently this is only configured for OSS = 0 // future changes will allow for extended oversampling // standard includes #include #include #include "itoa.h" // driver includes #include "HAL_Board.h" #include "HAL_Buttons.h" #include "HAL_Dogs102x6.h" #include "HAL_Menu.h" #include "HAL_MACROS.h" #include "clock.h" #include "bmp085.h" #include "iic.h" extern char time[9]; extern char date[9]; extern unsigned char *PTxData; // Pointer to TX data extern unsigned char TXByteCtr; extern unsigned char *PRxData; // Pointer to RX data extern unsigned char RXByteCtr; extern volatile unsigned char RxBuffer[3]; // Allocate 3 bytes of RAM, it's all we need here // types based from API // if initialize more than 1 var per line, the calculations are off // cal data int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; // true temp long ut; long x1; long x2; long b5; int bmp_temp = 0; //true pressure long up; long x3; long b3; unsigned long b4; long b6; unsigned long b7; long p; long bmp_pres = 0; // tx constants const unsigned char utTxData[] = { BMP085_CTRL_REG, BMP085_TEMP_REG }; // uncomp temp reg const unsigned char upTxData[] = { BMP085_CTRL_REG, BMP085_PRESSURE_REG }; // oss =0 see bmp085.h const unsigned char msbData[] = { BMP085_MSB_REG }; // read calibration data from prom - optimize? load all 22 bytes 1 shot? void bmp085_cal(void){ Dogs102x6_clearScreen(); Dogs102x6_stringDrawXY(4, 0, "Loading", DOGS102x6_DRAW_NORMAL); Dogs102x6_stringDrawXY(8, 10, "Calibration", DOGS102x6_DRAW_NORMAL); // store PROM data into usable variables ac1 = sendByte_getBytes(BMP085_ADDR, 0xAA, 2); __delay_cycles(1000); ac2 = sendByte_getBytes(BMP085_ADDR, 0xAC, 2); __delay_cycles(1000); ac3 = sendByte_getBytes(BMP085_ADDR, 0xAE, 2); __delay_cycles(1000); ac4 = sendByte_getBytes(BMP085_ADDR, 0xB0, 2); __delay_cycles(1000); ac5 = sendByte_getBytes(BMP085_ADDR, 0xB2, 2); __delay_cycles(1000); ac6 = sendByte_getBytes(BMP085_ADDR, 0xB4, 2); __delay_cycles(1000); b1 = sendByte_getBytes(BMP085_ADDR, 0xB6, 2); __delay_cycles(1000); b2 = sendByte_getBytes(BMP085_ADDR, 0xB8, 2); __delay_cycles(1000); mb = sendByte_getBytes(BMP085_ADDR, 0xBA, 2); __delay_cycles(1000); mc = sendByte_getBytes(BMP085_ADDR, 0xBC, 2); __delay_cycles(1000); md = sendByte_getBytes(BMP085_ADDR, 0xBE, 2); __delay_cycles(1000); // write to flash here and only run on intitial puc - not implemented yet Dogs102x6_clearScreen(); } // read uncompensated temperature and return msb & lsb unsigned int bmp085_ut(void){ iic_tx_init(BMP085_ADDR); __delay_cycles(1000); PTxData = (unsigned char *)utTxData; // send control reg and temp reg TXByteCtr = 2; // Load TX byte counter start_TX(); __delay_cycles(112505); // ? ~4.5ms at 25mhz ? 25001 * 4.5 // function returns ints return (sendByte_getBytes(BMP085_ADDR, BMP085_MSB_REG, 2)); } // read uncompensated pressure and return msb, lsb & xlsb unsigned long bmp085_up(void){ iic_tx_init(BMP085_ADDR); __delay_cycles(1000); PTxData = (unsigned char *)upTxData; // send control reg and temp reg TXByteCtr = 2; // Load TX byte counter start_TX(); __delay_cycles(112505); // ? ~4.5ms at 25mhz ? 25001 * 4.5 PTxData = (unsigned char *)msbData; // send msb read register TXByteCtr = 1; start_TX(); iic_rx_init(); // set RX interrupt __delay_cycles(1000); PRxData = (unsigned char *)RxBuffer; // rx buffer RXByteCtr = 3; // number of bytes to receive start_RX(); // returning longs instead of ints to allow 2^16 shifts return ( (( (long)RxBuffer[0] << 16) | ( (long)RxBuffer[1] << 8) | (long)RxBuffer[2]) >> 8); } void get_bmp085(){ unsigned char temp_buffer[8]; unsigned char pres_buffer[8]; bmp085_cal(); Dogs102x6_clearScreen(); Dogs102x6_stringDraw(0, 1, "GWDev BMP085", NORMAL); // header Dogs102x6_circleDraw(50, 34, 8, NORMAL); // circle for weather symbol while (!(buttonsPressed & BUTTON_S2)){ DigitalClockUpdate(); Dogs102x6_stringDraw(7, 0, &time[HOUR10], NORMAL); // clock here for demo ut = bmp085_ut(); up = bmp085_up(); // calc true temp x1 = ((long)ut - ac6) * ac5 >> 15; x2 = ((long)mc << 11) / (x1 + md); b5 = x1 + x2; bmp_temp = (b5 + 8) >> 4; // itoa function added itoa(bmp_temp, (char*)temp_buffer); // move integer into char buffer Dogs102x6_stringDraw(2, 24, (char*)temp_buffer, NORMAL); // display temperature on weather symbol // // calc true pressure b6 = b5 - 4000; x1 = (b2 * (b6 * b6) >> 12) >> 11; x2 = (ac2 * b6) >> 11; x3 = x1 + x2; b3 = ((long)ac1 * 4 + x3 + 2) >> 2; // ???? so many 'corrections' on the web this one works though x1 = ac3 * b6 >> 13; x2 = (b1 * ((b6 * b6) >> 12)) >> 16; x3 = ((x1 + x2) + 2) >> 2; b4 = (ac4 * (unsigned long)(x3 + 32768)) >> 15; b7 = ((unsigned long)up - b3) * 50000; //p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2; // ???? noobness - unsure of the formatting, below works // or if (b7 < 0x80000000) { p = (b7 * 2) / b4;} else {p = (b7 / b4) *2;} // x1 = (p >> 8) * (p >> 8); x1 = (x1 * 3038) >> 16; x2 = (-7357 * p) >> 16; bmp_pres = p + ((x1 + x2 + 3791) >> 4); // ltoa, part of stdlib.h ltoa(bmp_pres, (char*)pres_buffer); // move long integer into char buffer Dogs102x6_stringDraw(2, 60, (char*)pres_buffer, NORMAL); // display pressure on weather symbol // __delay_cycles(500000); } } Begin BMP085.h /****************************************************************/ /* Greg Whitmore */ /* greg@gwdeveloper.net */ /* gwdevprojects.blogspot.com */ /****************************************************************/ /* released under the "Use at your own risk" license */ /* use it how you want, where you want and have fun */ /* debugging the code. */ /* MSP-EXP430F5529 */ /****************************************************************/ #ifndef BMP085_H_ #define BMP085_H_ /* BMP085 Register Definitions */ #define BMP085_ADDR 0x77 #define BMP085_CTRL_REG 0xF4 #define BMP085_TEMP_REG 0x2E #define BMP085_PRESSURE_REG 0x34 // oss =0 #define BMP085_PRESSURE_REG_OSS1 0x74 // oss =1, longer delays needed 7.5ms #define BMP085_PRESSURE_REG_OSS2 0xB4 // oss =2, 13.5ms #define BMP085_PRESSURE_REG_OSS3 0xF4 // oss =3, 25.5ms #define BMP085_MSB_REG 0xF6 #define BMP085_LSB_REG 0xF7 #define BMP085_CONV_REG_XLSB 0xF8 // prototypes void bmp085_cal(void); unsigned int bmp085_ut(void); unsigned long bmp085_up(void); void get_bmp085(void); #endif /*BMP085_H_*/ Begin iic.c /****************************************************************/ /* Greg Whitmore */ /* greg@gwdeveloper.net */ /* gwdevprojects.blogspot.com */ /****************************************************************/ /* released under the "Use at your own risk" license */ /* use it how you want, where you want and have fun */ /* debugging the code. */ /* MSP-EXP430F5529 */ /****************************************************************/ #include #include "HAL_Board.h" #include "HAL_Buttons.h" #include "HAL_Dogs102x6.h" #include "bmp085.h" #include "iic.h" unsigned char *PTxData; // Pointer to TX data unsigned char TXByteCtr; unsigned char *PRxData; // Pointer to RX data unsigned char RXByteCtr; volatile unsigned char RxBuffer[3]; // Allocate 3 byte of RAM /* ignore remapping for now, iic needs to be moved from UCB0 to UCB1 const uint8_t iic_remap[] = { PM_UCB1SDA, PM_UCB1SCL, }; */ /* ignore this remap for now * * void remap_iic() { PMAPPWD = 0x02D52; PMAPCTL |= PMAPRECFG; P4MAP6 = PM_UCB1SDA; P4MAP7 = PM_UCB1SCL; P4SEL = BIT6+BIT7; UCB1CTL1 |= UCSWRST; // Enable SW reset UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB1CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB1BR0 = 12; // fSCL = SMCLK/12 = ~100kHz UCB1BR1 = 0; UCB1I2COA = 0x01; UCB1I2CSA = 0x48; // Slave Address is 048h UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation UCB1IE |= UCTXIE; // Enable TX interrupt } * */ // initialize iic void iic_init(void){ P3SEL |= 0x03; // Assign I2C pins to USCI_B0 UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = 0; // "fSCL = SMCLK/12 = ~100kHz" ----supposedly, UCB0BR1 = 0; // but any values for UCB0BR cause system to run funny UCB0I2COA = 0x43; // set own address UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation } void iic_tx_init(unsigned char slave_reg){ UCB0I2CSA = slave_reg; UCB0IE |= UCTXIE; // Enable TX interrupt } void iic_rx_init(void){ UCB0IE |= UCRXIE; // enable RX interrupt } // send 1 byte, return 2 bytes - needs the return expanded for X bytes int sendByte_getBytes(unsigned char slave_addr, unsigned char reg_2_read, int bytes_to_rx){ // transmit slave address and register to read iic_tx_init(slave_addr); __delay_cycles(1000); PTxData = (unsigned char *)®_2_read; // TX array start address TXByteCtr = sizeof reg_2_read; // Load TX byte counter start_TX(); // // receive requested bytes iic_rx_init(); // set RX interrupt __delay_cycles(1000); PRxData = (unsigned char *)RxBuffer; // rx buffer RXByteCtr = bytes_to_rx; // number of bytes to receive start_RX(); // return ((int)RxBuffer[0] << 8) | (int)RxBuffer[1]; // currently only returning 2 bytes } // start transmitting void start_TX(void){ UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition __bis_SR_register(LPM0_bits + GIE); // Enter LPM0, enable interrupts __no_operation(); // Remain in LPM0 until all data // is TX'd while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent } // restart and receive void start_RX(void){ while (UCB0CTL1 & UCTXSTP); // wait for stop UCB0CTL1 &= ~UCTR; // restart, set as receiver UCB0CTL1 |= UCTXSTT; // start condition __bis_SR_register(LPM0_bits + GIE); while (UCB0CTL1 & UCTXSTP); } // initial isr code combined from TI I2C examples for MSP430F5529 // ucsi BO isr states #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) { switch(__even_in_range(UCB0IV,12)) { case 0: break; // Vector 0: No interrupts case 2: break; // Vector 2: ALIFG case 4: // Vector 4: NACKIFG break; case 6: // Vector 6: STTIFG UCB0IFG &= ~UCSTTIFG; // Clear start condition int flag break; case 8: // Vector 8: STPIFG UCB0IFG &= ~UCSTPIFG; // Clear stop condition int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 if data was transmitted break; case 10: // Vector 10: RXIFG RXByteCtr--; // Decrement RX byte counter if (RXByteCtr) { *PRxData++ = UCB0RXBUF; // Move RX data to address PRxData if (RXByteCtr == 1) // Only one byte left? UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition } else { *PRxData = UCB0RXBUF; // Move final RX data to PRxData __bic_SR_register_on_exit(LPM0_bits); // Exit active CPU } break; case 12: // Vector 12: TXIFG if (TXByteCtr) // Check TX byte counter { UCB0TXBUF = *PTxData++; // Load TX buffer TXByteCtr--; // Decrement TX byte counter } else { UCB0CTL1 |= UCTXSTP; // I2C stop condition UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } default: break; } } Begin iic.h /****************************************************************/ /* Greg Whitmore */ /* greg@gwdeveloper.net */ /* gwdevprojects.blogspot.com */ /****************************************************************/ /* released under the "Use at your own risk" license */ /* use it how you want, where you want and have fun */ /* debugging the code. */ /* MSP-EXP430F5529 */ /****************************************************************/ #ifndef IIC_H_ #define IIC_H_ void remap_iic(void); void iic_init(void); void iic_tx_init(unsigned char slave_reg); void start_TX(void); void iic_rx_init(void); void start_RX(void); int sendByte_getBytes(unsigned char slave_addr, unsigned char reg_2_read, int bytes_to_rx); #endif /*IIC_H_*/ bluehash, RobG, GeekDoc and 1 other 4 Quote Link to post Share on other sites
bluehash 1,581 Posted June 7, 2011 Share Posted June 7, 2011 Today I learned how to read a weather station plot. Is this for your green house? Quote Link to post Share on other sites
gwdeveloper 275 Posted June 7, 2011 Author Share Posted June 7, 2011 Yeah, it sure is. Getting the barometric pressure was a big step. Temperature and humidity sensors, based on RF2500t, will be placed at various points in the gardens (we grow a lot... http://www.roundrockfunnyfarm.com) as well as in the greenhouse. The data will be used to calculate EvapoTranspiration using the Penman equation http://en.wikipedia.org/wiki/Penman_equation. There are a few companies that are making a killing on selling the evapotranspiration data which Texas A&M actually provides for free. Very few irrigation controllers calculate onsite ET and those that do have limited hardware features and are ridiculously expensive. Hopefully I can find a way to purchase CCS pretty soon at a discount. My whole program is about to roll over the 16k limit. Although, the user experience for the msp-exp430f5529 does include a full driver library that can be used without topping the limit. bluehash 1 Quote Link to post Share on other sites
atiom 0 Posted December 16, 2013 Share Posted December 16, 2013 Hello. I have a very noob question, but would really apreciate any help. I see that the BMP085 project shown above is composed of 4 files and that they have diferent fomat files, like .c and .h. What's the diference between this formats and how do I put all the files to work together in one project? And also what's the point in making all of these files insted of only one? Thanks! Quote Link to post Share on other sites
bluehash 1,581 Posted December 16, 2013 Share Posted December 16, 2013 @@atiom Looks like you are new to programming. Have you looked into Energia for programming? The .c is a source file and the .h is a header file. If you have code composer studio, you can add this file in a project you created(which is setup for a specific chip - MSP430G2553). Once the files are in, you compile it and then download to the chip. Quote Link to post Share on other sites
atiom 0 Posted December 22, 2013 Share Posted December 22, 2013 Thanks for your help bluehash. I have another questions regarding the BMP180. When I want to read the pressure value (16 bits), after the restart condition, I have to send only the MSB address, or the MSB and the LSB also? The datasheet is not clear about it. I`m facing some issues, the code posted here is not working for me. Quote Link to post Share on other sites
gwdeveloper 275 Posted December 23, 2013 Author Share Posted December 23, 2013 @@atiom you should be sending the control register and the MSB of the register you want to read: Pressure or Temperature. See functions bmp085_up() and bmp085_ut(). See the flowchart on page 15 of the datasheet. It steps you through exactly what should happen and what data you are sending to specific registers. What issues are you having with the code? Quote Link to post Share on other sites
atiom 0 Posted December 23, 2013 Share Posted December 23, 2013 Hi gwdeveloper. The problem I have here is that I always get the same value for the pressure value. For the purpose of detecting differences in pressure reading, I'm changing the frequency of a LED. But no matter how high or down I get, around 3 or 4 meters of difference from first reading, the frequency never changes, indicating the current pressure value is the same as the first reading, which is obviously wrong.I mostly worked on your code. I'll be posting it here, and it would be nice if you could take a quick look at it and see if there is anything wrong. #include <msp430.h> #include <stdlib.h> //BMP085 DEFINES #define BMP180_ADDR 0x77 #define BMP180_CTRL_REG 0xF4 #define BMP180_TEMPERATURE_REG 0x2E #define BMP180_PRESSURE_REG 0x34 //oss = 0 //#define BMP180_PRESSURE_REG_OSS1 0x74 //oss = 1, LONGER DELAY NEEDED 7.5ms //#define BMP180_PRESSURE_REG_OSS2 0xB4 //oss = 2, LONGER DELAY NEEDED 13.5ms //#define BMP180_PRESSURE_REG_OSS3 0xF4 //oss = 3, LONGER DELAY NEEDED 25.5ms #define BMP180_MSB_REG 0xF6 #define BMP180_LSB_REG 0xF7 #define BMP180_CONV_REG_XLSB 0xF8 //BMP085 FUNCTIONS void bmp180_calibration(void); unsigned int bmp180_ut(void); unsigned long bmp180_up(void); void get_bmp180(void); //I2C FUNCTIONS void i2c_tx_init(void); void i2c_rx_init(void); void start_TX(void); void start_RX(void); int sendByte_getBytes(unsigned char reg_to_read, int bytes_to_rx); //VARIABLES int i = 1; int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; //TRUE PRESSURE AND TEMPERATURE long ut; long x1; long x2; long b5; int bmp_temp = 0; long up; long x3; long b3; unsigned long b4; long b6; unsigned long b7; long p; volatile long bmp_pres = 0; //TIMER_B VARIABLES long first_pres = 0; int k = 1; //TX CONSTANTS const unsigned char utTxData[] = { BMP180_CTRL_REG, BMP180_TEMPERATURE_REG }; //UNCONPENSATED TEMPERATURE REGISTER const unsigned char upTxData[] = { BMP180_CTRL_REG, BMP180_PRESSURE_REG }; //UNCOMPENSATED PRESSURE REGISTER const unsigned char msbData[] = { BMP180_MSB_REG }; //I2C VARIABLES unsigned char *PTxData; //POINTER TO TX DATA volatile unsigned int TXByteCtr = 0; unsigned char *PRxData; //POINTER TO RX DATA volatile unsigned int RXByteCtr = 0; volatile unsigned char RxBuffer[3]; //ALLOCATE 3 BYTES OF RAM void main(void) { WDTCTL = WDTPW + WDTHOLD; //STOP WDT P3SEL |= 0x03; //ASSIGN I2C PINS TO USCI_B0 UCB0CTL1 |= UCSWRST; //ENABLE SW RESET UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; //I2C MASTER, SYNCHRONOUS MODE UCB0CTL1 = UCSSEL_2 + UCSWRST; //USE SMCLK, KEEP SW RESET UCB0BR0 = 0; //FSCL = SMCLK/12 =~ 100kHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; //CLEAR SW RESET, RESUME OPERATION P1DIR |= 0x01; P1OUT &= ~0x01; P6DIR |= 0x04; P6OUT &= ~0x04; P4DIR |= 0x80; //P4.7 OUTPUT PRESSURE DELTA TBCCTL0 = CCIE; //CCR0 INTERRUPT ENABLED __delay_cycles(100000); //AT LEAST 10ms (100ms) BEFORE FIRST COMUNICATION bmp180_calibration(); //LOAD CALIBRATION DATA get_bmp180(); //LOOP TO COLLECT TEMPERATURE AND PRESSURE } //STORE E2PROM DATA INTO USABLE VARIABLES void bmp180_calibration(void) { ac1 = sendByte_getBytes(0xAA, 2); //MSB ADRESS=0xAA, LSB ADRESS=AB, "EACH WORLD READ IS 16 BITS" WIDE (2 BYTES) __delay_cycles(1000); ac2 = sendByte_getBytes(0xAC, 2); __delay_cycles(1000); ac3 = sendByte_getBytes(0xAE, 2); __delay_cycles(1000); ac4 = sendByte_getBytes(0xB0, 2); __delay_cycles(1000); ac5 = sendByte_getBytes(0xB2, 2); __delay_cycles(1000); ac6 = sendByte_getBytes(0xB4, 2); __delay_cycles(1000); b1 = sendByte_getBytes(0xB6, 2); __delay_cycles(1000); b2 = sendByte_getBytes(0xB8, 2); __delay_cycles(1000); mb = sendByte_getBytes(0xBA, 2); __delay_cycles(1000); mc = sendByte_getBytes(0xBC, 2); __delay_cycles(1000); md = sendByte_getBytes(0xBE, 2); __delay_cycles(10000); } // READ UNCOMPENSATED TEMPERATURE AND RETURN MSB AND LSB unsigned int bmp180_ut(void) { i = 1; i2c_tx_init(); __delay_cycles(1000); PTxData = (unsigned char *)utTxData; //SEND CONTROL REGISTER AND TEMPERATURE REGISTER TXByteCtr = 2; //LOAD TX BYTE COUNTER start_TX(); __delay_cycles(200000); //LONG DELAY HERE WAITING FOR CONVERSION TO COMPLETE return (sendByte_getBytes(BMP180_MSB_REG, 2)); } //READ UNCOMPENSATED PRESSURE AND RETURN MSB, LSB AND XLSB unsigned long bmp180_up(void) { i = 1; i2c_tx_init(); __delay_cycles(1000); PTxData = (unsigned char *)upTxData; //SEND CONTROL REGISTER ADRESS AND PRESSURE REGISTER VALUE TXByteCtr = 2; //LOAD TX BYTE COUNTER start_TX(); __delay_cycles(200000); //LONG DELAY HERE WAITING FOR CONVERSION TO COMPLETE PTxData = (unsigned char *)msbData; //SEND MSB READ REGISTER TXByteCtr = 1; i = 0; start_TX(); i2c_rx_init(); __delay_cycles(1000); PRxData = (unsigned char *)RxBuffer; //RX BUFFER RXByteCtr = 3; //NUMBER OF BYTES TO RECIEVE start_RX(); return ( (( (long)RxBuffer[0] << 16) | ( (long)RxBuffer[1] << 8) | (long)RxBuffer[2]) >> 8); } //COLLECT UNCOMPESATED TEMPERATURE AND PRESSURE, CALCULATE COMPENSATED TEMPERATURE AND PRESSURE void get_bmp180() { while (1){ ut = bmp180_ut(); up = bmp180_up(); //CALCULATE TRUE TEMPERATURE x1 = ((long)ut - ac6) * ac5 >> 15; x2 = ((long)mc << 11) / (x1 + md); b5 = x1 + x2; bmp_temp = (b5 + 8) >> 4; //FINAL TEMPERATURE //CALCULATE TRUE PRESSURE b6 = b5 - 4000; x1 = (b2 * (b6 * b6) >> 12) >> 11; x2 = (ac2 * b6) >> 11; x3 = x1 + x2; b3 = ((long)ac1 * 4 + x3 + 2) >> 2; //LOTS OF "CORRECTIONS" ON THE WEB x1 = ac3 * b6 >> 13; x2 = (b1 * ((b6 * b6) >> 12)) >> 16; x3 = ((x1 + x2) + 2) >> 2; b4 = (ac4 * (unsigned long)(x3 + 32768)) >> 15; b7 = ((unsigned long)up - b3) * 50000; if (b7 < 0x80000000) { p = (b7 * 2) / b4;} else {p = (b7 / b4) *2;} x1 = (p >> 8) * (p >> 8); x1 = (x1 * 3038) >> 16; x2 = (-7357 * p) >> 16; bmp_pres = p + ((x1 + x2 + 3791) >> 4); //FINAL PRESSURE if ( k == 1 ){ first_pres = bmp_pres; //SAVE FIRST PRESSURE MEASUREMENT k = 0;} else { TBCTL = TBSSEL_2 + MC_1 + TBCLR; //COUNT MODE if ( bmp_pres > first_pres ){ //BLINK FASTER IF CURRENT PRESSURE IS HIGHER THEN first_pres TBCCR0 = 20000;} if (bmp_pres < first_pres){ //BLINK SLOWER IF CURRENT PRESSURE IS HIGHER THEN first_pres TBCCR0 = 65000;} else { P4OUT ^= 0x80;} //TOGGLE IF CURRENT PRESSURE IS EQUAL TO first_pres __delay_cycles(500000); }} } void i2c_tx_init() { UCB0I2CSA = BMP180_ADDR; UCB0IE |= UCTXIE; //TX INTERRUPT ENABLED } void i2c_rx_init(void) { UCB0IE |= UCRXIE; //RX INTERRUPT ENABLED } int sendByte_getBytes( unsigned char reg_to_read, int bytes_to_rx ) { i = 0; i2c_tx_init(); __delay_cycles(1000); PTxData = ( unsigned char *)reg_to_read; //TX ARRAY START ADRESS TXByteCtr = sizeof reg_to_read; //LOAD TX BYTE COUNTER start_TX(); i2c_rx_init(); //RECIEVE REQUESTED BYTES __delay_cycles(1000); PRxData = (unsigned char *)RxBuffer; //RX BUFFER RXByteCtr = bytes_to_rx; //NUMBER OF BYTES TO RECIEVE start_RX(); return (((int)RxBuffer[0] << 8) | (int)RxBuffer[1]); //CURRENTLY ONLY RETURNING TWO BYTES } //I2C TRANSMISSION START void start_TX(void) { UCB0CTL1 |= UCTR + UCTXSTT; //I2C TX, START CONDITION __bis_SR_register(LPM0_bits + GIE); //ENTER LPM0, GLOBAL INTERRUPT ENABLE, REMAIN IN LPM0 UNTIL ALL DATA IS TX'D __no_operation(); while (UCB0CTL1 & UCTXSTP); //ENSURE STOP CONDITION GOT SENT } //I2C RESTART AND RECIEVE void start_RX(void) { while (UCB0CTL1 & UCTXSTP); //WAIT FOR STOP CONDITION UCB0CTL1 &= ~UCTR; //SET AS RECIEVER UCB0CTL1 |= UCTXSTT; //RESTART, START CONDITION __bis_SR_register(LPM0_bits + GIE); while (UCB0CTL1 & UCTXSTP); } //I2C INTERRUPT SERVICE ROUTINE #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) { switch(__even_in_range(UCB0IV,12)) { case 0: break; //VECTOR 0: NO INTERRUPT FLAGS case 2: break; //VECTOR 2: ALIFG case 4: break; //VECTOR 4: NACKIFG case 6: //VECTOR 6: STTIFG UCB0IFG &= ~UCSTTIFG; //CLEAR START CONDITION FLAG break; case 8: //VECTOR 8: STPIFG UCB0IFG &= ~UCSTPIFG; //CLEAR STOP CONDITION FLAG __bic_SR_register_on_exit(LPM0_bits); //EXIT LPM0 break; case 10: //VECTOR 10: RXIFG RXByteCtr--; //DECREMENT RX BYTE COUNTER P1OUT ^= 0x01; //TOGGLE P1.0 if (RXByteCtr){ *PRxData++ = UCB0RXBUF; //MOVE RX DATA TO ADRESS PRxData if (RXByteCtr == 1) //ONLY ONE BYTE LEFT? UCB0CTL1 |= UCTXSTP;} //GENERATE I2C STOP CONDITION else{ *PRxData = UCB0RXBUF; //MOVE FINAL RX DATA TO PRxData __bic_SR_register_on_exit(LPM0_bits);} //EXIT LPM0 break; case 12: //VECTOR 12: TXIFG if (TXByteCtr){ //CHECK TX BYTE COUNTER P6OUT ^= 0x04; //TOGGLE P6.3 UCB0TXBUF = *PTxData++; //LOAD TX BUFFER TXByteCtr--;} //DECREMENT TX BYTE CUNTER else{ if( i == 1 ){ UCB0CTL1 |= UCTXSTP;} //I2C STOP CONDITION UCB0IFG &= ~UCTXIFG; //CLEAR USCI_B0 TX INTERRUPT FLAG __bic_SR_register_on_exit(LPM0_bits);} //EXIT LPM0 default: break; }} //TIMER 1 INTERRUPT SERVICE ROUTINE #pragma vector=TIMERB0_VECTOR __interrupt void TIMERB0_ISR (void) { P4OUT ^= 0x80; //TOGGLE P4.7 } Quote Link to post Share on other sites
gwdeveloper 275 Posted December 23, 2013 Author Share Posted December 23, 2013 I haven't tested or compiled your code but after a quick scan, the only quick thing I can think of is rate-dependent hysteresis on your led flashing function. Is the flashing LED your only method of debugging the pressure changes? Are you watching the bmp_pres and first_pres variables in CCS? What is the value stored there? I've also noticed that your delays in several functions are 10x and some are .5x the original code. Which msp430 are you using? Quote Link to post Share on other sites
atiom 0 Posted December 24, 2013 Share Posted December 24, 2013 I actually figured out where the problem is. Inside the TX ISR, when I load the UCB TXBUF with the pointer PTxData,the value that the TXBUF gets during the first load is FD instead of AA. The next time the TX ISR is called and the UCB0TXBUF is loaded the with new data from the PTxData pointer, the TXBUF gets a new value of FF instead of AC, and never changes again during the next ISR. But if I load the UCB0TXBUF directly with the right value, for example AA (to read ac1) the TXBUF gets it righ. I don't know what is causing this weird behavior, I have already tried to make some variables volatile, but no success. case 12: //VECTOR 12: TXIFG if (TXByteCtr){ //CHECK TX BYTE COUNTER P6OUT ^= 0x04; //TOGGLE P6.3 UCB0TXBUF = *PTxData++ //LOAD TX BUFFER TXByteCtr--;} //DECREMENT TX BYTE CUNTER else{ if( i == 1 ){ UCB0CTL1 |= UCTXSTP;} //I2C STOP CONDITION UCB0IFG &= ~UCTXIFG;} //CLEAR USCI_B0 TX INTERRUPT FLAG __bic_SR_register_on_exit(LPM0_bits);} //EXIT LPM0 default: break; Quote Link to post Share on other sites
gwdeveloper 275 Posted December 24, 2013 Author Share Posted December 24, 2013 @@atiom that actually sounds like the data is being clocked incorrectly. The bit rate is determined by your mcu's clock speed. I see that you have UCB0BR0 = 12. Check my original code and read the note. Setting the "proper" bit rate has never once worked for me on any msp430 using i2c. Leave those values to zero and data is clocked correctly. Might be something to try as I just tested my original code and it's running fine. Quote Link to post Share on other sites
atiom 0 Posted December 28, 2013 Share Posted December 28, 2013 Hello Gwdeveloper. I did what you said, set UCB0BR0 AND UCB0BR1 to zero, but that didn't help. The problem start right at the beginning, because I can't even obtain the calibration values ac1, ac2... I'm using the BMP180 instead of the BMP085, but after looking at both datasheets, I see nothing that would require changing the code. I have done some changes in the code since my last post, hope you could take a look at it and help me out again.I am working on a quadcopter project right now, from the ground up, and this issue is keeping me from advancing. I'm replacing the code I sent before, some posts above, with the latest version, but it is essentially based on your original code. Thank you very much in advance for your time and effort. Quote Link to post Share on other sites
gwdeveloper 275 Posted December 29, 2013 Author Share Posted December 29, 2013 I commented out all the code you added. Seems to be working fine now. It runs very slow as you have not set your clock speed, so I believe the default is 1Mhz. Use CCS to watch data for bmp_temp and bmp_pres; you can also check ac1, ac2, ac3... #include <msp430.h> #include <stdlib.h> //BMP085 DEFINES #define BMP180_ADDR 0x77 #define BMP180_CTRL_REG 0xF4 #define BMP180_TEMPERATURE_REG 0x2E #define BMP180_PRESSURE_REG 0x34 //oss = 0 //#define BMP180_PRESSURE_REG_OSS1 0x74 //oss = 1, LONGER DELAY NEEDED 7.5ms //#define BMP180_PRESSURE_REG_OSS2 0xB4 //oss = 2, LONGER DELAY NEEDED 13.5ms //#define BMP180_PRESSURE_REG_OSS3 0xF4 //oss = 3, LONGER DELAY NEEDED 25.5ms #define BMP180_MSB_REG 0xF6 #define BMP180_LSB_REG 0xF7 #define BMP180_CONV_REG_XLSB 0xF8 //BMP085 FUNCTIONS void bmp180_calibration(void); unsigned int bmp180_ut(void); unsigned long bmp180_up(void); void get_bmp180(void); //I2C FUNCTIONS void i2c_tx_init(void); void i2c_rx_init(void); void start_TX(void); void start_RX(void); int sendByte_getBytes(unsigned char reg_to_read, int bytes_to_rx); //VARIABLES //int i = 1; int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; //TRUE PRESSURE AND TEMPERATURE long ut; long x1; long x2; long b5; int bmp_temp = 0; long up; long x3; long b3; unsigned long b4; long b6; unsigned long b7; long p; volatile long bmp_pres = 0; //TIMER_B VARIABLES //long first_pres = 0; //int k = 1; //TX CONSTANTS const unsigned char utTxData[] = { BMP180_CTRL_REG, BMP180_TEMPERATURE_REG }; //UNCONPENSATED TEMPERATURE REGISTER const unsigned char upTxData[] = { BMP180_CTRL_REG, BMP180_PRESSURE_REG }; //UNCOMPENSATED PRESSURE REGISTER const unsigned char msbData[] = { BMP180_MSB_REG }; //I2C VARIABLES unsigned char *PTxData; //POINTER TO TX DATA volatile unsigned int TXByteCtr = 0; unsigned char *PRxData; //POINTER TO RX DATA volatile unsigned int RXByteCtr = 0; volatile unsigned char RxBuffer[3]; //ALLOCATE 3 BYTES OF RAM void main(void) { WDTCTL = WDTPW + WDTHOLD; //STOP WDT P3SEL |= 0x03; //ASSIGN I2C PINS TO USCI_B0 UCB0CTL1 |= UCSWRST; //ENABLE SW RESET UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; //I2C MASTER, SYNCHRONOUS MODE UCB0CTL1 = UCSSEL_2 + UCSWRST; //USE SMCLK, KEEP SW RESET UCB0BR0 = 0; //FSCL = SMCLK/12 =~ 100kHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; //CLEAR SW RESET, RESUME OPERATION /* P1DIR |= 0x01; P1OUT &= ~0x01; P6DIR |= 0x04; P6OUT &= ~0x04; P4DIR |= 0x80; //P4.7 OUTPUT PRESSURE DELTA TBCCTL0 = CCIE; //CCR0 INTERRUPT ENABLED */ __delay_cycles(100000); //AT LEAST 10ms (100ms) BEFORE FIRST COMUNICATION bmp180_calibration(); //LOAD CALIBRATION DATA get_bmp180(); //LOOP TO COLLECT TEMPERATURE AND PRESSURE } //STORE E2PROM DATA INTO USABLE VARIABLES void bmp180_calibration(void) { ac1 = sendByte_getBytes(0xAA, 2); //MSB ADRESS=0xAA, LSB ADRESS=AB, "EACH WORLD READ IS 16 BITS" WIDE (2 BYTES) __delay_cycles(1000); ac2 = sendByte_getBytes(0xAC, 2); __delay_cycles(1000); ac3 = sendByte_getBytes(0xAE, 2); __delay_cycles(1000); ac4 = sendByte_getBytes(0xB0, 2); __delay_cycles(1000); ac5 = sendByte_getBytes(0xB2, 2); __delay_cycles(1000); ac6 = sendByte_getBytes(0xB4, 2); __delay_cycles(1000); b1 = sendByte_getBytes(0xB6, 2); __delay_cycles(1000); b2 = sendByte_getBytes(0xB8, 2); __delay_cycles(1000); mb = sendByte_getBytes(0xBA, 2); __delay_cycles(1000); mc = sendByte_getBytes(0xBC, 2); __delay_cycles(1000); md = sendByte_getBytes(0xBE, 2); __delay_cycles(10000); } // READ UNCOMPENSATED TEMPERATURE AND RETURN MSB AND LSB unsigned int bmp180_ut(void) { //i = 1; i2c_tx_init(); __delay_cycles(1000); PTxData = (unsigned char *)utTxData; //SEND CONTROL REGISTER AND TEMPERATURE REGISTER TXByteCtr = 2; //LOAD TX BYTE COUNTER start_TX(); __delay_cycles(200000); //LONG DELAY HERE WAITING FOR CONVERSION TO COMPLETE return (sendByte_getBytes(BMP180_MSB_REG, 2)); } //READ UNCOMPENSATED PRESSURE AND RETURN MSB, LSB AND XLSB unsigned long bmp180_up(void) { //i = 1; i2c_tx_init(); __delay_cycles(1000); PTxData = (unsigned char *)upTxData; //SEND CONTROL REGISTER ADRESS AND PRESSURE REGISTER VALUE TXByteCtr = 2; //LOAD TX BYTE COUNTER start_TX(); __delay_cycles(200000); //LONG DELAY HERE WAITING FOR CONVERSION TO COMPLETE PTxData = (unsigned char *)msbData; //SEND MSB READ REGISTER TXByteCtr = 1; //i = 0; start_TX(); i2c_rx_init(); __delay_cycles(1000); PRxData = (unsigned char *)RxBuffer; //RX BUFFER RXByteCtr = 3; //NUMBER OF BYTES TO RECIEVE start_RX(); return ( (( (long)RxBuffer[0] << 16) | ( (long)RxBuffer[1] << 8) | (long)RxBuffer[2]) >> 8); } //COLLECT UNCOMPESATED TEMPERATURE AND PRESSURE, CALCULATE COMPENSATED TEMPERATURE AND PRESSURE void get_bmp180() { while (1){ ut = bmp180_ut(); up = bmp180_up(); //CALCULATE TRUE TEMPERATURE x1 = ((long)ut - ac6) * ac5 >> 15; x2 = ((long)mc << 11) / (x1 + md); b5 = x1 + x2; bmp_temp = (b5 + 8) >> 4; //FINAL TEMPERATURE //CALCULATE TRUE PRESSURE b6 = b5 - 4000; x1 = (b2 * (b6 * b6) >> 12) >> 11; x2 = (ac2 * b6) >> 11; x3 = x1 + x2; b3 = ((long)ac1 * 4 + x3 + 2) >> 2; //LOTS OF "CORRECTIONS" ON THE WEB x1 = ac3 * b6 >> 13; x2 = (b1 * ((b6 * b6) >> 12)) >> 16; x3 = ((x1 + x2) + 2) >> 2; b4 = (ac4 * (unsigned long)(x3 + 32768)) >> 15; b7 = ((unsigned long)up - b3) * 50000; if (b7 < 0x80000000) { p = (b7 * 2) / b4;} else {p = (b7 / b4) *2;} x1 = (p >> 8) * (p >> 8); x1 = (x1 * 3038) >> 16; x2 = (-7357 * p) >> 16; bmp_pres = p + ((x1 + x2 + 3791) >> 4); //FINAL PRESSURE /* if ( k == 1 ){ first_pres = bmp_pres; //SAVE FIRST PRESSURE MEASUREMENT k = 0;} else { TBCTL = TBSSEL_2 + MC_1 + TBCLR; //COUNT MODE if ( bmp_pres > first_pres ){ //BLINK FASTER IF CURRENT PRESSURE IS HIGHER THEN first_pres TBCCR0 = 20000;} if (bmp_pres < first_pres){ //BLINK SLOWER IF CURRENT PRESSURE IS HIGHER THEN first_pres TBCCR0 = 65000;} else { P4OUT ^= 0x80;} //TOGGLE IF CURRENT PRESSURE IS EQUAL TO first_pres __delay_cycles(500000); } */ } } void i2c_tx_init() { UCB0I2CSA = BMP180_ADDR; UCB0IE |= UCTXIE; //TX INTERRUPT ENABLED } void i2c_rx_init(void) { UCB0IE |= UCRXIE; //RX INTERRUPT ENABLED } int sendByte_getBytes( unsigned char reg_to_read, int bytes_to_rx ) { //i = 0; i2c_tx_init(); __delay_cycles(1000); PTxData = ( unsigned char *)®_to_read; //TX ARRAY START ADRESS TXByteCtr = sizeof reg_to_read; //LOAD TX BYTE COUNTER start_TX(); i2c_rx_init(); //RECIEVE REQUESTED BYTES __delay_cycles(1000); PRxData = (unsigned char *)RxBuffer; //RX BUFFER RXByteCtr = bytes_to_rx; //NUMBER OF BYTES TO RECIEVE start_RX(); return (((int)RxBuffer[0] << 8) | (int)RxBuffer[1]); //CURRENTLY ONLY RETURNING TWO BYTES } //I2C TRANSMISSION START void start_TX(void) { UCB0CTL1 |= UCTR + UCTXSTT; //I2C TX, START CONDITION __bis_SR_register(LPM0_bits + GIE); //ENTER LPM0, GLOBAL INTERRUPT ENABLE, REMAIN IN LPM0 UNTIL ALL DATA IS TX'D __no_operation(); while (UCB0CTL1 & UCTXSTP); //ENSURE STOP CONDITION GOT SENT } //I2C RESTART AND RECIEVE void start_RX(void){ while (UCB0CTL1 & UCTXSTP); //WAIT FOR STOP CONDITION UCB0CTL1 &= ~UCTR; //SET AS RECIEVER UCB0CTL1 |= UCTXSTT; //RESTART, START CONDITION __bis_SR_register(LPM0_bits + GIE); while (UCB0CTL1 & UCTXSTP); } //I2C INTERRUPT SERVICE ROUTINE #pragma vector = USCI_B0_VECTOR __interrupt void USCI_B0_ISR(void) { switch(__even_in_range(UCB0IV,12)) { case 0: break; //VECTOR 0: NO INTERRUPT FLAGS case 2: break; //VECTOR 2: ALIFG case 4: break; //VECTOR 4: NACKIFG case 6: //VECTOR 6: STTIFG UCB0IFG &= ~UCSTTIFG; //CLEAR START CONDITION FLAG break; case 8: //VECTOR 8: STPIFG UCB0IFG &= ~UCSTPIFG; //CLEAR STOP CONDITION FLAG __bic_SR_register_on_exit(LPM0_bits); //EXIT LPM0 break; case 10: //VECTOR 10: RXIFG RXByteCtr--; //DECREMENT RX BYTE COUNTER //P1OUT ^= 0x01; //TOGGLE P1.0 if (RXByteCtr){ *PRxData++ = UCB0RXBUF; //MOVE RX DATA TO ADRESS PRxData if (RXByteCtr == 1) //ONLY ONE BYTE LEFT? UCB0CTL1 |= UCTXSTP;} //GENERATE I2C STOP CONDITION else{ *PRxData = UCB0RXBUF; //MOVE FINAL RX DATA TO PRxData __bic_SR_register_on_exit(LPM0_bits);} //EXIT LPM0 break; case 12: //VECTOR 12: TXIFG if (TXByteCtr){ //CHECK TX BYTE COUNTER //P6OUT ^= 0x04; //TOGGLE P6.3 UCB0TXBUF = *PTxData++; //LOAD TX BUFFER TXByteCtr--;} //DECREMENT TX BYTE CUNTER else{ //if( i == 1 ){ UCB0CTL1 |= UCTXSTP; //} //I2C STOP CONDITION UCB0IFG &= ~UCTXIFG; //CLEAR USCI_B0 TX INTERRUPT FLAG __bic_SR_register_on_exit(LPM0_bits); //EXIT LPM0 } default: break; }} //TIMER 1 INTERRUPT SERVICE ROUTINE /* #pragma vector=TIMERB0_VECTOR __interrupt void TIMERB0_ISR (void) { P4OUT ^= 0x80; //TOGGLE P4.7 } */ Quote Link to post Share on other sites
atiom 0 Posted December 29, 2013 Share Posted December 29, 2013 It still isn't working for me. I' getting the exact same result as before. The RX buffer gets loaded with FD instead of AA. I'm using msp430 F5529 at 1MHz. Quote Link to post Share on other sites
gwdeveloper 275 Posted December 29, 2013 Author Share Posted December 29, 2013 Make sure you have this part correct; take note of the &. int sendByte_getBytes( unsigned char reg_to_read, int bytes_to_rx ) { //i = 0; i2c_tx_init(); __delay_cycles(1000); PTxData = ( unsigned char *)®_to_read; //TX ARRAY START ADRESS TXByteCtr = sizeof reg_to_read; //LOAD TX BYTE COUNTER ... Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.