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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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
| Bus configuration | |
|---|---|
| SDA | Channel 1 |
| SCL | Channel 0 |
| Statistics | |
| Decoded bytes | 16 |
| Detected bus errors | 0 |
| Index | Time | Hex | Bin |
|---|---|---|---|
| 0 | -5,00 μs | START | |
| 1 | 500,00 ns | 0xba | 0b10111010 |
| 2 | 91,50 μs | ACK | |
| 3 | 96,00 μs | 0x10 | 0b00010000 |
| 4 | 187,00 μs | ACK | |
| 5 | 202,00 μs | START | |
| 6 | 207,00 μs | 0xbb | 0b10111011 |
| 7 | 2,72 ms | ACK | |
| 8 | 2,72 ms | 0x32 | 0b00110010 |
| 9 | 2,81 ms | NACK | |
| 10 | 2,83 ms | STOP | |
| 11 | 8,32 ms | START | |
| 12 | 8,32 ms | 0xba | 0b10111010 |
| 13 | 8,41 ms | ACK | |
| 14 | 8,42 ms | 0x12 | 0b00010010 |
| 15 | 8,51 ms | ACK | |
| 16 | 8,52 ms | STOP | |
| 17 | 10,86 ms | START | |
| 18 | 10,87 ms | 0xba | 0b10111010 |
| 19 | 10,96 ms | ACK | |
| 20 | 10,96 ms | 0x01 | 0b00000001 |
| 21 | 11,06 ms | ACK | |
| 22 | 11,07 ms | STOP | |
| 23 | 14,90 ms | START | |
| 24 | 14,90 ms | 0xba | 0b10111010 |
| 25 | 14,99 ms | ACK | |
| 26 | 15,00 ms | 0x13 | 0b00010011 |
| 27 | 15,09 ms | ACK | |
| 28 | 15,11 ms | STOP | |
| 29 | 17,45 ms | START | |
| 30 | 17,45 ms | 0xba | 0b10111010 |
| 31 | 17,54 ms | ACK | |
| 32 | 17,55 ms | 0x01 | 0b00000001 |
| 33 | 17,64 ms | ACK | |
| 34 | 17,65 ms | STOP | |
| 35 | 19,99 ms | START | |
| 36 | 20,00 ms | 0xba | 0b10111010 |
| 37 | 20,09 ms | ACK | |
| 38 | 20,09 ms | 0x14 | 0b00010100 |
| 39 | 20,19 ms | ACK | |
| 40 | 20,20 ms | STOP | |
| 41 | 22,54 ms | START | |
| 42 | 22,55 ms | 0xba | 0b10111010 |
| 43 | 22,64 ms | ACK | |
| 44 | 22,64 ms | 0xca | 0b11001010 |
| 45 | 22,73 ms | ACK | |
| 46 | 22,75 ms | STOP |


Top Comments
-
fmilburn
-
Cancel
-
Vote Up
+1
Vote Down
-
-
Sign in to reply
-
More
-
Cancel
Comment-
fmilburn
-
Cancel
-
Vote Up
+1
Vote Down
-
-
Sign in to reply
-
More
-
Cancel
Children