Dual Brushless Motor ESC, 10-62V, up to 50A per motor. Motors ganged or independent, multiple control input methods, cycle-by-cycle current limit, speed mode and torque mode control. Motors tiny to kW. Speed limit and other parameters easily set in firmware. As used in 'The Brushless Brutalist' locomotive - www.jons-workshop.com. See also Model Engineer magazine June-October 2019.
Dependencies: mbed BufferedSerial Servo PCT2075 FastPWM
Update 17th August 2020 Radio control inputs completed
Revision 7:6deaeace9a3e, committed 2018-06-17
- Comitter:
- JonFreeman
- Date:
- Sun Jun 17 06:59:37 2018 +0000
- Parent:
- 6:f289a49c1eae
- Child:
- 8:93203f473f6e
- Commit message:
- Firmware for STM3 Twin Brushless Motor Electronic Speed Controller; Snapshot at 17th June 2018
Changed in this revision
--- a/DualBLS.h Tue Jun 05 07:19:39 2018 +0000
+++ b/DualBLS.h Sun Jun 17 06:59:37 2018 +0000
@@ -1,5 +1,3 @@
-//#define POWER_OF_TWO 12 // Range is 4 to 13, is log2N
-//typedef float ffty; // Choice of float or double float is HUGELY FASTER than double
const int HANDBRAKE = 0,
FORWARD = 8,
REVERSE = 16,
@@ -34,9 +32,9 @@
{0, 2, 2, "Servo2 0, 1, 2 = Not used, Input, Output"},
{1, 5, 2, "Command source 0 Invalid, 1 COM1, 2 COM2, 3 Pot, 4 Servo1, 5 Servo2"},
{'1', '9', '0', "Alternative ID ascii '1' to '9'"}, // defaults to '0' before eerom setup for first time
- {50, 250, 98, "Wheel diameter mm"}, // New 01/06/2018
- {10, 250, 27, "Motor pinion"}, // New 01/06/2018
- {50, 250, 85, "Wheel gear"}, // New 01/06/2018
+ {20, 253, 98, "Wheel diameter mm"}, // New 01/06/2018
+ {10, 253, 27, "Motor pinion"}, // New 01/06/2018
+ {20, 253, 85, "Wheel gear"}, // New 01/06/2018
} ;
const int numof_eeprom_options = sizeof(option_list) / sizeof (struct optpar);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F401RE.h Sun Jun 17 06:59:37 2018 +0000 @@ -0,0 +1,143 @@ +// Hoped to select servo functions from user info stored on EEROM. Too difficult. Do not define servo as in and out + +// Port A -> MotorA, Port B -> MotorB +const uint16_t +AUL = 1 << 0, // Feb 2018 Now using DGD21032 mosfet drivers via 74HC00 pwm gates (low side) - GOOD, works well with auto-tickle of high side drivers +AVL = 1 << 6, // These are which port bits connect to which mosfet driver +AWL = 1 << 4, + +AUH = 1 << 1, +AVH = 1 << 7, +AWH = 1 << 8, + +AUV = AUH | AVL, // Each of 6 possible output energisations made up of one hi and one low +AVU = AVH | AUL, +AUW = AUH | AWL, +AWU = AWH | AUL, +AVW = AVH | AWL, +AWV = AWH | AVL, + +KEEP_L_MASK_A = AUL | AVL | AWL, +KEEP_H_MASK_A = AUH | AVH | AWH, + +BRA = AUL | AVL | AWL, // All low side switches on (and all high side off) for braking + +BUL = 1 << 0, // Likewise for MotorB but different port bits on different port +BVL = 1 << 1, +BWL = 1 << 2, + +BUH = 1 << 10, +BVH = 1 << 12, +BWH = 1 << 13, + +BUV = BUH | BVL, +BVU = BVH | BUL, +BUW = BUH | BWL, +BWU = BWH | BUL, +BVW = BVH | BWL, +BWV = BWH | BVL, + +KEEP_L_MASK_B = BUL | BVL | BWL, +KEEP_H_MASK_B = BUH | BVH | BWH, + +BRB = BUL | BVL | BWL, + +PORT_A_MASK = AUL | AVL | AWL | AUH | AVH | AWH, // NEW METHOD FOR DGD21032 MOSFET DRIVERS +PORT_B_MASK = BUL | BVL | BWL | BUH | BVH | BWH; + +PortOut MotA (PortA, PORT_A_MASK); // Activate output ports to motor drivers +PortOut MotB (PortB, PORT_B_MASK); + +// Pin 1 VBAT NET +3V3 + +//DigitalIn J3 (PC_13, PullUp);// Pin 2 Jumper pulls to GND, R floats Hi +InterruptIn Temperature_pin (PC_13);// Pin 2 June 2018 - taken for temperature sensor - hard wired to T1 due to wrong thought T1 could be InterruptIn + + +// Pin 3 PC14-OSC32_IN NET O32I +// Pin 4 PC15-OSC32_OUT NET O32O +// Pin 5 PH0-OSC_IN NET PH1 +// Pin 6 PH1-OSC_OUT NET PH1 +// Pin 7 NRST NET NRST +AnalogIn Ain_DriverPot (PC_0); // Pin 8 Spare Analogue in, net SAIN fitted with external pull-down +AnalogIn Ain_SystemVolts (PC_1); // Pin 9 +AnalogIn Motor_A_Current (PC_2); // Pin 10 +AnalogIn Motor_B_Current (PC_3); // Pin 11 +// Pin 12 VSSA/VREF- NET GND +// Pin 13 VDDA/VREF+ NET +3V3 +// Pin 14 Port_A AUL +// Pin 15 Port_A AUH +// Pins 16, 17 BufferedSerial pc +BufferedSerial pc (PA_2, PA_3, 512, 4, NULL); // Pins 16, 17 tx, rx to pc via usb lead +// Pin 18 VSS NET GND +// Pin 19 VDD NET +3V3 +// Pin 20 Port_A AWL +// Pin 21 DigitalOut led1(LED1); +DigitalOut LED (PA_5); // Pin 21 +// Pin 22 Port_A AVL +// Pin 23 Port_A AVH +InterruptIn MBH2 (PC_4); // Pin 24 +InterruptIn MBH3 (PC_5); // Pin 25 +// Pin 26 Port_B BUL +// Pin 27 Port_B BVL +// Pin 28 Port_B BWL +// Pin 29 Port_B BUH +// Pin 30 VCAP1 +// Pin 31 VSS +// Pin 32 VDD +// Pin 33 Port_B BVH +// Pin 34 Port_B BWH +DigitalOut T4 (PB_14); // Pin 35 +DigitalOut T3 (PB_15); // Pin 36 +// BufferedSerial com2 pins 37 Tx, 38 Rx +BufferedSerial com2 (PC_6, PC_7); // Pins 37, 38 tx, rx to XBee module +FastPWM A_MAX_V_PWM (PC_8, 1), // Pin 39 pwm3/3 + A_MAX_I_PWM (PC_9, 1); // pin 40, prescaler value pwm3/4 +//InterruptIn MotB_Hall (PA_8); // Pin 41 +// Pin 41 Port_A AWH +// BufferedSerial com3 pins 42 Tx, 43 Rx +//InterruptIn tryseredge (PA_9); +BufferedSerial com3 (PA_9, PA_10); // Pins 42, 43 tx, rx to any aux module +// PA_9 is Tx. I wonder, can we also use InterruptIn on this pin to generate interrupts on tx bit transitions ? Let's find out ! +// No. + +// Feb 2018 Pins 44 and 45 now liberated, could use for serial or other uses +//BufferedSerial extra_ser (PA_11, PA_12); // Pins 44, 45 tx, rx to XBee module +DigitalOut T2 (PA_11); // Pin 44 +// was DigitalOut T1 (PA_12); // Pin 45 + + +//InterruptIn T1 (PA_12); // Pin 45 now input counting pulses from LMT01 temperature sensor +// InterruptIn DOES NOT WORK ON PA_12. Boards are being made, will have to wire link PA12 to PC13 +DigitalIn T1 (PA_12); +////InterruptIn T1 (PC_13); // Pin 45 now input counting pulses from LMT01 temperature sensor + + + +// Pin 46 SWDIO +// Pin 47 VSS +// Pin 48 VDD +// Pin 49 SWCLK + +//Was DigitalOut T5 (PA_15); // Pin 50 +DigitalIn T5 (PA_15); // Pin 50 now fwd/rev from remote control box if fitted +InterruptIn MAH1 (PC_10); // Pin 51 +InterruptIn MAH2 (PC_11); // Pin 52 +InterruptIn MAH3 (PC_12); // Pin 53 +InterruptIn MBH1 (PD_2); // Pin 54 +DigitalOut T6 (PB_3); // Pin 55 +FastPWM B_MAX_V_PWM (PB_4, 1), // Pin 56 pwm3/3 + B_MAX_I_PWM (PB_5, 1); // pin 57, prescaler value pwm3/4 + +I2C i2c (PB_7, PB_6); // Pins 58, 59 For 24LC64 eeprom +// Pin 60 BOOT0 + +// Servo pins, 2 off. Configured as Input to read radio control receiver +// If used as servo output, code gives pin to 'Servo' - seems to work +InterruptIn Servo1_i (PB_8); // Pin 61 to read output from rc rx +InterruptIn Servo2_i (PB_9); // Pin 62 to read output from rc rx + +// Pin 63 VSS +// Pin 64 VDD +// SYSTEM CONSTANTS +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/F446ZE.h Sun Jun 17 06:59:37 2018 +0000 @@ -0,0 +1,145 @@ +// 5TH JUNE 2018 NONE OF THIS IS RIGHT YET !! + +// Hoped to select servo functions from user info stored on EEROM. Too difficult. Do not define servo as in and out + +// Port A -> MotorA, Port B -> MotorB +const uint16_t +AUL = 1 << 0, // Feb 2018 Now using DGD21032 mosfet drivers via 74HC00 pwm gates (low side) - GOOD, works well with auto-tickle of high side drivers +AVL = 1 << 6, // These are which port bits connect to which mosfet driver +AWL = 1 << 4, + +AUH = 1 << 1, +AVH = 1 << 7, +AWH = 1 << 8, + +AUV = AUH | AVL, // Each of 6 possible output energisations made up of one hi and one low +AVU = AVH | AUL, +AUW = AUH | AWL, +AWU = AWH | AUL, +AVW = AVH | AWL, +AWV = AWH | AVL, + +KEEP_L_MASK_A = AUL | AVL | AWL, +KEEP_H_MASK_A = AUH | AVH | AWH, + +BRA = AUL | AVL | AWL, // All low side switches on (and all high side off) for braking + +BUL = 1 << 0, // Likewise for MotorB but different port bits on different port +BVL = 1 << 1, +BWL = 1 << 2, + +BUH = 1 << 10, +BVH = 1 << 12, +BWH = 1 << 13, + +BUV = BUH | BVL, +BVU = BVH | BUL, +BUW = BUH | BWL, +BWU = BWH | BUL, +BVW = BVH | BWL, +BWV = BWH | BVL, + +KEEP_L_MASK_B = BUL | BVL | BWL, +KEEP_H_MASK_B = BUH | BVH | BWH, + +BRB = BUL | BVL | BWL, + +PORT_A_MASK = AUL | AVL | AWL | AUH | AVH | AWH, // NEW METHOD FOR DGD21032 MOSFET DRIVERS +PORT_B_MASK = BUL | BVL | BWL | BUH | BVH | BWH; + +PortOut MotA (PortA, PORT_A_MASK); // Activate output ports to motor drivers +PortOut MotB (PortB, PORT_B_MASK); + +// Pin 1 VBAT NET +3V3 + +//DigitalIn J3 (PC_13, PullUp);// Pin 2 Jumper pulls to GND, R floats Hi +InterruptIn Temperature_pin (PC_13);// Pin 2 June 2018 - taken for temperature sensor - hard wired to T1 due to wrong thought T1 could be InterruptIn + + +// Pin 3 PC14-OSC32_IN NET O32I +// Pin 4 PC15-OSC32_OUT NET O32O +// Pin 5 PH0-OSC_IN NET PH1 +// Pin 6 PH1-OSC_OUT NET PH1 +// Pin 7 NRST NET NRST +AnalogIn Ain_DriverPot (PC_0); // Pin 8 Spare Analogue in, net SAIN fitted with external pull-down +AnalogIn Ain_SystemVolts (PC_1); // Pin 9 +AnalogIn Motor_A_Current (PC_2); // Pin 10 +AnalogIn Motor_B_Current (PC_3); // Pin 11 +// Pin 12 VSSA/VREF- NET GND +// Pin 13 VDDA/VREF+ NET +3V3 +// Pin 14 Port_A AUL +// Pin 15 Port_A AUH +// Pins 16, 17 BufferedSerial pc +BufferedSerial pc (PA_2, PA_3, 512, 4, NULL); // Pins 16, 17 tx, rx to pc via usb lead +// Pin 18 VSS NET GND +// Pin 19 VDD NET +3V3 +// Pin 20 Port_A AWL +// Pin 21 DigitalOut led1(LED1); +DigitalOut LED (PA_5); // Pin 21 +// Pin 22 Port_A AVL +// Pin 23 Port_A AVH +InterruptIn MBH2 (PC_4); // Pin 24 +InterruptIn MBH3 (PC_5); // Pin 25 +// Pin 26 Port_B BUL +// Pin 27 Port_B BVL +// Pin 28 Port_B BWL +// Pin 29 Port_B BUH +// Pin 30 VCAP1 +// Pin 31 VSS +// Pin 32 VDD +// Pin 33 Port_B BVH +// Pin 34 Port_B BWH +DigitalOut T4 (PB_14); // Pin 35 +DigitalOut T3 (PB_15); // Pin 36 +// BufferedSerial com2 pins 37 Tx, 38 Rx +BufferedSerial com2 (PC_6, PC_7); // Pins 37, 38 tx, rx to XBee module +FastPWM A_MAX_V_PWM (PC_8, 1), // Pin 39 pwm3/3 + A_MAX_I_PWM (PC_9, 1); // pin 40, prescaler value pwm3/4 +//InterruptIn MotB_Hall (PA_8); // Pin 41 +// Pin 41 Port_A AWH +// BufferedSerial com3 pins 42 Tx, 43 Rx +//InterruptIn tryseredge (PA_9); +BufferedSerial com3 (PA_9, PA_10); // Pins 42, 43 tx, rx to any aux module +// PA_9 is Tx. I wonder, can we also use InterruptIn on this pin to generate interrupts on tx bit transitions ? Let's find out ! +// No. + +// Feb 2018 Pins 44 and 45 now liberated, could use for serial or other uses +//BufferedSerial extra_ser (PA_11, PA_12); // Pins 44, 45 tx, rx to XBee module +DigitalOut T2 (PA_11); // Pin 44 +// was DigitalOut T1 (PA_12); // Pin 45 + + +//InterruptIn T1 (PA_12); // Pin 45 now input counting pulses from LMT01 temperature sensor +// InterruptIn DOES NOT WORK ON PA_12. Boards are being made, will have to wire link PA12 to PC13 +DigitalIn T1 (PA_12); +////InterruptIn T1 (PC_13); // Pin 45 now input counting pulses from LMT01 temperature sensor + + + +// Pin 46 SWDIO +// Pin 47 VSS +// Pin 48 VDD +// Pin 49 SWCLK + +//Was DigitalOut T5 (PA_15); // Pin 50 +DigitalIn T5 (PA_15); // Pin 50 now fwd/rev from remote control box if fitted +InterruptIn MAH1 (PC_10); // Pin 51 +InterruptIn MAH2 (PC_11); // Pin 52 +InterruptIn MAH3 (PC_12); // Pin 53 +InterruptIn MBH1 (PD_2); // Pin 54 +DigitalOut T6 (PB_3); // Pin 55 +FastPWM B_MAX_V_PWM (PB_4, 1), // Pin 56 pwm3/3 + B_MAX_I_PWM (PB_5, 1); // pin 57, prescaler value pwm3/4 + +I2C i2c (PB_7, PB_6); // Pins 58, 59 For 24LC64 eeprom +// Pin 60 BOOT0 + +// Servo pins, 2 off. Configured as Input to read radio control receiver +// If used as servo output, code gives pin to 'Servo' - seems to work +InterruptIn Servo1_i (PB_8); // Pin 61 to read output from rc rx +InterruptIn Servo2_i (PB_9); // Pin 62 to read output from rc rx + +// Pin 63 VSS +// Pin 64 VDD +// SYSTEM CONSTANTS +
--- a/cli_BLS_nortos.cpp Tue Jun 05 07:19:39 2018 +0000
+++ b/cli_BLS_nortos.cpp Sun Jun 17 06:59:37 2018 +0000
@@ -12,14 +12,16 @@
const int BROADCAST = '\r';
const int MAX_PARAMS = 20;
struct parameters {
- int32_t position_in_list, // set but not used Apr 2018, contains i for i'th menu item
-// last_time, // gets reading from clock() ; not known to be useful or reliable
- numof_dbls,
- target_unit;
+ struct kb_command const * command_list;
+ BufferedSerial * com; // pc or com2
+ char cmd_line[120];
+ char * cmd_line_ptr;
+ int32_t position_in_list, numof_dbls, target_unit, numof_menu_items, cl_index, gp_i;
double dbl[MAX_PARAMS];
- bool respond;
+ bool respond, resp_always;
} ;
+struct parameters pccom, lococom;
// WithOUT RTOS
extern BufferedSerial com2, pc;
extern void send_test () ;
@@ -28,12 +30,12 @@
extern void setI (double i) ;
extern void read_last_VI (double * val) ; // only for test from cli
-BufferedSerial * com;
+//BufferedSerial * com;
void null_cmd (struct parameters & a)
{
if (a.respond)
- com->printf ("At null_cmd, board ID %c, parameters : First %.3f, second %.3f\r\n", I_Am(), a.dbl[0], a.dbl[1]);
+ a.com->printf ("At null_cmd, board ID %c, parameters : First %.3f, second %.3f\r\n", I_Am(), a.dbl[0], a.dbl[1]);
}
extern void mode_set (int mode, double val) ; // called from cli to set fw, re, rb, hb
@@ -44,7 +46,7 @@
if (a.respond) {
double r[4];
read_supply_vi (r); // get MotorA.I.ave, MotorB.I.ave, Battery volts
- com->printf ("rdi%.0f %.0f %.1f\r", r[0], r[1], r[2]); // Format good to be unpicked by cli in touch screen controller
+ a.com->printf ("rdi%.0f %.0f %.1f\r", r[0], r[1], r[2]); // Format good to be unpicked by cli in touch screen controller
}
}
@@ -53,7 +55,7 @@
if (a.respond) {
double r[6];
read_last_VI (r);
- com->printf ("rvi%.2f %.2f %.2f %.2f\r", r[0], r[1], r[2], r[3]);
+ a.com->printf ("rvi%.2f %.2f %.2f %.2f\r", r[0], r[1], r[2], r[3]);
}
}
@@ -70,7 +72,7 @@
void rb_cmd (struct parameters & a) // Regen brake command
{
double b = a.dbl[0] / 100.0;
-// com->printf ("Applying brake %.3f\r\n", b);
+// a.com->printf ("Applying brake %.3f\r\n", b);
mode_set (REGENBRAKE, b);
// apply_brake (b);
}
@@ -84,9 +86,9 @@
for (int i = 0; i < 32; i++)
t[i] = 0xff;
for (int i = 0; i < 8191; i += 32) {
- com->printf (".");
+ a.com->printf (".");
if (!wr_24LC64 (i, t, 32))
- com->printf ("eeprom write prob\r\n");
+ a.com->printf ("eeprom write prob\r\n");
}
}
/*struct motorpairoptions { // This to be user settable in eeprom, 32 bytes
@@ -107,37 +109,37 @@
void mode_cmd (struct parameters & a) // With no params, reads eeprom contents. With params sets eeprom contents
{
- if (a.target_unit == BROADCAST) {
-// com->printf ("At mode_cmd, can not use BROADCAST with mode_cmd\r\n");
+ if (a.target_unit == BROADCAST || !a.resp_always) {
+// a.com->printf ("At mode_cmd, can not use BROADCAST with mode_cmd\r\n");
} else {
char t[36];
- com->printf ("At mode_cmd with node %d\r\n", a.target_unit);
+ a.com->printf ("At mode_cmd with node %d\r\n", a.target_unit);
rd_24LC64 (0, t, 32);
- com->printf ("Numof params=%d\r\n", a.numof_dbls);
+ a.com->printf ("Numof params=%d\r\n", a.numof_dbls);
for (int i = 0; i < numof_eeprom_options; i++)
- com->printf ("%2x\t%s\r\n", t[i], option_list[i].t);
+ a.com->printf ("%2x\t%s\r\n", t[i], option_list[i].t);
if (a.numof_dbls == 0) { // Read present contents, do not write
- com->printf ("That's it\r\n");
+ a.com->printf ("That's it\r\n");
} else { // Write new shit to eeprom
- com->printf ("\r\n");
+ a.com->printf ("\r\n");
if (a.numof_dbls != numof_eeprom_options) {
- com->printf ("params required = %d, you offered %d\r\n", numof_eeprom_options, a.numof_dbls);
+ a.com->printf ("params required = %d, you offered %d\r\n", numof_eeprom_options, a.numof_dbls);
} else { // Have been passed correct number of parameters
int b;
- com->printf("Ready to write params to eeprom\r\n");
+ a.com->printf("Ready to write params to eeprom\r\n");
for (int i = 0; i < numof_eeprom_options; i++) {
b = (int)a.dbl[i]; // parameter value to check against limits
if (i == 6) // Alternative ID must be turned to ascii
b |= '0';
if ((b < option_list[i].min) || (b > option_list[i].max)) { // if parameter out of range
- com->printf("Warning - Parameter = %d, out of range, setting to default %d\r\n", b, option_list[i].def);
+ a.com->printf("Warning - Parameter = %d, out of range, setting to default %d\r\n", b, option_list[i].def);
b = option_list[i].def;
}
- com->printf ("0x%2x\t%s\r\n", (t[i] = b), option_list[i].t);
+ a.com->printf ("0x%2x\t%s\r\n", (t[i] = b), option_list[i].t);
}
wr_24LC64 (0, t, numof_eeprom_options);
memcpy (mode_bytes,t,32);
- com->printf("Parameters set in eeprom\r\n");
+ a.com->printf("Parameters set in eeprom\r\n");
}
}
}
@@ -149,8 +151,8 @@
void hb_cmd (struct parameters & a)
{
if (a.respond) {
- com->printf ("numof params = %d\r\n", a.numof_dbls);
- com->printf ("Hand Brake : First %.3f, second %.3f\r\n", a.dbl[0], a.dbl[1]);
+ a.com->printf ("numof params = %d\r\n", a.numof_dbls);
+ a.com->printf ("Hand Brake : First %.3f, second %.3f\r\n", a.dbl[0], a.dbl[1]);
}
mode_set (HANDBRAKE, 0.0);
}
@@ -158,13 +160,13 @@
extern uint32_t last_temp_count;
void temperature_cmd (struct parameters & a) {
if (a.respond) {
- com->printf ("tem%c %d\r\n", mode_bytes[ID], (last_temp_count / 16) - 50);
+ a.com->printf ("tem%c %d\r\n", mode_bytes[ID], (last_temp_count / 16) - 50);
}
}
void bogie_constants_report_cmd (struct parameters & a) {
if (a.respond) {
- com->printf ("bc%c %d %d %d\r\n", mode_bytes[ID], mode_bytes[WHEELDIA], mode_bytes[MOTPIN], mode_bytes[WHEELGEAR]);
+ a.com->printf ("bc%c %d %d %d\r\n", mode_bytes[ID], mode_bytes[WHEELDIA], mode_bytes[MOTPIN], mode_bytes[WHEELGEAR]);
}
}
@@ -173,11 +175,19 @@
{
if (a.respond) {
uint32_t dest[3];
- read_RPM (dest);
- com->printf ("rpm%d %d\r", dest[0], dest[1]);
+ read_RPM (dest); // gets rpm for each motor
+ a.com->printf ("rpm%d %d\r", dest[0], dest[1]);
}
}
+extern double rpm2mph ;
+void mph_cmd (struct parameters & a) // to report miles per hour
+{
+ uint32_t dest[3];
+ read_RPM (dest); // gets rpm for each motor
+ a.com->printf ("mph%c %.3f\r\n", mode_bytes[ID], (double)(dest[0] + dest[1]) * rpm2mph / 2.0);
+}
+
void menucmd (struct parameters & a);
void vi_cmd (struct parameters & a)
@@ -197,21 +207,21 @@
void i_cmd (struct parameters & a)
{
// if (a.respond)
-// com->printf ("In setI, setting I to %.2f\r\n", a.dbl[0]);
+// a.com->printf ("In setI, setting I to %.2f\r\n", a.dbl[0]);
setI (a.dbl[0] / 100.0);
}
void kd_cmd (struct parameters & a) // kick the watchdog
{
WatchDog = WATCHDOG_RELOAD + (I_Am() & 0x0f);
-// com->printf ("Poked %d up Dog\r\n", WatchDog);
+// a.com->printf ("Poked %d up Dog\r\n", WatchDog);
}
void who_cmd (struct parameters & a)
{
int i = I_Am ();
if (I_Am() == a.target_unit)
- com->printf ("who%c\r\n", a.target_unit);
+ a.com->printf ("who%c\r\n", a.target_unit);
}
struct kb_command {
@@ -220,7 +230,7 @@
void (*f)(struct parameters &); // points to function
} ;
-struct kb_command const command_list[] = {
+struct kb_command const loco_command_list[] = {
{"ls", "Lists available commands", menucmd},
{"?", "Lists available commands, same as ls", menucmd},
{"fw", "forward", fw_cmd},
@@ -242,14 +252,55 @@
{"nu", "do nothing", null_cmd},
};
-const int numof_menu_items = sizeof(command_list) / sizeof(kb_command);
+//const int numof_loco_menu_items = sizeof(loco_command_list) / sizeof(kb_command);
+
+
+struct kb_command const pc_command_list[] = {
+ {"ls", "Lists available commands", menucmd},
+ {"?", "Lists available commands, same as ls", menucmd},
+ {"fw", "forward", fw_cmd},
+ {"re", "reverse", re_cmd},
+ {"rb", "regen brake 0 to 99 %", rb_cmd},
+ {"hb", "hand brake", hb_cmd},
+ {"v", "set motors V percent RANGE 0 to 100", v_cmd},
+ {"i", "set motors I percent RANGE 0 to 100", i_cmd},
+ {"vi", "set motors V and I percent RANGE 0 to 100", vi_cmd},
+ {"who", "search for connected units, e.g. 3who returs 'Hi there' if found", who_cmd},
+ {"mode", "read or set params in eeprom", mode_cmd},
+ {"erase", "set eeprom contents to all 0xff", erase_cmd},
+ {"tem", "report temperature", temperature_cmd},
+ {"kd", "kick the dog, reloads WatchDog", kd_cmd},
+ {"rpm", "read motor pair speeds", rpm_cmd},
+ {"mph", "read loco speed miles per hour", mph_cmd},
+ {"rvi", "read most recent values sent to pwms", rvi_cmd},
+ {"rdi", "read motor currents and power voltage", rdi_cmd},
+ {"bc", "bogie constants - wheel dia, motor pinion, wheel gear", bogie_constants_report_cmd},
+ {"nu", "do nothing", null_cmd},
+};
+
+void setup_comms () {
+ pccom.com = & pc;
+ pccom.command_list = pc_command_list;
+ pccom.numof_menu_items = sizeof(pc_command_list) / sizeof(kb_command);
+ pccom.cl_index = 0;
+ pccom.gp_i = 0; // general puropse integer, not used to 30/4/2018
+ pccom.resp_always = true;
+ lococom.com = & com2;
+ lococom.command_list = loco_command_list;
+ lococom.numof_menu_items = sizeof(loco_command_list) / sizeof(kb_command);
+ lococom.cl_index = 0;
+ lococom.gp_i = 0; // general puropse integer, toggles 0 / 1 to best guess source of rpm
+ lococom.resp_always = false;
+}
+
+
void menucmd (struct parameters & a)
{
if (a.respond) {
- com->printf("\r\n\nDouble Brushless Motor Driver 2018\r\nAt menucmd function - listing commands:-\r\n");
- for(int i = 0; i < numof_menu_items; i++)
- com->printf("[%s]\t\t%s\r\n", command_list[i].cmd_word, command_list[i].explan);
- com->printf("End of List of Commands\r\n");
+ a.com->printf("\r\n\nDouble Brushless Motor Driver 2018\r\nAt menucmd function - listing commands:-\r\n");
+ for(int i = 0; i < a.numof_menu_items; i++)
+ a.com->printf("[%s]\t\t%s\r\n", a.command_list[i].cmd_word, a.command_list[i].explan);
+ a.com->printf("End of List of Commands\r\n");
}
}
@@ -262,9 +313,77 @@
But for BROADCAST commands, '0' may respond on behalf of the group
*/
//void command_line_interpreter (void const *argument)
+void cli_core (struct parameters & a) {
+ const int MAX_CMD_LEN = 120;
+ int ch, IAm = I_Am();
+ char * pEnd;//, * cmd_line_ptr;
+ while (a.com->readable()) {
+ ch = a.com->getc();
+ if (a.cl_index > MAX_CMD_LEN) { // trap out stupidly long command lines
+ a.com->printf ("Error!! Stupidly long cmd line\r\n");
+ a.cl_index = 0;
+ }
+ if(ch != '\r') // was this the 'Enter' key?
+ a.cmd_line[a.cl_index++] = ch; // added char to command being assembled
+ else { // key was CR, may or may not be command to lookup
+ a.target_unit = BROADCAST; // Set to BROADCAST default once found command line '\r'
+ a.cmd_line_ptr = a.cmd_line;
+ a.cmd_line[a.cl_index] = 0; // null terminate command string
+ if(a.cl_index) { // If have got some chars to lookup
+ int i, wrdlen;
+ if (isdigit(a.cmd_line[0])) { // Look for command with prefix digit
+ a.cmd_line_ptr++; // point past identified digit prefix
+ a.target_unit = a.cmd_line[0]; // '0' to '9'
+ //com->printf ("Got prefix %c\r\n", cmd_line[0]);
+ }
+ for (i = 0; i < a.numof_menu_items; i++) { // Look for input match in command list
+ wrdlen = strlen(a.command_list[i].cmd_word);
+ if(strncmp(a.command_list[i].cmd_word, a.cmd_line_ptr, wrdlen) == 0 && !isalpha(a.cmd_line_ptr[wrdlen])) { // If match found
+ for (int k = 0; k < MAX_PARAMS; k++) {
+ a.dbl[k] = 0.0;
+ }
+ a.position_in_list = i;
+ a.numof_dbls = 0;
+ pEnd = a.cmd_line_ptr + wrdlen;
+ while (*pEnd) { // Assemble all numerics as doubles
+ a.dbl[a.numof_dbls++] = strtod (pEnd, &pEnd);
+ while (*pEnd && !isdigit(*pEnd) && '-' != *pEnd && '+' != *pEnd) {
+ pEnd++;
+ }
+ }
+ //com->printf ("\r\n"); // Not allowed as many may output this.
+ //for (int k = 0; k < param_block.numof_dbls; k++)
+ // com->printf ("Read %.3f\r\n", param_block.dbl[k]);
+// param_block.times[i] = clock();
+// a.respond = false;
+ a.respond = a.resp_always;
+ if (((a.target_unit == BROADCAST) && (IAm == '0')) || (IAm == a.target_unit))
+ a.respond = true; // sorted 26/4/18
+ // All boards to obey BROADCAST command, only specific board to obey number prefixed command
+ if ((a.target_unit == BROADCAST) || (IAm == a.target_unit))
+ a.command_list[i].f(a); // execute command if addressed to this unit
+ i = a.numof_menu_items + 1; // to exit for loop
+ } // end of match found
+ } // End of for numof_menu_items
+ if(i == a.numof_menu_items)
+ a.com->printf("No Match Found for CMD [%s]\r\n", a.cmd_line);
+ } // End of If have got some chars to lookup
+ //com->printf("\r\n>");
+ a.cl_index = 0;
+ } // End of else key was CR, may or may not be command to lookup
+ } // End of while (com->readable())
+}
+
+void command_line_interpreter_pc () {
+ cli_core (pccom);
+}
+void command_line_interpreter_loco () {
+ cli_core (lococom);
+}
+
void command_line_interpreter ()
{
- const int MAX_CMD_LEN = 120;
+/* const int MAX_CMD_LEN = 120;
static char cmd_line[MAX_CMD_LEN + 4];
static int cl_index = 0;
int ch, IAm = I_Am();
@@ -291,9 +410,9 @@
param_block.target_unit = cmd_line[0]; // '0' to '9'
//com->printf ("Got prefix %c\r\n", cmd_line[0]);
}
- for (i = 0; i < numof_menu_items; i++) { // Look for input match in command list
- wrdlen = strlen(command_list[i].cmd_word);
- if(strncmp(command_list[i].cmd_word, cmd_line_ptr, wrdlen) == 0 && !isalpha(cmd_line_ptr[wrdlen])) { // If match found
+ for (i = 0; i < a.numof_menu_items; i++) { // Look for input match in command list
+ wrdlen = strlen(a.command_list[i].cmd_word);
+ if(strncmp(a.command_list[i].cmd_word, a.cmd_line_ptr, wrdlen) == 0 && !isalpha(a.cmd_line_ptr[wrdlen])) { // If match found
for (int k = 0; k < MAX_PARAMS; k++) {
param_block.dbl[k] = 0.0;
}
@@ -328,7 +447,7 @@
} // End of else key was CR, may or may not be command to lookup
} // End of while (com->readable())
// Thread::wait(20); // Using RTOS on this project
-// }
+// }*/
}
--- a/main.cpp Tue Jun 05 07:19:39 2018 +0000
+++ b/main.cpp Sun Jun 17 06:59:37 2018 +0000
@@ -6,7 +6,7 @@
/*
New 29th May 2018 - YET TO CODE FOR - Fwd/Rev line from possible remote hand control box has signal routed to T5
- Also new LMT01 temperature sensor routed to T1 - and rerouted to PC_13 at InterruptIn on T1 (ports A and B I think) not workable
+ Also new LMT01 temperature sensor routed to T1 - and rerouted to PC_13 as InterruptIn on T1 (ports A and B I think) not workable
*/
@@ -28,154 +28,11 @@
*/
-//#if defined (TARGET_NUCLEO_F446ZE)
-#if defined (TARGET_NUCLEO_F401RE)
-
-// Hoped to select servo functions from user info stored on EEROM. Too difficult. Do not define servo as in and out
-
-// Port A -> MotorA, Port B -> MotorB
-const uint16_t
-AUL = 1 << 0, // Feb 2018 Now using DGD21032 mosfet drivers via 74HC00 pwm gates (low side) - GOOD, works well with auto-tickle of high side drivers
-AVL = 1 << 6, // These are which port bits connect to which mosfet driver
-AWL = 1 << 4,
-
-AUH = 1 << 1,
-AVH = 1 << 7,
-AWH = 1 << 8,
-
-AUV = AUH | AVL, // Each of 6 possible output energisations made up of one hi and one low
-AVU = AVH | AUL,
-AUW = AUH | AWL,
-AWU = AWH | AUL,
-AVW = AVH | AWL,
-AWV = AWH | AVL,
-
-KEEP_L_MASK_A = AUL | AVL | AWL,
-KEEP_H_MASK_A = AUH | AVH | AWH,
-
-BRA = AUL | AVL | AWL, // All low side switches on (and all high side off) for braking
-
-BUL = 1 << 0, // Likewise for MotorB but different port bits on different port
-BVL = 1 << 1,
-BWL = 1 << 2,
-
-BUH = 1 << 10,
-BVH = 1 << 12,
-BWH = 1 << 13,
-
-BUV = BUH | BVL,
-BVU = BVH | BUL,
-BUW = BUH | BWL,
-BWU = BWH | BUL,
-BVW = BVH | BWL,
-BWV = BWH | BVL,
-
-KEEP_L_MASK_B = BUL | BVL | BWL,
-KEEP_H_MASK_B = BUH | BVH | BWH,
-
-BRB = BUL | BVL | BWL,
-
-PORT_A_MASK = AUL | AVL | AWL | AUH | AVH | AWH, // NEW METHOD FOR DGD21032 MOSFET DRIVERS
-PORT_B_MASK = BUL | BVL | BWL | BUH | BVH | BWH;
-
-PortOut MotA (PortA, PORT_A_MASK); // Activate output ports to motor drivers
-PortOut MotB (PortB, PORT_B_MASK);
-
-// Pin 1 VBAT NET +3V3
-
-//DigitalIn J3 (PC_13, PullUp);// Pin 2 Jumper pulls to GND, R floats Hi
-InterruptIn Temperature_pin (PC_13);// Pin 2 June 2018 - taken for temperature sensor - hard wired to T1 due to wrong thought T1 could be InterruptIn
-
-
-// Pin 3 PC14-OSC32_IN NET O32I
-// Pin 4 PC15-OSC32_OUT NET O32O
-// Pin 5 PH0-OSC_IN NET PH1
-// Pin 6 PH1-OSC_OUT NET PH1
-// Pin 7 NRST NET NRST
-AnalogIn Ain_DriverPot (PC_0); // Pin 8 Spare Analogue in, net SAIN fitted with external pull-down
-AnalogIn Ain_SystemVolts (PC_1); // Pin 9
-AnalogIn Motor_A_Current (PC_2); // Pin 10
-AnalogIn Motor_B_Current (PC_3); // Pin 11
-// Pin 12 VSSA/VREF- NET GND
-// Pin 13 VDDA/VREF+ NET +3V3
-// Pin 14 Port_A AUL
-// Pin 15 Port_A AUH
-// Pins 16, 17 BufferedSerial pc
-BufferedSerial pc (PA_2, PA_3, 512, 4, NULL); // Pins 16, 17 tx, rx to pc via usb lead
-// Pin 18 VSS NET GND
-// Pin 19 VDD NET +3V3
-// Pin 20 Port_A AWL
-// Pin 21 DigitalOut led1(LED1);
-DigitalOut LED (PA_5); // Pin 21
-// Pin 22 Port_A AVL
-// Pin 23 Port_A AVH
-InterruptIn MBH2 (PC_4); // Pin 24
-InterruptIn MBH3 (PC_5); // Pin 25
-// Pin 26 Port_B BUL
-// Pin 27 Port_B BVL
-// Pin 28 Port_B BWL
-// Pin 29 Port_B BUH
-// Pin 30 VCAP1
-// Pin 31 VSS
-// Pin 32 VDD
-// Pin 33 Port_B BVH
-// Pin 34 Port_B BWH
-DigitalOut T4 (PB_14); // Pin 35
-DigitalOut T3 (PB_15); // Pin 36
-// BufferedSerial com2 pins 37 Tx, 38 Rx
-BufferedSerial com2 (PC_6, PC_7); // Pins 37, 38 tx, rx to XBee module
-FastPWM A_MAX_V_PWM (PC_8, 1), // Pin 39 pwm3/3
- A_MAX_I_PWM (PC_9, 1); // pin 40, prescaler value pwm3/4
-//InterruptIn MotB_Hall (PA_8); // Pin 41
-// Pin 41 Port_A AWH
-// BufferedSerial com3 pins 42 Tx, 43 Rx
-//InterruptIn tryseredge (PA_9);
-BufferedSerial com3 (PA_9, PA_10); // Pins 42, 43 tx, rx to any aux module
-// PA_9 is Tx. I wonder, can we also use InterruptIn on this pin to generate interrupts on tx bit transitions ? Let's find out !
-// No.
-
-// Feb 2018 Pins 44 and 45 now liberated, could use for serial or other uses
-//BufferedSerial extra_ser (PA_11, PA_12); // Pins 44, 45 tx, rx to XBee module
-DigitalOut T2 (PA_11); // Pin 44
-// was DigitalOut T1 (PA_12); // Pin 45
-
-
-//InterruptIn T1 (PA_12); // Pin 45 now input counting pulses from LMT01 temperature sensor
-// InterruptIn DOES NOT WORK ON PA_12. Boards are being made, will have to wire link PA12 to PC13
-DigitalIn T1 (PA_12);
-////InterruptIn T1 (PC_13); // Pin 45 now input counting pulses from LMT01 temperature sensor
-
-
-
-// Pin 46 SWDIO
-// Pin 47 VSS
-// Pin 48 VDD
-// Pin 49 SWCLK
-
-//Was DigitalOut T5 (PA_15); // Pin 50
-DigitalIn T5 (PA_15); // Pin 50 now fwd/rev from remote control box if fitted
-InterruptIn MAH1 (PC_10); // Pin 51
-InterruptIn MAH2 (PC_11); // Pin 52
-InterruptIn MAH3 (PC_12); // Pin 53
-InterruptIn MBH1 (PD_2); // Pin 54
-DigitalOut T6 (PB_3); // Pin 55
-FastPWM B_MAX_V_PWM (PB_4, 1), // Pin 56 pwm3/3
- B_MAX_I_PWM (PB_5, 1); // pin 57, prescaler value pwm3/4
-
-I2C i2c (PB_7, PB_6); // Pins 58, 59 For 24LC64 eeprom
-// Pin 60 BOOT0
-
-// Servo pins, 2 off. Configured as Input to read radio control receiver
-// If used as servo output, code gives pin to 'Servo' - seems to work
-InterruptIn Servo1_i (PB_8); // Pin 61 to read output from rc rx
-InterruptIn Servo2_i (PB_9); // Pin 62 to read output from rc rx
-
-// Pin 63 VSS
-// Pin 64 VDD
-// SYSTEM CONSTANTS
-
+#if defined (TARGET_NUCLEO_F401RE) // CPU in 64 pin LQFP
+#include "F401RE.h"
#endif
-#if defined (TARGET_NUCLEO_F446ZE)
+#if defined (TARGET_NUCLEO_F446ZE) // CPU in 144 pin LQFP
+#include "F446ZE.h"
#endif
/* Global variable declarations */
volatile uint32_t fast_sys_timer = 0; // gets incremented by our Ticker ISR every VOLTAGE_READ_INTERVAL_US
@@ -188,11 +45,14 @@
bool loop_flag = false; // made true in ISR_loop_timer, picked up and made false again in main programme loop
bool flag_8Hz = false; // As loop_flag but repeats 8 times per sec
bool temp_sensor_exists = false;
+bool eeprom_flag; // gets set according to 24LC674 being found or not
+bool mode_good_flag = false;
char mode_bytes[36];
uint32_t temp_sensor_count = 0, // incremented by every rising edge from LMT01
last_temp_count = 0; // global updated approx every 100ms after each LMT01 conversion completes
// struct single_bogie_options bogie;
+ double rpm2mph = 0.0; // gets calculated from eeprom mode entries if present
/* End of Global variable declarations */
Ticker tick_vread; // Device to cause periodic interrupts, used to time voltage readings etc
@@ -364,7 +224,7 @@
motor MotorA (&MotA, &A_MAX_V_PWM, &A_MAX_I_PWM, A_tabl, AHarr);
motor MotorB (&MotB, &B_MAX_V_PWM, &B_MAX_I_PWM, B_tabl, BHarr);
-motor * MotPtr[8]; // Array of pointers to some number of motor objects
+//motor * MotPtr[8]; // Array of pointers to some number of motor objects
motor::motor (PortOut * P , FastPWM * _maxV_ , FastPWM * _maxI_ , const uint16_t * lutptr, InterruptIn ** Hall) // Constructor
{ // Constructor
@@ -700,7 +560,9 @@
}
}
-extern void command_line_interpreter () ;
+extern void setup_comms () ;
+extern void command_line_interpreter_pc () ;
+extern void command_line_interpreter_loco () ;
extern int check_24LC64 () ; // Call from near top of main() to init i2c bus
extern bool wr_24LC64 (int mem_start_addr, char * source, int length) ;
extern bool rd_24LC64 (int mem_start_addr, char * dest, int length) ;
@@ -719,6 +581,12 @@
return IAm;
}
+double mph (int rpm) {
+ if (mode_good_flag) {
+ return rpm2mph * (double) rpm;
+ }
+ return -1.0;
+}
int main()
{
@@ -726,8 +594,8 @@
MotA = 0; // Output all 0s to Motor drive ports A and B
MotB = 0;
- MotPtr[0] = &MotorA; // Pointers to motor class objects
- MotPtr[1] = &MotorB;
+// MotPtr[0] = &MotorA; // Pointers to motor class objects
+// MotPtr[1] = &MotorB;
Temperature_pin.fall (&temp_sensor_isr);
Temperature_pin.mode (PullUp);
@@ -767,23 +635,18 @@
pc.baud (9600);
com3.baud (1200);
com2.baud (19200);
+ setup_comms ();
+ IAm = '0';
if (check_24LC64() != 0xa0) { // searches for i2c devices, returns address of highest found
pc.printf ("Check for 24LC64 eeprom FAILED\r\n");
com2.printf ("Check for 24LC64 eeprom FAILED\r\n");
+ eeprom_flag = false;
}
else { // Found 24LC64 memory on I2C
+ eeprom_flag = true;
bool k;
-// static const char ramtst[] = "I found the man sir!";
-// j = wr_24LC64 (0x1240, (char*)ramtst, strlen(ramtst));
-// for (int i = 0; i < TXTBUFSIZ; i++) buff[i] = 0; // Clear buffer
-// // need a way to check i2c busy - YES implemented ack_poll
-// k = rd_24LC64 (0x1240, buff, strlen(ramtst));
-// pc.printf("Ram test returned [%s], wr ret'd [%s], rd ret'd [%s]\r\n", buff, j ? "true" : "false", k ? "true" : "false");
-// com2.printf("Ram test returned [%s], wr ret'd [%s], rd ret'd [%s]\r\n", buff, j ? "true" : "false", k ? "true" : "false");
k = rd_24LC64 (0, mode_bytes, 32);
-// if (k)
-// com2.printf ("Good read from eeprom\r\n");
if (!k)
com2.printf ("Error reading from eeprom\r\n");
@@ -796,11 +659,16 @@
// else
// com2.printf ("%2x Good %s\r\n", buff[i], option_list[i].t);
}
- IAm = '0';
+ rpm2mph = 0.0;
if (err == 0) {
+ mode_good_flag = true;
MotorA.direction_set (mode_bytes[MOTADIR]);
MotorB.direction_set (mode_bytes[MOTBDIR]);
IAm = mode_bytes[ID];
+ rpm2mph = 60.0 // to Motor Revs per hour;
+ * ((double)mode_bytes[MOTPIN] / (double)mode_bytes[WHEELGEAR]) // Wheel revs per hour
+ * PI * ((double)mode_bytes[WHEELDIA] / 1000.0) // metres per hour
+ * 39.37 / (1760.0 * 36.0); // miles per hour
}
// Alternative ID 1 to 9
// com2.printf ("Alternative ID = 0x%2x\r\n", buff[6]);
@@ -826,7 +694,7 @@
Servo Servo2 (PB_9) ;
Servos[1] = & Servo2;
- pc.printf ("last_temp_count = %d\r\n", last_temp_count); // Has had time to do at least 1 conversion
+// pc.printf ("last_temp_count = %d\r\n", last_temp_count); // Has had time to do at least 1 conversion
if ((last_temp_count > 160) && (last_temp_count < 2400)) // in range -40 to +100 degree C
temp_sensor_exists = true;
/*
@@ -851,10 +719,12 @@
break;
}
*/
- pc.printf ("Ready to go!, wheel gear in position %d\r\n", WHEELGEAR);
+// pc.printf ("Ready to go!, wheel gear in position %d\r\n", WHEELGEAR);
+ pc.printf ("About to start!\r\n");
while (1) { // Loop forever, repeats synchroised by waiting for ticker Interrupt Service Routine to set 'loop_flag' true
while (!loop_flag) { // Most of the time is spent in this loop, repeatedly re-checking for commands from pc port
- command_line_interpreter () ; // Proceed beyond here once loop_timer ticker ISR has set loop_flag true
+ command_line_interpreter_pc () ; // Proceed beyond here once loop_timer ticker ISR has set loop_flag true
+ command_line_interpreter_loco () ; // Proceed beyond here once loop_timer ticker ISR has set loop_flag true
AtoD_reader (); // Performs A to D conversions at rate set by ticker interrupts
}
loop_flag = false; // Clear flag set by ticker interrupt handler
@@ -877,12 +747,12 @@
eighth_sec_count = 0;
MotorA.current_calc (); // Updates readings in MotorA.I.min, MotorA.I.ave and MotorA.I.max
MotorB.current_calc ();
- if (temp_sensor_exists) {
+/* if (temp_sensor_exists) {
double tmprt = (double) last_temp_count;
tmprt /= 16.0;
tmprt -= 50.0;
pc.printf ("Temp %.2f\r\n", tmprt);
- }
+ }*/
// com2.printf ("V=%+.2f, Pot=%+.2f, HA %d, HB %d, IAmin %d, IAave %d, IAmax %d, IB %d, Arpm %d, Brpm %d\r\n", Read_BatteryVolts(), Read_DriverPot(), MotorA.read_Halls (), MotorB.read_Halls (), MotorA.I.min, MotorA.I.ave, MotorA.I.max, MotorB.I.ave, (Apps * 60) / 24, (Bpps * 60) / 24);
}
} // End of if(flag_8Hz)