Compare commits

...

1 Commits

Author SHA1 Message Date
e0769f0c0d Test with modem connected 2026-03-05 19:49:44 +01:00
7 changed files with 8300 additions and 11 deletions

BIN
capture1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

8193
capture2.csv Normal file

File diff suppressed because it is too large Load Diff

BIN
capture2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

@@ -38,7 +38,7 @@ module sd_adc_q15 #(
);
lpf_iir_q15_k #(
.K(6)
.K(8)
) lpf (
.i_clk(i_clk_15), .i_rst_n(i_rst_n),
.i_x_q15(raw_sample_q15),
@@ -46,8 +46,8 @@ module sd_adc_q15 #(
);
decimate_by_r_q15 #(
.R(200), // 15MHz/200 = 75KHz
// .R(375), // 15MHz/375 = 40KHz
// .R(200), // 15MHz/200 = 75KHz
.R(375), // 15MHz/375 = 40KHz
.CNT_W(10)
) decimate (
.i_clk(i_clk_15), .i_rst_n(i_rst_n),

View File

@@ -57,6 +57,10 @@ module signal_scope_q15 #(
wire [3:0] wb_reg_idx = wb_adr[5:2];
reg [15:0] trigger_sample;
reg trigger_sample_valid;
reg wb_mem_read_pending;
reg wb_mem_read_half;
reg wb_mem_read_oob;
reg [16*4-1:0] wb_mem_rdata;
jtag_wb_bridge #(
.chain(chain),
@@ -119,6 +123,10 @@ module signal_scope_q15 #(
signal_b_pending <= 1'b0;
signal_c_pending <= 1'b0;
signal_d_pending <= 1'b0;
wb_mem_read_pending <= 1'b0;
wb_mem_read_half <= 1'b0;
wb_mem_read_oob <= 1'b0;
wb_mem_rdata <= {(16*4){1'b0}};
end else begin
// Sample signals
@@ -188,9 +196,16 @@ module signal_scope_q15 #(
// WB slave response: register window + capture memory window.
arm_req <= 1'b0;
wb_ack <= wb_cyc & wb_stb & !wb_ack;
if(wb_cyc & wb_stb & !wb_ack) begin
wb_ack <= 1'b0;
if(wb_mem_read_pending) begin
wb_ack <= 1'b1;
wb_rdt <= wb_mem_read_oob ? 32'b0 :
(wb_mem_read_half ? wb_mem_rdata[63:32] : wb_mem_rdata[31:0]);
wb_mem_read_pending <= 1'b0;
end else if(wb_cyc & wb_stb) begin
if(wb_we) begin
wb_ack <= 1'b1;
wb_rdt <= 32'b0;
if(wb_is_reg) begin
// Keep register write decode in one case so new writable registers
@@ -217,6 +232,7 @@ module signal_scope_q15 #(
end
end else begin
if(wb_is_reg) begin
wb_ack <= 1'b1;
case(wb_reg_idx)
// [3:2]=trigger_channel, [1]=trigger_enable, [0]=arm(write pulse only/read 0).
reg_control: wb_rdt <= {28'b0, trigger_channel, trigger_enable, 1'b0};
@@ -225,11 +241,12 @@ module signal_scope_q15 #(
reg_trig_val: wb_rdt <= {16'b0, trig_val};
default: wb_rdt <= 32'b0;
endcase
end else if(wb_mem_idx <= depth_last) begin
// A single frame is 64-bit: {a, b, c, d}. WB reads low/high 32-bit halves.
wb_rdt <= wb_adr[2] ? mem[wb_mem_idx][63:32] : mem[wb_mem_idx][31:0];
end else begin
wb_rdt <= 32'b0;
// Synchronous RAM read for BRAM inference: issue read now, acknowledge next cycle.
wb_mem_rdata <= mem[wb_mem_idx];
wb_mem_read_half <= wb_adr[2];
wb_mem_read_oob <= (wb_mem_idx > depth_last);
wb_mem_read_pending <= 1'b1;
end
end
end

View File

@@ -60,7 +60,7 @@ module toplevel(
// signal_q15 is unipolar and biased (0-3.3V -> 0..32767)
reg signed [15:0] signal_unbiased_q15 = 16'sd0;
reg signal_unbiased_valid = 1'b0;
localparam bias = 12050;
localparam bias = 2**14;
localparam gain = 2;
always @(posedge clk_15) begin
if (sys_reset_r) begin
@@ -91,7 +91,7 @@ module toplevel(
signal_scope_q15 #(
.depth(2**10),
.depth(2**13),
.chain(1)
) scope1 (
.i_clk(clk_15),

79
modem/modem_dtmf.py Executable file
View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python3
import argparse
import sys
import time
import serial
def read_response(port: serial.Serial, timeout_s: float) -> list[str]:
deadline = time.monotonic() + timeout_s
lines: list[str] = []
while time.monotonic() < deadline:
raw = port.readline()
if not raw:
continue
line = raw.decode(errors="replace").strip()
if not line:
continue
lines.append(line)
if line in {"OK", "ERROR"}:
break
return lines
def send_at(port: serial.Serial, command: str, timeout_s: float) -> tuple[bool, list[str]]:
port.write((command + "\r").encode())
port.flush()
lines = read_response(port, timeout_s)
ok = any(line == "OK" for line in lines)
err = any(line == "ERROR" for line in lines)
return ok and not err, lines
def send_and_log(port: serial.Serial, command: str, timeout_s: float) -> tuple[bool, list[str]]:
ok, lines = send_at(port, command, timeout_s)
print(f"> {command}")
for line in lines:
print(f"< {line}")
return ok, lines
def main() -> int:
parser = argparse.ArgumentParser(description="Control an AT modem and send DTMF tones")
parser.add_argument("device", help="Serial device path, e.g. /dev/ttyACM0")
parser.add_argument("--baud", type=int, default=115200, help="Serial baudrate (default: 115200)")
parser.add_argument("--timeout", type=float, default=2.0, help="AT command timeout seconds")
args = parser.parse_args()
try:
with serial.Serial(args.device, args.baud, timeout=0.2, write_timeout=1.0) as port:
port.reset_input_buffer()
port.reset_output_buffer()
# Inicialise
for cmd in ("AT", "ATZ0", "ATE1", "ATX0"):
ok, lines = send_and_log(port, cmd, args.timeout)
if not ok:
print(f"Modem did not accept {cmd}", file=sys.stderr)
return 1
send_and_log(port, "ATS6=0", args.timeout) # Set wait for dial tone time to 0
send_and_log(port, "ATS11=2", args.timeout) # set tone length to 1 ms
send_and_log(port, "ATH1", args.timeout)
while True:
send_and_log(port, "ATDT0123456789;", args.timeout)
send_and_log(port, "ATH0", args.timeout)
except serial.SerialException as exc:
print(f"Serial error: {exc}", file=sys.stderr)
return 1
print("Done")
return 0
if __name__ == "__main__":
raise SystemExit(main())