Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for RTC in M2M: Hardware #29

Closed
sy2002 opened this issue Nov 2, 2023 · 19 comments
Closed

Add support for RTC in M2M: Hardware #29

sy2002 opened this issue Nov 2, 2023 · 19 comments
Assignees
Labels
enhancement New feature or request V2.0.0

Comments

@sy2002
Copy link
Owner

sy2002 commented Nov 2, 2023

@MJoergen Please decide if you want to do this in 5.1 (then the existing label "R4/R5 Surge" is correct - or not, then delete that label).

Adding support for RTC in M2M makes sense because:

  1. Multiple cores can make use of an RTC: C64 core (GEOS), ZX Uno (currently outputs an error due to missing RTC when booting), the PC 486 core from MiSTer...

  2. The firmware can make use of the RTC and make sure that files on the SD card (FAT32) that are written to/changed (for example disk images) are showing the updated date/time: Add support for RTC in M2M: Firmware #30 (The firmware part is not a long hanging fruit for the R4/R5 surge, but maybe the hardware part is.)

  3. We need to abstract away the details of the different RTCs in R3/R3A vs. R4/R5 and even the fixed RTC for R3/R3A which uses a PMOD connector. So there are three RTCs as of now that we need to support.

@sy2002 sy2002 added enhancement New feature or request V2.0.0 labels Nov 2, 2023
@sy2002 sy2002 changed the title Add support for RTC in M2M Add support for RTC in M2M: Hardware Nov 2, 2023
@MJoergen
Copy link
Collaborator

MJoergen commented Nov 2, 2023

Here is the datasheet for the RTC in R4/R5: https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-3032-C7_App-Manual.pdf .

Notes from the datasheet:

  • This particular device does not perform clock stretching, meaning that (from the perspective of the RTC), the SCL is input only.
  • The information is transmitted byte-wise and each receiver acknowledges with a ninth bit.

For more details, see Chapter 6 pages 121-126

@MJoergen
Copy link
Collaborator

MJoergen commented Nov 2, 2023

The interface to the core is via the C64 cassette port.

@MJoergen
Copy link
Collaborator

MJoergen commented Nov 2, 2023

Question: Should we poll the RTC regularly, or should we just read it once after power-on? Surely the crystal oscillator on the MEGA65 is accurate enough for time keeping while the MEGA65 is turned on.

@sy2002 sy2002 removed the V2.0.0 label Nov 2, 2023
@MJoergen
Copy link
Collaborator

MJoergen commented Dec 16, 2023

The following is a description of what I intend to implement. In other words, this describes the interface to the QNICE CPU (firmware). This is all part of the QNICE device number 0x0006 (C_DEV_RTC defined in M2M/vhdl/qnice_wrapper.vhd).

This entity contains a free-running internal timer, running independently of the                                                   
external RTC. The internal timer can be stopped and started, and can be set (when
stopped). Furthermore, when internal timer is stopped, the date/time can be copied
between the internal timer and the external RTC.

Address | Data
0x7000  | Hundredths of a second (BCD format, 0x00-0x99)
0x7001  | Seconds                (BCD format, 0x00-0x60)
0x7002  | Minutes                (BCD format, 0x00-0x59)
0x7003  | Hours                  (BCD format, 0x00-0x23)
0x7004  | DayOfMonth             (BCD format, 0x01-0x31)
0x7005  | Month                  (BCD format, 0x01-0x12)
0x7006  | Year since 2000        (BCD format, 0x00-0x99)
0x7007  | DayOfWeek              (0x00 = Monday)
0x7008  | Command                (bit 0 : RO : I2C Busy)
                                 (bit 1 : RW : Copy from RTC to internal)
                                 (bit 2 : RW : Copy from internal to RTC)
                                 (bit 3 : RW : Internal Timer Running)

Addresses 0x7000 to 0x7007 provide R/W access to the internal timer.

