element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Embedded and Microcontrollers
  • Technologies
  • More
Embedded and Microcontrollers
Blog C++ library for ST Teseo GPS - pt. 1: Pico and I2C support
  • Blog
  • Forum
  • Documents
  • Quiz
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Embedded and Microcontrollers to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Jan Cumps
  • Date Created: 13 Jul 2024 12:35 AM Date Created
  • Views 2115 views
  • Likes 8 likes
  • Comments 17 comments
  • Teseo
  • gps
  • OO
  • teseo_c++
Related
Recommended

C++ library for ST Teseo GPS - pt. 1: Pico and I2C support

Jan Cumps
Jan Cumps
13 Jul 2024

The Teseo-LIV3 GPS module (as used in shabaz ' GPS / Galileo / BeiDou / GLONASS receiver) talks UART and I2C. I'm writing an OO driver for it, for embedded systems.

goals:

  • Teseo lib code does not need to know what the target microcontroller is.
  • Teseo lib code does not need to know if the project uses I2C or UART
  • controller and protocol functionality is provided by the user's project code. It has to plug in a reader and writer function.

In this first blog, I created a project that runs on a Pico, and uses I2C. The Teseo code doesn't know that. In this initial version, it's able to get location info ( $GPGLL message). That's the scenario documented in ST's application note AN5203 Teseo-LIV3F - I2C Positioning Sensor. Every second I ask the GPS for the location, and it 'll return the raw $GPGLL NMEA string. That's enough for a first version.

Pico resources:

  • I2C0
  • SDA: GP16
  • SCL:  GP17
  • baud: 100 * 1000

Connections:

  • 5V to VBUS
  • 0V to GND
  • SDA to GP16
  • SCL to GP17

image

Software

The library has 1 class, teseo. It understands (a little part of) the Teseo command set and replies. For the communication, it relies on I2C functions that I provide. I'm reusing the Callback mechanism that I posted here.

image

The picture shows how the design uses dependency injection. The Testeo class can be used as-is on each microcontroller family. You give it (inject) the platform logic to read, write and reset.

I talk about reset here, but that's a subject for the next post, where I add that functionality.

teseo_iface.cpp

module;

// ...

export module teseo;

import callbackmanager;

export namespace teseo {

// ...

class teseo {
public:

public:
    Callback<void, const std::string&>& getWriteCallback() {
        return writer;
    }
    Callback<void, std::string&>& getReadCallback() {
        return reader;
    }

    void write(const std::string& s);
    void read(std::string& s);

    void ask_gpgll() {
        write(gpgll_msg);
    }



private:
    static const std::string gpgll_msg;

    Callback<void, const std::string&> writer;
    Callback<void, std::string&> reader;

};

} // namespace teseo

The interface is simple. It allows you to set the callback for the reader and writer function, and provides a low level read and write. The first "smart" function, ask_gpgll(), can report your current location.

teseo.c

module;

// ...

module teseo;

namespace teseo {

void teseo::write(const std::string& s) {
    writer.call(s);
}

void teseo::read(std::string& s) {
    reader.call(s);
}

} // namespace teseo

Because I delegate the device dependent (and protocol dependent) communication mechanism, the Teseo class itself can focus on the Teseo's protocol. Its only role is to keep the conversation going. It will grow in a next version, when I'll learn it to parse the $GPGLL answer, and maybe do some other things like returning time.

If you look back at this class, you'll see that there are 0 lines that rely on Pico's SDK or on I2C.

main.cpp

Here is where we use the library, and we build the hardware dependent logic. All Pico and I2C code is in the main file. First the I2C initialisation:

import teseo;
import port_pico_reset;
import port_pico_communicate;

#define I2C_PORT (i2c0)
#define I2C_BAUD (100 * 1000)
#define I2C_SDA (16)
#define I2C_SCL (17)
// #define I2C_ADDR (0x3A << 1)
#define I2C_ADDR (0x3A)

// ...

void initcomms () {
    // I2C is "open drain", pull ups to keep signal high when no data is being sent (not. board has pullups)
    i2c_init(I2C_PORT, I2C_BAUD);
    gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
    gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
    // gpio_pull_up(I2C_SDA);
    // gpio_pull_up(I2C_SCL);
}

Then the two callbacks for reading and writing:

void write(const std::string& s) {
    i2c_write_blocking(i2c_default, I2C_ADDR, reinterpret_cast<const uint8_t*>(s.c_str()), s.length() +1, false);
    return;  
}

void read(std::string& s) {
    uint8_t buf[180] = { 0 };
    // read in one go as register addresses auto-increment
    i2c_read_blocking(i2c_default, I2C_ADDR, buf, 180, false);
    // find first non 0xFF. That's the start
    auto iter_begin =  std::find(std::begin(buf), std::end(buf), '$');
    // find first 0xFF. That's the end
    auto iter_end =  std::find(iter_begin, std::end(buf), 0xff);
    s = std::string(iter_begin, iter_end);
    return;
}

There is some filtering needed. The reply sits "somewhere in the 180 character buffer". All other characters are 0xff. There are many ways to capture only the relevant data. Because I'm OO-designing, I decided to use one of the standard template library solutions.

in main(), I first setup the peripheral, and register the two callbacks:

teseo::teseo gps;

// ...

int main() {
    initcomms();

    gps.getWriteCallback().set([](const std::string& s) -> void {
        write(s);
    });

    gps.getReadCallback().set([](std::string& s) -> void {
        read(s);
    });

Then a loop that asks the location every second.

    while (true) {
        std::string s();
        gps.ask_gpgll();
        gps.read(s);
        sleep_ms(1000);
    }
}

The screen capture below shows that std::string s has the reply:

"$GPGLL,5051.80611,N,00422.57858,E,200736.000,V,N*4D\r\n"

image

Configure the Teseo as a position sensor:

warning: this changes the default behaviour of the Teseo-LIV3F IC.

By default, the Teseo sends a constant stream of various data via I2C. comparable to the output you see in @shabaz' blog. In this case, we want it to return only the data we're asking for. The ST application note shows the 3 commands you have execute to get this behaviour. You have to do it once before using the GPS (over UART, I2C or with Teseo-Suite). Alternatively, I could learn my lib to do that, but I prefer (at this moment) not to change the Teseo-LIV3F settings when running my example. To avoid getting angry comments in the blog.

$PSTMCFGMSGL,3,1,0,0
$PSTMSETPAR,1227,1,2
$PSTMSAVEPAR

(from the appnote:) This set of commands will:

  • Reset the i2c message list
  • Disable the eco-ing message
  • Save the configuration on flash

Now the Teseo-LIV3F is configured to support I2C Positioning Sensor.

If you want to get the default behaviour back, submit the command $PSTMRESTOREPAR.
In the next post, I will try to change the settings at startup anyways, but not persist them on the IC. It will then return to default after a reset or power cycle.

For reference:
Software manual
Application Note for I2C
Firmware details with commands list

This first version of the project is attached. The build directory contains the firmware .uf2 file. Thanks for reading.

pico_gps_teseo_i2c_20240713_02.zip

Next:  C++ library for ST Teseo GPS - pt. 2: Dynamic GPS configuration (and some other things) 
visit the github repository (git clone https://github.com/jancumps/pico_gps_teseo.git)
view the online documentation
Link to all posts.

  • Sign in to reply
  • Jan Cumps
    Jan Cumps 1 month ago in reply to Jan Cumps

    After the early 90s:

    • i got to learn someone, i didn't work out
    • i got to learn someone, i didn't work out (2)
    •  I started to date someone
    • I got engaged, I married
    • I had 3 children

      queue about 15 years

    • marriage got south
    • divorced
    • met girl A
    • met girl B
    • met my future fiancée
    • Kid 1 had relations. Bought house. Settles
    • Kid 2 had relations. Bought house. Settles
    • Kid 3 had relations. Bought house. Settles
    • I proposed and am engaged

    And here, we are still challenging C++ '98.

    The future is there for those who want to reap it.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps 1 month ago in reply to shabaz

    I can see why it's a "non-rule", since it almost encouraged people to cram things in to classes where it didn't make sense, rather than take the overhead to create (and version-control and document etc) new files!

    yes. A rule that overruled (sic) object oriented analysis and design principles.

    And once a rule is written down, it's hard to challenge it. Particularly when you are a consultant or a new employee.
    Because they have to challenge someone who's up the chain.

    It's a luxury when you are in a company where a rule is "up for challenge" for a good cause. Without ego hurt.

    Often, design rules owners are mature, and have been through the motions. That's a good thing. If they aren't stuck.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps 1 month ago in reply to shabaz

    Yes. 

    On the other side: every time I use C++, STL, Exceptions (or even a HAL or an RTOS) on a design here,
    the majority of the comments challenge that. Not the design I'm presenting.

    (and sometimes, what once was a pattern, later becomes an anti-pattern. Read: Singleton)

    It's human. We evolve. But there are things that will linger on forever. For nothing.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • Jan Cumps
    Jan Cumps 1 month ago in reply to genebren

    Most of these were relevant, and worth ruling.
    But the times move on.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • shabaz
    shabaz 1 month ago in reply to Jan Cumps

    Plus I suspect some things made better sense in the past, when people were just using editors or very basic IDEs. One side benefit of the one-class-per-file was that each file was named the single class name, so you'd just seek out in the file system the particular class you were interested in. I used to have a graphical tool to see which files were modified (I needed that for checking in the code too).

    Nowadays no-one would do that, since the IDE will locate your class definition and functions in a second.

    I can see why it's a "non-rule", since it almost encouraged people to cram things in to classes where it didn't make sense, rather than take the overhead to create (and version-control and document etc) new files!

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube