@@ -75,6 +75,7 @@ impl SysctlExt for SYSCTL {
75
75
aclk : ACLK { _ownership : ( ) } ,
76
76
apb0 : APB0 { _ownership : ( ) } ,
77
77
pll0 : PLL0 { _ownership : ( ) } ,
78
+ timer0 : Timer0 { _ownership : ( ) } ,
78
79
}
79
80
}
80
81
}
@@ -87,6 +88,8 @@ pub struct Parts {
87
88
pub pll0 : PLL0 ,
88
89
/// entry for controlling the enable/disable/frequency of apb0
89
90
pub apb0 : APB0 ,
91
+ /// entry for controlling the enable/disable/frequency of Timer
92
+ pub timer0 : Timer0 ,
90
93
// todo: SRAM, APB-bus, ROM, DMA, AI, PLL1, PLL2, APB1, APB2
91
94
}
92
95
@@ -302,3 +305,74 @@ impl ACLK {
302
305
}
303
306
}
304
307
}
308
+
309
+ pub struct Timer0 {
310
+ _ownership : ( ) ,
311
+ }
312
+
313
+ impl Timer0 {
314
+ pub fn enable ( & mut self , apb0 : & mut APB0 ) {
315
+ apb0. enable ( ) ;
316
+ clk_en_peri ( ) . modify ( |_, w| w. timer0_clk_en ( ) . set_bit ( ) ) ;
317
+ }
318
+
319
+ pub fn disable ( & mut self ) {
320
+ clk_en_peri ( ) . modify ( |_, w| w. timer0_clk_en ( ) . clear_bit ( ) ) ;
321
+ }
322
+
323
+ fn use_external ( & mut self ) {
324
+ sysctl ( )
325
+ . clk_sel0
326
+ . modify ( |_, w| w. timer0_clk_sel ( ) . clear_bit ( ) ) ;
327
+ }
328
+
329
+ fn use_pll0 ( & mut self ) {
330
+ sysctl ( )
331
+ . clk_sel0
332
+ . modify ( |_, w| w. timer0_clk_sel ( ) . set_bit ( ) ) ;
333
+ }
334
+
335
+ pub fn set_frequency ( & mut self , resolution : impl Into < Hertz > ) -> Hertz {
336
+ let resolution = resolution. into ( ) . 0 ;
337
+ // resolution = input / ((timer0_clk + 1) * 2), timer0_clk is 8 bits
338
+
339
+ // find a nearest input
340
+ let in0_nearest_clk = ( CLOCK_FREQ_IN0 / resolution / 2 - 1 ) . min ( 255 ) ;
341
+ let in0_result = CLOCK_FREQ_IN0 / ( ( in0_nearest_clk + 1 ) * 2 ) ;
342
+ let in0_diff = ( in0_result as i64 - resolution as i64 ) . abs ( ) ;
343
+
344
+ let pll0_freq = PLL0 :: steal ( ) . get_frequency ( ) . 0 ;
345
+ let pll0_nearest_clk = ( pll0_freq / resolution / 2 - 1 ) . min ( 255 ) ;
346
+ let pll0_result = pll0_freq / ( ( pll0_nearest_clk + 1 ) * 2 ) ;
347
+ let pll0_diff = ( pll0_result as i64 - resolution as i64 ) . abs ( ) ;
348
+
349
+ if in0_diff <= pll0_diff {
350
+ unsafe {
351
+ self . use_external ( ) ;
352
+ sysctl ( )
353
+ . clk_th2
354
+ . modify ( |_, w| w. timer0_clk ( ) . bits ( in0_nearest_clk as u8 ) ) ;
355
+ }
356
+ Hertz ( in0_result)
357
+ } else {
358
+ self . use_pll0 ( ) ;
359
+ unsafe {
360
+ sysctl ( )
361
+ . clk_th2
362
+ . modify ( |_, w| w. timer0_clk ( ) . bits ( pll0_nearest_clk as u8 ) ) ;
363
+ }
364
+ Hertz ( pll0_result)
365
+ }
366
+ }
367
+ pub fn get_frequency ( & self ) -> Hertz {
368
+ let threshold = sysctl ( ) . clk_th2 . read ( ) . timer0_clk ( ) . bits ( ) as u32 ;
369
+ let input = if sysctl ( ) . clk_sel0 . read ( ) . timer0_clk_sel ( ) . bit ( ) {
370
+ PLL0 :: steal ( ) . get_frequency ( ) . 0
371
+ } else {
372
+ CLOCK_FREQ_IN0
373
+ } ;
374
+ Hertz ( input / ( ( threshold + 1 ) * 2 ) )
375
+ }
376
+ }
377
+
378
+ // todo: Timer1, Timer2, maybe with a macro
0 commit comments