Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 12:44 11 Jul 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : PicoMite Basic and PCF8523 RTC

Author Message
Mark
Regular Member

Joined: 26/11/2022
Location: United States
Posts: 85
Posted: 04:05am 04 Jan 2025
Copy link to clipboard 
Print this post

I am trying to use an Adafruit PiCowbell AdaLogger with PicoMite Basic 6.0.01 on a Pico.

The Adalogger has a MicroSD card and a PCF8523 battery backed RTC. MMBasic doesn't have support for the PCF8523, but I thought I would try and write some code to access it using the RTC setreg and getreg commands. I can successfully write the date and time to the appropriate registers and read them back as long as the Pico is powered up. If I cycle the Pico's power, my code reads back garbage in the registers.  I have verified that the RTC works properly using CircuitPython.  After a quick look at the MMBASIC source code, I'm guessing that the built in RTC code is writing to the 8523's registers as part of its interrogation to see which RTC is installed. If this is the case, is there a way to disable the interrogation?  Or is there any way to use the PCF8523 without modifying the MMBASIC source code?

My idea would be to have some MMBASIC code run at startup to read the registers on the 8523 and set MMBASIC's clock. As the Adalogger is an inexpensive board that plugs directly into the Pico this would make a nice solution for data storage and time stamping.

Thanks,
Mark
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2608
Posted: 07:46am 04 Jan 2025
Copy link to clipboard 
Print this post

You may need to disregard the inbuilt RTC functions and write a Sub using I2C commands to write and read the registers.

To set the time in the RTC start by converting Time$ to numbers that can be sent over I2C.
eg.
Hours = Val(Left$(Time$,2))
Mins = Val(Mid$(Time$,4,2))
Secs = Val(right$(Time$,2))

To update the Pico time build a string from the I2C data from the RTC then use it to set the time.
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4038
Posted: 08:21am 04 Jan 2025
Copy link to clipboard 
Print this post

I'm a little surprised if MMBasic happens to cause trouble.

Looking at bits of code, the PCF8563 is at different I2C address(es) to the PCF8523 so I think that's not the problem.

However, the PCF8523 looks to use the same I2C addr as the DS1307 (which MMBasic supports).

It looks to use different registers, though.  You'd sort of expect that would mean the chip would ignore things for a DS1307 but ... maybe it does or doesn't?

Probably need some tests / data sheet reading... (sorry, not by me).

BTW I think the data logger is here

John
Edited 2025-01-04 18:22 by JohnS
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7858
Posted: 08:40am 04 Jan 2025
Copy link to clipboard 
Print this post

It's a pity they used the PCF8523 in a data logger. The DS3231 is *far* more accurate and temperature stable. The PCF8523 can lose or gain up to 2 seconds per day.

IMHO Phil's approach is the correct one. Don't attempt to use the MMBasic RTC support, create new routines for the DS3231. I certainly wouldn't recommend modifying MMBasic to add support for an inferior chip. Also, remember that you can't release modified versions of MMBasic without permission so even if you got it to work you may not be able to share that version.
.
Edited 2025-01-04 18:50 by Mixtel90
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 4038
Posted: 12:05pm 04 Jan 2025
Copy link to clipboard 
Print this post

  Mixtel90 said  The PCF8523 can lose or gain up to 2 seconds per day.

Oh.

Kinda wish I'd not looked around the code now!

John
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7858
Posted: 12:15pm 04 Jan 2025
Copy link to clipboard 
Print this post

I'd sacrifice a couple of pins to I2c and use one of the mini RTC modules with it.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
Mark
Regular Member

Joined: 26/11/2022
Location: United States
Posts: 85
Posted: 09:07pm 04 Jan 2025
Copy link to clipboard 
Print this post

I got it working

While the PCF8523 is not optimal, the PiCowbell ADALogger is an inexpensive and convenient way to add a SD card and RTC to a Pico. Just solder on headers and plug the Pico directly into it. No point to point wiring.

To get the SD Card portion working:
 OPTION SDCARD GP17,GP18,GP19,GP16

Don't do any OPTION SYSTEM I2C or MMBASIC will trash the PCF8523's time registers on boot.

I've attached a file with subroutines SetRTCTime and GetRTCTime

Call SetRTCTime year, month, day, hour, minute to set the RTC's time

Call GetRTCTime to set the system clock (date and time) with the RTC's time. This could be added to a startup routine to make it automatic.

Mark
PCF8523.bas.zip
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7858
Posted: 09:17pm 04 Jan 2025
Copy link to clipboard 
Print this post

Excellent news! :)
This could do to go in Fruit of the Shed (with a suitable explanatory note).
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2608
Posted: 09:26pm 04 Jan 2025
Copy link to clipboard 
Print this post

That will be very useful for anyone using that chip.
With your routines saved to the Library they effectively become part of MMBasic on the module.
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2608
Posted: 05:27am 05 Jan 2025
Copy link to clipboard 
Print this post

Mark, I hope you don't mind, I have tampered with your routines to allow the RTC to be updated from the MMBasic clock, if it has already been set.

Call SetRTCTime without any parameters and it will read Time$ and Date$ to set the RTC.
If you include the parameters it should work the same as before.
Added seconds also.
As I don't have a PCF8523 this is entirely untested.
' PCF8523 RTC chip routines for setting and reading the date and time.
' By @Mark on TBS
' https://www.thebackshed.com/forum/ViewTopic.php?FID=16&TID=17577#232042

