Skip to content

Commit 7d337df

Browse files
saif-chipflowrobtaylor
authored andcommitted
Add pwm for motors (#18)
* -Add pwm for 10 motors needed. -Add integration test for pwm * resume unintendedly deleted agent. * fix compilation error * revert main.cc to origin/main
1 parent 64e2c99 commit 7d337df

File tree

6 files changed

+309
-196
lines changed

6 files changed

+309
-196
lines changed

my_design/design.py

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,9 @@
1919

2020
from .ips.spi import SPISignature, SPIPeripheral
2121
from .ips.i2c import I2CSignature, I2CPeripheral
22+
from .ips.pwm import PWMPins, PWMPeripheral
2223

23-
__all__ = ["MotorSignature", "JTAGSignature", "MySoC"]
24-
25-
MotorSignature = wiring.Signature({
26-
"pwm_o": Out(1),
27-
"dir_o": Out(1),
28-
"stop_i": In(1),
29-
})
24+
__all__ = ["JTAGSignature", "MySoC"]
3025

3126
JTAGSignature = wiring.Signature({
3227
"trst_i": In(1),
@@ -63,7 +58,7 @@ def __init__(self):
6358
interfaces[f"i2c_{i}"] = Out(I2CSignature)
6459

6560
for i in range(self.motor_count):
66-
interfaces[f"motor_{i}"] = Out(MotorSignature)
61+
interfaces[f"motor_pwm{i}"] = Out(PWMPins.Signature())
6762

6863
interfaces[f"pdm_ao"] = Out(self.pdm_ao_width)
6964

@@ -96,6 +91,7 @@ def __init__(self):
9691
self.csr_pdm_ao_base = 0xb8000000
9792

9893
self.periph_offset = 0x00100000
94+
self.motor_offset = 0x00000100
9995

10096
self.sram_size = 0x800 # 2KiB
10197
self.bios_start = 0x100000 # 1MiB into spiflash to make room for a bitstream
@@ -207,25 +203,15 @@ def elaborate(self, platform):
207203

208204
setattr(m.submodules, f"i2c_{i}", i2c)
209205

206+
210207
# Motor drivers
211208
for i in range(self.motor_count):
212-
# TODO: create a PWM peripheral and replace this GPIO
213-
soft_motor_pins = GPIOPins(width=3)
214-
pwm = GPIOPeripheral(name=f"motor_pwm_{i}", pins=soft_motor_pins)
215-
216-
base_addr = self.csr_motor_base + i * self.periph_offset
217-
csr_decoder.add(pwm.bus, addr=base_addr - self.csr_base)
218-
sw.add_periph("gpio", f"MOTOR_PWM_{i}", base_addr)
219-
220-
# FIXME: These assignments will disappear once we have a relevant peripheral available
221-
motor_pins = getattr(self, f"motor_{i}")
222-
m.d.comb += [
223-
motor_pins.pwm_o.eq(soft_motor_pins.o[0]),
224-
motor_pins.dir_o.eq(soft_motor_pins.o[1]),
225-
soft_motor_pins.i[2].eq(motor_pins.stop_i),
226-
]
227-
228-
setattr(m.submodules, f"motor_pwm_{i}", pwm)
209+
motor_pwm = PWMPeripheral(name=f"motor_pwm{i}", pins=getattr(self, f"motor_pwm{i}"))
210+
base_addr = self.csr_motor_base + i * self.motor_offset
211+
csr_decoder.add(motor_pwm.bus, addr=base_addr - self.csr_base)
212+
213+
sw.add_periph("motor_pwm", f"MOTOR_PWM{i}", base_addr)
214+
setattr(m.submodules, f"motor_pwm{i}", motor_pwm)
229215

230216
# PDM for analog outputs
231217
# TODO: create a PDM peripheral and replace this GPIO
@@ -276,6 +262,3 @@ def elaborate(self, platform):
276262
soc_top = MySoC()
277263
with open("build/soc_top.v", "w") as f:
278264
f.write(verilog.convert(soc_top, name="soc_top"))
279-
280-
281-

my_design/ips/pwm.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
from amaranth import *
2+
from amaranth import Elaboratable, Module
3+
from amaranth.build import Platform
4+
5+
from amaranth.lib import wiring
6+
from amaranth.lib.wiring import In, Out, flipped, connect
7+
from amaranth.lib.cdc import FFSynchronizer
8+
from amaranth_soc import csr
9+
10+
__all__ = ["PWMPeripheral", "PWMPins"]
11+
12+
13+
class PWMPins(wiring.PureInterface):
14+
class Signature(wiring.Signature):
15+
def __init__(self):
16+
super().__init__({
17+
"pwm_o": Out(1),
18+
"dir_o": Out(1),
19+
"stop_i": In(1),
20+
})
21+
22+
def create(self, *, path=(), src_loc_at=0):
23+
return PWMPins(path=path, src_loc_at=1 + src_loc_at)
24+
25+
def __init__(self, *, path=(), src_loc_at=0):
26+
super().__init__(self.Signature(), path=path, src_loc_at=1 + src_loc_at)
27+
28+
29+
class PWMPeripheral(wiring.Component):
30+
class Numr(csr.Register, access="rw"):
31+
"""Numerator value for PWM duty cycle"""
32+
val: csr.Field(csr.action.RW, unsigned(16))
33+
34+
class Denom(csr.Register, access="rw"):
35+
"""Denominator value for PWM duty cycle
36+
"""
37+
val: csr.Field(csr.action.RW, unsigned(16))
38+
39+
class Conf(csr.Register, access="rw"):
40+
"""Enable register
41+
"""
42+
en: csr.Field(csr.action.RW, unsigned(1))
43+
dir: csr.Field(csr.action.RW, unsigned(1))
44+
45+
class Stop_int(csr.Register, access="rw"):
46+
"""Stop_int register
47+
"""
48+
stopped: csr.Field(csr.action.RW1C, unsigned(1))
49+
50+
class Status(csr.Register, access="r"):
51+
"""Status register
52+
"""
53+
stop_pin: csr.Field(csr.action.R, unsigned(1))
54+
55+
"""pwm peripheral."""
56+
def __init__(self, *, name, pins):
57+
self.pins = pins
58+
59+
regs = csr.Builder(addr_width=5, data_width=8, name=name)
60+
61+
self._numr = regs.add("numr", self.Numr(), offset=0x0)
62+
self._denom = regs.add("denom", self.Denom(), offset=0x4)
63+
self._conf = regs.add("conf", self.Conf(), offset=0x8)
64+
self._stop_int = regs.add("stop_int", self.Stop_int(), offset=0xC)
65+
self._status = regs.add("status", self.Status(), offset=0x10)
66+
67+
self._bridge = csr.Bridge(regs.as_memory_map())
68+
69+
super().__init__({
70+
"bus": In(csr.Signature(addr_width=regs.addr_width, data_width=regs.data_width)),
71+
})
72+
self.bus.memory_map = self._bridge.bus.memory_map
73+
74+
def elaborate(self, platform):
75+
m = Module()
76+
m.submodules.bridge = self._bridge
77+
count = Signal(unsigned(16), reset=0x0)
78+
connect(m, flipped(self.bus), self._bridge.bus)
79+
80+
#synchronizer
81+
stop = Signal()
82+
m.submodules += FFSynchronizer(i=self.pins.stop_i, o=stop)
83+
m.d.comb += self._stop_int.f.stopped.set.eq(stop)
84+
85+
with m.If((self._conf.f.en.data == 1) & (self._stop_int.f.stopped.data == 0) ):
86+
m.d.sync += count.eq(count+1)
87+
with m.Else():
88+
m.d.sync += count.eq(0)
89+
90+
with m.If((self._numr.f.val.data > 0) & (count <= self._numr.f.val.data) & (self._conf.f.en.data == 1) & (self._stop_int.f.stopped.data == 0 )):
91+
m.d.comb += self.pins.pwm_o.eq(1)
92+
with m.Else():
93+
m.d.comb += self.pins.pwm_o.eq(0)
94+
95+
with m.If(count >= self._denom.f.val.data):
96+
m.d.sync += count.eq(0)
97+
98+
m.d.comb += self.pins.dir_o.eq(self._conf.f.dir.data)
99+
m.d.comb += self._status.f.stop_pin.r_data.eq(stop)
100+
101+
return m

my_design/sim/main.cc

Lines changed: 85 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,85 @@
1-
#undef NDEBUG
2-
3-
#include <cxxrtl/cxxrtl.h>
4-
#include <cxxrtl/cxxrtl_server.h>
5-
#include "sim_soc.h"
6-
#include "models.h"
7-
8-
#include <fstream>
9-
#include <filesystem>
10-
11-
using namespace cxxrtl::time_literals;
12-
using namespace cxxrtl_design;
13-
14-
int main(int argc, char **argv) {
15-
p_sim__top top;
16-
17-
spiflash_model flash("flash", top.p_flash____clk__o, top.p_flash____csn__o,
18-
top.p_flash____d__o, top.p_flash____d__oe, top.p_flash____d__i);
19-
20-
uart_model uart_0("uart_0", top.p_uart__0____tx__o, top.p_uart__0____rx__i);
21-
uart_model uart_1("uart_1", top.p_uart__1____tx__o, top.p_uart__1____rx__i);
22-
23-
gpio_model gpio_0("gpio_0", top.p_gpio__0____o, top.p_gpio__0____oe, top.p_gpio__0____i);
24-
gpio_model gpio_1("gpio_1", top.p_gpio__1____o, top.p_gpio__1____oe, top.p_gpio__1____i);
25-
26-
spi_model spi_0("spi_0", top.p_user__spi__0____sck__o, top.p_user__spi__0____csn__o, top.p_user__spi__0____mosi__o, top.p_user__spi__0____miso__i);
27-
spi_model spi_1("spi_1", top.p_user__spi__1____sck__o, top.p_user__spi__1____csn__o, top.p_user__spi__1____mosi__o, top.p_user__spi__1____miso__i);
28-
spi_model spi_2("spi_2", top.p_user__spi__2____sck__o, top.p_user__spi__2____csn__o, top.p_user__spi__2____mosi__o, top.p_user__spi__2____miso__i);
29-
30-
i2c_model i2c_0("i2c_0", top.p_i2c__0____sda__oe, top.p_i2c__0____sda__i, top.p_i2c__0____scl__oe, top.p_i2c__0____scl__i);
31-
i2c_model i2c_1("i2c_1", top.p_i2c__1____sda__oe, top.p_i2c__1____sda__i, top.p_i2c__1____scl__oe, top.p_i2c__1____scl__i);
32-
33-
cxxrtl::agent agent(cxxrtl::spool("spool.bin"), top);
34-
if (getenv("DEBUG")) // can also be done when a condition is violated, etc
35-
std::cerr << "Waiting for debugger on " << agent.start_debugging() << std::endl;
36-
37-
open_event_log("events.json");
38-
open_input_commands("../../my_design/tests/input.json");
39-
40-
unsigned timestamp = 0;
41-
auto tick = [&]() {
42-
// agent.print(stringf("timestamp %d\n", timestamp), CXXRTL_LOCATION);
43-
44-
flash.step(timestamp);
45-
uart_0.step(timestamp);
46-
uart_1.step(timestamp);
47-
48-
gpio_0.step(timestamp);
49-
gpio_1.step(timestamp);
50-
51-
spi_0.step(timestamp);
52-
spi_1.step(timestamp);
53-
spi_2.step(timestamp);
54-
55-
i2c_0.step(timestamp);
56-
i2c_1.step(timestamp);
57-
58-
top.p_clk.set(false);
59-
agent.step();
60-
agent.advance(1_us);
61-
++timestamp;
62-
63-
top.p_clk.set(true);
64-
agent.step();
65-
agent.advance(1_us);
66-
++timestamp;
67-
68-
// if (timestamp == 10)
69-
// agent.breakpoint(CXXRTL_LOCATION);
70-
};
71-
72-
flash.load_data("../software/software.bin", 0x00100000U);
73-
agent.step();
74-
agent.advance(1_us);
75-
76-
top.p_rst.set(true);
77-
tick();
78-
79-
top.p_rst.set(false);
80-
for (int i = 0; i < 2000000; i++)
81-
tick();
82-
83-
close_event_log();
84-
return 0;
85-
}
1+
#undef NDEBUG
2+
3+
#include <cxxrtl/cxxrtl.h>
4+
#include <cxxrtl/cxxrtl_server.h>
5+
#include "sim_soc.h"
6+
#include "models.h"
7+
8+
#include <fstream>
9+
#include <filesystem>
10+
11+
using namespace cxxrtl::time_literals;
12+
using namespace cxxrtl_design;
13+
14+
int main(int argc, char **argv) {
15+
p_sim__top top;
16+
17+
spiflash_model flash("flash", top.p_flash____clk__o, top.p_flash____csn__o,
18+
top.p_flash____d__o, top.p_flash____d__oe, top.p_flash____d__i);
19+
20+
uart_model uart_0("uart_0", top.p_uart__0____tx__o, top.p_uart__0____rx__i);
21+
uart_model uart_1("uart_1", top.p_uart__1____tx__o, top.p_uart__1____rx__i);
22+
23+
gpio_model gpio_0("gpio_0", top.p_gpio__0____o, top.p_gpio__0____oe, top.p_gpio__0____i);
24+
gpio_model gpio_1("gpio_1", top.p_gpio__1____o, top.p_gpio__1____oe, top.p_gpio__1____i);
25+
26+
spi_model spi_0("spi_0", top.p_user__spi__0____sck__o, top.p_user__spi__0____csn__o, top.p_user__spi__0____mosi__o, top.p_user__spi__0____miso__i);
27+
spi_model spi_1("spi_1", top.p_user__spi__1____sck__o, top.p_user__spi__1____csn__o, top.p_user__spi__1____mosi__o, top.p_user__spi__1____miso__i);
28+
spi_model spi_2("spi_2", top.p_user__spi__2____sck__o, top.p_user__spi__2____csn__o, top.p_user__spi__2____mosi__o, top.p_user__spi__2____miso__i);
29+
30+
i2c_model i2c_0("i2c_0", top.p_i2c__0____sda__oe, top.p_i2c__0____sda__i, top.p_i2c__0____scl__oe, top.p_i2c__0____scl__i);
31+
i2c_model i2c_1("i2c_1", top.p_i2c__1____sda__oe, top.p_i2c__1____sda__i, top.p_i2c__1____scl__oe, top.p_i2c__1____scl__i);
32+
33+
cxxrtl::agent agent(cxxrtl::spool("spool.bin"), top);
34+
if (getenv("DEBUG")) // can also be done when a condition is violated, etc
35+
std::cerr << "Waiting for debugger on " << agent.start_debugging() << std::endl;
36+
37+
open_event_log("events.json");
38+
open_input_commands("../../my_design/tests/input.json");
39+
40+
unsigned timestamp = 0;
41+
auto tick = [&]() {
42+
// agent.print(stringf("timestamp %d\n", timestamp), CXXRTL_LOCATION);
43+
44+
flash.step(timestamp);
45+
uart_0.step(timestamp);
46+
uart_1.step(timestamp);
47+
48+
gpio_0.step(timestamp);
49+
gpio_1.step(timestamp);
50+
51+
spi_0.step(timestamp);
52+
spi_1.step(timestamp);
53+
spi_2.step(timestamp);
54+
55+
i2c_0.step(timestamp);
56+
i2c_1.step(timestamp);
57+
58+
top.p_clk.set(false);
59+
agent.step();
60+
agent.advance(1_us);
61+
++timestamp;
62+
63+
top.p_clk.set(true);
64+
agent.step();
65+
agent.advance(1_us);
66+
++timestamp;
67+
68+
// if (timestamp == 10)
69+
// agent.breakpoint(CXXRTL_LOCATION);
70+
};
71+
72+
flash.load_data("../software/software.bin", 0x00100000U);
73+
agent.step();
74+
agent.advance(1_us);
75+
76+
top.p_rst.set(true);
77+
tick();
78+
79+
top.p_rst.set(false);
80+
for (int i = 0; i < 2000000; i++)
81+
tick();
82+
83+
close_event_log();
84+
return 0;
85+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/* SPDX-License-Identifier: BSD-2-Clause */
2+
#ifndef MOTOR_PWM_H
3+
#define MOTOR_PWM_H
4+
5+
#include <stdint.h>
6+
7+
typedef struct {
8+
uint32_t numr;
9+
uint32_t denom;
10+
uint32_t conf;
11+
uint32_t stop_int;
12+
uint32_t status;
13+
} motor_pwm_regs_t;
14+
15+
#endif
16+

0 commit comments

Comments
 (0)