Merge pull request #1662 from enjoy-digital/multi-channel-pwm
soc/cores/pwm: Add MultiChannelPWM core reusing PWM module.
This commit is contained in:
commit
4b72dd047e
|
@ -19,7 +19,7 @@ class PWM(Module, AutoCSR):
|
||||||
Pulse Width Modulation can be useful for various purposes: dim leds, regulate a fan, control
|
Pulse Width Modulation can be useful for various purposes: dim leds, regulate a fan, control
|
||||||
an oscillator. Software can configure the PWM width and period and enable/disable it.
|
an oscillator. Software can configure the PWM width and period and enable/disable it.
|
||||||
"""
|
"""
|
||||||
def __init__(self, pwm=None, clock_domain="sys", with_csr=True,
|
def __init__(self, pwm=None, clock_domain="sys", counter=None, with_csr=True,
|
||||||
default_enable = 0,
|
default_enable = 0,
|
||||||
default_width = 0,
|
default_width = 0,
|
||||||
default_period = 0):
|
default_period = 0):
|
||||||
|
@ -32,30 +32,34 @@ class PWM(Module, AutoCSR):
|
||||||
|
|
||||||
# # #
|
# # #
|
||||||
|
|
||||||
counter = Signal(32, reset_less=True)
|
|
||||||
|
|
||||||
sync = getattr(self.sync, clock_domain)
|
sync = getattr(self.sync, clock_domain)
|
||||||
|
|
||||||
|
# PWM Counter/Period logic.
|
||||||
|
if counter is None:
|
||||||
|
self.counter = counter = Signal(32, reset_less=True)
|
||||||
sync += [
|
sync += [
|
||||||
|
counter.eq(0),
|
||||||
|
If(self.enable & ~self.reset,
|
||||||
|
If(counter < (self.period - 1),
|
||||||
|
counter.eq(counter + 1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# PWM Width logic.
|
||||||
|
sync += [
|
||||||
|
pwm.eq(0),
|
||||||
If(self.enable & ~self.reset,
|
If(self.enable & ~self.reset,
|
||||||
counter.eq(counter + 1),
|
|
||||||
If(counter < self.width,
|
If(counter < self.width,
|
||||||
pwm.eq(1)
|
pwm.eq(1)
|
||||||
).Else(
|
|
||||||
pwm.eq(0)
|
|
||||||
),
|
|
||||||
If(counter >= (self.period - 1),
|
|
||||||
counter.eq(0)
|
|
||||||
)
|
)
|
||||||
).Else(
|
|
||||||
counter.eq(0),
|
|
||||||
pwm.eq(0)
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
if with_csr:
|
if with_csr:
|
||||||
self.add_csr(clock_domain)
|
self.add_csr(clock_domain)
|
||||||
|
|
||||||
def add_csr(self, clock_domain):
|
def add_enable_width_csr(self, clock_domain):
|
||||||
self._enable = CSRStorage(description="""PWM Enable.\n
|
self._enable = CSRStorage(description="""PWM Enable.\n
|
||||||
Write ``1`` to enable PWM.""",
|
Write ``1`` to enable PWM.""",
|
||||||
reset = self.enable.reset)
|
reset = self.enable.reset)
|
||||||
|
@ -63,13 +67,55 @@ class PWM(Module, AutoCSR):
|
||||||
Defines the *Duty cycle* of the PWM. PWM is active high for *Width* ``{cd}_clk`` cycles and
|
Defines the *Duty cycle* of the PWM. PWM is active high for *Width* ``{cd}_clk`` cycles and
|
||||||
active low for *Period - Width* ``{cd}_clk`` cycles.""".format(cd=clock_domain),
|
active low for *Period - Width* ``{cd}_clk`` cycles.""".format(cd=clock_domain),
|
||||||
reset = self.width.reset)
|
reset = self.width.reset)
|
||||||
self._period = CSRStorage(32, reset_less=True, description="""PWM Period.\n
|
|
||||||
Defines the *Period* of the PWM in ``{cd}_clk`` cycles.""".format(cd=clock_domain),
|
|
||||||
reset = self.period.reset)
|
|
||||||
|
|
||||||
n = 0 if clock_domain == "sys" else 2
|
n = 0 if clock_domain == "sys" else 2
|
||||||
self.specials += [
|
self.specials += [
|
||||||
MultiReg(self._enable.storage, self.enable, n=n),
|
MultiReg(self._enable.storage, self.enable, n=n),
|
||||||
MultiReg(self._width.storage, self.width, n=n),
|
MultiReg(self._width.storage, self.width, n=n),
|
||||||
MultiReg(self._period.storage, self.period, n=n),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def add_period_csr(self, clock_domain):
|
||||||
|
self._period = CSRStorage(32, reset_less=True, description="""PWM Period.\n
|
||||||
|
Defines the *Period* of the PWM in ``{cd}_clk`` cycles.""".format(cd=clock_domain),
|
||||||
|
reset = self.period.reset)
|
||||||
|
|
||||||
|
n = 0 if clock_domain == "sys" else 2
|
||||||
|
self.specials += MultiReg(self._period.storage, self.period, n=n)
|
||||||
|
|
||||||
|
def add_csr(self, clock_domain):
|
||||||
|
self.add_enable_width_csr(clock_domain)
|
||||||
|
self.add_period_csr(clock_domain)
|
||||||
|
|
||||||
|
# Multi Channel Pulse Width Modulation -------------------------------------------------------------
|
||||||
|
|
||||||
|
class MultiChannelPWM(Module, AutoCSR):
|
||||||
|
"""Multi-Channel Pulse Width Modulation
|
||||||
|
|
||||||
|
PWM module with Multi-Channel support.
|
||||||
|
"""
|
||||||
|
def __init__(self, pads, clock_domain="sys",
|
||||||
|
default_enable = 0,
|
||||||
|
default_width = 0,
|
||||||
|
default_period = 0):
|
||||||
|
|
||||||
|
# # #
|
||||||
|
|
||||||
|
nchannels = len(pads)
|
||||||
|
|
||||||
|
counter = Signal(32, reset_less=True)
|
||||||
|
for n in range(nchannels):
|
||||||
|
pwm = PWM(
|
||||||
|
pwm = pads[n],
|
||||||
|
clock_domain = clock_domain,
|
||||||
|
with_csr = False,
|
||||||
|
counter = None if n == 0 else counter,
|
||||||
|
default_enable = default_enable,
|
||||||
|
default_width = default_width,
|
||||||
|
default_period = default_period,
|
||||||
|
)
|
||||||
|
|
||||||
|
if n == 0:
|
||||||
|
self.comb += counter.eq(pwm.counter)
|
||||||
|
pwm.add_period_csr(clock_domain)
|
||||||
|
pwm.add_enable_width_csr(clock_domain)
|
||||||
|
self.add_module(name=f"channel{n}", module=pwm)
|
||||||
|
|
Loading…
Reference in New Issue