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
24LC64_eeprom.cpp@14:acaa1add097b, 2019-11-30 (annotated)
- 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?
User | Revision | Line number | New 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 |