0

I'm trying to run example from Raspberry for attaching GPS PA1010D module to Pi Pico. Unfortunately I2C does not read any data. the function i2c_read_blocking returns PICO_ERROR_GENERIC. LED on GPS is flashing so it has a fix, so it should return data. When I connected MPU650 sensor via I2C to Pico it worked ok. Any ideas what's wrong?

Here is the full code:

/**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/i2c.h"
#include "string.h"

/* Example code to talk to a PA1010D Mini GPS module.
   This example reads the Recommended Minimum Specific GNSS Sentence, which includes basic location and time data, each second, formats and displays it.
   Connections on Raspberry Pi Pico board, other boards may vary.
   GPIO PICO_DEFAULT_I2C_SDA_PIN (On Pico this is 4 (physical pin 6)) -> SDA on PA1010D board
   GPIO PICO_DEFAULT_I2C_SCK_PIN (On Pico this is 5 (physical pin 7)) -> SCL on PA1010D board
   3.3v (physical pin 36) -> VCC on PA1010D board
   GND (physical pin 38)  -> GND on PA1010D board
*/

// ---GPS PA1010D
#define GPS_SDA_PIN 2
#define GPS_SCL_PIN 3
#define GPS_I2C i2c1

const int addr = 0x10;
const int max_read = 250;

#ifdef i2c_default

void pa1010d_write_command(const char command[], int com_length) {
    // Convert character array to bytes for writing
    uint8_t int_command[com_length];

    for (int i = 0; i < com_length; ++i) {
        int_command[i] = command[i];
        i2c_write_blocking(GPS_I2C, addr, &int_command[i], 1, true);
    }
}

void pa1010d_parse_string(char output[], char protocol[]) {
    // Finds location of protocol message in output
    char *com_index = strstr(output, protocol);
    int p = com_index - output;

    // Splits components of output sentence into array
    int no_of_fields = 14;
    int max_len = 15;

    int n = 0;
    int m = 0;

    char gps_data[no_of_fields][max_len];
    memset(gps_data, 0, sizeof(gps_data));

    bool complete = false;
    while (output[p] != '$' && n < max_len && complete == false) {
        if (output[p] == ',' || output[p] == '*') {
            n += 1;
            m = 0;
        } else {
            gps_data[n][m] = output[p];
            // Checks if sentence is complete
            if (m < no_of_fields) {
                m++;
            } else {
                complete = true;
            }
        }
        p++;
    }

    // Displays GNRMC data
    // Similarly, additional if statements can be used to add more protocols 
    if (strcmp(protocol, "GNRMC") == 0) {
        printf("Protcol:%s\n", gps_data[0]);
        printf("UTC Time: %s\n", gps_data[1]);
        printf("Status: %s\n", gps_data[2][0] == 'V' ? "Data invalid. GPS fix not found." : "Data Valid");
        printf("Latitude: %s\n", gps_data[3]);
        printf("N/S indicator: %s\n", gps_data[4]);
        printf("Longitude: %s\n", gps_data[5]);
        printf("E/W indicator: %s\n", gps_data[6]);
        printf("Speed over ground: %s\n", gps_data[7]);
        printf("Course over ground: %s\n", gps_data[8]);
        printf("Date: %c%c/%c%c/%c%c\n", gps_data[9][0], gps_data[9][1], gps_data[9][2], gps_data[9][3], gps_data[9][4],
               gps_data[9][5]);
        printf("Magnetic Variation: %s\n", gps_data[10]);
        printf("E/W degree indicator: %s\n", gps_data[11]);
        printf("Mode: %s\n", gps_data[12]);
        printf("Checksum: %c%c\n", gps_data[13][0], gps_data[13][1]);
    }
}

void pa1010d_read_raw(char numcommand[]) {
    uint8_t buffer[max_read];

    int i = 0;
    bool complete = false;

    int bytesRead = i2c_read_blocking(GPS_I2C, addr, buffer, max_read, false);

    // Convert bytes to characters
    if(bytesRead == PICO_ERROR_GENERIC)
    {
        printf("PICO_ERROR_GENERIC, bytes= %d \n", bytesRead);
    }
    else
    {
        while (i < bytesRead && complete == false) {
            numcommand[i] = buffer[i];
            printf("---raw data [ %d ]: %s \n", i, numcommand[i]);
            // Stop converting at end of message 
            if (buffer[i] == 10 && buffer[i + 1] == 10) {
                complete = true;
            }
            i++;
        }
    }

}

