[Contest] RIOT Clock

Let's talk about anything related to the 6502 microprocessor.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: [Contest] RIOT Clock

Post by Chromatix »

The next big challenge with dealing with so many LEDs is positioning them accurately on the PCB - and they should be the first components placed, due to their visual impact. This will obviously also dominate the overall size of the PCB, with the face size being similar to that of a decent wall-mounted regulator clock; the minimum practical diameter of a 60-LED circle is about 3 inches, assuming 3mm LEDs, but the minutes and hours circles will be much larger than the seconds circle. I'm presently working on the basis of an 8-inch minutes circle, with the hours circle about an inch smaller, and the hour marks placed between them. This leaves plenty of PCB space on which to put the other display elements, control devices, and logic.

KiCad doesn't have any good built-in tools to assist with this, but it does have a Python scripting interface, and this particular task is common enough that someone already wrote a script showing how this ought to be done. It definitely does help that I laid out the LED matrix with a custom schematic symbol and a unique reference prefix, so that the reference numbering is consistent with the order the LEDs should be placed.

At some point, I might even get around to writing the firmware…
jds
Posts: 196
Joined: 10 Mar 2016

Re: [Contest] RIOT Clock

Post by jds »

There are some good modern LCD driver IC's with I2C bus, I don't know if you wanted to go to that, but maybe it's an option? The 6532 could bit-bang I2C without much trouble.

As for the LED's, another option is these 8x8 LED matrix's https://www.aliexpress.com/item/32262061747.html. They are cheap and would be easy to mount. Maybe a 2x2 grid of these would do. That's a lot of LED's, but it could also be used as a display of sorts to show other information?

And then you can get 60 LED's arranged in a circle here: https://www.aliexpress.com/item/32825994855.html. They are digitally controlled with 24-bit color for each LED, so that's 180 bytes that you need to clock out to update the display, you wouldn't need to store that data it could be easily calculated as needed, and I guess you only need 1 update per second if showing the second hand, so could be easy enough. And the advantage is that you only need 1 I/O port pin to control them all.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: [Contest] RIOT Clock

Post by Chromatix »

I'm not likely to use 8x8 matrix drivers, because I can build a 3x10x6 matrix setup more cheaply as described in previous posts, while for the day-of-week and month displays I need the ability to drive a 16-segment display which an 8x8 matrix driver can't easily do. I've found an 8x16 display driver which does the latter job competently, and everything is driven with an SPI-compatible port and selector, so I consider the LED driving problem essentially solved. (SPI is actually easier to bit-bang than I2C.)

Hence why I'm moving onto the problem of physically aligning all the components on the PCB design, so that they form neat circles and are sufficiently easy to route traces to.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: [Contest] RIOT Clock

Post by Chromatix »

I've temporarily moved onto writing the firmware, specifically some routines to manipulate date and time in a calendrically consistent manner. This is complicated by the fact that both the RTC chip maintaining the time and the display operate in BCD format, so I either have to do the manipulations in BCD as well, or convert between BCD and binary. For the moment at least, I'm taking the former approach.

One of the things this clock has to do regularly is convert the UTC (well, strictly it's UT1 as it's not precise enough to use leap seconds) time maintained by the RTC chip into the local timezone displayed on the face, including correcting the date if necessary. So there will be a (binary format) value indicating the timezone offset in quarter-hours, in approximately the range ±48, and it will get to call an IncQuarterHour or DecQuarterHour subroutine repeatedly to reduce a copy of that value to zero. These will fall through successively to IncHour, IncDay, IncMonth, and even IncYear (and corresponding decrementers too) as necessary. There are also incrementer routines for single seconds and minutes, for use when setting the clock.

There are actually three copies of the date and time variables, kept for different purposes, and the routines can be made to operate on any of them by using the Y register as an offset. It's fractionally slower, but saves a lot of code space. Handling the day increments in particular takes a lot of code, due to handling variable month lengths and Gregorian leap years. I will need to write a companion set of unit tests to ensure that these routines operate correctly; rather than burn these into the clock's ROM, I'll concatenate and run them in my own 65C02 simulator. Or I could burn them into an inaccessible (to the 6507) part of the 8KB ROM, point the NMI vector at them, and thereby run them on a full NMOS 6502 that I have lying around. Whatever works.

