Skip to content

Commit 4ddd628

Browse files
feat: add pattern generator SCPI commands
1 parent cb50ee8 commit 4ddd628

5 files changed

Lines changed: 406 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ target_sources(pslab_pico PRIVATE
1919
src/application/protocol/la.c
2020
src/application/protocol/dso.c
2121
src/application/protocol/mso.c
22+
src/application/protocol/pg.c
2223
src/application/communication_commands.c
2324
src/application/gateway/i2c_commands.c
2425
src/application/gateway/uart_commands.c
2526
src/application/logic_analyser_commands.c
2627
src/application/dso_commands.c
2728
src/application/mixed_signal_commands.c
29+
src/application/pattern_generator_commands.c
2830
src/system/instrument/dso.c
2931
src/system/instrument/mixed_signal.c
3032
src/system/pattern_generator.c
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
#include "application/pattern_generator_commands.h"
2+
3+
#include <string.h>
4+
5+
#include "system/pattern_generator.h"
6+
7+
enum {
8+
PG_DEFAULT_PIN_BASE = 16,
9+
PG_DEFAULT_PIN_COUNT = 1,
10+
PG_DEFAULT_RATE_HZ = 1000,
11+
PG_MAX_PIN_COUNT = 8,
12+
PG_MAX_PATTERN_WORDS = 16384,
13+
PG_MAX_RATE_HZ = 75000000,
14+
};
15+
16+
static PatternGenerator pg;
17+
static bool pg_initialized;
18+
static uint32_t pattern_buffer[PG_MAX_PATTERN_WORDS];
19+
20+
static struct {
21+
uint32_t pin_base;
22+
uint32_t pin_count;
23+
uint32_t rate_hz;
24+
uint32_t pattern_words;
25+
PatternGeneratorMode mode;
26+
} state = {
27+
.pin_base = PG_DEFAULT_PIN_BASE,
28+
.pin_count = PG_DEFAULT_PIN_COUNT,
29+
.rate_hz = PG_DEFAULT_RATE_HZ,
30+
.pattern_words = 0,
31+
.mode = PATTERN_GENERATOR_MODE_ONCE,
32+
};
33+
34+
static bool config_is_valid(void)
35+
{
36+
return state.pin_count >= 1 && state.pin_count <= PG_MAX_PIN_COUNT &&
37+
state.pin_base + state.pin_count <= 30 && state.rate_hz >= 1 &&
38+
state.rate_hz <= PG_MAX_RATE_HZ;
39+
}
40+
41+
static bool apply_config(void)
42+
{
43+
if (!config_is_valid()) {
44+
return false;
45+
}
46+
47+
PatternGeneratorConfig config = {
48+
.pin_base = state.pin_base,
49+
.pin_count = state.pin_count,
50+
.rate_hz = state.rate_hz,
51+
};
52+
53+
if (pg_initialized) {
54+
return pattern_generator_configure(&pg, &config);
55+
}
56+
57+
pg_initialized = pattern_generator_init(&pg, &config);
58+
return pg_initialized;
59+
}
60+
61+
void pg_reset_state(void)
62+
{
63+
pg_stop();
64+
if (pg_initialized) {
65+
pattern_generator_deinit(&pg);
66+
}
67+
68+
pg_initialized = false;
69+
state.pin_base = PG_DEFAULT_PIN_BASE;
70+
state.pin_count = PG_DEFAULT_PIN_COUNT;
71+
state.rate_hz = PG_DEFAULT_RATE_HZ;
72+
state.pattern_words = 0;
73+
state.mode = PATTERN_GENERATOR_MODE_ONCE;
74+
memset(pattern_buffer, 0, sizeof(pattern_buffer));
75+
}
76+
77+
void pg_task(void)
78+
{
79+
if (pg_initialized) {
80+
pattern_generator_task(&pg);
81+
}
82+
}
83+
84+
bool pg_set_pins(uint32_t pin_base, uint32_t pin_count)
85+
{
86+
if (pin_count < 1 || pin_count > PG_MAX_PIN_COUNT ||
87+
pin_base + pin_count > 30 || pg_is_running()) {
88+
return false;
89+
}
90+
91+
uint32_t old_pin_base = state.pin_base;
92+
uint32_t old_pin_count = state.pin_count;
93+
state.pin_base = pin_base;
94+
state.pin_count = pin_count;
95+
96+
if (pg_initialized && !apply_config()) {
97+
state.pin_base = old_pin_base;
98+
state.pin_count = old_pin_count;
99+
return false;
100+
}
101+
102+
return true;
103+
}
104+
105+
bool pg_set_rate(uint32_t rate_hz)
106+
{
107+
if (rate_hz < 1 || rate_hz > PG_MAX_RATE_HZ || pg_is_running()) {
108+
return false;
109+
}
110+
111+
uint32_t old_rate_hz = state.rate_hz;
112+
state.rate_hz = rate_hz;
113+
114+
if (pg_initialized && !apply_config()) {
115+
state.rate_hz = old_rate_hz;
116+
return false;
117+
}
118+
119+
return true;
120+
}
121+
122+
bool pg_set_mode_once(void)
123+
{
124+
if (pg_is_running()) {
125+
return false;
126+
}
127+
128+
state.mode = PATTERN_GENERATOR_MODE_ONCE;
129+
return true;
130+
}
131+
132+
bool pg_set_mode_loop(void)
133+
{
134+
if (pg_is_running()) {
135+
return false;
136+
}
137+
138+
state.mode = PATTERN_GENERATOR_MODE_LOOP;
139+
return true;
140+
}
141+
142+
bool pg_upload_data(uint8_t const *data, size_t len)
143+
{
144+
if (!data || len == 0 || (len % sizeof(uint32_t)) != 0 || pg_is_running()) {
145+
return false;
146+
}
147+
148+
size_t word_count = len / sizeof(uint32_t);
149+
if (word_count > PG_MAX_PATTERN_WORDS) {
150+
return false;
151+
}
152+
153+
memcpy(pattern_buffer, data, len);
154+
state.pattern_words = (uint32_t)word_count;
155+
return true;
156+
}
157+
158+
bool pg_start(void)
159+
{
160+
if (state.pattern_words == 0) {
161+
return false;
162+
}
163+
164+
if (!pg_initialized && !apply_config()) {
165+
return false;
166+
}
167+
168+
return pattern_generator_start(
169+
&pg,
170+
pattern_buffer,
171+
state.pattern_words,
172+
state.mode
173+
);
174+
}
175+
176+
void pg_stop(void)
177+
{
178+
if (pg_initialized) {
179+
pattern_generator_stop(&pg);
180+
}
181+
}
182+
183+
uint32_t pg_get_pin_base(void) { return state.pin_base; }
184+
185+
uint32_t pg_get_pin_count(void) { return state.pin_count; }
186+
187+
uint32_t pg_get_rate(void) { return state.rate_hz; }
188+
189+
bool pg_get_mode_loop(void) { return state.mode == PATTERN_GENERATOR_MODE_LOOP; }
190+
191+
uint32_t pg_get_pattern_words(void) { return state.pattern_words; }
192+
193+
bool pg_is_running(void)
194+
{
195+
return pg_initialized && pattern_generator_is_running(&pg);
196+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef PATTERN_GENERATOR_COMMANDS_H
2+
#define PATTERN_GENERATOR_COMMANDS_H
3+
4+
#include <stdbool.h>
5+
#include <stddef.h>
6+
#include <stdint.h>
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
void pg_reset_state(void);
13+
void pg_task(void);
14+
15+
bool pg_set_pins(uint32_t pin_base, uint32_t pin_count);
16+
bool pg_set_rate(uint32_t rate_hz);
17+
bool pg_set_mode_once(void);
18+
bool pg_set_mode_loop(void);
19+
bool pg_upload_data(uint8_t const *data, size_t len);
20+
bool pg_start(void);
21+
void pg_stop(void);
22+
23+
uint32_t pg_get_pin_base(void);
24+
uint32_t pg_get_pin_count(void);
25+
uint32_t pg_get_rate(void);
26+
bool pg_get_mode_loop(void);
27+
uint32_t pg_get_pattern_words(void);
28+
bool pg_is_running(void);
29+
30+
#ifdef __cplusplus
31+
}
32+
#endif
33+
34+
#endif

src/application/protocol/common.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "application/dso_commands.h"
2121
#include "application/logic_analyser_commands.h"
2222
#include "application/mixed_signal_commands.h"
23+
#include "application/pattern_generator_commands.h"
2324
#include "application/protocol/bus/i2c.h"
2425
#include "application/protocol/bus/uart.h"
2526
#include "platform/platform.h"
@@ -108,6 +109,18 @@ extern scpi_result_t scpi_cmd_read_mso_analog_q(scpi_t *context);
108109
extern scpi_result_t scpi_cmd_status_mso_q(scpi_t *context);
109110
extern scpi_result_t scpi_cmd_metadata_mso_q(scpi_t *context);
110111

112+
// Forward declarations of pattern generator functions needed by common
113+
extern scpi_result_t scpi_cmd_pattern_generator_pins(scpi_t *context);
114+
extern scpi_result_t scpi_cmd_pattern_generator_pins_q(scpi_t *context);
115+
extern scpi_result_t scpi_cmd_pattern_generator_rate(scpi_t *context);
116+
extern scpi_result_t scpi_cmd_pattern_generator_rate_q(scpi_t *context);
117+
extern scpi_result_t scpi_cmd_pattern_generator_mode(scpi_t *context);
118+
extern scpi_result_t scpi_cmd_pattern_generator_mode_q(scpi_t *context);
119+
extern scpi_result_t scpi_cmd_pattern_generator_data(scpi_t *context);
120+
extern scpi_result_t scpi_cmd_pattern_generator_start(scpi_t *context);
121+
extern scpi_result_t scpi_cmd_pattern_generator_stop(scpi_t *context);
122+
extern scpi_result_t scpi_cmd_pattern_generator_status_q(scpi_t *context);
123+
111124
static scpi_result_t scpi_cmd_la_wifi_read_q(scpi_t *context);
112125
static scpi_result_t scpi_cmd_dso_wifi_read_q(scpi_t *context);
113126
static scpi_result_t scpi_cmd_mso_wifi_read_q(scpi_t *context);
@@ -210,6 +223,7 @@ static scpi_result_t protocol_reset(scpi_t *context)
210223
la_reset_state();
211224
dso_commands_reset();
212225
mso_commands_reset();
226+
pg_reset_state();
213227
return SCPI_RES_OK;
214228
}
215229

