I'm road testing the  Ultra-Low Power Arm Cortex-M4 Darwin MCU EVM.

In these blog posts I try to build a real world low power design.

This time I'm porting ROHM's Arduino library and example sketch for the pressure sensor BM1383AGLV BM1383AGLV from the Rohm SensorShield-EVK-003 (Arduino Compatible)  kit to the Maxim 32660 microcontroller. In this part, the i2c read and write functions and the pressure sensor init procedure.

 

i2c Read Function

 

The Arduino code for the pressure sensor performs these activities:

 

  Wire.beginTransmission(BM1383AGLV_DEVICE_ADDRESS);
  Wire.write(memory_address);
  rc = Wire.endTransmission(false);
  if (rc != 0) {
    return (rc);
  }

  Wire.requestFrom(BM1383AGLV_DEVICE_ADDRESS, size, true);
  cnt = 0;
  while(Wire.available()) {
    data[cnt] = Wire.read();
    cnt++;
  }

 

  • Start
  • write the register you want to get the value from,
  • generate a restart,
  • then read the requested number of bytes.
  • Stop

 

For the MAXIM controller, here's the ported code

 

uint8_t read(uint8_t memory_address, uint8_t *data, int size) {
    uint8_t rc;
    uint8_t reg;
    reg = memory_address;

    printf("Master writes data to Slave.\n");
    if((rc = I2C_MasterWrite(MXC_I2C0, _address, &reg, sizeof(reg), 1)) != sizeof(reg)) { // with restart
        printf("Error writing %d\n", rc);
        while(1);
    }

    printf("Master reads data from Slave.\n");
    if((rc = I2C_MasterRead(MXC_I2C0, _address, data, size, 0)) != size) { // with a stop
        printf("Error reading %d\n", rc);
        while(1);
    }

  return (rc);
}

 

i2c Write Function

 

Again, the simplified Arduino code:

 

  Wire.beginTransmission(BM1383AGLV_DEVICE_ADDRESS);
  Wire.write(memory_address);
  Wire.write(data, size);
  rc = Wire.endTransmission();

 

  • Start
  • write the register you want to get the write to,
  • then write the data bytes.
  • Stop

 

For MAXIM:

 

uint8_t write(uint8_t *data, int size) {
    uint8_t rc;

    printf("Master writes data to Slave.\n");
    if((rc = I2C_MasterWrite(MXC_I2C0, _address, data, size, 0)) != size) { // with a stop
        printf("Error writing %d\n", rc);
        while(1);
    }

    return (rc);
}

 

The Initialisation

 

 

The pressure sensor has to be configured before it can be used. This is done via a set of i2c commands.

 

ROHM's example

 

  rc = read(BM1383AGLV_ID, &reg, sizeof(reg));
  if (rc != 0) {
    Serial.println(F("Can't access BM1383AGLV"));
    return (rc);
  }
  Serial.print(F("BM1383AGLV ID Register Value = 0x"));
  Serial.println(reg, HEX);

  if (reg != BM1383AGLV_ID_VAL) {
    Serial.println(F("Can't find BM1383AGLV"));
    return (rc);
  }

  reg = BM1383AGLV_POWER_DOWN_VAL;
  rc = write(BM1383AGLV_POWER_DOWN, &reg, sizeof(reg));
  if (rc != 0) {
    Serial.println(F("Can't write BM1383AGLV POWER_DOWN register"));
    return (rc);
  }

  delay(WAIT_BETWEEN_POWER_DOWN_AND_RESET);

  reg = BM1383AGLV_RESET_VAL;
  rc = write(BM1383AGLV_RESET, &reg, sizeof(reg));
  if (rc != 0) {
    Serial.println(F("Can't write BM1383AGLV RESET register"));
    return (rc);
  }

  reg = BM1383AGLV_MODE_CONTROL_VAL;
  rc = write(BM1383AGLV_MODE_CONTROL, &reg, sizeof(reg));
  if (rc != 0) {
    Serial.println(F("Can't write BM1383AGLV MODE_CONTROL register"));
    return (rc);
  }

  delay(WAIT_TMT_MAX);

 

They are reusing the i2c read and write helpers. I'm doing the same in the ported code.

  • They check the sensor ID, and compare it with the expected value.
  • Then they bounce the sensor,
  • and set the operating mode.

 

MAX32660 port:

 

