-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
I've been testing the PA1010D i2c GPS (happy to supply one to anyone who's got a head for mysteries) with the Pico, starting with CircuitPython and reducing down to a minimum amount of C++ SDK code to reproduce.
Long story short, it will stall hard after about one i2c read using Pico's hardware I2C.
Using either CircuitPython bitbangio
or the I2C PIO driver from the Pico Examples it will read perfectly happily and - indeed - in the same setup for testing this I've had valid GPS data pouring out using a CircuitPython example and bitbangio
in lieu of hardware i2c.
Works:
#include <stdio.h>
#include "pico/stdlib.h"
#include "pio_i2c.h"
#define PIN_SDA 4
#define PIN_SCL 5
int main() {
stdio_init_all();
PIO pio = pio0;
uint sm = 0;
uint offset = pio_add_program(pio, &i2c_program);
i2c_program_init(pio, sm, offset, PIN_SDA, PIN_SCL);
uint addr = 0x10;
while (1) {
int ret;
uint8_t rxdata[11];
ret = pio_i2c_read_blocking(pio, sm, addr, rxdata, 10);
rxdata[10] = '\n';
printf(rxdata);
sleep_ms(1000);
}
return 0;
}
Stalls:
#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
int main() {
stdio_init_all();
i2c_init(i2c0, 100 * 1000);
gpio_set_function(4, GPIO_FUNC_I2C);
gpio_set_function(5, GPIO_FUNC_I2C);
gpio_pull_up(4);
gpio_pull_up(5);
int addr = 0x10;
while (1) {
int ret;
uint8_t rxdata[11];
ret = i2c_read_blocking(i2c0, addr, rxdata, 10, false);
rxdata[10] = '\n';
printf(rxdata);
sleep_ms(1000);
}
return 0;
}
I've played with the i2c baud rate to no avail. The hardware i2c seems to inevitably get stuck in this loop:
do {
abort_reason = i2c->hw->tx_abrt_source;
abort = (bool) i2c->hw->clr_tx_abrt;
if (timeout_check) {
timeout = timeout_check(ts);
abort |= timeout;
}
} while (!abort && !i2c_get_read_available(i2c));
CircuitPython suggested that either Data or Clock was pulled low, preventing the detection of i2c pull-ups once this state is entered. Using C++ to sleuth this further suggests that SDA
is held low. It would seem to be the GPS itself that's entered a bad state and is holding SDA
low. Why Pico's hardware i2c would cause it to do this totally eludes me. Unplugging the GPS and re-inserting it seems to clear this state.
Weirder still. If I get the GPS into a bad state whereupon it's totally unresponsive to hardware I2C, running the PIO I2C example will get it working again. I've tried this a few times. It's... odd.
And. I'm baffled.