Skip to content

Commit 88da51d

Browse files
committed
feat(allwinner-hal): add ledc ccu
feat(examples): add nezha-d1-blinky Signed-off-by: Woshiluo Luo <woshiluo.luo@outlook.com>
1 parent 602e19c commit 88da51d

File tree

3 files changed

+223
-2
lines changed

3 files changed

+223
-2
lines changed

allwinner-hal/src/ccu.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,3 +308,48 @@ impl<const I: usize> ClockConfig for SPI<I> {
308308
}
309309
}
310310
}
311+
312+
/// LED Control (LEDC) clock type.
313+
pub struct LEDC;
314+
315+
impl ClockReset for LEDC {
316+
#[inline]
317+
unsafe fn deassert_reset_only(ccu: &RegisterBlock) {
318+
unsafe {
319+
ccu.ledc_bgr.modify(|v| v.deassert_reset());
320+
}
321+
}
322+
#[inline]
323+
unsafe fn assert_reset_only(ccu: &RegisterBlock) {
324+
unsafe {
325+
ccu.ledc_bgr.modify(|v| v.assert_reset());
326+
}
327+
}
328+
}
329+
330+
impl ClockGate for LEDC {
331+
#[inline]
332+
unsafe fn unmask_gate_only(ccu: &RegisterBlock) {
333+
unsafe {
334+
ccu.ledc_bgr.modify(|v| v.gate_pass());
335+
}
336+
}
337+
#[inline]
338+
unsafe fn mask_gate_only(ccu: &RegisterBlock) {
339+
unsafe {
340+
ccu.ledc_bgr.modify(|v| v.gate_mask());
341+
}
342+
}
343+
#[inline]
344+
unsafe fn disable_in(ccu: &RegisterBlock) {
345+
unsafe {
346+
ccu.ledc_bgr.modify(|v| v.gate_mask().assert_reset());
347+
}
348+
}
349+
#[inline]
350+
unsafe fn enable_in(ccu: &RegisterBlock) {
351+
unsafe {
352+
ccu.ledc_bgr.modify(|v| v.gate_pass().deassert_reset());
353+
}
354+
}
355+
}

allwinner-hal/src/ccu/register.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ pub struct RegisterBlock {
4444
_reserved10: [u32; 9],
4545
/// 0x96c - SPI Bus Gating Reset register.
4646
pub spi_bgr: RW<SpiBusGating>,
47+
_reserved11: [u32; 0xA0],
48+
/// 0xbf0 - LDEC Clock register.
49+
pub ledc_clk: RW<LedcClock>,
50+
_reserved12: [u32; 2],
51+
/// 0xbfc - LDEC Bus Gating Reset register.
52+
pub ledc_bgr: RW<LedcBusGating>,
4753
}
4854

4955
/// CPU AXI Configuration register.
@@ -493,6 +499,113 @@ impl SmhcBusGating {
493499
}
494500
}
495501

