![]() |
Forum Index : Microcontroller and PC projects : PicoMite Basic and PCF8523 RTC
Author | Message | ||||
Mark Regular Member ![]() Joined: 26/11/2022 Location: United StatesPosts: 85 |
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: AustraliaPosts: 2608 |
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 KingdomPosts: 4038 |
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 KingdomPosts: 7858 |
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 KingdomPosts: 4038 |
Oh. Kinda wish I'd not looked around the code now! John |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7858 |
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 StatesPosts: 85 |
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 KingdomPosts: 7858 |
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: AustraliaPosts: 2608 |
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: AustraliaPosts: 2608 |
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 StatesPosts: 85 |
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 StatesPosts: 85 |
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 KingdomPosts: 7858 |
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 |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |