Go Down

Topic: Issues with changing the slave address of pressure sensors (Read 143 times) previous topic - next topic

Max_Merker

Hello guys,

I am trying to change the slave address of a NPA 201 pressure sensor by Amphenol Sensors. I want to connect up to 50 sensors with the Arduino UNO R3 and according to the data sheet, it is possible to change the address by modifying the sensor's EEPROM. Right now I am working with the NPA 201 EV-Board which has the I2C pull-ups included. The procedure for the address change is explained in the application note attached below, however, I had some problems sending the commands via the Wire.h library. Somehow I managed to manipulate the wrong data bits in the EEPROM and already destroyed one sensor by trying to change its address :( I can't find the sensor with the i2c_scanner anymore...

A possible issue could be that I could not send the commands in step 2 (see Application Note) properly. I checked some of the Wire.h-commands on an oscilloscope, and I can't figure out how to realize a command like that one:

[7 bit address + Read bit (=1)] , [command byte ( = 0x20 )]

Whenever I use "Wire.requestFrom(sensor_address);" it doesn't seem to accept any other command bytes. It is also possible that all the commands worked properly and that I just modified the wrong bits in the memory.
I also tried out the Soft.I2C library but couldn't get it done yet.

Do you guys have any idea how to send commands like that with the Wire.h library or could you think of any other possibilities? I'd prefer not to use a multiplexer, because space is limited in my application.

I'll attach my code below (the one that killed the sensor), maybe there are some other mistakes in it which I did not seeā€¦

I am grateful for any kind of help and suggestions, thanks for your time! :)

Cheers, Max


Code: [Select]

/* NPA 201
25.07.2017
*/

#include <Wire.h>

const int sensor_addr    = 0x27;   //default sensor address
const int read_delay    = 21;       //read delay suggested in datasheet
const int power_delay   = 1000;     //delay before powering on the sensor
int PowerPin            = 13;
int rbuf[5], msb[17], lsb[17];        //msb und lsb for memory read, rbuf for pressure reading
float P, T, Pconv, Tconv ;
byte error;

void setup() {
  pinMode(PowerPin, OUTPUT);
 
  Wire.begin();           // join i2c bus
  Serial.begin(9600);     // start serial communication
}

void loop() {

  // NPA201 barometric pressure sensor

  //power on sensor (the sensor needs to be set in command mode right after start-up
  delay(power_delay);
  digitalWrite(PowerPin, HIGH);
  delay(1);                               // necessary delay for sensor probably due to start-up time

  // put sensor in command mode
  Wire.beginTransmission(sensor_addr);    // transmit to device
  Wire.write(0xA9);                       // start command mode
  error = Wire.endTransmission();         // stop transmitting

  delay(read_delay);
  if (error == 0) {
    Serial.println("transmission 1 successful");
  }
  else {
    Serial.println("error in transmission 1");
  }




  // Read data from sensor memory
  for (int i = 20; i <= 36; i++) {          //assuming decimal counting here, maybe that was a first issue
    Serial.print("Location ");
    Serial.println(i);
   
    Wire.beginTransmission(sensor_addr);    // transmit to device
    Wire.write(i);                          // move to each register location. That was my workaround trying to read out the memory data
    Wire.endTransmission();                 // stop transmitting
    delay(read_delay);

    //read register data and output to serial console
    Wire.requestFrom(sensor_addr, 3);       // request 3 bytes from sensor
    Serial.print("Statusbyte: ");
    Serial.println(Wire.read(),BIN);
    Serial.print("MSB: ");
    msb[i] = Wire.read();
    lsb[i] = Wire.read();
    Serial.println(msb[i],BIN);
    Serial.print("LSB: ");
    Serial.println(lsb[i],BIN);
   

  }                   
    //MODIFY ADDRESS DETAILS

    lsb[22] = 0x28;                        //Word02 (Location 22) should contain address details
    Serial.println("new address: ");
    Serial.print(lsb[22], BIN);



    // increment sensor memory page counter

    Wire.beginTransmission(sensor_addr);
    Wire.write(0x5E);                        // increment memory page
    error = Wire.endTransmission();         // stop transmitting
 
    delay(read_delay);
      if (error == 0) {
      Serial.println("sensor incrementation successful");
    }
     else {
    Serial.println("error in transmission (step 4)");
  }



    //Write new memory page to sensor
int k = 20;                                                       // k as counter to access previously saved register values

  for (int j = 40; j<=56; j++) {
   
    Wire.beginTransmission(sensor_addr);                          // transmit to device
    Wire.write(j);Wire.write(msb[k]);Wire.write(lsb[k]);          // send command bytes to memory
    Wire.endTransmission();                                       // stop transmitting
    delay(read_delay);

    k = k+1;

  }                       // end of writing loop



    // create memory page checksum

  Wire.beginTransmission(sensor_addr);    // transmit to device
  Wire.write(0xAA);                       // checksum command
  error = Wire.endTransmission();         // stop transmitting
 
  delay(read_delay);
  if (error == 0) {
    Serial.println("checksum  successful");
  }
  else {
    Serial.println("error in transmission (step 6)");
  }
   




  //exit programming mode
  Wire.beginTransmission(sensor_addr);    // transmit to device
  Wire.write(0xA8);                       // end command mode
  error = Wire.endTransmission();         // stop transmitting
 
  delay(read_delay);
  if (error == 0) {
    Serial.println("Exit Programming mode successful");
  }
  else {
    Serial.println("error in transmission (step 7)");
  }
 

  // check status
  Wire.requestFrom(sensor_addr, 1);
  Serial.print("Statusbyte: ");
  Serial.println(Wire.read(),BIN);




  //----------------------------------------------------------------------
  digitalWrite(PowerPin, LOW);
  Serial.println("Sensor off");


 
 
  delay(60000);                  // delay in msec

}


