Skip to content

Commit 733dff4

Browse files
saif-chipflowrobtaylor
authored andcommitted
- Implement a single bit pdm. Include an integration test (#20)
- Use output pins without pins interface - pdm outval can now be maximum 16 bits - modify header to replace din with outval - add unit test for pdm
1 parent 5461e69 commit 733dff4

File tree

6 files changed

+184
-18
lines changed

6 files changed

+184
-18
lines changed

my_design/design.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from .ips.spi import SPISignature, SPIPeripheral
2121
from .ips.i2c import I2CSignature, I2CPeripheral
2222
from .ips.pwm import PWMPins, PWMPeripheral
23+
from .ips.pdm import PDMPeripheral
2324

2425
__all__ = ["JTAGSignature", "MySoC"]
2526

@@ -45,7 +46,7 @@ def __init__(self):
4546
self.user_spi_count = 3
4647
self.i2c_count = 2
4748
self.motor_count = 10
48-
self.pdm_ao_width = 6
49+
self.pdm_ao_count = 6
4950
self.uart_count = 2
5051

5152
self.gpio_banks = 2
@@ -60,7 +61,8 @@ def __init__(self):
6061
for i in range(self.motor_count):
6162
interfaces[f"motor_pwm{i}"] = Out(PWMPins.Signature())
6263

63-
interfaces[f"pdm_ao"] = Out(self.pdm_ao_width)
64+
for i in range(self.pdm_ao_count):
65+
interfaces[f"pdm_ao_{i}"] = Out(1)
6466

6567
for i in range(self.uart_count):
6668
interfaces[f"uart_{i}"] = Out(UARTPins.Signature())
@@ -90,8 +92,9 @@ def __init__(self):
9092
self.csr_motor_base = 0xb7000000
9193
self.csr_pdm_ao_base = 0xb8000000
9294

93-
self.periph_offset = 0x00100000
94-
self.motor_offset = 0x00000100
95+
self.periph_offset = 0x00100000
96+
self.motor_offset = 0x00000100
97+
self.pdm_ao_offset = 0x00000010
9598

9699
self.sram_size = 0x800 # 2KiB
97100
self.bios_start = 0x100000 # 1MiB into spiflash to make room for a bitstream
@@ -213,18 +216,15 @@ def elaborate(self, platform):
213216
sw.add_periph("motor_pwm", f"MOTOR_PWM{i}", base_addr)
214217
setattr(m.submodules, f"motor_pwm{i}", motor_pwm)
215218

216-
# PDM for analog outputs
217-
# TODO: create a PDM peripheral and replace this GPIO
218-
soft_pdm_pins = GPIOPins(width=self.pdm_ao_width)
219-
pdm = GPIOPeripheral(name=f"pdm_ao", pins=soft_pdm_pins)
220-
221-
csr_decoder.add(pdm.bus, addr=self.csr_pdm_ao_base - self.csr_base)
222-
sw.add_periph("gpio", f"PDM_AO_{i}", self.csr_pdm_ao_base)
223-
224-
# FIXME: This assignment will disappear once we have a relevant peripheral available
225-
m.d.comb += [self.pdm_ao.eq(soft_pdm_pins.o)]
226-
227-
m.submodules.pdm_ao = pdm
219+
# pdm_ao
220+
for i in range(self.pdm_ao_count):
221+
pdm = PDMPeripheral(name=f"pdm{i}", bitwidth=10)
222+
base_addr = self.csr_pdm_ao_base + i * self.pdm_ao_offset
223+
csr_decoder.add(pdm.bus, addr=base_addr - self.csr_base)
224+
225+
sw.add_periph("pdm", f"PDM{i}", base_addr)
226+
setattr(m.submodules, f"pdm{i}", pdm)
227+
m.d.comb += getattr(self, f"pdm_ao_{i}").eq(pdm.pdm_ao)
228228

229229
# SoC ID
230230

my_design/ips/pdm.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
from amaranth import *
3+
from amaranth import Elaboratable, Module
4+
from amaranth.build import Platform
5+
6+
from amaranth.lib import wiring
7+
from amaranth.lib.wiring import In, Out, flipped, connect
8+
from amaranth_soc import csr
9+
10+
__all__ = ["PDMPeripheral"]
11+
12+
class PDMPeripheral(wiring.Component):
13+
class OutVal(csr.Register, access="rw"):
14+
"""Analog sample value"""
15+
val: csr.Field(csr.action.RW, unsigned(16))
16+
17+
class Conf(csr.Register, access="rw"):
18+
"""Configuration register """
19+
en: csr.Field(csr.action.RW, unsigned(1))
20+
21+
22+
def __init__(self, *, name, bitwidth):
23+
self._bitwidth = bitwidth
24+
25+
26+
regs = csr.Builder(addr_width=3, data_width=8, name=name)
27+
28+
self._outval = regs.add("outval", self.OutVal(), offset=0x0)
29+
self._conf = regs.add("conf", self.Conf(), offset=0x4)
30+
31+
self._bridge = csr.Bridge(regs.as_memory_map())
32+
33+
super().__init__({
34+
"bus": In(csr.Signature(addr_width=regs.addr_width, data_width=regs.data_width)),
35+
"pdm_ao": Out(1),
36+
})
37+
self.bus.memory_map = self._bridge.bus.memory_map
38+
39+
@property
40+
def bitwidth(self):
41+
return self._bitwidth
42+
43+
def elaborate(self, platform):
44+
m = Module()
45+
m.submodules.bridge = self._bridge
46+
maxval = Const(int((2**self._bitwidth)-1), unsigned(self._bitwidth))
47+
error = Signal(unsigned(self._bitwidth), reset=0x0)
48+
error_0 = Signal(unsigned(self._bitwidth), reset=0x0)
49+
error_1 = Signal(unsigned(self._bitwidth), reset=0x0)
50+
pdm_ao = Signal()
51+
connect(m, flipped(self.bus), self._bridge.bus)
52+
m.d.sync += [
53+
error_1.eq(error + maxval - self._outval.f.val.data),
54+
error_0.eq(error - self._outval.f.val.data),
55+
]
56+
with m.If(self._outval.f.val.data >= error):
57+
m.d.sync += [
58+
pdm_ao.eq(1),
59+
error.eq(error_1),
60+
]
61+
with m.Else():
62+
m.d.sync += [
63+
pdm_ao.eq(0),
64+
error.eq(error_0),
65+
]
66+
67+
with m.If(self._conf.f.en.data == 1):
68+
m.d.comb += self.pdm_ao.eq(pdm_ao)
69+
with m.Else():
70+
m.d.comb += self.pdm_ao.eq(0)
71+
return m

my_design/ips/test_pdm.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from amaranth import *
2+
from amaranth.sim import Simulator, Tick
3+
4+
from pdm import PDMPeripheral
5+
import unittest
6+
7+
class TestPdmPeripheral(unittest.TestCase):
8+
9+
REG_OUTVAL = 0x00
10+
REG_CONF = 0x04
11+
12+
13+
def _write_reg(self, dut, reg, value, width=4):
14+
for i in range(width):
15+
yield dut.bus.addr.eq(reg + i)
16+
yield dut.bus.w_data.eq((value >> (8 * i)) & 0xFF)
17+
yield dut.bus.w_stb.eq(1)
18+
yield Tick()
19+
yield dut.bus.w_stb.eq(0)
20+
21+
def _check_reg(self, dut, reg, value, width=4):
22+
result = 0
23+
for i in range(width):
24+
yield dut.bus.addr.eq(reg + i)
25+
yield dut.bus.r_stb.eq(1)
26+
yield Tick()
27+
result |= (yield dut.bus.r_data) << (8 * i)
28+
yield dut.bus.r_stb.eq(0)
29+
self.assertEqual(result, value)
30+
31+
def test_pdm_ao(self):
32+
dut = PDMPeripheral(name="dut", bitwidth=10)
33+
def testbench():
34+
yield from self._write_reg(dut, self.REG_OUTVAL, 0xFF, 4)
35+
yield Tick()
36+
yield from self._write_reg(dut, self.REG_CONF, 0x1, 1)
37+
for i in range(6): yield Tick()
38+
self.assertEqual((yield dut.pdm_ao), 1) # assert two cycles of logic '1' (4us)
39+
yield Tick()
40+
self.assertEqual((yield dut.pdm_ao), 1)
41+
yield Tick()
42+
self.assertEqual((yield dut.pdm_ao), 0) # assert 6 cycles of logic '0' (12us)
43+
for i in range(5): yield Tick()
44+
self.assertEqual((yield dut.pdm_ao), 0)
45+
yield Tick()
46+
self.assertEqual((yield dut.pdm_ao), 1) # assert start of the next pulse
47+
for i in range(50): yield Tick()
48+
sim = Simulator(dut)
49+
sim.add_clock(2e-6)
50+
sim.add_testbench(testbench)
51+
with sim.write_vcd("pdm_ao_test.vcd", "pdm_ao_test.gtkw"):
52+
sim.run()
53+
54+
def test_conf(self):
55+
dut = PDMPeripheral(name="dut", bitwidth=10)
56+
def testbench():
57+
yield from self._write_reg(dut, self.REG_OUTVAL, 0xFF, 4)
58+
yield Tick()
59+
yield from self._write_reg(dut, self.REG_CONF, 0x1, 1)
60+
for i in range(6): yield Tick()
61+
self.assertEqual((yield dut.pdm_ao), 1)
62+
yield from self._write_reg(dut, self.REG_CONF, 0x0, 1)
63+
yield Tick()
64+
self.assertEqual((yield dut.pdm_ao), 0)
65+
for i in range(50): yield Tick()
66+
sim = Simulator(dut)
67+
sim.add_clock(2e-6)
68+
sim.add_testbench(testbench)
69+
with sim.write_vcd("pdm_conf_test.vcd", "pdm_conf_test.gtkw"):
70+
sim.run()
71+
72+
if __name__ == "__main__":
73+
unittest.main()
74+

my_design/software/drivers/pdm.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* SPDX-License-Identifier: BSD-2-Clause */
2+
#ifndef PDM_H
3+
#define PDM_H
4+
5+
#include <stdint.h>
6+
7+
typedef struct {
8+
uint32_t outval;
9+
uint32_t conf;
10+
} pdm_regs_t;
11+
12+
#endif
13+

my_design/software/main.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,15 @@ void main() {
8282
MOTOR_PWM9->numr = 0x7F;
8383
MOTOR_PWM9->denom = 0xFF;
8484
MOTOR_PWM9->conf = 0x3;
85-
85+
86+
PDM0->outval = 0xFF;
87+
PDM1->outval = 0x7F;
88+
PDM2->outval = 0x3F;
89+
90+
PDM0->conf = 0x1;
91+
PDM1->conf = 0x1;
92+
PDM2->conf = 0x0;
93+
8694
puts("GPIO: ");
8795
puthex(GPIO_1->in);
8896
puts(" ");

my_design/steps/_chipflow_top.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def _connect_interface(interface, name):
5252
_connect_interface(getattr(soc, f"motor_pwm{pwm_idx}"), f"motor_pwm{pwm_idx}")
5353

5454
for ao_idx in range(6):
55-
m.d.comb += platform.request(f"pdm_ao_{ao_idx}").o.eq(soc.pdm_ao[ao_idx])
55+
m.d.comb += platform.request(f"pdm_ao_{ao_idx}").o.eq(getattr(soc, f"pdm_ao_{ao_idx}"))
5656

5757
for gpio_bank in range(2):
5858
gpio = getattr(soc, f"gpio_{gpio_bank}")

0 commit comments

Comments
 (0)