6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 12:27 am

All times are UTC




Post new topic Reply to topic  [ 13 posts ] 
Author Message
PostPosted: Thu Apr 30, 2020 1:50 pm 
Offline

Joined: Fri Jan 25, 2019 2:29 pm
Posts: 193
Location: Madrid, Spain
Hi all,

Let's say you have a SBC with a variable clock frequency. Let's also say you have a (not so perfect) RTC, in the form of a 6526 with its TOD registers, so you can measure time with 0.1s precision.

You also have 4 16 bit timers (2 on the 6526, 2 on the 6522). Unfortunately, there's no easy way to chain both devices, although there may be a way if needed. Still, with a 32bit counter, we can count up to 4Billion PHI2 ticks.

Now, there are some delays I need to program in my firmware, and until now, I'm stuck at 1MHz so I can have this delay to be pretty much constant, no need to adjust for different speeds.

I'd like to be able to measure the clock speed, so I can tune this delay to the current speed.

The first thing that comes into my mind... Set TOD to a known value, start a 32 bit counter combining 2 of the timers. Set a TOD alarm n seconds later and, depending on the value of the counter/timer, we can infer the clock speed.

It seems doable, but this may be the most complicated thing I've ever tried on assembly... Mostly because I haven't tried many things of course.

I'm going to start working on it this weekend, so I'm not looking for a solution, but I wanted to hear other people's approaches to this problem.

Oh! One last thing. Yes, a real 6526 won't go too fast anyway. All the spares I have are not even the 6526A rated for 2Mhz, but I hope this will :)

Cheers!


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 30, 2020 2:17 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
I would think the RTC would be pretty stable, and while the readout is quantised, the time between two ticks should be pretty reliable. So, maybe
- check the time
- set an interrupt in the near future
- when it fires, zero your free-running counters, or capture the value, and set a new interrupt in the new near future
- when it fires, read off the number of ticks.

So the whole thing could be done within 0.2 seconds. You could even run a software counter between the two interrupts, and that would measure the CPU clock speed without using the timers at all.


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 30, 2020 2:58 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Here's an idea you may find interesting, although it's clearly a tradeoff. Instead of the RTC, your timebase could be the mains frequency (50 or 60 Hz, depending on your location). Assuming you're on the grid you'll find these to be fairly accurate, although they fall short of laboratory precision (especially on occasions when the grid is being stressed by a large scale upset).

1/60 of a second is 16 666 microseconds -- which means a single 16-bit counter would do; there'd be no need to cascade multiple timers.

OTOH you'd need some extra circuitry to make the mains frequency visible to the SBC. That'll be inconvenient to arrange if the SBC's DC comes from an enclosed power supply such as a wall wart, but quite easy to arrange if you have access to the low-voltage side of a step-down transformer -- just some simple signal conditioning, and the result feeds one bit of an input port on the SBC.

Conceivably, the signal could also be used as part of a power-fail detection scheme. Or for experiments to compare the stability of the grid with that of the RTC... ? :roll: Dunno. But it'd give you one more timing reference to play with. :)

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 30, 2020 3:48 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Here's a thought: you can run two 16 bit counters with different terminal counts, and then with a bit of arithmetic figure out what the total time is. So if one counts down from 65535 and the other from 65521 you end up with very nearly 32 bits of range, because the two numbers share no prime factors...


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 30, 2020 5:20 pm 
Offline
User avatar

Joined: Sat Dec 01, 2018 1:53 pm
Posts: 730
Location: Tokyo, Japan
Dr Jefyll wrote:
Here's an idea you may find interesting, although it's clearly a tradeoff. Instead of the RTC, your timebase could be the mains frequency (50 or 60 Hz, depending on your location)....
OTOH you'd need some extra circuitry to make the mains frequency visible to the SBC. That'll be inconvenient to arrange if the SBC's DC comes from an enclosed power supply such as a wall wart, but quite easy to arrange if you have access to the low-voltage side of a step-down transformer -- just some simple signal conditioning, and the result feeds one bit of an input port on the SBC.

If you're using a 6526 CIA with a working RTC, you already have a 50 Hz or 60 Hz signal on your board that's exactly as reliable as the RTC: it's whatever you're putting into the 6522's TOD pin. :-)

The Commodore 64 indeed drove that pin from wall frequency (taken from the 9 VAC supplied by the PSU), which is why programmers who mistakenly assume that NTSC systems all run on 60 Hz power end up slowing down time in Tokyo as compared to Osaka. (Japan has a split power grid; here in the east where I am we run on 50 Hz but over in the west they use 60 Hz. And yes, there are some massive high-voltage DC lines in the middle of the country.)

On the board in question the TOD signal appears to be generated by the Arduino Nano; I don't know what the software in there is doing though.