pylon

If we take the AN seriously (I hope we can), you cannot use the Wire library to do this as it follows the I2C standard and this procedure breaks with the standard. It expects another byte to be sent in a read request after the address byte and read bit is sent before the slave has to answer. I never saw such a procedure before. As far as I can see the Arduino I2C hardware isn't able to handle that process. That means you probably have to program that out using a bitbang software emulation.

chucktodd

#2
Aug 01, 2017, 12:09 am Last Edit: Aug 01, 2017, 12:24 am by chucktodd Reason: timeouts
If we take the AN seriously (I hope we can), you cannot use the Wire library to do this as it follows the I2C standard and this procedure breaks with the standard. It expects another byte to be sent in a read request after the address byte and read bit is sent before the slave has to answer. I never saw such a procedure before. As far as I can see the Arduino I2C hardware isn't able to handle that process. That means you probably have to program that out using a bitbang software emulation.
I disagree,

I decode the Programing sequence as:
Code: [Select]

uint8_t sensorOldAddress=0x27;  // whatever the 'current' address is
uint8_t sensorNewAddress; // whatever the address is to be changed to.

// with the appnote, I CANNOT tell where there are 17(decimal) or 0x17(hex memory cells?)
// I am assuming 0x17(HEX)

// Also, I cannot tell whether XX=20 means XX=0x20 or XX=20  (big Difference!!!!)

uint8_t buffer[0x17][4]; // temp storage of EEPROM contents of sensor
bool success=true;

Wire.beginTransmission(sensorOldAddress);
Wire.write(0xA9); // start command mode
Wire.endTransmission();

// read all 23 EEPROM words
uint8_t dataWord=0; // start a 0
while((dataWord<0x17)&&(success)){
  uint8_t err=Wire.requestFrom(sensorOldAddress),4);
  if (err==4){
    buffer[dataWord][0]=Wire.read();
    buffer[dataWord][1]=Wire.read();
    buffer[dataWord][2]=Wire.read();
    buffer[dataWord][3]=Wire.read();
    }
  else {
     Serial.println("Something Bad Happend");
     success=false;
    }
  dataWord++;
  }
if(success){

  // printout values
  dataWord=0;
  Serial.println("EEPROM Contents");
  while(dataWord<0x17){
    Serial.print(dataWord,HEX);
    Serial.print(": ");
    Serial.print(buffer[dataWord][0],HEX);
    Serial.print(' ');
    Serial.print(buffer[dataWord][1],HEX);
    Serial.print(' ');
    Serial.print(buffer[dataWord][2],HEX);
    Serial.print(' ');
    Serial.println(buffer[dataWord][3],HEX);
    dataWord++;
    }

  if(false){ // change address, put some decision logic here!

    // sent new address

    buffer[2][3]=(buffer[2][3]&0x80)|sensorNewAddress;

  // increment to next config storage location (only 3 available)

    Wire.beginTransmission(sensorOldAddress);
    Wire.write(0x5E);
    Wire.endTransmission();

    dataWord=0;
    while((dataWord<0x17)&&success){
      Wire.beginTransmission(sensorOldAddress);
      Wire.write(dataWord+0x40);
      Wire.write(buffer[dataWord][2]);
      Wire.write(buffer[dataWord][3]);
      uint8_t err=Wire.endTransmission();
      if(err!=0){
        success=false;
        }
      else dataWord++;
     }

// have sensor calculate new checksum

    Wire.beginTransmission(sensorOldAddress);
    Wire.write(0xAA);
    Wire.endTransmission();
    }
// Ext Program mode

  Wire.beginTransmission(sensorOldAddress);
  Wire.Write(0xA8);
  Wire.endTransmission();
  }

// all done.
// power Cycle Sensor, it should now respond to new address



EDIT: add
This code has no ready/busy detection, the appnote did not specify any, but the datasheet does?

I would probably insert a call to:
Code: [Select]

bool waitReadyI2c(uint8_t address){ // wait up to 1 second for device
bool ready=false;
unsigned long timeout=millis();
while((millis()-timeout<1000)&&(!ready)){
  Wire.beginTransmission(address);
  ready = Wire.endTransmission()==0;
  }
return ready;


before writing each of the 'words', fail if not ready

Chuck.
Currently building mega http server 90% done, the Last 10% is killing me.

el_supremo

Did you try the search function of this forum?
This thread might have useful info.

Pete
Don't send me technical questions via Private Message.

Max_Merker

Yeee, thanks for the quick replies!

@Pete: Yeah I saw that post, but I couldn't get much more out of it than the regular pressure/temperature reading procedure (which works perfectly fine).

@Chuck: Thanks for the code, I'll try to work with the suggestions! By now I finally got an answer from Amphenol, the data words are in HEX, so resulting in 23 Words from 0x00 to 0x16.

Max

pylon

Quote
I disagree,
In this case table 1 on page 2 is completely misleading! On step 2 you have byte 1 the address and read bit, byte 2 is the memory address. This byte is marked as "Send" and not "Return".

chucktodd

In this case table 1 on page 2 is completely misleading! On step 2 you have byte 1 the address and read bit, byte 2 is the memory address. This byte is marked as "Send" and not "Return".
Ya, that Datasheet created more questions than it answered.

Chuck.
Currently building mega http server 90% done, the Last 10% is killing me.

Go Up