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:
Sun Sep 29 16:34:37 2019 +0000
Revision:
13:ef7a06fa11de
Parent:
12:d1d21a2941ef
Child:
14:acaa1add097b
Stable code as at end of 2019 running season

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 0:435bf84ce48a 9 const int addr_rd = 0xa1; // set bit 0 for read, clear bit 0 for write
JonFreeman 0:435bf84ce48a 10 const int addr_wr = 0xa0; // set bit 0 for read, clear bit 0 for write
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 12:d1d21a2941ef 50 char settings [36];
JonFreeman 12:d1d21a2941ef 51 bool rd_24LC64 (int start_addr, char * dest, int length) ;
JonFreeman 12:d1d21a2941ef 52 bool wr_24LC64 (int start_addr, char * dest, int length) ;
JonFreeman 12:d1d21a2941ef 53 bool set_24LC64_internal_address (int start_addr) ;
JonFreeman 12:d1d21a2941ef 54 bool ack_poll () ;
JonFreeman 12:d1d21a2941ef 55 public:
JonFreeman 12:d1d21a2941ef 56 eeprom_settings (PinName sda, PinName scl); // Constructor
JonFreeman 12:d1d21a2941ef 57 char rd (uint32_t) ; // Read one setup char value from private buffer 'settings'
JonFreeman 12:d1d21a2941ef 58 bool wr (char, uint32_t) ; // Write one setup char value to private buffer 'settings'
JonFreeman 12:d1d21a2941ef 59 bool save () ; // Write 'settings' buffer to EEPROM
JonFreeman 12:d1d21a2941ef 60 uint32_t errs () ; // Return errors
JonFreeman 12:d1d21a2941ef 61 } ;
JonFreeman 12:d1d21a2941ef 62 */
JonFreeman 12:d1d21a2941ef 63
JonFreeman 12:d1d21a2941ef 64 bool eeprom_settings::set_defaults () { // Put default settings into EEPROM and local buffer
JonFreeman 12:d1d21a2941ef 65 for (int i = 0; i < numof_eeprom_options2; i++)
JonFreeman 12:d1d21a2941ef 66 settings[i] = option_list2[i].def; // Load defaults and 'Save Settings'
JonFreeman 12:d1d21a2941ef 67 return save ();
JonFreeman 12:d1d21a2941ef 68 }
JonFreeman 12:d1d21a2941ef 69
JonFreeman 12:d1d21a2941ef 70 uint32_t eeprom_settings::errs () {
JonFreeman 12:d1d21a2941ef 71 return errors;
JonFreeman 12:d1d21a2941ef 72 }
JonFreeman 12:d1d21a2941ef 73
JonFreeman 12:d1d21a2941ef 74 // Use : eeprom_settings (SDA_PIN, SCL_PIN);
JonFreeman 12:d1d21a2941ef 75 eeprom_settings::eeprom_settings (PinName sda, PinName scl) : i2c(sda, scl) // Constructor
JonFreeman 12:d1d21a2941ef 76 {
JonFreeman 12:d1d21a2941ef 77 errors = 0;
JonFreeman 12:d1d21a2941ef 78 for (int i = 0; i < 36; i++)
JonFreeman 12:d1d21a2941ef 79 settings[i] = 0;
JonFreeman 12:d1d21a2941ef 80 i2c.frequency(400000); // Speed 400000 max.
JonFreeman 12:d1d21a2941ef 81 int last_found = 0, q; // Note address bits 3-1 to match addr pins on device
JonFreeman 12:d1d21a2941ef 82 for (int i = 0; i < 255; i += 2) { // Search for devices at all possible i2c addresses
JonFreeman 12:d1d21a2941ef 83 i2c.start();
JonFreeman 12:d1d21a2941ef 84 q = i2c.write(i); // may return error code 2 when no start issued
JonFreeman 12:d1d21a2941ef 85 switch (q) {
JonFreeman 12:d1d21a2941ef 86 case ACK:
JonFreeman 12:d1d21a2941ef 87 pc.printf ("I2C device found at 0x%x\r\n", i);
JonFreeman 12:d1d21a2941ef 88 last_found = i;
JonFreeman 12:d1d21a2941ef 89 case 2: // Device not seen at this address
JonFreeman 12:d1d21a2941ef 90 break;
JonFreeman 12:d1d21a2941ef 91 default:
JonFreeman 12:d1d21a2941ef 92 pc.printf ("Unknown error %d in check_24LC64\r\n", q);
JonFreeman 12:d1d21a2941ef 93 errors |= 512;
JonFreeman 12:d1d21a2941ef 94 break;
JonFreeman 12:d1d21a2941ef 95 }
JonFreeman 12:d1d21a2941ef 96 }
JonFreeman 12:d1d21a2941ef 97 i2c.stop();
JonFreeman 12:d1d21a2941ef 98 if (errors || last_found != 0xa0) {
JonFreeman 12:d1d21a2941ef 99 pc.printf ("Error - EEPROM not seen %d\r\n", errors);
JonFreeman 12:d1d21a2941ef 100 errors |= 0xa0;
JonFreeman 12:d1d21a2941ef 101 ESC_Error.set (FAULT_EEPROM, errors); // Set FAULT_EEPROM bits if 24LC64 problem
JonFreeman 12:d1d21a2941ef 102 }
JonFreeman 12:d1d21a2941ef 103 else { // Found 24LC64 memory on I2C. Attempt to load settings from EEPROM
JonFreeman 12:d1d21a2941ef 104 errors = 0;
JonFreeman 12:d1d21a2941ef 105 if (!rd_24LC64 (0, settings, 32))
JonFreeman 12:d1d21a2941ef 106 ESC_Error.set (FAULT_EEPROM, 2); // Set FAULT_EEPROM bit 1 if 24LC64 problem
JonFreeman 12:d1d21a2941ef 107 for (int i = 0; i < numof_eeprom_options2; i++) {
JonFreeman 12:d1d21a2941ef 108 if ((settings[i] < option_list2[i].min) || (settings[i] > option_list2[i].max)) {
JonFreeman 12:d1d21a2941ef 109 pc.printf ("EEROM error with %s\r\n", option_list2[i].t);
JonFreeman 12:d1d21a2941ef 110 errors++;
JonFreeman 12:d1d21a2941ef 111 }
JonFreeman 12:d1d21a2941ef 112 }
JonFreeman 12:d1d21a2941ef 113 }
JonFreeman 12:d1d21a2941ef 114 ESC_Error.set (FAULT_EEPROM, errors); // sets nothing if 0
JonFreeman 12:d1d21a2941ef 115 if (errors > 1) {
JonFreeman 12:d1d21a2941ef 116 pc.printf ("Bad settings found at startup. Restoring defaults\r\n");
JonFreeman 12:d1d21a2941ef 117 for (int i = 0; i < numof_eeprom_options2; i++)
JonFreeman 12:d1d21a2941ef 118 settings[i] = option_list2[i].def; // Load defaults and 'Save Settings'
JonFreeman 12:d1d21a2941ef 119 if (!wr_24LC64 (0, settings, 32)) // Save settings
JonFreeman 12:d1d21a2941ef 120 pc.printf ("Error saving EEPROM in mode19\r\n");
JonFreeman 12:d1d21a2941ef 121 }
JonFreeman 12:d1d21a2941ef 122 else // 0 or 1 error max found
JonFreeman 12:d1d21a2941ef 123 pc.printf ("At startup, settings errors = %d\r\n", errors);
JonFreeman 12:d1d21a2941ef 124 } // endof constructor
JonFreeman 12:d1d21a2941ef 125
JonFreeman 12:d1d21a2941ef 126 bool eeprom_settings::ack_poll () { // wait short while for any previous memory operation to complete
JonFreeman 0:435bf84ce48a 127 const int poll_tries = 40;
JonFreeman 0:435bf84ce48a 128 int poll_count = 0;
JonFreeman 0:435bf84ce48a 129 bool i2cfree = false;
JonFreeman 0:435bf84ce48a 130 while (poll_count++ < poll_tries && !i2cfree) {
JonFreeman 0:435bf84ce48a 131 i2c.start ();
JonFreeman 0:435bf84ce48a 132 if (i2c.write(addr_wr) == ACK)
JonFreeman 0:435bf84ce48a 133 i2cfree = true;
JonFreeman 0:435bf84ce48a 134 else
JonFreeman 3:ecb00e0e8d68 135 wait_ms (1);
JonFreeman 0:435bf84ce48a 136 }
JonFreeman 0:435bf84ce48a 137 return i2cfree;
JonFreeman 0:435bf84ce48a 138 }
JonFreeman 0:435bf84ce48a 139
JonFreeman 12:d1d21a2941ef 140 bool eeprom_settings::set_24LC64_internal_address (int start_addr) {
JonFreeman 0:435bf84ce48a 141 if (!ack_poll())
JonFreeman 0:435bf84ce48a 142 {
JonFreeman 0:435bf84ce48a 143 pc.printf ("Err in set_24LC64_internal_address, no ACK writing device address byte\r\n");
JonFreeman 0:435bf84ce48a 144 i2c.stop();
JonFreeman 0:435bf84ce48a 145 return false;
JonFreeman 0:435bf84ce48a 146 }
JonFreeman 0:435bf84ce48a 147 int err = 0;
JonFreeman 0:435bf84ce48a 148 if (i2c.write(start_addr >> 8) != ACK) err++;
JonFreeman 0:435bf84ce48a 149 if (i2c.write(start_addr & 0xff) != ACK) err++;
JonFreeman 0:435bf84ce48a 150 if (err) {
JonFreeman 0:435bf84ce48a 151 pc.printf ("In set_24LC64_internal_address, Believe Device present, failed in writing 2 mem addr bytes %d\r\n", err);
JonFreeman 0:435bf84ce48a 152 i2c.stop();
JonFreeman 0:435bf84ce48a 153 return false;
JonFreeman 0:435bf84ce48a 154 }
JonFreeman 0:435bf84ce48a 155 return true;
JonFreeman 0:435bf84ce48a 156 }
JonFreeman 0:435bf84ce48a 157
JonFreeman 12:d1d21a2941ef 158 bool eeprom_settings::rd_24LC64 (int start_addr, char * dest, int length) {
JonFreeman 12:d1d21a2941ef 159 int acknak = ACK;
JonFreeman 12:d1d21a2941ef 160 if(length < 1)
JonFreeman 12:d1d21a2941ef 161 return false;
JonFreeman 12:d1d21a2941ef 162 if (!set_24LC64_internal_address (start_addr)) {
JonFreeman 12:d1d21a2941ef 163 pc.printf ("In rd_24LC64, failed to set_ramaddr\r\n");
JonFreeman 12:d1d21a2941ef 164 return false;
JonFreeman 12:d1d21a2941ef 165 }
JonFreeman 12:d1d21a2941ef 166 i2c.start();
JonFreeman 12:d1d21a2941ef 167 if (i2c.write(addr_rd) != ACK) {
JonFreeman 12:d1d21a2941ef 168 pc.printf ("Errors in rd_24LC64 sending addr_rd\r\n");
JonFreeman 12:d1d21a2941ef 169 return false;
JonFreeman 12:d1d21a2941ef 170 }
JonFreeman 12:d1d21a2941ef 171 while(length--) {
JonFreeman 12:d1d21a2941ef 172 if(length == 0)
JonFreeman 12:d1d21a2941ef 173 acknak = 0;
JonFreeman 12:d1d21a2941ef 174 *dest++ = i2c.read(acknak);
JonFreeman 12:d1d21a2941ef 175 }
JonFreeman 12:d1d21a2941ef 176 i2c.stop();
JonFreeman 12:d1d21a2941ef 177 return true;
JonFreeman 12:d1d21a2941ef 178 }
JonFreeman 12:d1d21a2941ef 179
JonFreeman 12:d1d21a2941ef 180 bool eeprom_settings::wr_24LC64 (int start_addr, char * source, int length) {
JonFreeman 0:435bf84ce48a 181 int err = 0;
JonFreeman 0:435bf84ce48a 182 if(length < 1 || length > 32) {
JonFreeman 0:435bf84ce48a 183 pc.printf ("Length out of range %d in wr_24LC64\r\n", length);
JonFreeman 0:435bf84ce48a 184 return false;
JonFreeman 0:435bf84ce48a 185 }
JonFreeman 3:ecb00e0e8d68 186 ack_poll ();
JonFreeman 0:435bf84ce48a 187 if (!set_24LC64_internal_address (start_addr)) {
JonFreeman 0:435bf84ce48a 188 pc.printf ("In wr_24LC64, Believe Device present, failed in writing 2 mem addr bytes %d\r\n", err);
JonFreeman 0:435bf84ce48a 189 return false;
JonFreeman 0:435bf84ce48a 190 }
JonFreeman 0:435bf84ce48a 191 while(length--)
JonFreeman 0:435bf84ce48a 192 err += ACK - i2c.write(*source++);
JonFreeman 0:435bf84ce48a 193 i2c.stop();
JonFreeman 0:435bf84ce48a 194 if (err) {
JonFreeman 0:435bf84ce48a 195 pc.printf ("in wr_24LC64, device thought good, mem addr write worked, failed writing string\r\n");
JonFreeman 0:435bf84ce48a 196 return false;
JonFreeman 0:435bf84ce48a 197 }
JonFreeman 13:ef7a06fa11de 198 // pc.printf ("In wr_24LC64 No Errors Found!\r\n");
JonFreeman 0:435bf84ce48a 199 return true;
JonFreeman 0:435bf84ce48a 200 }
JonFreeman 0:435bf84ce48a 201
JonFreeman 12:d1d21a2941ef 202 char eeprom_settings::rd (uint32_t i) { // Read one setup char value from private buffer 'settings'
JonFreeman 12:d1d21a2941ef 203 if (i > 31) {
JonFreeman 12:d1d21a2941ef 204 pc.printf ("ERROR Attempt to read setting %d\r\n");
JonFreeman 12:d1d21a2941ef 205 return 0;
JonFreeman 0:435bf84ce48a 206 }
JonFreeman 12:d1d21a2941ef 207 return settings[i];
JonFreeman 12:d1d21a2941ef 208 }
JonFreeman 12:d1d21a2941ef 209
JonFreeman 12:d1d21a2941ef 210 bool eeprom_settings::wr (char c, uint32_t i) { // Read one setup char value from private buffer 'settings'
JonFreeman 12:d1d21a2941ef 211 if (i > 31)
JonFreeman 0:435bf84ce48a 212 return false;
JonFreeman 12:d1d21a2941ef 213 settings[i] = c;
JonFreeman 0:435bf84ce48a 214 return true;
JonFreeman 0:435bf84ce48a 215 }
JonFreeman 0:435bf84ce48a 216
JonFreeman 12:d1d21a2941ef 217 bool eeprom_settings::save () { // Write 'settings' buffer to EEPROM
JonFreeman 12:d1d21a2941ef 218 return wr_24LC64 (0, settings, 32);
JonFreeman 0:435bf84ce48a 219 }
JonFreeman 12:d1d21a2941ef 220