From 5df6824b3aec0ab01fc837e7294bdbcda6352fa6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Hamal=20Dvo=C5=99=C3=A1k?= <mordae@anilinux.org>
Date: Sun, 28 Jan 2024 13:14:30 +0100
Subject: [PATCH] Add sweep, noise and faster LO generator
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Jan Hamal Dvořák <mordae@anilinux.org>
---
 src/main.c | 107 +++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 84 insertions(+), 23 deletions(-)

diff --git a/src/main.c b/src/main.c
index dc57bdb..112917f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -263,39 +263,27 @@ static float lo_freq_init(float req_freq)
 	float freq = roundf(req_freq / step_hz) * step_hz;
 
 	unsigned step = (float)UINT_MAX / (float)CLK_SYS_HZ * freq;
-	unsigned sin_acc = 0;
-	unsigned cos_acc = UINT_MAX / 4;
-	unsigned sin_err = 0;
-	unsigned cos_err = 0;
 
-	int prev_sin_bit = 0;
-	int prev_cos_bit = 1;
+	interp0->ctrl[0] = (31 << SIO_INTERP0_CTRL_LANE0_MASK_MSB_LSB) |
+			   (0 << SIO_INTERP0_CTRL_LANE0_MASK_LSB_LSB) |
+			   (0 << SIO_INTERP0_CTRL_LANE0_SHIFT_LSB);
+	interp0->ctrl[1] = interp0->ctrl[0];
+
+	interp0->base[0] = step;
+	interp0->base[1] = step;
+	interp0->accum[1] = UINT_MAX / 4;
 
 	for (int i = 0; i < LO_WORDS; i++) {
 		unsigned bsin = 0, bcos = 0;
 
 		for (int j = 0; j < 32; j++) {
-			int sin_bit = (sin_acc + sin_err) >> 31;
+			int sin_bit = interp0->peek[0] >> 31;
 			bsin |= sin_bit;
 			bsin <<= 1;
 
-			int cos_bit = (cos_acc + cos_err) >> 31;
+			int cos_bit = interp0->pop[1] >> 31;
 			bcos |= cos_bit;
 			bcos <<= 1;
-
-			if (prev_sin_bit != sin_bit) {
-				sin_err = (sin_acc + sin_err) & 0x7fffffff;
-			}
-
-			if (prev_cos_bit != cos_bit) {
-				cos_err = (cos_acc + cos_err) & 0x7fffffff;
-			}
-
-			prev_sin_bit = sin_bit;
-			prev_cos_bit = cos_bit;
-
-			sin_acc += step;
-			cos_acc += step;
 		}
 
 		lo_sin[i] = bsin;
@@ -693,7 +681,7 @@ static void command(const char *cmd)
 {
 	static char tmp[83];
 	int n, x;
-	float f;
+	float f, g;
 
 	if (1 == sscanf(cmd, " help %[\a]", tmp)) {
 		puts("help             - this help");
@@ -701,6 +689,8 @@ static void command(const char *cmd)
 		puts("bias I O         - output negated I to O");
 		puts("rx N FREQ        - receive on pin N");
 		puts("tx N FREQ        - transmit on pin N");
+		puts("sweep N F G MS   - sweep from F to G with MS at step");
+		puts("noise N          - transmit random noise");
 		return;
 	}
 
@@ -802,6 +792,77 @@ static void command(const char *cmd)
 		return;
 	}
 
+	if (5 == sscanf(cmd, " sweep %i %f %f %i %[\a]", &n, &f, &g, &x, tmp)) {
+		dma_channel_abort(tx_dma);
+
+		if (!f || !g) {
+			gpio_init(n);
+			puts("stopped");
+			return;
+		}
+
+		send_init(n);
+
+		const float step_hz = (float)CLK_SYS_HZ / (LO_WORDS * 32);
+		const float start = roundf(f / step_hz) * step_hz;
+		const float stop = roundf(g / step_hz) * step_hz;
+
+		int steps = roundf((stop - start) / step_hz);
+
+		for (int i = 0; i < LO_WORDS; i++)
+			lo_cos[i] = 0;
+
+		dma_channel_config dma_conf = dma_channel_get_default_config(tx_dma);
+		channel_config_set_transfer_data_size(&dma_conf, DMA_SIZE_32);
+		channel_config_set_read_increment(&dma_conf, true);
+		channel_config_set_write_increment(&dma_conf, false);
+		channel_config_set_ring(&dma_conf, false, LO_BITS_DEPTH + 2);
+		channel_config_set_dreq(&dma_conf, pio_get_dreq(pio1, 2, true));
+		dma_channel_configure(tx_dma, &dma_conf, &pio1->txf[2], lo_cos, UINT_MAX, true);
+
+		for (int i = 0; i < steps; i++) {
+			int c = getchar_timeout_us(0);
+			if ('\n' == c || '\r' == c)
+				break;
+
+			float actual = lo_freq_init(start + i * step_hz);
+			printf("frequency = %10.6f MHz\n", actual / MHZ);
+			sleep_ms(x);
+		}
+
+		dma_channel_abort(tx_dma);
+		return;
+	}
+
+	if (2 == sscanf(cmd, " noise %i %[\a]", &n, tmp)) {
+		send_init(n);
+
+		for (int i = 0; i < LO_WORDS; i++)
+			lo_cos[i] = rand();
+
+		dma_channel_config dma_conf = dma_channel_get_default_config(tx_dma);
+		channel_config_set_transfer_data_size(&dma_conf, DMA_SIZE_32);
+		channel_config_set_read_increment(&dma_conf, true);
+		channel_config_set_write_increment(&dma_conf, false);
+		channel_config_set_ring(&dma_conf, false, LO_BITS_DEPTH + 2);
+		channel_config_set_dreq(&dma_conf, pio_get_dreq(pio1, 2, true));
+		dma_channel_configure(tx_dma, &dma_conf, &pio1->txf[2], lo_cos, UINT_MAX, true);
+
+		puts("Transmitting noise, press ENTER to stop.");
+
+		while (true) {
+			int c = getchar_timeout_us(0);
+			if ('\n' == c || '\r' == c)
+				break;
+
+			for (int i = 0; i < LO_WORDS; i++)
+				lo_cos[i] = rand();
+		}
+
+		dma_channel_abort(tx_dma);
+		return;
+	}
+
 	puts("unknown command");
 }