LPS331使用 高精度大気圧モジュールとのI2Cでの通信テスト

秋月で、「LPS331使用 高精度大気圧モジュール」を650円で入手しましたので、そのテストです。大気圧モジュールの温度補償用として精度は±2 degCほどのようですが、温度計もついています。通信プロトコルとして、I2CとSPIに対応しています。5番ピンをプルアップするかしないかで、I2C/SPIの切り替えができます。AVRを使って、I2Cの通信の練習をしようと思いましたので、I2Cモードで通信のテストをしてみます。AVRにはTWIにハードウェア対応しているatmega328Pを使います。

LPS331APは3.3V動作です。まず、この前作ったUSB-AVRライタは5V供給ですので、3.3 Vレギュレータを入れて、3.3 Vにもジャンパピンで対応できるようにさくりと工作しました。

そして、適当にコーディングをしてから、PC5(SCL), PC4(SDA)をLPS331APへ配線します。WHO_AM_Iを連打するコードをつくり、ロジック・アナライザで動作チェックをしました。

一発目から無事、通信できていました。

ロジック・アナライザのカラフルな感じが好きです。


チップLED付きです。

コードはこちら。SCL, SDAを外部でプルアップしない場合は、PC5, PC4についてPORTCレジスタに1を入れてやれば、AVR内部でプルアップしてもらえます。ただAVRのプルアップは弱いので(抵抗が大きいので)100kbps以上の早い通信をしようとすると失敗しました。エラー処理はしていません。


#include <avr/io.h>
#include <util/delay.h>
#include <util/twi.h>

#define SLA_R  0b10111001
#define SLA_W  0b10111000

#define SCL PORTC5
#define SDA PORTC4

int8_t read_one(uint8_t reg_add);

int main(void){
  PORTC = (1 << SCL) | (1 << SDA);//pull up

  // 1e6/(16+2*TWBR*TWPS) < 100 kHz = 1e5
  //TWSR |= (0 << TWPS1) | (0 << TWPS0); //prescaler 1
  //TWBR = 0x00;// TWBR = 0
  //TWAR = //address & general call
  while(1){
    read_one(0x0f);
    _delay_ms(100);
  }
}

int8_t read_one(uint8_t reg_add){
  int8_t res;
  // ST send start bit
  TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // | (1 << TWIE);
  while (!(TWCR & (1 << TWINT))); // wait
  if((TWSR & 0xf8) != TW_START){ // chk status
    return -1; //error
  }

  // SLA+W
  TWDR = SLA_W;
  TWCR = (1 << TWINT) | (1 << TWEN);//return
  while (!(TWCR & (1 << TWINT)));//wait
  if((TWSR & 0xf8) != TW_MT_SLA_ACK){ //chk
    return -1;//error
  }

  // SUB: multiread? + register add
  TWDR = reg_add + (0 << 7); //single read MSB = 0;
  TWCR = (1 << TWINT) | (1 << TWEN);
  while (!(TWCR & (1 << TWINT)));//wait
  if((TWSR & 0xf8) != TW_MT_DATA_ACK){ //chk
    return -1;//error
  }

  // SR
  TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); // | (1 << TWIE);
  while (!(TWCR & (1 << TWINT))); // wait
  if((TWSR & 0xf8) != TW_REP_START){ // chk status
    return -1; //error
  }

  // SLA + R
  TWDR = SLA_R;
  TWCR = (1 << TWINT) | (1 << TWEN);//return
  while (!(TWCR & (1 << TWINT)));//wait
  if((TWSR & 0xf8) != TW_MR_SLA_ACK){ //chk
    return -1;//error
  }

  // DATA read
  TWCR = (1 << TWINT) | (1 << TWEN) | (0 << TWEA); //NACK
  while (!(TWCR & (1 << TWINT)));//wait
  if((TWSR & 0xf8) != TW_MR_DATA_NACK){ //chk
    return -1;//error
  }
  res = TWDR;

  // SP
  TWCR = (1 << TWINT) | (1 << TWSTO)| (1 << TWEN);

  return res;
}