Motor Evaluation Kit NEVC-MCTRL-100-t01-1.0.0
Firmware for NEVB-MCTRL-100-01 for trapezoidal control of BLDC motors using Hall-effect sensors
Loading...
Searching...
No Matches
scpi.cpp
Go to the documentation of this file.
1/* This file has been prepared for Doxygen automatic documentation generation.*/
30#include "scpi.h"
31
40const scpi_choice_def_t motorDirections[] = {
41 {"FORWard", DIRECTION_FORWARD},
42 {"REVErse", DIRECTION_REVERSE},
43 SCPI_CHOICE_LIST_END /* termination of option list */
44};
45
55static scpi_result_t MeasureMotorSpeed(scpi_t *context)
56{
57 if (lastCommutationTicks == 0xffff)
58 {
59 SCPI_ResultDouble(context, 0);
60 }
61 else
62 {
63 SCPI_ResultDouble(context, ((motorConfigs.tim4Freq * 20) / (lastCommutationTicks * MOTOR_POLES)));
64 }
65
66 return SCPI_RES_OK;
67}
68
78static scpi_result_t MeasureMotorCurrent(scpi_t *context)
79{
80 SCPI_ResultDouble(context, ((double)current * 5 * 1000000) / ((double)1024 * CURRENT_GAIN * CURRENT_SENSE_RESISTOR));
81
82 return SCPI_RES_OK;
83}
84
95static scpi_result_t MeasureMotorDirection(scpi_t *context)
96{
98 {
99 SCPI_ResultText(context, "UNKNown");
100 }
101 else
102 {
103 const char *name;
104
105 SCPI_ChoiceToName(motorDirections, motorFlags.actualDirection, &name);
106
107 SCPI_ResultText(context, name);
108 }
109
110 return SCPI_RES_OK;
111}
112
122static scpi_result_t MeasureGateVoltage(scpi_t *context)
123{
124 SCPI_ResultDouble(context, ((double)gateVref * 5 * (GATE_RTOP + GATE_RBOTTOM)) / ((double)1024 * GATE_RBOTTOM));
125
126 return SCPI_RES_OK;
127}
128
139#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_OPEN_LOOP)
140static scpi_result_t ConfigureMotorDutyCycleSource(scpi_t *context)
141#elif (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
142static scpi_result_t ConfigureMotorSpeedSource(scpi_t *context)
143#endif
144{
145 scpi_bool_t param;
146
147 /* read first parameter if present */
148 if (!SCPI_ParamBool(context, &param, TRUE))
149 {
150 return SCPI_RES_ERR;
151 }
152 else
153 {
154 if (param == SPEED_INPUT_SOURCE_LOCAL)
155 {
157 }
158 else
159 {
161 speedInput = 0;
162 }
163 }
164
165 return SCPI_RES_OK;
166}
167
168#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_OPEN_LOOP)
175static scpi_result_t ConfigureMotorDutyCycle(scpi_t *context)
176{
177 double param;
178
179 // Read first parameter if present
180 if (!SCPI_ParamDouble(context, &param, TRUE))
181 {
182 return SCPI_RES_ERR;
183 }
184 else
185 {
186 // Check if within range
187 if ((param < 0.0) | (param > 100.0))
188 {
189 return SCPI_RES_ERR;
190 }
191
192 speedInput = (param * SPEED_CONTROLLER_MAX_INPUT) / 100;
193 }
194
195 return SCPI_RES_OK;
196}
197#elif (SPEED_CONTROL_METHOD == SPEED_CONTROL_CLOSED_LOOP)
204static scpi_result_t ConfigureMotorSpeed(scpi_t *context)
205{
206 uint32_t param;
207
208 // Read first parameter if present
209 if (!SCPI_ParamUInt32(context, &param, TRUE))
210 {
211 return SCPI_RES_ERR;
212 }
213 else
214 {
215 // Check if within range
216 if (param > ((((uint32_t)SPEED_CONTROLLER_MAX_SPEED * 15) << 3) / MOTOR_POLES))
217 {
218 return SCPI_RES_ERR;
219 }
220
221 speedInput = ((param * SPEED_CONTROLLER_MAX_INPUT * MOTOR_POLES) >> 3) / ((uint32_t)SPEED_CONTROLLER_MAX_SPEED * 15);
222 }
223
224 return SCPI_RES_OK;
225}
226#endif
227
234static scpi_result_t MeasureGateDutyCycle(scpi_t *context)
235{
236 if (motorFlags.enable == TRUE)
237 {
238 // Reading 16 bit register so disabling interrupts for atomic operation
239 cli();
240 uint16_t duty = 0xff & OCR4A;
241 duty |= (0x03 & TC4H) << 8;
242 sei();
243
244 SCPI_ResultDouble(context, ((double)duty / (double)motorConfigs.tim4Top * 100));
245 }
246 else
247 {
248 SCPI_ResultDouble(context, 0);
249 }
250
251 return SCPI_RES_OK;
252}
253
268static scpi_result_t ConfigureMotorEnable(scpi_t *context)
269{
270 scpi_bool_t param;
271
272 /* read first parameter if present */
273 if (!SCPI_ParamBool(context, &param, TRUE))
274 {
275 return SCPI_RES_ERR;
276 }
277 else
278 {
279 if (param)
280 {
281 // Set the enable pin
282 PORTD |= (1 << ENABLE_PIN);
283 }
284 else
285 {
286 // Clear the enable pin
287 PORTD &= ~(1 << ENABLE_PIN);
288 }
289 }
290
291 return SCPI_RES_OK;
292}
293
303static scpi_result_t GetConfigureMotorEnable(scpi_t *context)
304{
305 SCPI_ResultBool(context, (scpi_bool_t)motorFlags.enable);
306
307 return SCPI_RES_OK;
308}
309
324static scpi_result_t ConfigureMotorDirection(scpi_t *context)
325{
326 int32_t param;
327
328 /* read first parameter if present */
329 if (!SCPI_ParamChoice(context, motorDirections, &param, TRUE))
330 {
331 return SCPI_RES_ERR;
332 }
333 else
334 {
335 if (param)
336 {
337 // Set the direction pin if param is 1
338 PORTD |= (1 << DIRECTION_COMMAND_PIN);
339 }
340 else
341 {
342 // Clear the direction pin if param is 0
343 PORTD &= ~(1 << DIRECTION_COMMAND_PIN);
344 }
345 }
346
347 return SCPI_RES_OK;
348}
349
360static scpi_result_t GetConfigureMotorDirection(scpi_t *context)
361{
362 const char *name;
363
364 SCPI_ChoiceToName(motorDirections, motorFlags.desiredDirection, &name);
365
366 SCPI_ResultText(context, name);
367
368 return SCPI_RES_OK;
369}
370
381static scpi_result_t ConfigureMotorFrequency(scpi_t *context)
382{
383 // Clear the enable pin
384 PORTD &= ~(1 << ENABLE_PIN);
385
386 uint32_t param;
387
388 // Read first parameter if present
389 if (!SCPI_ParamUInt32(context, &param, TRUE))
390 {
391 return SCPI_RES_ERR;
392 }
393 else
394 {
395 // Check if within range
396 if ((param < 7183) | (param > 100000))
397 {
398 return SCPI_RES_ERR;
399 }
400
401 // Reload the configs
402 motorConfigs.tim4Freq = param;
404
405 // Wait until motor is stopped
406 while (faultFlags.motorStopped == FALSE)
407 {
408 ;
409 }
410
411 // Re-init timers
412 TimersInit();
413 }
414
415 return SCPI_RES_OK;
416}
417
427static scpi_result_t GetConfigureMotorFrequency(scpi_t *context)
428{
429 SCPI_ResultDouble(context, (double)motorConfigs.tim4Freq);
430
431 return SCPI_RES_OK;
432}
433
444static scpi_result_t ConfigureMotorDeadTime(scpi_t *context)
445{
446 // Clear the enable pin
447 PORTD &= ~(1 << ENABLE_PIN);
448
449 uint32_t param;
450
451 // Read first parameter if present
452 if (!SCPI_ParamUInt32(context, &param, TRUE))
453 {
454 return SCPI_RES_ERR;
455 }
456 else
457 {
458 // Check if within range
459 if ((param < 350) | (param > 1875))
460 {
461 return SCPI_RES_ERR;
462 }
463
464 // Reload the config
466
467 // Wait until motor is stopped
468 while (faultFlags.motorStopped == FALSE)
469 {
470 ;
471 }
472
473 // Re-init timers
474 TimersInit();
475 }
476
477 return SCPI_RES_OK;
478}
479
489static scpi_result_t GetConfigureMotorDeadTime(scpi_t *context)
490{
491 SCPI_ResultDouble(context, (double)motorConfigs.tim4DeadTime);
492
493 return SCPI_RES_OK;
494}
495
504const scpi_command_t scpi_commands[] PROGMEM = {
505 /* IEEE Mandated Commands (SCPI std V1999.0 4.1.1) */
506 {"*CLS", SCPI_CoreCls, 0},
507 {"*IDN?", SCPI_CoreIdnQ, 0},
508 {"*RST", SCPI_CoreRst, 0},
509
510 /* Required SCPI commands (SCPI std V1999.0 4.2.1) */
511 {"SYSTem:ERRor[:NEXT]?", SCPI_SystemErrorNextQ, 0},
512 {"SYSTem:ERRor:COUNt?", SCPI_SystemErrorCountQ, 0},
513 {"SYSTem:VERSion?", SCPI_SystemVersionQ, 0},
514
515 /* Motor */
516 {"CONFigure:MOTOr:ENABle", ConfigureMotorEnable, 0},
517 {"CONFigure:MOTOr:ENABle?", GetConfigureMotorEnable, 0},
518#if (SPEED_CONTROL_METHOD == SPEED_CONTROL_OPEN_LOOP)
519 {"CONFigure:MOTOr:GATE:DUTYcycle:SOURce", ConfigureMotorDutyCycleSource, 0},
520 {"CONFigure:MOTOr:GATE:DUTYcycle", ConfigureMotorDutyCycle, 0},
521#else
522 {"CONFigure:MOTOr:SPEED:SOURce", ConfigureMotorSpeedSource, 0},
523 {"CONFigure:MOTOr:SPEED", ConfigureMotorSpeed, 0},
524#endif
525 {"CONFigure:MOTOr:GATE:FREQuency", ConfigureMotorFrequency, 0},
526 {"CONFigure:MOTOr:GATE:FREQuency?", GetConfigureMotorFrequency, 0},
527 {"CONFigure:MOTOr:GATE:DEADtime", ConfigureMotorDeadTime, 0},
528 {"CONFigure:MOTOr:GATE:DEADtime?", GetConfigureMotorDeadTime, 0},
529 {"CONFigure:MOTOr:DIREction", ConfigureMotorDirection, 0},
530 {"CONFigure:MOTOr:DIREction?", GetConfigureMotorDirection, 0},
531 {"MEASure:MOTOr:SPEEd?", MeasureMotorSpeed, 0},
532 {"MEASure:MOTOr:CURRent?", MeasureMotorCurrent, 0},
533 {"MEASure:MOTOr:DIREction?", MeasureMotorDirection, 0},
534 {"MEASure:MOTOr:GATE:VOLTage?", MeasureGateVoltage, 0},
535 {"MEASure:MOTOr:GATE:DUTYcycle?", MeasureGateDutyCycle, 0},
536
537 SCPI_CMD_LIST_END};
538
549size_t SCPI_Write(scpi_t *context, const char *data, size_t len)
550{
551 (void)context;
552 Serial.write(data, len);
553 return len;
554}
555
565scpi_result_t SCPI_Flush(scpi_t *context)
566{
567 (void)context;
568 Serial.flush();
569 return SCPI_RES_OK;
570}
571
581int SCPI_Error(scpi_t *context, int_fast16_t err)
582{
583 (void)context;
584#if (REMOTE_DEBUG_MODE == TRUE)
585 Serial.print(err);
586 Serial.print(", \"");
587 Serial.print(SCPI_ErrorTranslate(err));
588 Serial.println("\"");
589#endif
590 return 0;
591}
592
605scpi_result_t SCPI_Control(scpi_t *context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val)
606{
607 (void)context;
608
609 return SCPI_RES_OK;
610}
611
622scpi_result_t SCPI_Reset(scpi_t *context)
623{
624 (void)context;
625
626 // Clear the enable pin
627 PORTD &= ~(1 << ENABLE_PIN);
628
629 // Wait until motor is stopped
630 while (faultFlags.motorStopped == FALSE)
631 {
632 ;
633 }
634
635 // Reset configurations
636 ConfigsInit();
637
638 // Re-init timers
639 TimersInit();
640
641 return SCPI_RES_OK;
642}
643
651scpi_interface_t scpi_interface = {
652 /*.error = */ SCPI_Error,
653 /*.write = */ SCPI_Write,
654 /*.control = */ SCPI_Control,
655 /*.flush = */ SCPI_Flush,
656 /*.reset = */ SCPI_Reset,
657};
658
666
674
#define TIM4_TOP(tim4Freq)
Definition main.h:1059
#define DIRECTION_FORWARD
Forward direction flag value.
Definition main.h:575
#define DIRECTION_COMMAND_PIN
Pin where direction command input is located.
Definition main.h:621
#define SPEED_INPUT_SOURCE_LOCAL
Speed input source - Local or speed input pin.
Definition main.h:629
#define SPEED_CONTROLLER_MAX_INPUT
Maximum Speed Reference Input.
Definition main.h:674
#define DIRECTION_REVERSE
Reverse direction flag value.
Definition main.h:577
#define ENABLE_PIN
Enable input pin.
Definition main.h:623
#define SPEED_INPUT_SOURCE_REMOTE
Speed input source - Remote input.
Definition main.h:631
#define TRUE
TRUE constant value, defined to be compatible with comparisons.
Definition main.h:537
#define FALSE
FALSE constant value.
Definition main.h:535
#define DIRECTION_UNKNOWN
Unknown direction flag value.
Definition main.h:579
#define CURRENT_GAIN
Current Gain for Current Measurement.
Definition main.h:220
#define GATE_RBOTTOM
Bottom resistor value in the gate voltage potential divider.
Definition main.h:512
#define CURRENT_SENSE_RESISTOR
Current Sense Resistor Value.
Definition main.h:238
#define MOTOR_POLES
Number of poles in the motor.
Definition main.h:60
#define SPEED_CONTROLLER_MAX_SPEED
Speed Controller Maximum Speed.
Definition main.h:396
#define GATE_RTOP
Top resistor value in the gate voltage potential divider.
Definition main.h:492
volatile motorflags_t motorFlags
Motor control flags placed in I/O space for fast access.
Definition main.ino:76
volatile uint8_t speedInput
The most recent "speed" input measurement.
Definition main.ino:125
volatile motorconfigs_t motorConfigs
Motor Configs.
Definition main.ino:90
volatile uint16_t current
Current measurement (Register Value).
Definition main.ino:161
volatile faultflags_t faultFlags
Fault flags placed in I/O space for fast access.
Definition main.ino:84
volatile uint16_t lastCommutationTicks
The number of 'ticks' between two hall sensor changes (store).
Definition main.ino:118
void TimersInit(void)
Initializes and synchronizes Timers.
Definition main.ino:405
static void ConfigsInit(void)
Initializes motorConfigs.
Definition main.ino:320
volatile uint16_t gateVref
Gate voltage measurement (Register Value)
Definition main.ino:190
static scpi_result_t MeasureGateVoltage(scpi_t *context)
Measures and returns the gate voltage of the motor.
Definition scpi.cpp:122
scpi_interface_t scpi_interface
SCPI interface structure.
Definition scpi.cpp:651
scpi_result_t SCPI_Reset(scpi_t *context)
Resets the SCPI context.
Definition scpi.cpp:622
scpi_result_t SCPI_Control(scpi_t *context, scpi_ctrl_name_t ctrl, scpi_reg_val_t val)
Handles control messages for the SCPI interface (dummy)
Definition scpi.cpp:605
static scpi_result_t MeasureMotorSpeed(scpi_t *context)
Measures the motor speed.
Definition scpi.cpp:55
static scpi_result_t GetConfigureMotorDeadTime(scpi_t *context)
Retrieves the configured motor dead time.
Definition scpi.cpp:489
static scpi_result_t GetConfigureMotorFrequency(scpi_t *context)
Retrieves the configured motor frequency.
Definition scpi.cpp:427
static scpi_result_t GetConfigureMotorDirection(scpi_t *context)
Retrieves the configured direction of the motor.
Definition scpi.cpp:360
const scpi_command_t scpi_commands[]
Array of SCPI commands.
Definition scpi.cpp:504
static scpi_result_t MeasureMotorCurrent(scpi_t *context)
Measures and returns the motor's current.
Definition scpi.cpp:78
static scpi_result_t ConfigureMotorDeadTime(scpi_t *context)
Configures the motor's dead time.
Definition scpi.cpp:444
scpi_error_t scpi_error_queue_data[4]
SCPI error queue data array.
Definition scpi.cpp:673
size_t SCPI_Write(scpi_t *context, const char *data, size_t len)
Writes data to the SCPI interface.
Definition scpi.cpp:549
static scpi_result_t ConfigureMotorDirection(scpi_t *context)
Sets the motor's direction based on the input parameter.
Definition scpi.cpp:324
static scpi_result_t ConfigureMotorEnable(scpi_t *context)
Configures the motor's enable state.
Definition scpi.cpp:268
char scpi_input_buffer[64]
SCPI input buffer.
Definition scpi.cpp:665
int SCPI_Error(scpi_t *context, int_fast16_t err)
Handles SCPI errors and outputs them to the Serial interface.
Definition scpi.cpp:581
const scpi_choice_def_t motorDirections[]
Array or enumeration of possible motor directions.
Definition scpi.cpp:40
static scpi_result_t GetConfigureMotorEnable(scpi_t *context)
Retrieves the current motor enable state.
Definition scpi.cpp:303
scpi_t scpi_context
SCPI context structure.
Definition scpi.cpp:681
scpi_result_t SCPI_Flush(scpi_t *context)
Flushes the Serial interface buffer.
Definition scpi.cpp:565
static scpi_result_t ConfigureMotorDutyCycleSource(scpi_t *context)
Configures the motor's speed input source.
Definition scpi.cpp:140
static scpi_result_t ConfigureMotorFrequency(scpi_t *context)
Configures the motor's operating frequency.
Definition scpi.cpp:381
static scpi_result_t MeasureGateDutyCycle(scpi_t *context)
Measures and returns the gate PWM duty cycle.
Definition scpi.cpp:234
static scpi_result_t ConfigureMotorDutyCycle(scpi_t *context)
Configures the motor's speed input by changing the duty cycle.
Definition scpi.cpp:175
static scpi_result_t MeasureMotorDirection(scpi_t *context)
Measures and reports the current direction of the motor.
Definition scpi.cpp:95
SCPI implementation header file.
#define SCPI_INPUT_BUFFER_LENGTH
Definition scpi.h:47
#define SCPI_ERROR_QUEUE_SIZE
The SCPI error queue size or the maximum number of error retained in memory.
Definition scpi.h:50
uint8_t motorStopped
Is motor stopped?
Definition main.h:1005
uint16_t tim4Top
Corresponding TIM4 top value for TIM4 frequency.
Definition main.h:1028
uint8_t speedInputSource
SpeedInput source select (only for remote mode).
Definition main.h:1032
uint16_t tim4DeadTime
Corresponding dead time for TIM4 output.
Definition main.h:1030
uint32_t tim4Freq
TIM4 or gate switching frequency.
Definition main.h:1026
uint8_t desiredDirection
The desired direction of rotation.
Definition main.h:989
uint8_t enable
Is the motor enabled?
Definition main.h:985
uint8_t actualDirection
The actual direction of rotation.
Definition main.h:987