1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
//! A safe, bare-metal driver for the ATmega328P's timers written in bare metal rust, using the Atmega328p datasheet registers
// Copyright (c) 2026 [Darell Ethan Kiganga]
// SPDX-License-Identifier: MIT
#![allow(dead_code)]
/// Prescaler and their values set
#[repr(u8)]
pub enum Prescaler {
NoClockSource = 0,
NoPrescaling = 1,
Prescaler8 = 2,
Prescaler64 = 3,
Prescaler256 = 4,
Prescaler1024 = 5,
}
/// AVR-Atmega328p Timer0
pub struct Timer0 {
_priv: (),
}
/// AVR-Atmega328p Timer1
pub struct Timer1 {
_priv: (),
}
static mut TIMER0_TAKING: bool = false;
static mut TIMER1_TAKING: bool = false;
pub mod timer0 {
use super::{Prescaler, TIMER0_TAKING, Timer0};
impl Timer0 {
const PRR: *mut u8 = 0x64 as *mut u8; // Power reduction register
const TCCR0A: *mut u8 = 0x44 as *mut u8;
const TCCR0B: *mut u8 = 0x45 as *mut u8;
const OCR0A: *mut u8 = 0x47 as *mut u8;
const OCR0B: *mut u8 = 0x48 as *mut u8;
const TIFR0: *mut u8 = 0x35 as *mut u8; // Timer0 interrupt register
const TCNT0: *mut u8 = 0x46 as *mut u8; // Timer register
const TIMSK0: *mut u8 = 0x6E as *mut u8;
/// Take timer0
pub fn take() -> Option<Self> {
unsafe {
if TIMER0_TAKING {
None
} else {
TIMER0_TAKING = true;
Some(Timer0 { _priv: () })
}
}
}
/// Starting the counter module
pub fn start(&self) {
unsafe {
// Reading the PRR (Power reduction register state)
let val = core::ptr::read_volatile(Self::PRR);
// Writing 0 to bit 5 (PRTIM0) to start the timer0 module
core::ptr::write_volatile(Self::PRR, val & !(1 << 5 as u8));
}
}
/* NORMAL MODE METHODS */
/// Set timer0 to normal mode after starting
pub fn set_normal_mode(&self) {
unsafe {
// Read TCCR0A
let val = core::ptr::read_volatile(Self::TCCR0A);
let other_val = core::ptr::read_volatile(Self::TCCR0B);
// Clear WGM0 bits for TCCR0A
core::ptr::write_volatile(Self::TCCR0A, val & !(1 | 2));
core::ptr::write_volatile(Self::TCCR0B, other_val & !(1 << 3 as u8));
}
}
/// Select your desired prescaler based on the already defined ones
pub fn set_prescaler(&self, prescaler: Prescaler) {
unsafe {
// Read TCCR0B
let val = core::ptr::read_volatile(Self::TCCR0B);
// Clear all CS0 bits
let clear = val & !(1 << 0 as u8 | 1 << 1 as u8 | 1 << 2 as u8);
// Clear flags
core::ptr::write_volatile(Self::TIFR0, 1 << 1 as u8);
// Set clock source
core::ptr::write_volatile(Self::TCCR0B, clear | prescaler as u8);
}
}
/// Wait for Normal mode delay
pub fn wait(&self) {
unsafe {
// Check the timer and wait for it then set the flag once it's done counting
while (core::ptr::read_volatile(Self::TIFR0) & 1) == 0 {
// Wait...
}
core::ptr::write_volatile(Self::TIFR0, 1);
}
}
/* CTC MODE METHODS */
/// Set timer0 CTC mode
pub fn set_ctc_mode(&self) {
unsafe {
// Read TCCR0A and TCCR0B
let val = core::ptr::read_volatile(Self::TCCR0A);
let other_val = core::ptr::read_volatile(Self::TCCR0B);
// Set the mode
core::ptr::write_volatile(Self::TCCR0A, val & !(1 << 0 as u8) | (1 << 1 as u8));
core::ptr::write_volatile(Self::TCCR0B, other_val & !(1 << 3 as u8));
}
}
/// Set value for OCR0A
/// Top value = ((clock speed) / (Chosen prescaler * frequency target in Hz) - 1
/// Top value must be between 0 and 255 as this is an 8 bit timer
pub fn set_top_value(&self, top: u8) {
unsafe {
core::ptr::write_volatile(Self::OCR0A, top);
}
}
/// Wait for OCR0A to match
pub fn wait_for_match(&self) {
unsafe {
while (core::ptr::read_volatile(Self::TIFR0) & (1 << 1 as u8)) == 0 {
// Wait...
}
core::ptr::write_volatile(Self::TIFR0, 1 << 1 as u8);
}
}
/// Assumes a 16Mhz clock speed
/// Delays for the specified number of milliseconds used as an argument for 'ms'
/// Uses Timer0 in CTC mode with Prescaler 64 and a TOP value of 249.
pub fn delay_ms(&self, ms: u16) {
self.set_ctc_mode();
self.set_top_value(249);
self.set_prescaler(Prescaler::Prescaler64);
for _i in 0..ms {
self.wait_for_match();
}
}
}
impl Drop for Timer0 {
fn drop(&mut self) {
unsafe { TIMER0_TAKING = false; }
}
}
}
pub mod timer1 {
use super::{Prescaler, TIMER1_TAKING, Timer1};
impl Timer1 {
const PRR: *mut u8 = 0x64 as *mut u8; // Power reduction register
const TCCR1A: *mut u8 = 0x80 as *mut u8;
const TCCR1B: *mut u8 = 0x81 as *mut u8;
const OCR1A: *mut u16 = 0x88 as *mut u16; // Low register
const OCR1B: *mut u16 = 0x8A as *mut u16; // Low register
const TIFR1: *mut u8 = 0x36 as *mut u8; // Timer1 interrupt register
const TCNT1: *mut u16 = 0x84 as *mut u16; // Timer register (Low)
const TIMSK1: *mut u8 = 0x6F as *mut u8;
const ICR1: *mut u16 = 0x86 as *mut u16; // ICR1
pub fn take() -> Option<Self> {
unsafe {
if TIMER1_TAKING {
None
} else {
TIMER1_TAKING = true;
Some(Timer1 { _priv: () })
}
}
}
/// Starting the counter module
pub fn start(&self) {
unsafe {
// Reading the PRR (Power reduction register state)
let val = core::ptr::read_volatile(Self::PRR);
// Writing 0 to bit 3 (PRTIM1) to start the timer1 module
core::ptr::write_volatile(Self::PRR, val & !(1 << 3 as u8));
}
}
pub fn set_normal_mode(&self) {
unsafe {
// Read TCCR1A and TCCR1B
let val = core::ptr::read_volatile(Self::TCCR1A);
let other_val = core::ptr::read_volatile(Self::TCCR1B);
// Clear WGMx bits for TCCR1A and TCCR1B
core::ptr::write_volatile(Self::TCCR1A, val & !(1 << 0 as u8 | 1 << 1 as u8));
core::ptr::write_volatile(Self::TCCR1B, other_val & !(1 << 3 as u8 | 1 << 4 as u8));
}
}
/// Select your prescaler, based on the ones implemented, from no clocksource, till prescaler 1024
pub fn set_prescaler(&self, prescaler: Prescaler) {
unsafe {
// Read TCCR1B
let val = core::ptr::read_volatile(Self::TCCR1B);
// Clear all CS1 bits
let clear = val & !(1 << 0 as u8 | 1 << 1 as u8 | 1 << 2 as u8);
// Clear flags
core::ptr::write_volatile(Self::TIFR1, 1 << 1 as u8);
// Set clock source
core::ptr::write_volatile(Self::TCCR1B, clear | prescaler as u8);
}
}
/// Wait for Normal mode delay on timer1
pub fn wait(&self) {
unsafe {
while (core::ptr::read_volatile(Self::TIFR1) & 1) == 0 {
// Wait...
}
core::ptr::write_volatile(Self::TIFR1, 1);
}
}
/// Set CTC mode for timer1
pub fn set_ctc_mode(&self) {
unsafe {
// Read TCCR0A and TCCR0B
let val = core::ptr::read_volatile(Self::TCCR1A);
let other_val = core::ptr::read_volatile(Self::TCCR1B);
// Set the mode
core::ptr::write_volatile(Self::TCCR1A, val & !(1 << 0 as u8) & !(1 << 1 as u8));
core::ptr::write_volatile(Self::TCCR1B, other_val & !(1 << 4 as u8) | (1 << 3 as u8));
}
}
// Wait for OCR1A to match
pub fn wait_for_match(&self) {
unsafe {
while (core::ptr::read_volatile(Self::TIFR1) & (1 << 1 as u8)) == 0 {
// Wait...
}
core::ptr::write_volatile(Self::TIFR1, 1 << 1 as u8);
}
}
/// Set value for OCR1A
/// Top value (top) = ((clock speed) / (Chosen prescaler * frequency target in Hz) - 1.
/// For time, the formula is OCR1 = ((Clock speed * target in seconds) / Prescaler) - 1.
/// Must be less than or equal to ICR1
pub fn set_top_value(&self, top: u16) {
unsafe {
core::ptr::write_volatile(Self::OCR1A, top);
}
}
/// Set Fast PWM Mode 14
/// ICR1 (top) = ((cpu frequency in Hz) / (prescaler * desired frequency in Hz)) - 1
/// ICR1 must be between 0 and 65535
pub fn set_fast_pwm(&self, top: u16) {
unsafe {
// Clear flags before starting
core::ptr::write_volatile(Self::TIFR1, 1 << 1 as u8);
// Read TCCR1A and TCCR1B
let val = core::ptr::read_volatile(Self::TCCR1A);
let other_val = core::ptr::read_volatile(Self::TCCR1B);
let clear = val & !(1 << 0 as u8) & !(1 << 1 as u8) & !(1 << 6 as u8) & !(1 << 7 as u8);
let other_clear = other_val & !(1 << 3 as u8) & !(1 << 4 as u8);
// Configure WGM for Mode 14 Fast PWM while clearing some bits
core::ptr::write_volatile(Self::TCCR1A, clear | (1 << 1 as u8) | 1 << 7 as u8);
core::ptr::write_volatile(Self::TCCR1B, other_clear | (1 << 3 as u8) | (1 << 4 as u8));
core::ptr::write_volatile(Self::ICR1, top);
}
}
/// Since the top value for OCR1A is automatically calculated as it reads the current ICR1 value, you don't need to put the value here
/// Set your duty cycle in %. Eg, using '50' as an argument
pub fn set_duty_cycle(&self, duty_in_percentage: u16) {
unsafe {
// Read the ICR1 register to find the top value
let val = core::ptr::read_volatile(Self::ICR1);
let safe_duty = if duty_in_percentage > 100 {
100
} else {
duty_in_percentage
};
// Calculate the OCR1A value based on the ICR1 value got by the duty in percentage
let top_val_for_ocr1a = (safe_duty as u32 * (val as u32 + 1)) / 100;
core::ptr::write_volatile(Self::OCR1A, top_val_for_ocr1a as u16);
}
}
/// Assumes a 16Mhz clock speed
/// Sets the servo angle (0-180).
/// Timer1 is in PWM Mode 14 with a 16MHz clock and assumes Prescaler 8 for the best accuracy.
pub fn set_servo_angle(&self, angle: u16) {
unsafe {
let val = core::ptr::read_volatile(Self::ICR1);
let safe_angle = if angle > 180 {
180
} else {
angle
};
let min_ticks_ms = (val as u32 + 1) / 20; // For 0 degrees
let max_ticks_2ms = (val as u32 + 1) / 10; // For 180 degrees
let ticks_per_degree_ocr1a = min_ticks_ms + (safe_angle as u32 * (max_ticks_2ms - min_ticks_ms)) / 180; // value for ocr1a
core::ptr::write_volatile(Self::OCR1A, ticks_per_degree_ocr1a as u16);
}
}
}
impl Drop for Timer1 {
fn drop(&mut self) {
unsafe { TIMER1_TAKING = false; }
}
}
}