#endif

int main() {
    stdio_init_all();
    puts("Default I2C pins were not defined");

    char numcommand[max_read];

    // Decide which protocols you would like to retrieve data from
    char init_command[] = "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n";

    // This example will use I2C0 on the default SDA and SCL pins (4, 5 on a Pico)
    i2c_init(i2c_default, 400 * 1000);
    gpio_set_function(GPS_SDA_PIN, GPIO_FUNC_I2C);
    gpio_set_function(GPS_SCL_PIN, GPIO_FUNC_I2C);
    gpio_pull_up(GPS_SDA_PIN);
    gpio_pull_up(GPS_SCL_PIN);

    // Make the I2C pins available to picotool
    bi_decl(bi_2pins_with_func(GPS_SDA_PIN, GPS_SCL_PIN, GPIO_FUNC_I2C));

    printf("Hello, PA1010D! Reading raw data from module...\n");

    pa1010d_write_command(init_command, sizeof(init_command));

    while (1) {
        // Clear array
        memset(numcommand, 0, max_read);
        // Read and re-format
        pa1010d_read_raw(numcommand);
        pa1010d_parse_string(numcommand, "GNRMC");

        // Wait for data to refresh
        sleep_ms(1000);

        // Clear terminal 
        // printf("\e[1;1H\e[2J");
    }
    return 0;
}

EDIT: I also tried this GPS with Arduino. I ran example GPS_I2C_EchoTest form Adafruit's library and the same result, nothing received from GPS. I used code snipped to detect addresses of any device connected to Pico via I2C and it detects that GPS is connected and its address.


EDIT 2: It has started to work :) I'm not sure what was the problem. I changed the wires and connected to different I2C pins on Pico.

Dominik
  • 25
  • 5
  • Just a guess ... From: https://www.mouser.com/datasheet/2/737/adafruit_mini_gps_pa1010d_module-2489873.pdf page 8 (re. SCL/SDA): _These pins have **10K pullups** to Vin. They are level shifted so you can use 3 or 5V logic_ So, do you [still] want to do: `gpio_pull_up(GPS_SDA_PIN); gpio_pull_up(GPS_SCL_PIN);` ??? Are you [doubly] sure about the wiring of `VIN/GND/SCL/SDA`? Note that the module also supports UART (at 9600 baud). Getting that working first might help? – Craig Estey Aug 21 '22 at 18:18
  • 1
    The existing code will output the EOS (0x00) string terminator after the newline. Change `pa1010d_write_command(init_command, sizeof(init_command));` into `pa1010d_write_command(init_command, strlen(init_command));`. – Craig Estey Aug 21 '22 at 18:21
  • @CraigEstey I'm using different module, this one https://shop.pimoroni.com/products/pa1010d-gps-breakout?variant=32257258881107 It does not support UART (unless I miss something). I'll remove the `gpio_pull_up(GPS_SDA_PIN); gpio_pull_up(GPS_SCL_PIN);` and try again. Maybe I will also try with Arduino Nano, to check if the module works. – Dominik Aug 21 '22 at 18:46
  • 1
    All these SDK boards seem to be based on the `MTK3333` chip. The _chip_ has UART even if the board doesn't break it out to a pin. Here's one that gives more detail on the low level i2c process: https://manuals.plus/m/a8d5d131175f1f525104da3a3178d6c9119956f05607f0ccd31c1cf8280a53a9 – Craig Estey Aug 21 '22 at 19:41
  • I returned from travel and started working on this again. @CraigEstey removing `gpio_pull_up(GPS_SDA_PIN); gpio_pull_up(GPS_SCL_PIN)` did not help. I also tried it on Arduino, with example GPS_I2C_EchoTest form Adafruit's [library](https://github.com/adafruit/Adafruit_GPS) and the same result, nothing received from GPS. I used code snipped to detect addresses of any device connected to Pico via I2C and it detects that GPS is connected and it's address. – Dominik Sep 02 '22 at 17:08

0 Answers0