502+
/// LEDC Clock register.
503+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
504+
#[repr(transparent)]
505+
pub struct LedcClock(u32);
506+
507+
impl LedcClock {
508+
const CLK_SRC_SEL: u32 = 1 << 24;
509+
const FACTOR_N: u32 = 0x3 << 8;
510+
const FACTOR_M: u32 = 0xf << 0;
511+
const CLK_GATING: u32 = 1 << 31;
512+
513+
/// Get LEDC clock source.
514+
#[inline]
515+
pub const fn clock_source(self) -> SmhcClockSource {
516+
match (self.0 & Self::CLK_SRC_SEL) >> 24 {
517+
0x0 => SmhcClockSource::Hosc,
518+
0x1 => SmhcClockSource::PllPeri1x,
519+
_ => panic!("impossible clock source"),
520+
}
521+
}
522+
/// Set LEDC clock source.
523+
#[inline]
524+
pub const fn set_clock_source(self, val: SmhcClockSource) -> Self {
525+
let val = match val {
526+
SmhcClockSource::Hosc => 0x0,
527+
SmhcClockSource::PllPeri1x => 0x1,
528+
_ => panic!("impossible clock source"),
529+
};
530+
Self((self.0 & !Self::CLK_SRC_SEL) | (val << 24))
531+
}
532+
/// Get LEDC clock divide factor N.
533+
#[inline]
534+
pub const fn factor_n(self) -> PeriFactorN {
535+
match (self.0 & Self::FACTOR_N) >> 8 {
536+
0 => PeriFactorN::N1,
537+
1 => PeriFactorN::N2,
538+
2 => PeriFactorN::N4,
539+
3 => PeriFactorN::N8,
540+
_ => unreachable!(),
541+
}
542+
}
543+
/// Set LEDC clock divide factor N.
544+
#[inline]
545+
pub const fn set_factor_n(self, val: PeriFactorN) -> Self {
546+
let val = match val {
547+
PeriFactorN::N1 => 0,
548+
PeriFactorN::N2 => 1,
549+
PeriFactorN::N4 => 2,
550+
PeriFactorN::N8 => 3,
551+
};
552+
Self((self.0 & !Self::FACTOR_N) | (val << 8))
553+
}
554+
/// Get LEDC clock divide factor M.
555+
#[inline]
556+
pub const fn factor_m(self) -> u8 {
557+
(self.0 & Self::FACTOR_M) as u8
558+
}
559+
/// Set LEDC clock divide factor M.
560+
#[inline]
561+
pub const fn set_factor_m(self, val: u8) -> Self {
562+
Self((self.0 & !Self::FACTOR_M) | val as u32)
563+
}
564+
/// Enable clock gating.
565+
#[inline]
566+
pub const fn enable_clock_gating(self) -> Self {
567+
Self(self.0 | Self::CLK_GATING)
568+
}
569+
/// Disable clock gating.
570+
#[inline]
571+
pub const fn disable_clock_gating(self) -> Self {
572+
Self(self.0 & !Self::CLK_GATING)
573+
}
574+
/// Get if clock gating is enabled.
575+
#[inline]
576+
pub const fn is_clock_gating_enabled(self) -> bool {
577+
self.0 & Self::CLK_GATING != 0
578+
}
579+
}
580+
581+
/// LEDC Clock Reset register.
582+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
583+
#[repr(transparent)]
584+
pub struct LedcBusGating(u32);
585+
586+
impl LedcBusGating {
587+
/// Disable clock gate for LEDC.
588+
#[inline]
589+
pub const fn gate_mask(self) -> Self {
590+
Self(self.0 & !(1 << 0))
591+
}
592+
/// Enable clock gate for LEDC.
593+
#[inline]
594+
pub const fn gate_pass(self) -> Self {
595+
Self(self.0 | (1 << 0))
596+
}
597+
/// Assert reset signal for LEDC.
598+
#[inline]
599+
pub const fn assert_reset(self) -> Self {
600+
Self(self.0 & !(1 << (0 + 16)))
601+
}
602+
/// Deassert reset signal for LEDC.
603+
#[inline]
604+
pub const fn deassert_reset(self) -> Self {
605+
Self(self.0 | (1 << (0 + 16)))
606+
}
607+
}
608+
496609
#[cfg(test)]
497610
mod tests {
498611
use super::{
@@ -514,6 +627,8 @@ mod tests {
514627
assert_eq!(offset_of!(RegisterBlock, uart_bgr), 0x90c);
515628
assert_eq!(offset_of!(RegisterBlock, spi_clk), 0x940);
516629
assert_eq!(offset_of!(RegisterBlock, spi_bgr), 0x96c);
630+
assert_eq!(offset_of!(RegisterBlock, ledc_clk), 0xbf0);
631+
assert_eq!(offset_of!(RegisterBlock, ledc_bgr), 0xbfc);
517632
}
518633

519634
#[test]
Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,71 @@
11
#![no_std]
22
#![no_main]
33

4-
// use allwinner_hal::prelude::*;
4+
use allwinner_hal::{ccu::*, prelude::*};
55
use allwinner_rt::{Clocks, Peripherals, entry};
66

7+
#[inline]
8+
fn sleep(n: u32) {
9+
for _ in 0..n * 100_000 {
10+
unsafe { core::arch::asm!("nop") }
11+
}
12+
}
13+
714
#[entry]
815
fn main(p: Peripherals, _c: Clocks) {
9-
// TODO implement using LEDC peripheral
16+
unsafe {
17+
LEDC::unmask_gate_only(&p.ccu);
18+
LEDC::enable_in(&p.ccu);
19+
p.ccu.ledc_clk.modify(|x| x.enable_clock_gating());
20+
p.gpio.pc0.into_function::<4>();
21+
}
22+
23+
let ledc = p.ledc;
24+
unsafe {
25+
// Soft reset LDEC
26+
ledc.ledc_control.modify(|x| x.clear_soft_reset());
27+
// Wait reset done
28+
while ledc.ledc_control.read().soft_reset() {
29+
core::hint::spin_loop();
30+
}
31+
}
32+
33+
const STEPS: [u8; 3] = [1, 2, 3];
34+
let mut color = [0, 0, 0];
35+
36+
let wrap_color = |input: u32, flag: bool| {
37+
if flag { 255 - input } else { input }
38+
};
39+
let color_to_u32 = |color: &[u32; 3]| {
40+
let green = wrap_color(color[0] & 0xff, ((color[0] & 0x100) >> 8) == 0);
41+
let red = wrap_color(color[1] & 0xff, ((color[1] & 0x100) >> 8) == 0);
42+
let blue = wrap_color(color[2] & 0xff, ((color[2] & 0x100) >> 8) == 0);
43+
(green << 16) | (red << 8) | blue
44+
};
45+
46+
loop {
47+
unsafe {
48+
// Soft reset LDEC
49+
ledc.ledc_control.modify(|x| x.clear_soft_reset());
50+
// Wait reset done
51+
while ledc.ledc_control.read().soft_reset() {
52+
core::hint::spin_loop();
53+
}
54+
55+
ledc.ledc_data_reg.write(color_to_u32(&color));
56+
57+
// Send on data
58+
ledc.ledc_control
59+
.modify(|x| x.set_total_data_length(1).enable());
60+
61+
while ledc.ledc_control.read().is_enabled() {
62+
core::hint::spin_loop();
63+
}
64+
65+
sleep(10);
66+
for i in 0..3 {
67+
color[i] += STEPS[i] as u32;
68+
}
69+
}
70+
}
1071
}

0 commit comments

Comments
 (0)