The LPS25H pressure sensor (Pololu product #2724) works fine with the Arduino sample code provided by Pololu engineers, running on a Pro Mini board (5V, 16 MHz). It also responds correctly to the Arduino program I2C-Scanner, which returns the (8 bit) device address 0xBA.
However, I prefer minimal code and to use the Atmel Studio IV / avr-gcc environment. I find that the LPS25H does not work with some very simple routines that make hardware I2C calls. I’ve been using these routines without any problems for several years on a variety of devices, including RTCs like the DS1307, memory chips like 24C32, Melexis thermal sensor, etc.
The following code is a simple address scanner, which properly detects a DS3231 RTC (0xD0) breakout also containing an 24C32 memory chip (0xAE), however, it does not detect the LPS25H. The response of the LPS25H to the START command transmitting the (8 bit) device address 0XBA is TWSR = 0x20, which is a NAK.
The LPS25H is connected directly to the Pro Mini with Vin=Vcc (5V), Gnd, SCL and SDA connected to PC5 and PC4, respectively. Those same connections work fine with the Arduino I2C Scanner, running in the Arduino environment.
I’ve been working on this for a couple of days, going back and forth between the Arduino environment and the Atmel Studio environment and not getting anywhere, so if someone can see what I’m missing, I would greatly appreciate it! I have looked through the Arduino Wire/twi.c library to see what that code is doing, and the calls to the I2C hardware look pretty much the same, so nothing has jumped out at me yet. Subtle timing problem?
#define F_CPU 16000000UL
#include <util/delay.h>
#include <avr/io.h>
#include "uart.c"
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
#define LED PB5
// ---------------------------------------------------------------------------
// I2C (TWI) ROUTINES
//
// On the AVRmega series, PA4 is the data line (SDA) and PA5 is the clock (SCL
// The standard clock rate is 100 KHz, and set by I2C_Init. It depends on the AVR osc. freq.
#define F_SCL 100000L // I2C clock speed 100 KHz
#define TW_READBIT 1 //low bit of device address for read
#define TW_START 0xA4 // send start condition (TWINT,TWSTA,TWEN)
#define TW_STOP 0x94 // send stop condition (TWINT,TWSTO,TWEN)
#define TW_ACK 0xC4 // return ACK to slave
#define TW_NACK 0x84 // don't return ACK to slave
#define TW_SEND 0x84 // send data (TWINT,TWEN)
#define TW_READY (TWCR & 0x80) // ready when TWINT returns to logic 1.
#define TW_STATUS (TWSR & 0xF8) // returns value of status register
#define I2C_Stop() TWCR = TW_STOP // inline macro for stop condition
void I2C_Init(){
// at 16 MHz, the SCL frequency will be 16/(16+2(TWBR)), assuming prescalar of 0.
// so for 100KHz SCL, TWBR = ((F_CPU/F_SCL)-16)/2 = ((16/0.1)-16)/2 = 144/2 = 72.
TWSR = 0; // set prescalar to zero
TWBR = ((F_CPU/F_SCL)-16)/2; // set SCL frequency in TWI bit register
}
unsigned char I2C_Detect(unsigned char addr){
// look for device at specified address; return 1=found, 0=not found
TWCR = TW_START; // send start condition
while (!TW_READY); //wait
TWDR = addr; // load device's bus address
TWCR = TW_SEND; // and send it
while (!TW_READY);
// printf("%02X %02x ",addr,TW_STATUS);
return (TW_STATUS==0x18); // return 1 if found; 0 otherwise
}
void ShowDevices(void){
for (unsigned char addr=1; addr<128; addr++) { // search all 127 addresses
if (I2C_Detect(addr<<1)) // I2C detected?
printf(" .%02X ",addr<<1);
}
}
int main( void ) {
DDRB |= (1 << LED); // set LED to output
// PORTC |= (1<<PC4)|(1<<PC5); //pullup on SDA, SDC
uart_init(9600);
stdout = &mystdout; //Required for printf init
printf("Init I2C\r\n");
I2C_Init();
printf("Showing devices");
ShowDevices();
printf("\r\ndone\r\n");
while(1);
}
code.zip (3.73 KB)