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

Committer:
JonFreeman
Date:
Sat Nov 30 16:34:58 2019 +0000
Revision:
14:acaa1add097b
Parent:
13:ef7a06fa11de
Child:
16:d1e4b9ad3b8b
Proved inverter board for radio control inputs work.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 0:435bf84ce48a 1 #include "mbed.h"
JonFreeman 13:ef7a06fa11de 2 #include "STM3_ESC.h"
JonFreeman 0:435bf84ce48a 3 #include "BufferedSerial.h"
JonFreeman 0:435bf84ce48a 4 extern BufferedSerial pc;
JonFreeman 12:d1d21a2941ef 5 extern error_handling_Jan_2019 ESC_Error ; // Provides array usable to store error codes.
JonFreeman 3:ecb00e0e8d68 6 // Code for 24LC64 8k x 8 bit eeprom
JonFreeman 0:435bf84ce48a 7 // Code based on earlier work using memory FM24W256, also at i2c address 0xa0;
JonFreeman 12:d1d21a2941ef 8
JonFreeman 14:acaa1add097b 9 const int addr_rd = 0xa1; // set bit 0 for read, clear bit 0 for write 24LC64
JonFreeman 14:acaa1add097b 10 const int addr_wr = 0xa0; // set bit 0 for read, clear bit 0 for write 24LC64
JonFreeman 0:435bf84ce48a 11 const int ACK = 1;
JonFreeman 0:435bf84ce48a 12
JonFreeman 12:d1d21a2941ef 13 struct optpar {
JonFreeman 12:d1d21a2941ef 14 int min, max, def; // min, max, default
JonFreeman 12:d1d21a2941ef 15 const char * t; // description
JonFreeman 12:d1d21a2941ef 16 } ;
JonFreeman 12:d1d21a2941ef 17 struct optpar option_list2[] = {
JonFreeman 12:d1d21a2941ef 18 {0, 1, 1, "MotorA direction 0 or 1"},
JonFreeman 12:d1d21a2941ef 19 {0, 1, 0, "MotorB direction 0 or 1"},
JonFreeman 12:d1d21a2941ef 20 {4, 8, 8, "MotorA poles 4 or 6 or 8"},
JonFreeman 12:d1d21a2941ef 21 {4, 8, 8, "MotorB poles 4 or 6 or 8"},
JonFreeman 12:d1d21a2941ef 22 {1, 4, 1, "MotorA 0R05 ohm current shunt resistors 1 to 4"},
JonFreeman 12:d1d21a2941ef 23 {1, 4, 1, "MotorB 0R05 ohm current shunt resistors 1 to 4"},
JonFreeman 12:d1d21a2941ef 24 {0, 1, 0, "Servo1 0 = Not used, 1= Output"},
JonFreeman 12:d1d21a2941ef 25 {0, 1, 0, "Servo2 0 = Not used, 1= Output"},
JonFreeman 12:d1d21a2941ef 26 {0, 1, 0, "RC Input1 0 = Not used, 1= Output"},
JonFreeman 12:d1d21a2941ef 27 {0, 1, 0, "RC Input2 0 = Not used, 1= Output"},
JonFreeman 12:d1d21a2941ef 28 {2, 5, 2, "Command source 2= COM2 (Touch Screen), 3= Pot, 4= RC Input1, 5= RC Input2"},
JonFreeman 12:d1d21a2941ef 29 {'1', '9', '0', "Alternative ID ascii '1' to '9'"}, // defaults to '0' before eerom setup for first time
JonFreeman 12:d1d21a2941ef 30 {10, 250, 60, "Top speed MPH * 10 range 1.0 to 25.0"}, // New Jan 2019 TOP_SPEED
JonFreeman 12:d1d21a2941ef 31 {50, 253, 98, "Wheel diameter mm"}, // New 01/06/2018
JonFreeman 12:d1d21a2941ef 32 {10, 253, 27, "Motor pinion"}, // New 01/06/2018
JonFreeman 12:d1d21a2941ef 33 {50, 253, 85, "Wheel gear"}, // New 01/06/2018
JonFreeman 12:d1d21a2941ef 34 {0, 100, 0, "Future 1"},
JonFreeman 12:d1d21a2941ef 35 {0, 100, 0, "Future 2"},
JonFreeman 12:d1d21a2941ef 36 {0, 100, 0, "Future 3"},
JonFreeman 12:d1d21a2941ef 37 {0, 100, 0, "Future 4"},
JonFreeman 12:d1d21a2941ef 38 {0, 100, 0, "Future 5"},
JonFreeman 12:d1d21a2941ef 39 } ;
JonFreeman 12:d1d21a2941ef 40
JonFreeman 12:d1d21a2941ef 41 const int numof_eeprom_options2 = sizeof(option_list2) / sizeof (struct optpar);
JonFreeman 12:d1d21a2941ef 42
JonFreeman 12:d1d21a2941ef 43
JonFreeman 12:d1d21a2941ef 44
JonFreeman 12:d1d21a2941ef 45
JonFreeman 12:d1d21a2941ef 46 /*
JonFreeman 12:d1d21a2941ef 47 class eeprom_settings {
JonFreeman 12:d1d21a2941ef 48 I2C i2c;
JonFreeman 12:d1d21a2941ef 49 uint32_t errors;
JonFreeman 14:acaa1add097b 50 uint32_t i2c_device_count;
JonFreeman 14:acaa1add097b 51 uint32_t i2c_device_list[12]; // max 12 i2c devices
JonFreeman 12:d1d21a2941ef 52 char settings [36];
JonFreeman 12:d1d21a2941ef 53 bool rd_24LC64 (int start_addr, char * dest, int length) ;
JonFreeman 12:d1d21a2941ef 54 bool wr_24LC64 (int start_addr, char * dest, int length) ;
JonFreeman 12:d1d21a2941ef 55 bool set_24LC64_internal_address (int start_addr) ;
JonFreeman 12:d1d21a2941ef 56 bool ack_poll () ;
JonFreeman 12:d1d21a2941ef 57 public:
JonFreeman 12:d1d21a2941ef 58 eeprom_settings (PinName sda, PinName scl); // Constructor
JonFreeman 14:acaa1add097b 59 bool do_we_have_i2c (uint32_t x) ;
JonFreeman 12:d1d21a2941ef 60 char rd (uint32_t) ; // Read one setup char value from private buffer 'settings'
JonFreeman 12:d1d21a2941ef 61 bool wr (char, uint32_t) ; // Write one setup char value to private buffer 'settings'
JonFreeman 12:d1d21a2941ef 62 bool save () ; // Write 'settings' buffer to EEPROM
JonFreeman 12:d1d21a2941ef 63 uint32_t errs () ; // Return errors
JonFreeman 12:d1d21a2941ef 64 } ;
JonFreeman 12:d1d21a2941ef 65 */
JonFreeman 12:d1d21a2941ef 66
JonFreeman 12:d1d21a2941ef 67 bool eeprom_settings::set_defaults () { // Put default settings into EEPROM and local buffer
JonFreeman 12:d1d21a2941ef 68 for (int i = 0; i < numof_eeprom_options2; i++)
JonFreeman 12:d1d21a2941ef 69 settings[i] = option_list2[i].def; // Load defaults and 'Save Settings'
JonFreeman 12:d1d21a2941ef 70 return save ();
JonFreeman 12:d1d21a2941ef 71 }
JonFreeman 12:d1d21a2941ef 72
JonFreeman 12:d1d21a2941ef 73 uint32_t eeprom_settings::errs () {
JonFreeman 12:d1d21a2941ef 74 return errors;
JonFreeman 12:d1d21a2941ef 75 }
JonFreeman 12:d1d21a2941ef 76
JonFreeman 14:acaa1add097b 77 bool eeprom_settings::do_we_have_i2c (uint32_t x) {
JonFreeman 14:acaa1add097b 78 for (int i = 0; i < i2c_device_count; i++) {
JonFreeman 14:acaa1add097b 79 if (i2c_device_list[i] == x)
JonFreeman 14:acaa1add097b 80 return true;
JonFreeman 14:acaa1add097b 81 }
JonFreeman 14:acaa1add097b 82 return false;
JonFreeman 14:acaa1add097b 83 }
JonFreeman 14:acaa1add097b 84
JonFreeman 12:d1d21a2941ef 85 // Use : eeprom_settings (SDA_PIN, SCL_PIN);
JonFreeman 12:d1d21a2941ef 86 eeprom_settings::eeprom_settings (PinName sda, PinName scl) : i2c(sda, scl) // Constructor
JonFreeman 12:d1d21a2941ef 87 {
JonFreeman 14:acaa1add097b 88 errors = i2c_device_count = 0;
JonFreeman 12:d1d21a2941ef 89 for (int i = 0; i < 36; i++)
JonFreeman 12:d1d21a2941ef 90 settings[i] = 0;
JonFreeman 14:acaa1add097b 91 for (int i = 0; i < 12; i++)
JonFreeman 14:acaa1add097b 92 i2c_device_list[i] = 0;
JonFreeman 12:d1d21a2941ef 93 i2c.frequency(400000); // Speed 400000 max.
JonFreeman 14:acaa1add097b 94 // int last_found = 0, q; // Note address bits 3-1 to match addr pins on device
JonFreeman 14:acaa1add097b 95 int q;
JonFreeman 12:d1d21a2941ef 96 for (int i = 0; i < 255; i += 2) { // Search for devices at all possible i2c addresses
JonFreeman 12:d1d21a2941ef 97 i2c.start();
JonFreeman 12:d1d21a2941ef 98 q = i2c.write(i); // may return error code 2 when no start issued
JonFreeman 12:d1d21a2941ef 99 switch (q) {
JonFreeman 12:d1d21a2941ef 100 case ACK:
JonFreeman 12:d1d21a2941ef 101 pc.printf ("I2C device found at 0x%x\r\n", i);
JonFreeman 14:acaa1add097b 102 // last_found = i;
JonFreeman 14:acaa1add097b 103 i2c_device_list[i2c_device_count++] = i;
JonFreeman 12:d1d21a2941ef 104 case 2: // Device not seen at this address
JonFreeman 12:d1d21a2941ef 105 break;
JonFreeman 12:d1d21a2941ef 106 default:
JonFreeman 14:acaa1add097b 107 pc.printf ("Unknown error %d from i2c.write while looking for i2c devices\r\n", q);
JonFreeman 12:d1d21a2941ef 108 errors |= 512;
JonFreeman 12:d1d21a2941ef 109 break;
JonFreeman 12:d1d21a2941ef 110 }
JonFreeman 12:d1d21a2941ef 111 }
JonFreeman 12:d1d21a2941ef 112 i2c.stop();
JonFreeman 14:acaa1add097b 113 // if (errors || last_found != 0xa0) {
JonFreeman 14:acaa1add097b 114 if (errors || !do_we_have_i2c(0xa0)) {
JonFreeman 12:d1d21a2941ef 115 pc.printf ("Error - EEPROM not seen %d\r\n", errors);
JonFreeman 12:d1d21a2941ef 116 errors |= 0xa0;
JonFreeman 12:d1d21a2941ef 117 ESC_Error.set (FAULT_EEPROM, errors); // Set FAULT_EEPROM bits if 24LC64 problem
JonFreeman 12:d1d21a2941ef 118 }
JonFreeman 12:d1d21a2941ef 119 else { // Found 24LC64 memory on I2C. Attempt to load settings from EEPROM
JonFreeman 12:d1d21a2941ef 120 errors = 0;
JonFreeman 12:d1d21a2941ef 121 if (!rd_24LC64 (0, settings, 32))
JonFreeman 12:d1d21a2941ef 122 ESC_Error.set (FAULT_EEPROM, 2); // Set FAULT_EEPROM bit 1 if 24LC64 problem
JonFreeman 12:d1d21a2941ef 123 for (int i = 0; i < numof_eeprom_options2; i++) {
JonFreeman 12:d1d21a2941ef 124 if ((settings[i] < option_list2[i].min) || (settings[i] > option_list2[i].max)) {
JonFreeman 12:d1d21a2941ef 125 pc.printf ("EEROM error with %s\r\n", option_list2[i].t);
JonFreeman 12:d1d21a2941ef 126 errors++;
JonFreeman 12:d1d21a2941ef 127 }
JonFreeman 12:d1d21a2941ef 128 }
JonFreeman 12:d1d21a2941ef 129 }
JonFreeman 12:d1d21a2941ef 130 ESC_Error.set (FAULT_EEPROM, errors); // sets nothing if 0
JonFreeman 12:d1d21a2941ef 131 if (errors > 1) {
JonFreeman 12:d1d21a2941ef 132 pc.printf ("Bad settings found at startup. Restoring defaults\r\n");
JonFreeman 12:d1d21a2941ef 133 for (int i = 0; i < numof_eeprom_options2; i++)
JonFreeman 12:d1d21a2941ef 134 settings[i] = option_list2[i].def; // Load defaults and 'Save Settings'
JonFreeman 12:d1d21a2941ef 135 if (!wr_24LC64 (0, settings, 32)) // Save settings
JonFreeman 12:d1d21a2941ef 136 pc.printf ("Error saving EEPROM in mode19\r\n");
JonFreeman 12:d1d21a2941ef 137 }
JonFreeman 12:d1d21a2941ef 138 else // 0 or 1 error max found
JonFreeman 12:d1d21a2941ef 139 pc.printf ("At startup, settings errors = %d\r\n", errors);
JonFreeman 12:d1d21a2941ef 140 } // endof constructor
JonFreeman 12:d1d21a2941ef 141
JonFreeman 12:d1d21a2941ef 142 bool eeprom_settings::ack_poll () { // wait short while for any previous memory operation to complete
JonFreeman 0:435bf84ce48a 143 const int poll_tries = 40;
JonFreeman 0:435bf84ce48a 144 int poll_count = 0;
JonFreeman 0:435bf84ce48a 145 bool i2cfree = false;
JonFreeman 0:435bf84ce48a 146 while (poll_count++ < poll_tries && !i2cfree) {
JonFreeman 0:435bf84ce48a 147 i2c.start ();
JonFreeman 0:435bf84ce48a 148 if (i2c.write(addr_wr) == ACK)
JonFreeman 0:435bf84ce48a 149 i2cfree = true;
JonFreeman 0:435bf84ce48a 150 else
JonFreeman 3:ecb00e0e8d68 151 wait_ms (1);
JonFreeman 0:435bf84ce48a 152 }
JonFreeman 0:435bf84ce48a 153 return i2cfree;
JonFreeman 0:435bf84ce48a 154 }
JonFreeman 0:435bf84ce48a 155
JonFreeman 12:d1d21a2941ef 156 bool eeprom_settings::set_24LC64_internal_address (int start_addr) {
JonFreeman 0:435bf84ce48a 157 if (!ack_poll())
JonFreeman 0:435bf84ce48a 158 {
JonFreeman 0:435bf84ce48a 159 pc.printf ("Err in set_24LC64_internal_address, no ACK writing device address byte\r\n");
JonFreeman 0:435bf84ce48a 160 i2c.stop();
JonFreeman 0:435bf84ce48a 161 return false;
JonFreeman 0:435bf84ce48a 162 }
JonFreeman 0:435bf84ce48a 163 int err = 0;
JonFreeman 0:435bf84ce48a 164 if (i2c.write(start_addr >> 8) != ACK) err++;
JonFreeman 0:435bf84ce48a 165 if (i2c.write(start_addr & 0xff) != ACK) err++;
JonFreeman 0:435bf84ce48a 166 if (err) {
JonFreeman 0:435bf84ce48a 167 pc.printf ("In set_24LC64_internal_address, Believe Device present, failed in writing 2 mem addr bytes %d\r\n", err);
JonFreeman 0:435bf84ce48a 168 i2c.stop();
JonFreeman 0:435bf84ce48a 169 return false;
JonFreeman 0:435bf84ce48a 170 }
JonFreeman 0:435bf84ce48a 171 return true;
JonFreeman 0:435bf84ce48a 172 }
JonFreeman 0:435bf84ce48a 173
JonFreeman 12:d1d21a2941ef 174 bool eeprom_settings::rd_24LC64 (int start_addr, char * dest, int length) {
JonFreeman 12:d1d21a2941ef 175 int acknak = ACK;
JonFreeman 12:d1d21a2941ef 176 if(length < 1)
JonFreeman 12:d1d21a2941ef 177 return false;
JonFreeman 12:d1d21a2941ef 178 if (!set_24LC64_internal_address (start_addr)) {
JonFreeman 12:d1d21a2941ef 179 pc.printf ("In rd_24LC64, failed to set_ramaddr\r\n");
JonFreeman 12:d1d21a2941ef 180 return false;
JonFreeman 12:d1d21a2941ef 181 }
JonFreeman 12:d1d21a2941ef 182 i2c.start();
JonFreeman 12:d1d21a2941ef 183 if (i2c.write(addr_rd) != ACK) {
JonFreeman 12:d1d21a2941ef 184 pc.printf ("Errors in rd_24LC64 sending addr_rd\r\n");
JonFreeman 12:d1d21a2941ef 185 return false;
JonFreeman 12:d1d21a2941ef 186 }
JonFreeman 12:d1d21a2941ef 187 while(length--) {
JonFreeman 12:d1d21a2941ef 188 if(length == 0)
JonFreeman 12:d1d21a2941ef 189 acknak = 0;
JonFreeman 12:d1d21a2941ef 190 *dest++ = i2c.read(acknak);
JonFreeman 12:d1d21a2941ef 191 }
JonFreeman 12:d1d21a2941ef 192 i2c.stop();
JonFreeman 12:d1d21a2941ef 193 return true;
JonFreeman 12:d1d21a2941ef 194 }
JonFreeman 12:d1d21a2941ef 195
JonFreeman 12:d1d21a2941ef 196 bool eeprom_settings::wr_24LC64 (int start_addr, char * source, int length) {
JonFreeman 0:435bf84ce48a 197 int err = 0;
JonFreeman 0:435bf84ce48a 198 if(length < 1 || length > 32) {
JonFreeman 0:435bf84ce48a 199 pc.printf ("Length out of range %d in wr_24LC64\r\n", length);
JonFreeman 0:435bf84ce48a 200 return false;
JonFreeman 0:435bf84ce48a 201 }
JonFreeman 3:ecb00e0e8d68 202 ack_poll ();
JonFreeman 0:435bf84ce48a 203 if (!set_24LC64_internal_address (start_addr)) {
JonFreeman 0:435bf84ce48a 204 pc.printf ("In wr_24LC64, Believe Device present, failed in writing 2 mem addr bytes %d\r\n", err);
JonFreeman 0:435bf84ce48a 205 return false;
JonFreeman 0:435bf84ce48a 206 }
JonFreeman 0:435bf84ce48a 207 while(length--)
JonFreeman 0:435bf84ce48a 208 err += ACK - i2c.write(*source++);
JonFreeman 0:435bf84ce48a 209 i2c.stop();
JonFreeman 0:435bf84ce48a 210 if (err) {
JonFreeman 0:435bf84ce48a 211 pc.printf ("in wr_24LC64, device thought good, mem addr write worked, failed writing string\r\n");
JonFreeman 0:435bf84ce48a 212 return false;
JonFreeman 0:435bf84ce48a 213 }
JonFreeman 13:ef7a06fa11de 214 // pc.printf ("In wr_24LC64 No Errors Found!\r\n");
JonFreeman 0:435bf84ce48a 215 return true;
JonFreeman 0:435bf84ce48a 216 }
JonFreeman 0:435bf84ce48a 217
JonFreeman 12:d1d21a2941ef 218 char eeprom_settings::rd (uint32_t i) { // Read one setup char value from private buffer 'settings'
JonFreeman 12:d1d21a2941ef 219 if (i > 31) {
JonFreeman 12:d1d21a2941ef 220 pc.printf ("ERROR Attempt to read setting %d\r\n");
JonFreeman 12:d1d21a2941ef 221 return 0;
JonFreeman 0:435bf84ce48a 222 }
JonFreeman 12:d1d21a2941ef 223 return settings[i];
JonFreeman 12:d1d21a2941ef 224 }
JonFreeman 12:d1d21a2941ef 225
JonFreeman 12:d1d21a2941ef 226 bool eeprom_settings::wr (char c, uint32_t i) { // Read one setup char value from private buffer 'settings'
JonFreeman 12:d1d21a2941ef 227 if (i > 31)
JonFreeman 0:435bf84ce48a 228 return false;
JonFreeman 12:d1d21a2941ef 229 settings[i] = c;
JonFreeman 0:435bf84ce48a 230 return true;
JonFreeman 0:435bf84ce48a 231 }
JonFreeman 0:435bf84ce48a 232
JonFreeman 12:d1d21a2941ef 233 bool eeprom_settings::save () { // Write 'settings' buffer to EEPROM
JonFreeman 12:d1d21a2941ef 234 return wr_24LC64 (0, settings, 32);
JonFreeman 0:435bf84ce48a 235 }
JonFreeman 12:d1d21a2941ef 236