@@ -356,6 +370,18 @@ static scpi_command_t const g_SCPI_COMMANDS[] = {
356370
{ "MSO:METadata?", scpi_cmd_metadata_mso_q },
357371
{ "MSO:WIFI:READ?", scpi_cmd_mso_wifi_read_q },
358372

373+
// Digital pattern generator commands
374+
{ "PG:CONFigure:PINS", scpi_cmd_pattern_generator_pins },
375+
{ "PG:CONFigure:PINS?", scpi_cmd_pattern_generator_pins_q },
376+
{ "PG:CONFigure:RATE", scpi_cmd_pattern_generator_rate },
377+
{ "PG:CONFigure:RATE?", scpi_cmd_pattern_generator_rate_q },
378+
{ "PG:CONFigure:MODE", scpi_cmd_pattern_generator_mode },
379+
{ "PG:CONFigure:MODE?", scpi_cmd_pattern_generator_mode_q },
380+
{ "PG:DATA", scpi_cmd_pattern_generator_data },
381+
{ "PG:STARt", scpi_cmd_pattern_generator_start },
382+
{ "PG:STOP", scpi_cmd_pattern_generator_stop },
383+
{ "PG:STATus?", scpi_cmd_pattern_generator_status_q },
384+
359385
// Built-in test signal commands
360386
{ "TEST:SQUare", scpi_cmd_test_square },
361387
{ "TEST:SQUare?", scpi_cmd_test_square_q },
@@ -632,6 +658,8 @@ void protocol_task(void)
632658
return;
633659
}
634660

661+
pg_task();
662+
635663
// Step USB task
636664
usb_cdc_task();
637665

0 commit comments

Comments
 (0)