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@13:ef7a06fa11de, 2019-09-29 (annotated)
- 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?
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 | 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 |