Function ToBCD%(d%)
 Local i% = d% Mod 100
 ToBCD% = ((i% \ 10) << 4) + (i% Mod 10)
End Function

Function FromBCD%(b%)
 FromBCD% = (b% >> 4) * 10 + (b% And 15)
End Function

Function D2$(i%)
 D2$ = Format$(i%,"%02g")
End Function

Function DOW%(y%,mo%,d%)
 ' 0 = Saturday
 Local i% = y% Mod 100
 DOW% = (i% + (i% \ 4) + mo% + d% - 1) Mod 7
End Function

Sub OpenI2C
 SetPin GP4,GP5,I2C
 I2C Open 1000,1000
End Sub

Sub SetRTCTime y%,mo%,d%,h%,mi%,se%

 If y% = 0 and date$ <> "01-01-2024" Then 'use "01-01-2000" for old firmware
  y% = Val(Right$(Date$,4))
  mo% = Val(Mid$(Date$,4,2))
  d% = Val(Left$(Date$,2))
  h% = Val(Left$(Time$,2))
  mi% = Val(Mid$(Time$,4,2))
  se% = Val(Right$(Time$,2))
 EndIf

 Local seb% = ToBCD%(se%)
 Local mib% = ToBCD%(mi%)
 Local hb% = ToBCD%(h%)
 Local db% = ToBCD%(d%)
 Local dwb% = ToBCD%(DOW%(y%,mo%,d%))
 Local mob% = ToBCD%(mo%)
 Local yb% = ToBCD%(y%)
 Dim data%(7) = (3,seb%,mib%,hb%,db%,dow%,mob%,yb%)
 OpenI2C
 I2C Write &H68, 0, 8, data%()
 I2C Close
End Sub

Sub GetRTCTime
 Local data%(6), se%, mi%, h%, d%, mo%, y%
 OpenI2C
 I2C Write &H68, 0, 1, 3
 I2C Read &H68, 0, 7, data%()
 I2C Close
 se% = FromBCD%(data%(0) And 127)
 mi% = FromBCD%(data%(1) And 127)
 h% = FromBCD%(data%(2) And 127)
 d% = FromBCD%(data%(3) And 63)
 mo% = FromBCD%(data%(5) And 31)
 y% = FromBCD%(data%(6))
 Time$ = D2$(h%) + ":" + D2$(mi%) + ":" + D2$(se%)
 Date$ = D2$(y% + 2000) + "-" + D2$(mo%) + "-" + D2$(d%)
End Sub

End

Edited 2025-01-05 16:25 by phil99
 
Mark
Regular Member

Joined: 26/11/2022
Location: United States
Posts: 85
Posted: 10:41pm 05 Jan 2025
Copy link to clipboard 
Print this post

Thanks for the comments. Putting the code in the library and MM.STARTUP was my plan all along.  When putting code in the Library, I want to reduce identifiers, to reduce the possibility of conflict with user program identifiers, so I did a little rework on my code. I didn't consider setting the RTC time from the PicoMite clock because that's not likely to be a good reference for time.

I reworked the main GetRTCTime and SetRTCTime to be just one subroutine, which I named MM.Startup so it runs automatically, if it is called with no arguments (as when it runs at startup), it sets DATE$ and TIME$ from the PCF8523 RTC. If it is called with year, month, day, hour, minute it set the RTC's clock.

The attached code also shows my MM.Prompt subroutine adding the current working directory to the prompt.


Library.bas.zip

P.S. I have no idea if this is easy or not, but has there been any consideration of allowing local functions and subroutines within functions and subroutines so they are only visible within the outer routine, analogous to local variables?
 
Mark
Regular Member

Joined: 26/11/2022
Location: United States
Posts: 85
Posted: 10:41pm 05 Jan 2025
Copy link to clipboard 
Print this post

Thanks for the comments. Putting the code in the library and MM.STARTUP was my plan all along.  When putting code in the Library, I want to reduce identifiers, to reduce the possibility of conflict with user program identifiers, so I did a little rework on my code. I didn't consider setting the RTC time from the PicoMite clock because that's not likely to be a good reference for time.

I reworked the main GetRTCTime and SetRTCTime to be just one subroutine, which I named MM.Startup so it runs automatically, if it is called with no arguments (as when it runs at startup), it sets DATE$ and TIME$ from the PCF8523 RTC. If it is called with year, month, day, hour, minute it set the RTC's clock.

The attached code also shows my MM.Prompt subroutine adding the current working directory to the prompt.


Library.bas.zip

P.S. I have no idea if this is easy or not, but has there been any consideration of allowing local functions and subroutines within functions and subroutines so they are only visible within the outer routine, analogous to local variables?
 
Mixtel90

Guru

Joined: 05/10/2019
Location: United Kingdom
Posts: 7858
Posted: 11:00pm 05 Jan 2025
Copy link to clipboard 
Print this post

I would recommend that you don't call any of your own routines MM.STARTUP. They should be ordinary SUB and FUNCTION blocks. In this way anyone can use their own custom MM.STARTUP. You should put a call to your own SUB GetRTC or whatever in MM.STARTUP. Any other calls can then be added to it (or removed) as required without disturbing anything else.

SUB and FUNCTION blocks in the Library can still use LOCAL variables as usual so they don't clash with anything else.

MM.STARTUP is a bit special. You can only have one instance of it, so it makes sense not to clutter it up if at all possible.
Mick

Zilog Inside! nascom.info for Nascom & Gemini
Preliminary MMBasic docs & my PCB designs
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025