Speaking of leap years, these are fairly easy to test for by keeping the year and century distinct as is natural with BCD format (this makes handling the 400-year rule much easier), but BCD adds the complication that I can't check for divisibility by 4 merely through the least significant bits. Instead I have to mask with $13, then check whether the result is either zero or $12. Two extra instructions and four extra bytes is not a huge penalty, fortunately, just an extra semantic complication to deal with.
User avatar
cjs
Posts: 759
Joined: 01 Dec 2018
Location: Tokyo, Japan
Contact:

Re: [Contest] RIOT Clock

Post by cjs »

Chromatix wrote:
I will need to write a companion set of unit tests to ensure that these routines operate correctly; rather than burn these into the clock's ROM, I'll concatenate and run them in my own 65C02 simulator.
I'll be very interested to see how you do these. I've been heavily unit testing most of my 6502 code (because I'm a crap programmer) using py65 and a test framework I consed up that lets me write the unit tests in Python and run them with pytest. (Pytest is great for many reasons, but a particularly useful thing for my 6502 programming is that I can parameterize the tests so that they can run multiple times with different parameters. This is particularly good for all those edge cases in assembly code. It's not unusal for me to have 30 cases or more of a particular test.)

Once the test framework settles down a bit, and maybe after I've added support for another CPU such as 6800 or 6809, I'll be extracting it out to its own repo and documenting it. But documentation might appear earlier if anybody demands it!
Curt J. Sampson - github.com/0cjs
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: [Contest] RIOT Clock

Post by BigEd »

Neat little divisibility check there!
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: [Contest] RIOT Clock

Post by Chromatix »

I eventually factored out a "number of days in this month" function, as follows - noting that everything is in BCD, and Y points to the relevant time/date structure:

Code: Select all

MonthDays:
  LDX utcMonth,Y
  CPX #$A
  BMI :+
  LDA months-7,X    ; Oct/Nov/Dec
  RTS
: LDA months-1,X    ; Jan-Sept
  CMP #$29
  BEQ :+
  RTS   ; not February
: TAX
  LDA utcYear,Y
  BNE :+
  LDA utcCentury,Y
: AND #$13
  BEQ :+
  EOR #$12
  BEQ :+
  DEX    ; not a leap year
: TXA
  RTS

months:
  .byte $31,$29,$31,$30,$31,$30,$31,$31,$30,$31,$30,$31
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: [Contest] RIOT Clock

Post by barrym95838 »

If months points to the first byte of a 12-byte table, where are months-7 and months-1 pointing?

[Edit: oh, you edited it while I was pondering ... looks like the last ten bytes of your table are two identical sets of five, so you could CPX #8 and get rid of the last five, right? :) ]

Code: Select all

MonthDays:
  LDA utcMonth,Y
  CMP #8
  BCC :+
  SBC #5    ; Aug-Dec->Mar-Jul
: TAX
  LDA months-1,X    ; Jan-Jul
  CMP #$29
  BNE :+++     ; not Feb
  TAX
  LDA utcYear,Y
  BNE :+
  LDA utcCentury,Y
: AND #$13
  BEQ :+
  EOR #$12
  BEQ :+
  DEX    ; not a leap year
: TXA
: RTS

months:
  .byte $31,$29,$31,$30,$31,$30,$31
Last edited by barrym95838 on Wed Feb 05, 2020 7:00 am, edited 7 times in total.
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: [Contest] RIOT Clock

Post by Chromatix »

Yeah, a hazard of copying by hand from a different screen.
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: [Contest] RIOT Clock

Post by Chromatix »

There *is* such a thing as "premature optimisation", you know. If I find myself in desperate need of a few bytes of ROM, then I can look into coding some of this stuff more tightly. Otherwise, I'm content to adopt a style that's easier to maintain.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: [Contest] RIOT Clock

Post by barrym95838 »

You have quickly and correctly diagnosed my ailment, kind sir! Once my brain starts itching, I have to scratch it or I won't get any sleep. Please, ignore the freak in the crowd and carry on ...

[Edit: BTW, on second thought, it doesn't make much sense to save five bytes of table if seven bytes of code are required to utilize those savings ... oy vey ...]

Code: Select all

MonthDays:
  LDA utcMonth,Y
  CMP #8
  ADC #0    ; Adjust Aug-Dec
  LDX #$31
  LSR
  BCS :++  ; JanMarMayJulAugOctDec
  DEX
  LSR
  BNE :++   ; AprJunSepNov
  LDX #$29
  LDA utcYear,Y
  BNE :+
  LDA utcCentury,Y
: AND #$13
  BEQ :+
  EOR #$12
  BEQ :+
  DEX    ; not a leap year
: TXA
  RTS
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)
Post Reply