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