Description
Describe the bug
The sensors on this board, require an IO pin to be set high to enable the Pull up resistors on the Wire1 SCL/SDA pins, in addition, some if not
all of the sensors require another pin to be set high in order to enable those sensors.
With the MBED code base the initVariant does this with the code:
// Errata Nano33BLE - I2C pullup is controlled by the SWO pin.
// Configure the TRACEMUX to disable routing SWO signal to pin.
NRF_CLOCK->TRACECONFIG = 0;
// FIXME: bootloader enables interrupt on COMPARE[0], which we don't handle
// Disable it here to avoid getting stuck when OVERFLOW irq is triggered
nrf_rtc_event_disable(NRF_RTC1, NRF_RTC_INT_COMPARE0_MASK);
nrf_rtc_int_disable(NRF_RTC1, NRF_RTC_INT_COMPARE0_MASK);
// FIXME: always enable I2C pullup and power @startup
// Change for maximum powersave
pinMode(PIN_ENABLE_SENSORS_3V3, OUTPUT);
pinMode(PIN_ENABLE_I2C_PULLUP, OUTPUT);
digitalWrite(PIN_ENABLE_SENSORS_3V3, HIGH);
delay(10);
digitalWrite(PIN_ENABLE_I2C_PULLUP, HIGH);
// Set high drive pin to properly power the bmi150
nrf_gpio_cfg(
digitalPinToPinName(PIN_ENABLE_SENSORS_3V3),
NRF_GPIO_PIN_DIR_OUTPUT,
NRF_GPIO_PIN_INPUT_DISCONNECT,
NRF_GPIO_PIN_NOPULL,
NRF_GPIO_PIN_H0H1,
NRF_GPIO_PIN_NOSENSE);
In the zephyr setup, I know some of this is being handled:
In the file: zephyr\boards\nano_33_ble\arduino_nano_33_ble-common.dtsi, it has:
vdd_env: vdd-env {
compatible = "regulator-fixed";
regulator-name = "vdd_env";
enable-gpios = <&gpio0 22 GPIO_ACTIVE_HIGH>;
regulator-boot-on;
startup-delay-us = <5000>;
};
zephyr,user {
/* I2C pull-ups are connected to VDD via pin voltage level */
pull-up-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>;
};
Where: <&gpio0 22 GPIO_ACTIVE_HIGH> is the same as mbed PIN_ENABLE_SENSORS_3V3 and
<&gpio1 0 GPIO_ACTIVE_HIGH> - is the same as mbed PIN_ENABLE_I2C_PULLUP
I believe that the Pull up resistor IO pin as well as the USER/Power led is initialized in the function board_init,
which is contained in the file board.c which is in the same directory as the .dtsi mentioned above:
static int board_init(void)
{
int res;
static const struct gpio_dt_spec pull_up =
GPIO_DT_SPEC_GET(DT_PATH(zephyr_user), pull_up_gpios);
static const struct gpio_dt_spec user_led =
GPIO_DT_SPEC_GET(DT_ALIAS(led4), gpios);
if (!gpio_is_ready_dt(&pull_up)) {
return -ENODEV;
}
if (!gpio_is_ready_dt(&user_led)) {
return -ENODEV;
}
res = gpio_pin_configure_dt(&pull_up, GPIO_OUTPUT_HIGH);
if (res) {
return res;
}
return gpio_pin_configure_dt(&user_led, GPIO_OUTPUT_INACTIVE);
}
SYS_INIT(board_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
However I do not see anywhere that initializes the enable pin.
Note: my pr #50 adds the extra IO pins to the pin table to match MBED including:
<&gpio1 0 0>, /* D32 I2C_PULL */
<&gpio0 22 0>; /* D33 VDD_ENV_ENABLE */
To confirm some of this, I modified the ReadSensorsImperial (for temp and ...) to print out the state of the processors IO ports
at startup and was trying some code to see if I can get zephyr into same state:
/*
HS300x - Read Sensors Imperial
This example reads data from the on-board HS300x sensor of the
Nano 33 BLE Sense then, prints the temperature and humidity sensor
values in imeprial units to the Serial Monitor once a second.
The circuit:
- Arduino Nano 33 BLE Sense R2
This example code is in the public domain.
*/
#include <Arduino_HS300x.h>
void print_nrf_gpio(NRF_GPIO_Type *pX) {
Serial.print("\tOUT:"); Serial.print(pX->OUT, HEX);
Serial.print(" IN:"); Serial.print(pX->IN, HEX);
Serial.print(" DIR:"); Serial.print(pX->DIR, HEX);
Serial.print(" LATCH:"); Serial.print(pX->LATCH, HEX);
Serial.print(" DETECTMODE:"); Serial.print(pX->DETECTMODE, HEX);
for(uint8_t i = 0; i < 32; i++) {
if ((i & 0x7) == 0)Serial.print("\n\t");
Serial.print(pX->PIN_CNF[i]);
Serial.print(" ");
}
Serial.println();
}
void setup() {
Serial.begin(9600);
while (!Serial);
// BUGBUG: lets try to see the initial state of the pins:
// port0 0x50000000
// port1 0x50000300
Serial.println("\nGPIO P0 registers");
print_nrf_gpio(NRF_P0);
Serial.println("\nGPIO P1 registers");
print_nrf_gpio(NRF_P1);
#ifdef __ZEPHYR__
pinMode(32, OUTPUT); //I2C_PULL
digitalWrite(32, HIGH);
pinMode(33, OUTPUT); //VDD_ENV_ENABLE
digitalWrite(33, HIGH);
// Hack to set HIGH output on P1[22]
//uint32_t pin22_cnf = NRF_P0->PIN_CNF[22];
//pin22_cnf |= (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos);
NRF_P0->PIN_CNF[22] = 0x73; //pin22_cnf;
delay(500);
Serial.println("Registers after our modes");
Serial.println("\nGPIO P0 registers");
print_nrf_gpio(NRF_P0);
Serial.println("\nGPIO P1 registers");
print_nrf_gpio(NRF_P1);
#endif
Wire1.begin();
Wire1.setClock(400000);
if (!HS300x.begin()) {
Serial.println("Failed to initialize humidity temperature sensor!");
while (1);
}
Serial.println("Humidity temperature sensor initialized!");
}
void loop() {
// Passing in FAHRENHEIT as the unit parameter to ENV.readTemperature(...),
// allows you to read the sensor values in imperial units
float temperature = HS300x.readTemperature(FAHRENHEIT);
float humidity = HS300x.readHumidity();
// print each of the sensor values
Serial.print("Temperature = ");
Serial.print(temperature);
Serial.println(" °F");
Serial.print("Humidity = ");
Serial.print(humidity);
Serial.println(" %");
// print an empty line
Serial.println();
// wait 1 second to print again
delay(1000);
}
When I run this on MBED I see:
GPIO P0 registers
OUT:400000 IN:40000 DIR:402000 LATCH:0 DETECTMODE:0
2 2 2 2 2 2 2 2
2 2 2 2 2 3 2 2
2 2 2 2 2 2 771 2
2 2 2 2 2 2 2 2
GPIO P1 registers
OUT:209 IN:400 DIR:209 LATCH:0 DETECTMODE:0
3 2 2 3 2 2 2 2
2 3 0 2 2 2 2 2
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Humidity temperature sensor initialized!
Temperature = 66.38 °F
Humidity = 38.82 %
Temperature = 66.32 °F
Humidity = 38.72 %
From the processor manual which I downloaded from:
https://docs-be.nordicsemi.com/bundle/ps_nrf52840/attach/nRF52840_PS_v1.11.pdf?_LANG=enus
Pull up resistor: P1:0 - PIN_CNF[0] = 3
Page 349 - 3 -> DIR=OUTPUT, INPUT=Disconnect bit(0) of OUT is 1 so HIGH
Enable Pin: P0:22 PIN_CNF[22] = 0x771 Not 100% with bits here
but DIR=0x1 or OUTPUT
DRIVE= 0x70 - H0D1 - High drive High drive '0', disconnect '1' (normally used for wired-and connections)
SENSE = 0x700? - only two bits 11 LOW?, but only two bits... I think not connected...
Now if I run it with my Zephyr setup (with PR code mentioned), I see output of:
GPIO P0 registers
OUT:9010040 IN:8004C004 DIR:9012040 LATCH:0 DETECTMODE:0
2 2 1536 2 2 2 3 2
2 2 2 2 2 1 1536 1536
3 2 2 2 2 2 2 2
3 2 2 3 2 2 2 1536
GPIO P1 registers
OUT:700D IN:508 DIR:720F LATCH:0 DETECTMODE:0
3 3 3 3 2 2 2 2
0 3 0 2 3 3 3 2
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Registers after our modes
GPIO P0 registers
OUT:9410040 IN:8004C004 DIR:9412040 LATCH:0 DETECTMODE:0
2 2 1536 2 2 2 3 2
2 2 2 2 2 1 1536 1536
3 2 2 2 2 2 3 2
3 2 2 3 2 2 2 1536
GPIO P1 registers
OUT:700D IN:508 DIR:720F LATCH:0 DETECTMODE:0
3 3 3 3 2 2 2 2
0 3 0 2 3 3 3 2
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
Humidity temperature sensor initialized!
With this we see: P1:0 is PIN_CNF = 3 which is correct low bit set so HIGH...
However, the Enable pin P0:22 CNF=2 which is default INPUT but INPUT disconnected.
I tried some hacks to set the ENABLE to output, however my hack to try to set the CFG failed so far.
With out the code to set the enable high:
pinMode(33, OUTPUT); //VDD_ENV_ENABLE
digitalWrite(33, HIGH);
The Sensor would fail to initialize, and we loop forever.
With the code to enable it, it says the sensor was initialized, but then the board crashes. From Serial1 output I see:
[00:00:02.796,691] <err> os: ***** USAGE FAULT *****
[00:00:02.805,297] <err> os: No coprocessor instructions
[00:00:02.814,483] <err> os: r0/a1: 0x4287d6a7 r1/a2: 0x4050fad4 r2/a3: 0xa6666668
[00:00:02.826,446] <err> os: r3/a4: 0x10a1f5a8 r12/ip: 0x00000000 r14/lr: 0x2000badf
[00:00:02.838,378] <err> os: xpsr: 0x21000000
[00:00:02.846,496] <err> os: Faulting instruction address (r15/pc): 0x2000bade
[00:00:02.857,604] <err> os: >>> ZEPHYR FATAL ERROR 33: Unknown error on CPU 0
[00:00:02.868,682] <err> os: Current thread: 0x20001898 (main)
[00:00:02.878,265] <err> os: Halting system
uart:~$
So far two questions:
a) Who is supposed to initialize this pin.
b) How in zephyr do you set the CFG - Drive field of the CNF registers? As per the comment in the MBED init code:
// Set high drive pin to properly power the bmi150
Next up try to see where it is actually faulting.