The Command byte (address 0x08) is used to start or stop the internal timer, and to
synchronize with the external RTC.  Any changes to the internal timer are only allowed
when the internal timer is stopped. So addresses 0x00 to 0x07 are read-only, when the
internal timer is running.
The protocol for synchronizing with the RTC is as follows:
1. Stop the internal timer by writing 0x00 to Command.
2. Read from Command and make sure value read is zero (otherwise wait).
3. Write either 0x02 (read from RTC) or 0x04 (write to RTC) to the command byte.
4. Read from Command and wait until value read is zero. (Note: The I2C transaction
   takes approximately 1 millisecond to complete).
5. Start the internal timer by writing 0x08 to Command.
Optionally, you may use auto-start in step 3 above by writing 0x0A or 0x0C. This
will automatically re-start the internal timer right after the I2C transaction is
complete, so that step 5 can be skipped.
Note: The Command byte automatically clears, when the command is completed. Reading
from the Command byte gives the status of the current command.

@sy2002
Copy link
Owner Author

sy2002 commented Dec 16, 2023

@MJoergen Sounds good. So the intend is to use this timer as the actual data source for all possible cores, independent of the actual RTC? Like this timer being a "cache" for us not needing to talk via I2C all the time? And then from time to time use command bit 1 to sync for example every 1 second or so? And maybe even offer a menu item in the OSM where the user can adjust the RTC via command bit 2 (without the need of using the MEGA65's setup menu?) And in the C64's case then the MiSTer F83 RTC implementation (MJoergen#103) always uses this timer instead of directly accessing the RTC?

@MJoergen
Copy link
Collaborator

@MJoergen Sounds good. So the intend is to use this timer as the actual data source for all possible cores, independent of the actual RTC? Like this timer being a "cache" for us not needing to talk via I2C all the time? And then from time to time use command bit 1 to sync for example every 1 second or so? And maybe even offer a menu item in the OSM where the user can adjust the RTC via command bit 2 (without the need of using the MEGA65's setup menu?) And in the C64's case then the MiSTer F83 RTC implementation (MJoergen#103) always uses this timer instead of directly accessing the RTC?

Exactly! This internal timer is meant as an abstraction. Basically, hide all the various board specific variants, and instead provide a generic interface.

@MJoergen
Copy link
Collaborator

No need to periodically sync from external RTC to internal RTC. The accuracy is good enough to be less than 1 second within 24 h. I suggest a menu item where the user can manually choose a "sync from external RTC" if he/she so chooses.

@MJoergen
Copy link
Collaborator

Note: The description in #29 (comment) has been updated.

This can now been tested in hardware as follows:

MC FFF4 0006 -> Select RTC device
MD 7000 7008 -> Dump current time
MC FFF4 0006 -> Select RTC device
MC 7008 0000 -> Stop timer, enable writing
MC 7000 xxxx -> Set new timer value
...
MC 7007 xxxx -> etc.
MC 7008 000C -> Copy new timer value to RTC and start internal timer

Power cycle machine.

MC FFF4 0006 -> Select RTC device
MD 7000 7008 -> Dump current time

@MJoergen
Copy link
Collaborator

This is verified in the C64 repo in commit 111feea.

@sy2002 sy2002 assigned sy2002 and unassigned MJoergen Jan 1, 2024
@sy2002 sy2002 reopened this Jan 1, 2024
@sy2002
Copy link
Owner Author

sy2002 commented Jan 1, 2024

Self assigned to test on my R3 machine:

  • Need to add battery before test - and need to ensure that clock ticks at all using the MEGA65 core
  • Need to update sysdef.asm for new device

@sy2002
Copy link
Owner Author

sy2002 commented Jan 5, 2024

@MJoergen Not sure if I am doing everything correctly. The date / time that I have set on my MEGA65 is:

6th of January 2023 (sic!)
16:22 (or a few minutes/seconds later)

When doing this here:

MC FFF4 0006 -> Select RTC device
MD 7000 7007 -> Dump current time

I am receiving:

0027 0050 0024 0096 0006 0001 0023 0003 

If I decode correctly, then the DATE is correct: 6th of January 2023
Second 50 and Minute 24 seems reasonable, but hour 96 does not.
Also the day of week is not correct as the 6th of January 2023 (sic!) was a Friday.

I am stopping here. We can do this test together during our next Skype chat.

@lydon42
Copy link
Collaborator

lydon42 commented Jan 5, 2024

For R3 RTC 0x96 is BCD 16 and highest bit 7 set == 24h mode (MIL as in military time).

The MEGA65 currently converts this in mega65-libc, the VHDL just transfers the data over I2C to the RTC. Perhaps it is a good idea to let the M2M framework handle this and only expose 24h time to the cores via the framework?

2024-01-05_155749_052190393

Note: in 12h mode 0x31 would be 11am!

@MJoergen
Copy link
Collaborator

MJoergen commented Jan 6, 2024

Thanks @sy2002 for the test and @lydon42 for the hint. That behavior is indeed unintended. I will fix the VHDL to only expose pure 24-hour format.

It turns out reading the spec that there is another bug as well:
image
So I need to set this bit before updating the RTC, and clear it again afterwards.

@MJoergen MJoergen assigned MJoergen and unassigned sy2002 Jan 6, 2024
@sy2002 sy2002 added the V2.0.0 label Jan 6, 2024
MJoergen added a commit that referenced this issue Jan 7, 2024
This addresses issue #29
@MJoergen
Copy link
Collaborator

MJoergen commented Jan 7, 2024

Please retest

@MJoergen MJoergen removed their assignment Jan 7, 2024
@sy2002
Copy link
Owner Author

sy2002 commented Jan 13, 2024

@MJoergen ❌ Test failed:

  • I used commit 42ac705 (M2M framework, develop branch) to test.
  • I ran the MEGA65 core before to confirm the date/time: 14th of January 2023, 13:50:00 (which is "correct", this is the date/time I deliberately set)
  • Here is the output of the MMIO-dump, which is worse than last time, where at least the date was decoded correctly:
grafik

@sy2002 sy2002 assigned MJoergen and unassigned sy2002 Jan 13, 2024
@MJoergen
Copy link
Collaborator

I believe the problem is that the RTC chip is accessed immediately after power-on, and that it sometimes won't respond. I can't find any information in the datasheet on when the RTC is ready after power-on, so now I'm trying with a 200 ms delay after power-on.

@MJoergen
Copy link
Collaborator

Well, that didn't help. I still sometimes get a "NACK" on the I2C transaction to the RTC chip.

@MJoergen
Copy link
Collaborator

@sy2002 : Fixed in commit e8bfed6. Please try again.

@MJoergen MJoergen assigned sy2002 and unassigned MJoergen Jan 13, 2024
@sy2002
Copy link
Owner Author

sy2002 commented Jan 14, 2024

✅ SUCCESS

Here is what I did:

  1. Synthesized newest M2M framework for R3 using commit ae5c109
  2. Boot the MEGA65 core and get the "current time": 15.1.2023, 16:43:34 (which is obviously not correct, but intentional)
  3. Boot the M2M framework and dump the current date/time using MMIO: ✅ CORRECT
  4. Use the above-mentioned command to set the date/time to the current date time (14.1.2024, 15:54:00 and day of week 6)
  5. Power-Cycle and boot the MEGA65 core to see if the MEGA65's start screen shows the date/time that I set: ✅ CORRECT
  6. Now load the M2M framwork demo core again and use the QMON> debug console to dump $7000 to $7007 to see if date/time is correct here to: ✅ CORRECT

I did only test this cycle here once. Olivier's RTC is not working so we cannot ask him to do this test.

I tend to believe that your "retry" fix works and therefore I am closing this and will merge the fix into the C64, so that I can start testing this in GEOS.

@sy2002 sy2002 closed this as completed Jan 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request V2.0.0
Projects
None yet
Development

No branches or pull requests

3 participants