At any rate, if my brain is working correctly (dubious: it's 2 a.m. here) it seems to reduce to the same problem either way, except that if you read the TOD clock from the 6522 you have only 100 ms resolution rather than 16.66 or 20 ms resolution. But that simply means that it will take you longer (up to 200 ms) to figure out your current clock frequency, right? Basically, you just poll the tenths-of-a-second register until it changes, then start incrementing a counter while polling that register until it changes again. There's no need to increment your counter for every clock cycle, so long as every increment takes a fixed number of clock cycles. I guess that could be a bit tricky to program, come to think of it, since you'll definitely need more than eight bits, so you need to ensure that you use the same number of cycles regardless of how many or few bytes through which you propagate the carry. But maybe not: just always propagate the carry the same way with ADC #0 instructions.

_________________
Curt J. Sampson - github.com/0cjs


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 30, 2020 6:39 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8544
Location: Southern California
daniMolina wrote:
You also have 4 16 bit timers (2 on the 6526, 2 on the 6522). Unfortunately, there's no easy way to chain both devices, although there may be a way if needed. Still, with a 32bit counter, we can count up to 4Billion PHI2 ticks.

With the 6522, you can make a free-running T1 toggle PB7 on each time-out, then run that into PB6 and use it to trigger T2; so there's a way to get a 32-bit timer.

In the 6502 interrupts primer, I show code for an NMI-driven RTC, here. You could set that up, and see how it compares to a reliable time source. If you want the code a whole lot shorter, you can omit the part that watches for carrying at 60 seconds, 60 minutes, 24 hours, day of month, etc., and just go with the 32-bit count of centiseconds.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 30, 2020 7:27 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Any timing source that's independent of the CPU clock can be used for this. One convenient example might be the NXP UARTs, which have internal timers driven by the UART clock, which is typically a standard value for easy baud generation. You can compare the rates at which these timers run relative to one driven by the CPU clock, eg. in a 6522.


Top
 Profile  
Reply with quote  
PostPosted: Thu Apr 30, 2020 10:13 pm 
Offline

Joined: Fri Jan 25, 2019 2:29 pm
Posts: 193
Location: Madrid, Spain
Nice to see that, each one with his own variations, but I think the general idea is the same... which was somewhat expected. Compare clock ticks against a known time source.

I forgot to mention, the main obstacle here is that the SBC is already built and running, and this has been an afterthought... that's why I said there was no straightforward way of linking 6526 and 6522 timers.

I do have a 60/50 hz signal on the board, not from mains, but generated with an Arduino to drive the TOD pin. So that seems to be the most logical approach.

I'll let you know how it goes :)


Top
 Profile  
Reply with quote  
PostPosted: Fri May 01, 2020 8:28 am 
Offline

Joined: Tue Sep 03, 2002 12:58 pm
Posts: 336
BigEd wrote:
Here's a thought: you can run two 16 bit counters with different terminal counts, and then with a bit of arithmetic figure out what the total time is. So if one counts down from 65535 and the other from 65521 you end up with very nearly 32 bits of range, because the two numbers share no prime factors...


I think using the unknown clock to measure the period of the 50/60Hz clock is going to be simplest (as long as you know which it is...). But this is an interesting alternative, giving you almost a 32 bit counter without having to connect the two halves.

It's possible to do it, but not obvious how. The magic that you need is called the Chinese Remainder Theorem. You're given s = n%a and t = n%b, with a and b known and coprime. The Chinese Remainder Theorem states that n is uniquely determined up to mod a*b, and the usual proof provides an algorithm for finding it.

The first step is to find x and y such that x*a + y*b = 1, which can be done with the extended Euclidean algorithm. In this case a and b are constants, and x = -4680, y = 4681.

Then n = (s*y*b + t*x*a)%(a*b) = (306703801*s - 306703800*t)%(4293918735) = (306703801*s + 3987214935*t)%(4293918735)

It's best to do the mod while you're doing the multiplications, to avoid the need for 48 bit intermediate values. Each time you double the multiplicand (or is it the multiplier?), if it goes above the modulus, subtract the modulus from it. And each time you add to the result, again subtract the modulus if it gets too big.

It's a fair amount of work, and you might not find further use for that 32 bit modular multiplication routine. But it's definitely an interesting method, and worth knowing.


Top
 Profile  
Reply with quote  
PostPosted: Fri May 01, 2020 8:36 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
Hee hee, "a bit of arithmetic"! There might be some mistake in the following, but what if:
- one counter free runs with a full 16 bit range
- the other counts one short, from 65534 down to 0

For simplicity, assuming they start at the same time, the second counter starts 1 ahead of the first one, and every time it wraps, it gets 1 further ahead. So when we take a reading - again assuming we can stop both at the same time, or take an instant reading of both - the difference between the counters tells us the number of wraps, and so we just multiply that up and add the remainder, and that's our count.

If that would work, it would need some carefully cycle-counted adjustments to account for the starting of the two counters and reading the two counters at slightly different times.

Still a little bit involved!


Top
 Profile  
Reply with quote  
PostPosted: Fri May 01, 2020 9:48 am 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1488
Location: Scotland
daniMolina wrote:
I'm going to start working on it this weekend, so I'm not looking for a solution, but I wanted to hear other people's approaches to this problem.


Keeping it simple:

Code:
Disable interrupts (if you're using them at this point)
Set a 32-bit counter to zero.
Poll the RTC until you see a change in the 0.1s register.
Loop
  Increment 32-bit counter
Until the RTC 0.1s register changes again.
Enable interrupts (if using them at this point)


You now have a value that's representative of a 0.1s interval.

Scale this to what you need - cycle count the loop, etc. or feed a known (e.g 1Mhz) clock into the 6502 and do some calculations on paper. With a known clock you should be able to calculate and build up a table of intervals from e.g. 0Mhz to 31Mhz in 0.125Mhz steps which would take 1KB of RAM (256 x 32-bit values) which you can then use as a look-up table for subsequent runs - so. run the loop (which will take up to 0.2s) lookup the value (binary chop to get an in-between point) then you can say the clock is between 1.125 and 1.250 Mhz - if that's good enough for you.

If your math is good, then use 2 known clocks and work out a better fit algorithm for generating the look-up table as there will be a fixed offset in the counting loop.

-Gordon

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Fri May 01, 2020 5:09 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Quote:
I forgot to mention, the main obstacle here is that the SBC is already built and running, and this has been an afterthought... that's why I said there was no straightforward way of linking 6526 and 6522 timers.

But you do have such a way, at least for a one-off timing measurement: the CPU itself. The VIA's two 16-bit timers, which can count Phi2 cycles, can be cascaded together internally. The 6526 also has an internal timer that can be driven by Phi2, in addition to the TOD clock, but I'm not certain whether Phi2 in this context is always as fast as the CPU clock (because sometimes you run the old, slow CIA - right?).

I think the correct approach here is to set up the VIA to cascade its timers in free-running mode, but load Timer 1 with an initial estimate of clock cycles per millisecond (ie. 1024 for just over 1MHz). Generate interrupts every TOD pulse, ie. every 50Hz, 20ms, and check how far Timer 2 in the VIA has advanced between pulses. If it's more than 20 counts, you need to increase the reload value in Timer 1. If it's less, you need to reduce it. Repeat this process until a specified number of pulses (say 50) in a row all produce the correct count in Timer 2, such that Timer 1 has not needed adjustment. The current reload value of Timer 1 will then be the Phi2 frequency in kHz.


Top
 Profile  
Reply with quote  
PostPosted: Sat May 02, 2020 4:33 pm 
Offline

Joined: Fri Jan 25, 2019 2:29 pm
Posts: 193
Location: Madrid, Spain
drogon wrote:
daniMolina wrote:
I'm going to start working on it this weekend, so I'm not looking for a solution, but I wanted to hear other people's approaches to this problem.


Keeping it simple:

Code:
Disable interrupts (if you're using them at this point)
Set a 32-bit counter to zero.
Poll the RTC until you see a change in the 0.1s register.
Loop
  Increment 32-bit counter
Until the RTC 0.1s register changes again.
Enable interrupts (if using them at this point)



This has been (with some changes, and a weird math accident) my approach in the end

Code:
         ldx #$56      // Counter LO prescaler
         stx $A0         // Counter LO stored
         ldy #$08        // Counter HI prescaler
         sty $A1         // Counter HI stored
         lda #$00      
         sta $A2         // Result location

         lda CIA_TODT
w1:         cmp CIA_TODT
         beq w1         // Wait for 10ths to change   
         lda CIA_TODT   // Store new 10ths value
      
n1:         dec $A0         // Dec LO counter
         bne n2         // If not 0, end
         stx $A0         // If 0, restore LO
         dec $A1         // and dec HI counter
         bne n2         // If not 0, end
         sty $A1         // If 0, restore HI
         inc $A2         // and increase result
n2:         cmp CIA_TODT   // Has 10ths changed?
         beq n1         // If not, continue


I initialize a 16 bit counter (A0,A1 in zp) to some value.
Then check current 10ths of second in TOD register, and wait for it to change.
Repeat
Decrease my counter by 1. Once it reaches 0, increase the result (stored in A2)
until 10ths changes again

A0 and A1 it's not a 16 bit counter, as every time A0 reaches 0, I reload the initial value, so they're actually to 8 bit counters chained together.

At the end of the loop, the result in A2 is in hundreds of KHz
10 for 1.0 Mhz
11 for 1.1 Mhz
...

I've tested it between 500 KHz and 1.2 Mhz with an original 6526 and seems accurate.

I tried to get the value for the counter with a somewhat "scientific" approach, calculating the cycles the loop needed and so on... and I was off by almost 10x... so it ended being a trial and error. More a quick hack than a verified solution, but good enough for my needs.

My TTL 6526 still has no TOD implemented, so I'll have to wait (for myself to build it!) to test this at higher speeds.

Thanks for all your tips!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 13 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 27 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: