Serial Monitor is printing garbage instead of what I want (RPI Pico & PCF8563)

Hi everyone !

Here’s the project : I’m trying to drive a PCF8563 with I2C 1 on pins 14 & 15
Working:

  • I2C Communication, signals are OK on scope
  • Firmware compilation & upload

Not working:

  • Serial Monitor, as in the title (see screenshot below)
    image

main.cpp

#include <Arduino.h>
#include "RTC.h"

RTC rtc; //this is a custom class

void setup() {
  Serial.begin(9600);
  rtc.begin(5000);
  rtc.setCLKOUTFreq(RTC::CLKOUT_FREQ::F1024);
}

void loop() {
  delay(1000);
  int seconds = rtc.getSeconds();
  Serial.println("Second : " + seconds);
}

platformio.ini

[env:pico]
platform = raspberrypi
board = pico
framework = arduino
build_flags = -std=gnu++17
build_unflags = -std=gnu++11
monitor_speed = 9600

RTC.cpp

#include "RTC.h"
#include <Wire.h>

#define PCF8563address 0x51

#define WIRE1_SDA 14
#define WIRE1_SCL 15
MbedI2C Wire1(WIRE1_SDA, WIRE1_SCL);

const byte CLKOUT_REGISTER_ADDRESS = 0x0D;
const byte SECONDS_REGISTER = 0x02;

const uint32_t SCL_FREQ = 400000;

RTC::RTC(){}

RTC::~RTC(){
    Wire1.end();
}

void RTC::begin(unsigned long timeoutMs){
    Wire1.begin();
    Wire1.setTimeout(timeoutMs);
    Wire1.setClock(SCL_FREQ);
}

uint8_t RTC::setCLKOUTFreq(RTC::CLKOUT_FREQ freq){
    Wire1.beginTransmission(PCF8563address);

    int bytesWritten = Wire1.write(CLKOUT_REGISTER_ADDRESS);
    bytesWritten += Wire1.write(0x80 + freq);
    Serial.println(bytesWritten + " written bytes");

    return Wire1.endTransmission();
}

uint8_t RTC::getSeconds(){
    Wire1.beginTransmission(PCF8563address);
    Wire1.write(SECONDS_REGISTER);
    Wire1.endTransmission();

    Wire1.requestFrom(PCF8563address, 1);
    int secBcd = Wire1.read() & 0x7F;
    return bcdToDec(secBcd);
}

uint8_t RTC::bcdToDec(uint8_t bcd){
    uint8_t u = bcd & 0x0F;
    uint8_t d = (bcd & 0xF0) * 10;
    return u + d;
}

uint8_t RTC::decToBcd(uint8_t dec){
    uint8_t u = dec % 10;
    uint8_t d = (dec - u) / 10;
    return u | (d << 4);
}

Tried these solutions but it changed NOTHING :frowning_with_open_mouth:

  • In Serial Monitor outputs unreadable characters topic
  • Match baud on .ini and Serial.begin (also tried (baud in .ini)/4 in Serial.begin and (baud in Serial.begin)/4 in .ini)
  • Put monitor_flags = --raw(but doens’t exists in my case)
  • Put monitor_filters = direct
  • Set explicitly the flash speed
  • Change Serial to Serial1 (and SerialUSB)
  • Moving the delay to between I2C operation and Serial.println
  • Added a second delay like this :
  int seconds = rtc.getSeconds();
  delay(500);
  Serial.println("Second : " + seconds);
  delay(500);

All of that just for showing seconds to test reading values from the PCF8563 chip :frowning_with_open_mouth:
I confirm that I endTransmission with stop bit after each writing operation

Any other ideas to solve this once and for all? (literally for all, this time)
PS: each of these solutions change garbage output a little bit, but it’s still garbage
PS 2: this problem and the SUPER SLOW compilation time (20 seconds to 2 minutes) are getting me out of patience, so I apologize for any misbehavior I may have

Change this to an explicit

Serial.println("Second : " + String(seconds));

since seconds is of type int, it can also be interepreted as: "write the string "Second: ", but with the start index being forwarded by seconds bytes.

So, as seconds increases, it starts printing at the later parts of the string.

You want to print seconds as a String, convert it explicitly to String.

Well, that was … just that :expressionless: (I am complete idiot… or not at all because C# does the implicit string conversion and not the crappy start index forward operation as you mentioned, so switching to C++ was challenging)

Thanks anyway :smile:

C/C++ is very focused on pointers. Writing "ABCDEF" creates a const char[], not an Arduino String object in the first place. Which is also a const char*. And a const char* ptr “+” int num is defined as forwarding a pointer by num elements (with char being usually 1 byte). Forwarding a pointer by n elements is an extremely common and often needed operation in C/C++, where we often work on raw pointers and memory, so I wouldn’t call it weird. C# is different in that regard, there, that character sequence is a UTF16 string directly.

Once the right side of the expression is fixed to String though, then the constructor for String(const char*) also kicks in, evaluating the while thing as String + String, which is then implemented as string concatination.

See: