Skip to content

Commit 1d997fa

Browse files
committed
timers done
1 parent 8a6ea87 commit 1d997fa

File tree

2 files changed

+173
-69
lines changed

2 files changed

+173
-69
lines changed

256Hz_Timer.md

Lines changed: 0 additions & 17 deletions
This file was deleted.

hardware/Timers.md

Lines changed: 173 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,62 @@
11
# Timers & Oscillators
22

3-
- [Seconds Timer](#seconds-timer)
4-
- [Clock Timer](#clock-timer)
5-
- [General Purpose Timers](#general-purpose-timers)
3+
- [Oscillators][]
4+
- [OSC1][]
5+
- [OSC1 specs][]
6+
- [OSC3][]
7+
- [OSC3 specs][]
8+
- [Seconds Timer][]
9+
- [Clock Timer][]
10+
- [Programmable timers][]
11+
- [Programmable timer configuration][]
12+
- [Programmable timer interrupts][]
13+
14+
[Oscillators]: #oscillators
15+
[OSC1]: #osc1
16+
[OSC1 specs]: #osc1-specs
17+
[OSC3]: #osc3
18+
[OSC3 specs]: #osc3-specs
19+
[Seconds Timer]: #seconds-timer
20+
[Clock Timer]: #clock-timer
21+
[Programmable timers]: #programmable-timers
22+
[Programmable timer configuration]: #programmable-timer-configuration
23+
[Programmable timer interrupts]: #programmable-timer-interrupts
24+
25+
[sleep]: Standby.md#sleep
626

727
## Oscillators
828

929
There are two oscillators on the board (external to the CPU) named OSC1 and OSC3.
1030

1131
### OSC1
1232

13-
This is a low-power 32768 Hz oscillator notably used for maintaining the real-time clock, but is also used elsewhere. There is no way to disable this oscillator outside of putting the system into [sleep](Standby.md#sleep) mode.
33+
This is a low-power 32.768 kHz crystal resonator (passive oscillator) notably used for maintaining the real-time clock, but is also used elsewhere. There is no way to disable this oscillator outside of putting the system into [sleep][] mode.
1434

15-
This oscillator is labeled `Y1` on the circuit board but does not have any text visible on the component itself. It's not a surface-mount component.
35+
This oscillator is labeled `Y1` on the circuit board and it does have text but it may not be visible; it's an engraved text `KDS` followed by a number representing the final digit of the year it was printed in then a letter representing the month (A for January up to M for December). It's not a surface-mount component, but is glued down.
1636

1737
In previous documentation and code, this oscillator was once known in the community as "oscillator 2".
1838

19-
Things left to discover:
20-
21-
* Part number
22-
* Accuracy
23-
* Confirm that it's crystal
39+
#### OSC1 specs
40+
41+
* Part number: [DT-26](https://www.kds.info/product/dt-26/) ([datasheet](https://datasheet.lcsc.com/lcsc/1811121541_KDS-Daishinku-DT-26-32.768K-6pF-20PPM_C127496.pdf))
42+
* D - Daishinku Corp (company name)
43+
* T - Tuning fork crystal resonator
44+
* 2 - 2 mm diameter
45+
* 6 - 6 mm height
46+
* Load Capacitance: unconfirmed
47+
* Drive Level: 1.0μW (2.0μW max.)
48+
* Frequency Tolerance: ±20 ppm max. (at 25℃)
49+
* Series Resistance: unconfirmed
50+
* Turnover Temperature: +25℃±5℃
51+
* Parabolic Coefficient: -0.04 ppm/℃² max.
52+
* Operating Temperature Range: -10 to +60℃
53+
* Storage Temperature Range: -20 to +70℃
54+
* Shunt Capacitance: 1.1pF typ.
55+
* Aging: ±5 ppm/year
2456

2557
### OSC3
2658

27-
This is the high-speed 4.00 MHz ceramic oscillator used for the general purpose timers. It can be disabled by writing a 0 to the OSCC register and is also disabled when the system enters [sleep](Standby.md#sleep) mode.
59+
This is the high-speed 4.00 MHz ceramic resonator (passive oscillator) used for the general purpose timers. It can be disabled by writing a 0 to the OSCC register and is also disabled when the system enters [sleep][] mode.
2860

2961
This oscillator is labeled `Y2` on the circuit board and has text printed on the top which looks like a curved M in a box followed by `4.00` and then a single-character serial such as `L` or `J`. It is a surface-mount component.
3062

@@ -40,7 +72,7 @@ When switching voltages you cannot jump directly between 1.6 V and 3.2 V safely
4072

4173
In previous documentation and code, this oscillator was once known in the community as "oscillator 1".
4274

43-
#### OSC3 Specs
75+
#### OSC3 specs
4476

4577
These specs are unfortunately from the 2009 datasheet, when ideally we would like a 2001 datasheet.
4678

@@ -60,9 +92,9 @@ These specs are unfortunately from the 2009 datasheet, when ideally we would lik
6092

6193
## Seconds Timer
6294

63-
A timer which increments once every second. It uses OSC1 as its clock source.
95+
A timer which increments once every second. It uses [OSC1][] as its clock source.
6496

65-
This timer informs the real-time clock (RTC) in commercial games. As such, if homebrew resets or pauses the timer or sleeps the console, it will force commercial games to ask for the user to enter the time again.
97+
This timer informs the real-time clock (RTC) in commercial games. As such, if homebrew resets or pauses the timer or sleeps the console (TODO?), it will force commercial games to ask for the user to enter the time again.
6698

6799
* Write 0 to STRUN to pause this timer or 1 to start it.
68100
* When reading, 0 means paused and 1 means running.
@@ -76,7 +108,7 @@ There are no interrupts related to this timer.
76108

77109
## Clock Timer
78110

79-
A timer which increments 256 times per second. It uses OSC1 as its clock source.
111+
A timer which increments 256 times per second. It uses [OSC1][] as its clock source.
80112

81113
* Write 0 to TMRUN to pause this timer or 1 to start it.
82114
* When reading, 0 means paused and 1 means running.
@@ -121,56 +153,145 @@ There are four interrupts tripped by this timer at different Hz.
121153

122154
In previous documentation and code, this timer was once known in the community as the "256Hz Timer".
123155

124-
## General Purpose Timers
156+
## Programmable timers
157+
158+
The Pokémon mini offers 3 pairs of general purpose programmable timers. Each set can independently be used either as a single 16-bit timer or split into two 8-bit channels with their own interrupts. These timers count down at a configurable rate.
159+
160+
Each of the 6 8-bit timers can individually be configured to use either OSC1 or OSC3 as its source clock. When using a pair as a 16-bit timer, it uses the clock source of the first member of the pair (for example, PTM0) and the interupt of the second member (for example, PTM1).
161+
162+
In previous documentation, these timers were known as the "general purpose timers", which is still an acceptable name, but this documentation will use "programmable timers" or PTs.
163+
164+
### PTM0-1
165+
166+
16-bit timer comprised of PTM0 as the lower order 8 bits and PTM1 as the higher order 8 bits. That is, `PTM1:PTM0` or given PTM1 is 0x10 and PTM0 is 0xf3, the value is 0x10f3.
167+
168+
In previous documentation and code, this timer has been known in the community as the "timer 1".
169+
170+
### PTM2-3
171+
172+
16-bit timer comprised of PTM2 as the lower order 8 bits and PTM3 as the higher order 8 bits. That is, `PTM3:PTM2` or given PTM3 is 0x10 and PTM2 is 0xf3, the value is 0x10f3.
173+
174+
In previous documentation and code, this timer has been known in the community as the "timer 2".
175+
176+
### PTM4-5
177+
178+
16-bit timer comprised of PTM4 as the lower order 8 bits and PTM5 as the higher order 8 bits. That is, `PTM5:PTM4` or given PTM5 is 0x10 and PTM4 is 0xf3, the value is 0x10f3.
179+
180+
In previous documentation and code, this timer has been known in the community as the "timer 3".
181+
182+
### Programmable timer configuration
183+
184+
When choosing which timer to use for some purpose, you must choose whether to use some pair as a 16-bit timer or to split it and use one of the 8-bit timers. To use the 16-bit timer, write a 1 to the respective MODE16 register (see table below) and to use one of the 8-bit timers, write a 0 to it (this is the initial value).
185+
186+
| Register | pm.h | Timer L | Timer H | Timer 16 |
187+
| -------- | ----------- | ------- | ------- | -------- |
188+
| MODE16_A | TMR1_CTRL_L | PTM0 | PTM1 | PTM0-1 |
189+
| MODE16_B | TMR2_CTRL_L | PTM2 | PTM3 | PTM2-3 |
190+
| MODE16_C | TMR3_CTRL_L | PTM4 | PTM5 | PTM4-5 |
191+
192+
To set MODE16 with pm.h, use, for example, `TMR1_CTRL_L |= 0x80;`
193+
To unset MODE16 with pm.h, use, for example, `TMR1_CTRL_L &= ~0x80;`
125194

126-
TODO
195+
Before you first enable a timer, you'll want to configure its basic settings. Set the clock source via PRTF*x* where *x* is the timer index. Write a 1 to use [OSC1][] and a 0 to use [OSC3][]. You likely won't change this again unless you intend to repurpose the timer. To make this selection, refer the table below.
127196

128-
## Timer Overview
197+
| For timer(s) | Use OSC1 | Use OSC3 |
198+
| ------------- | ---------------- | ----------------- |
199+
| PTM0 & PTM0-1 | `TMR1_OSC |= 1;` | `TMR1_OSC &= ~1;` |
200+
| PTM1 | `TMR1_OSC |= 2;` | `TMR1_OSC &= ~2;` |
201+
| PTM2 & PTM2-3 | `TMR2_OSC |= 1;` | `TMR2_OSC &= ~1;` |
202+
| PTM3 | `TMR2_OSC |= 2;` | `TMR2_OSC &= ~2;` |
203+
| PTM4 & PTM4-5 | `TMR3_OSC |= 1;` | `TMR3_OSC &= ~1;` |
204+
| PTM5 | `TMR3_OSC |= 2;` | `TMR3_OSC &= ~2;` |
129205

130-
The Pokémon mini offers 3 general purpose timer units. Each timer is broken down into several blocks to provide it with variable clock rates, the ability to be broken down into two independent 8-bit timers, and each timer can generate two unique interrupts.
206+
After this you configure the division ratio (prescale), reload data (preset), and compare data (pivot). This can be changed regularly while the timer is running in order to adjust when some overflow occurs.
131207

132-
## Timer Control
208+
The prescale along with the clock source determines how quickly the counter decrements. Refer to the table below:
133209

134-
Each timer is configured using 6 registers, TIM_SCALE\*, TIM_OSCI\*, TIM_CTL\*_L, TIM_CTL\*_H, TIM_PRE\*_L and TIM_PRE\*_H. These registers provide the ability to change the clock rate of both the low and high 8-bits of the counter, set if there is a borrow chain to the upper 8-bits (16-bit counter mode) as well as enable and reset the timer (load counter from the preset). Beginning with the TIM_OSCI\*, each timer has the ability to run from oscillator 1 (System Clock) or oscillator 2 (32768 Hz RTC Clock). The pre-scale is further decided by selecting one of 8 different pre-scale values from a table in the TIM_SCALE\* register.
210+
| Prescale | fOSC1 / div = Hz | OSC3 / div = Hz |
211+
| -------- | ------------------- | -------------------- |
212+
| 0 | 32768 / 1 = 32768 | 4M / 2 = 2M |
213+
| 1 | 32768 / 2 = 16384 | 4M / 8 = 500k |
214+
| 2 | 32768 / 4 = 8192 | 4M / 32 = 125k |
215+
| 3 | 32768 / 8 = 4096 | 4M / 64 = 62500 |
216+
| 4 | 32768 / 16 = 2048 | 4M / 128 = 31250 |
217+
| 5 | 32768 / 32 = 1024 | 4M / 256 = 15625 |
218+
| 6 | 32768 / 64 = 512 | 4M / 1024 = 3906.25 |
219+
| 7 | 32768 / 128 = 256 | 4M / 4096 = 976.5625 |
135220

136-
Further more, timers must be enabled individually (by setting the enable flag in TIM_SCALE\* TIM_CTL\*_L and TIM_CTL\*_H) as well as by group (Upper half of TIM_ENA_OSCI1). TIM_ENA_OSCI1 disables oscillator 1 or 2 if either respective bit is clear ($10 and $20).
221+
When a timer underflows, it loads the preset into the counter as the starting value to count down from. It can also be reset to this value manually by writing a 1 to PSET*x* where *x* is the timer index.
137222

138-
**Timer Prescale (Oscillator 1)**
139-
| Prescale | Clk Div. | Hz |
140-
| -------- | ---------- | -------- |
141-
| 0 | CPU / 2 | 2000000 |
142-
| 1 | CPU / 8 | 500000 |
143-
| 2 | CPU / 32 | 125000 |
144-
| 3 | CPU / 64 | 62500 |
145-
| 4 | CPU / 128 | 31250 |
146-
| 5 | CPU / 256 | 15625 |
147-
| 6 | CPU / 1024 | 3906.25 |
148-
| 7 | CPU / 4096 | 976.5625 |
223+
When the pivot is matched, a compare match interrupt is triggered but the timer is not reset at that point. On matching PTM4-5 (TODO: or just PTM5?), an output signal is sent to the speaker.
149224

150-
**Timer Prescale (Oscillator 2)**
151-
| Prescale | Clk Div. | Hz |
152-
| -------- | ----------- | ----- |
153-
| 0 | 32768 / 1 | 32768 |
154-
| 1 | 32768 / 2 | 16384 |
155-
| 2 | 32768 / 4 | 8192 |
156-
| 3 | 32768 / 8 | 4096 |
157-
| 4 | 32768 / 16 | 2048 |
158-
| 5 | 32768 / 32 | 1024 |
159-
| 6 | 32768 / 64 | 512 |
160-
| 7 | 32768 / 128 | 256 |
225+
The table below lists the timers and which registers control these three values. The use of a colon between two registers indicates the values are concatenated together such that `0x10:0xa5` would become `0x10a5`. The register using the timer's name (for example, PTM0) is the data register which contains the count value for reading; for the 16-bit timers this is `PTMy:PTMx` for any `PTMx-y`.
161226

162-
The timer control registers affect the values of the timers themselves. Enable must be set for timing, this means there are a total of 3 bits that must be enabled for any timer to begin counting. writing a logical 1 to a reset bit in a control register will cause that respective 8-bit section to copy the respective value out of preset. All timers count down. When any timer underflows, it's value is copied from the preset value.
227+
| Timer | Prescale | Preset | Pivot |
228+
| ------ | -------- | --------- | --------- |
229+
| PTM0 | PST0 | RDR0 | CDR0 |
230+
| PTM1 | PST1 | RDR1 | CDR1 |
231+
| PTM2 | PST2 | RDR2 | CDR2 |
232+
| PTM3 | PST3 | RDR3 | CDR3 |
233+
| PTM4 | PST4 | RDR4 | CDR4 |
234+
| PTM5 | PST5 | RDR5 | CDR5 |
235+
| PTM0-1 | PST0 | RDR1:RDR0 | CDR1:CDR0 |
236+
| PTM2-3 | PST2 | RDR3:RDR2 | CDR3:CDR2 |
237+
| PTM4-5 | PST4 | RDR5:RDR4 | CDR5:CDR4 |
163238

164-
## 16-bit mode
239+
With pm.h:
165240

166-
When a timer is operating in 16-bit mode, all the upper-8 bit settings are unceremoniously ignored. Enables, reset and and everything no longer control the behavior of the timer. They remain writable, but they no longer actively function. This includes enables, resets and pre-scale values. The lower-8 bit configuration is effective over the full 16-bit value. Additionally, all lower-8 underflow IRQs are effectively disabled. The timer only presets when the full 16-bit value underflows.
241+
| Timer | Prescale | Preset | Pivot | Data |
242+
| ------ | ---------- | ---------- | ---------- | ---------- |
243+
| PTM0 | TMR1_SCALE | TMR1_PRE_L | TMR1_PVT_L | TMR1_CNT_L |
244+
| PTM1 | TMR1_SCALE | TMR1_PRE_H | TMR1_PVT_H | TMR1_CNT_H |
245+
| PTM2 | TMR2_SCALE | TMR2_PRE_L | TMR2_PVT_L | TMR2_CNT_L |
246+
| PTM3 | TMR2_SCALE | TMR2_PRE_H | TMR2_PVT_H | TMR2_CNT_H |
247+
| PTM4 | TMR3_SCALE | TMR3_PRE_L | TMR3_PVT_L | TMR3_CNT_L |
248+
| PTM5 | TMR3_SCALE | TMR3_PRE_H | TMR3_PVT_H | TMR3_CNT_H |
249+
| PTM0-1 | TMR1_SCALE | TMR1_PRE | TMR1_PVT | TMR1_CNT |
250+
| PTM2-3 | TMR2_SCALE | TMR2_PRE | TMR2_PVT | TMR2_CNT |
251+
| PTM4-5 | TMR3_SCALE | TMR3_PRE | TMR3_PVT | TMR3_CNT |
167252

168-
## IRQ Operation
253+
The scale registers are constructed as `PRPRTy:PSTy:PRPRTx:PSTx` where each PST register is 3 bits and y = x + 1. This means that in order to set the prescale for PTM0 you must do `TMR1_SCALE &= ~0x07;` to clear then `TMR1_SCALE |= prescale;` to assign it. For PTM1 you must do `TMR1_SCALE &= ~0x70;` to clear then `TMR1_SCALE |= prescale << 4;` to assign it. They are initialized to 0 so there's no need to clear it in startup code. PRPRT registers should always be set to 1.
169254

170-
Each timer provides two irqs. These IRQs appear to be fixed function, which provides the only known difference between Timers 1-2 and Timer 3.
255+
### Programmable timer interrupts
171256

172-
Timers 1-3 have a primary IRQ, this fires anytime the upper 8-bit of the counter underflows (16- or 8-bit operations) The secondary IRQ of Timer 1-2 occurs when the lower 8-bit counter underflows (8-bit mode only) The secondary IRQ of Timer 3 occurs when the value of the counter becomes less than or equal-to the value in it's comparator. In 8-bit mode only the upper 8-bit of the value is used.
257+
There are two interrupts for each timer: the underflow and the compare data interrupts. Underflow occurs the tick after a count reaches 0, causing it to preset. The compare data interrupt occurs when the count is equal to the value stored in the relevant CDR register.
173258

174-
## Sound
259+
Although all of these interrupts exist and can be accessed by reading the count or factor flag directely, not all of them are mapped to ROM locations (that is, there's no means to make them jump to software code automatically).
175260

176-
Timer 3 is also used for [sound](PM_Audio.md "wikilink") within the Pokémon mini.
261+
| Timer interrupt | Factor | Enable | Priority | Software entry address |
262+
| ---------------- | ------ | ------ | -------- | ---------------------- |
263+
| PTM0 underflow | FTU0 | ETU0 | PPT0-1 | $2126 |
264+
| PTM0 CDR match | FTC0 | ETC0 | n/a | n/a |
265+
| PTM1 underflow | FTU1 | ETU1 | PPT0-1 | $2120 |
266+
| PTM1 CDR match | FTC1 | ETC1 | n/a | n/a |
267+
| PTM2 underflow | FTU2 | ETU2 | PPT2-3 | $211a |
268+
| PTM2 CDR match | FTC2 | ETC2 | n/a | n/a |
269+
| PTM3 underflow | FTU3 | ETU3 | PPT2-3 | $2114 |
270+
| PTM3 CDR match | FTC3 | ETC3 | n/a | n/a |
271+
| PTM4 underflow | FTU4 | ETU4 | n/a | n/a |
272+
| PTM4 CDR match | FTC4 | ETC4 | n/a | n/a |
273+
| PTM5 underflow | FTU5 | ETU5 | PPT4-5 | $212c |
274+
| PTM5 CDR match | FTC5 | ETC5 | PPT4-5 | $2132 |
275+
| PTM0-1 underflow | FTU1 | ETU1 | PPT0-1 | $2120 |
276+
| PTM0-1 CDR match | FTC1 | ETC1 | n/a | n/a |
277+
| PTM2-3 underflow | FTU3 | ETU3 | PPT2-3 | $2114 |
278+
| PTM2-3 CDR match | FTC3 | ETC3 | n/a | n/a |
279+
| PTM4-5 underflow | FTU5 | ETU5 | PPT4-5 | $212c |
280+
| PTM4-5 CDR match | FTC5 | ETC5 | PPT4-5 | $2132 |
281+
282+
For more information about how interrupts work, see [Interrupts](cpu/Interrupts.md).
283+
For information on using PTM4-5 for audio, see [Audio / Sound](cpu/Sound.md).
284+
285+
### Enabling and pausing programmable timers
286+
287+
In order to turn a timer on, the following must be done, where x is some timer index (use 0 for PTM0-1, etc):
288+
289+
* CKSEL*x* should already be set to 0 by default, do not change it
290+
* Set PRPRT*x* register to 1
291+
* Set PTRUN*x* register to 1
292+
293+
To pause the timer, reset PTRUN*x* register to 0. The timer will decrement once more before pausing.
294+
To resume the timer, set PTRUN*x* register back to 1.
295+
To preset the timer count, write 1 to PSET*x*.
296+
297+
When using the HALT operation, the timers are not paused. When using the SLP operation, the timers will be paused and will resume from where they left off when the console reawakens.

0 commit comments

Comments
 (0)