uint8_t BM1383AGLV_init(uint8_t address) {
    uint8_t rc = 0;
    const sys_cfg_i2c_t sys_i2c_cfg = NULL; /* No system specific configuration needed. */

    _address = (address<<1);

    //Setup the I2CM
    I2C_Shutdown(I2C_MASTER);
    if((rc = I2C_Init(I2C_MASTER, I2C_STD_MODE, &sys_i2c_cfg)) != E_NO_ERROR) {
        printf("Error initializing I2C%d.  (Error code = %d)\n", I2C_MASTER_IDX, rc);
        return 1;
    }

    rc = read(BM1383AGLV_ID, &(rxdata[0]), sizeof(rxdata[0]));
    if (rc != sizeof(rxdata[0])) {
        printf("Can't access BM1383AGLV\n");
        return (rc);
    }
    printf("BM1383AGLV ID Register Value = 0x%02x\n", rxdata[0]);

    if (rxdata[0] != BM1383AGLV_ID_VAL) {
        printf("Can't find BM1383AGLV\n");
        return (rc);
    }

    txdata[0] = BM1383AGLV_POWER_DOWN_VAL;
    rc = write(BM1383AGLV_POWER_DOWN, &(txdata[0]), sizeof(txdata[0]));
    if (rc != sizeof(txdata[0])) {
        printf("Can't write BM1383AGLV POWER_DOWN register");
        return (rc);
    }
    mxc_delay(MXC_DELAY_MSEC(WAIT_BETWEEN_POWER_DOWN_AND_RESET)); // todo: check when going to low power. This can start the systicks when not active

    txdata[0] = BM1383AGLV_RESET_VAL;
    rc = write(BM1383AGLV_RESET, &(txdata[0]), sizeof(txdata[0]));
    if (rc != sizeof(txdata[0])) {
        printf("Can't write BM1383AGLV RESET register");
        return (rc);
    }

    txdata[0] = BM1383AGLV_MODE_CONTROL_VAL;
    rc = write(BM1383AGLV_MODE_CONTROL, &(txdata[0]), sizeof(txdata[0]));
    if (rc != sizeof(txdata[0])) {
        printf("Can't write BM1383AGLV MODE_CONTROL register");
        return (rc);
    }

    mxc_delay(MXC_DELAY_MSEC(WAIT_TMT_MAX)); // todo: check when going to low power. This can start the systicks when not active

    return E_NO_ERROR;
}

uint8_t BM1383AGLV_initDefault() {
    return BM1383AGLV_init(BM1383AGLV_DEVICE_ADDRESS);
}

 

I am breaking an isolation rule here. I'm initialising i2c in the sensor's init code.

This code to prepare the i2c channel should be outside the sensor's API.

I didn't do this here because in my design the sensor API is the only piece dependent on i2c.

 

Here is the capture of the traffic during the init process:

 

 

I2C Analysis results


16 december 2018
Bus configuration
SDAChannel 1
SCLChannel 0
Statistics
Decoded bytes16
Detected bus errors0
IndexTimeHexBin
0-5,00 μsSTART
1500,00 ns0xba0b10111010
291,50 μsACK
396,00 μs0x100b00010000
4187,00 μsACK
5202,00 μsSTART
6207,00 μs0xbb0b10111011
72,72 msACK
82,72 ms0x320b00110010
92,81 msNACK
102,83 msSTOP
118,32 msSTART
128,32 ms0xba0b10111010
138,41 msACK
148,42 ms0x120b00010010
158,51 msACK
168,52 msSTOP
1710,86 msSTART
1810,87 ms0xba0b10111010
1910,96 msACK
2010,96 ms0x010b00000001
2111,06 msACK
2211,07 msSTOP
2314,90 msSTART
2414,90 ms0xba0b10111010
2514,99 msACK
2615,00 ms0x130b00010011
2715,09 msACK
2815,11 msSTOP
2917,45 msSTART
3017,45 ms0xba0b10111010
3117,54 msACK
3217,55 ms0x010b00000001
3317,64 msACK
3417,65 msSTOP
3519,99 msSTART
3620,00 ms0xba0b10111010
3720,09 msACK
3820,09 ms0x140b00010100
3920,19 msACK
4020,20 msSTOP
4122,54 msSTART
4222,55 ms0xba0b10111010
4322,64 msACK
4422,64 ms0xca0b11001010
4522,73 msACK
4622,75 msSTOP

 

part 1: IDE install and Build First Example
part 2: Mod the PCB for Power Measurement
part 3: Power Measurement
part 4a: Low Power Sensor design - Barometer Hardware
part 4b: Low Power Sensor design - Barometer i2c and Init
part 4c: Low Power Sensor design - Barometer, Not Yet Power Optimised
MAX32660 Evaluation Kit - part 5: FreeRTOS Example
side note A: C++ Eclipse Project
side note B: Create a Release Configuration