Touch screen drivers control dashboard for miniature locomotive. Features meters for speed, volts, power. Switches for lights, horns. Drives multiple STM3_ESC brushless motor controllers for complete brushless loco system as used in "The Brute" - www.jons-workshop.com
Dependencies: TS_DISCO_F746NG mbed Servo LCD_DISCO_F746NG BSP_DISCO_F746NG QSPI_DISCO_F746NG AsyncSerial FastPWM
main.cpp@12:a25bdf135348, 2019-01-14 (annotated)
- Committer:
- JonFreeman
- Date:
- Mon Jan 14 16:39:41 2019 +0000
- Revision:
- 12:a25bdf135348
- Parent:
- 11:a573664b1a59
- Child:
- 14:6bcec5ac21ca
Tidied, better documented, more OOP, interim release
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
JonFreeman | 4:67478861c670 | 1 | /* |
JonFreeman | 12:a25bdf135348 | 2 | November 2018 - Jon Freeman |
JonFreeman | 12:a25bdf135348 | 3 | Cloned from Loco_TS_2018_06 on 23rd November 2018 |
JonFreeman | 4:67478861c670 | 4 | |
JonFreeman | 12:a25bdf135348 | 5 | Touch Screen controller communicates with 1, 2, ... n Brushless STM3 Controller boards via opto-isolated serial port. |
JonFreeman | 4:67478861c670 | 6 | |
JonFreeman | 4:67478861c670 | 7 | 9 pid D connector retained but wiring NOT compatible with 2017. |
JonFreeman | 4:67478861c670 | 8 | This time pins are : - |
JonFreeman | 4:67478861c670 | 9 | 1 Not Used on TS2018, connection from Twin BLDC Controller only - Pot wiper |
JonFreeman | 4:67478861c670 | 10 | 2 Not Used on TS2018, connection from Twin BLDC Controller only - GND |
JonFreeman | 4:67478861c670 | 11 | 3 Not Used on TS2018, connection from Twin BLDC Controller only - Weak +5 (top of pot) |
JonFreeman | 12:a25bdf135348 | 12 | 4 Not Used on TS2018, connection from Twin BLDC Controller only - Fwd / Rev switched between pins 2 and 3 above |
JonFreeman | 4:67478861c670 | 13 | 5 TS2018 high voltage output - power up signal to Twin BLDC Controllers, +10 to + 70 Volt (full supply via 3k3 0.5W safety resistor) |
JonFreeman | 4:67478861c670 | 14 | 6 Twin BLDC Rx- <- TS2018 Tx data ||GND to avoid exposing TS +5v rail to the outside world |
JonFreeman | 4:67478861c670 | 15 | 7 Twin BLDC Rx+ <- TS2018 +5v ||Tx\ to avoid exposing TS +5v rail to the outside world, INVERTED Txd idles lo |
JonFreeman | 4:67478861c670 | 16 | 8 Twin BLDC Tx- <- TS2018 GND |
JonFreeman | 4:67478861c670 | 17 | 9 Twin BLDC Tx+ <- TS2018 Rx data with 1k pullup to +5, line idles hi |
JonFreeman | 4:67478861c670 | 18 | */ |
adustm | 0:99e26e18b424 | 19 | #include "mbed.h" |
JonFreeman | 4:67478861c670 | 20 | #include "Electric_Loco.h" |
JonFreeman | 5:21a8ac83142c | 21 | #include "AsyncSerial.hpp" |
JonFreeman | 5:21a8ac83142c | 22 | #include "Servo.h" |
JonFreeman | 4:67478861c670 | 23 | #include "TS_DISCO_F746NG.h" |
JonFreeman | 4:67478861c670 | 24 | #include "LCD_DISCO_F746NG.h" |
JonFreeman | 12:a25bdf135348 | 25 | |
JonFreeman | 12:a25bdf135348 | 26 | char const_version_string[] = {"1.0.0\0"}; // Version string, readable from serial ports |
JonFreeman | 12:a25bdf135348 | 27 | |
JonFreeman | 12:a25bdf135348 | 28 | LCD_DISCO_F746NG lcd ; // LCD display |
JonFreeman | 12:a25bdf135348 | 29 | TS_DISCO_F746NG touch_screen ; // Touch Screen |
JonFreeman | 12:a25bdf135348 | 30 | screen_touch_handler slider ; // Loco driver's slider control |
JonFreeman | 4:67478861c670 | 31 | |
JonFreeman | 12:a25bdf135348 | 32 | // see movingcoilmeter.h ffi |
JonFreeman | 12:a25bdf135348 | 33 | moving_coil_meter Voltmeter ( LCD_COLOR_BLACK, LCD_COLOR_WHITE, LCD_COLOR_RED, LCD_COLOR_BLUE, LCD_COLOR_MAGENTA, |
JonFreeman | 12:a25bdf135348 | 34 | VOLTMETER_X, VOLTMETER_Y, V_A_SIZE, 22.0, 61.0, 1.25 * PI, -0.25 * PI , 20, "V", ONE_DP, false), |
JonFreeman | 12:a25bdf135348 | 35 | Powermeter ( LCD_COLOR_BLACK, LCD_COLOR_WHITE, LCD_COLOR_RED, LCD_COLOR_BLUE, LCD_COLOR_BLUE, |
JonFreeman | 12:a25bdf135348 | 36 | AMMETER_X, AMMETER_Y, V_A_SIZE, -1400.0, 1400.0, 1.25 * PI, -0.25 * PI , 14, "Watt", NO_DPS, false), |
JonFreeman | 12:a25bdf135348 | 37 | Speedo ( SPEEDO_BODY_COLOUR, SPEEDO_DIAL_COLOUR, LCD_COLOR_RED, SPEEDO_TEXT_COLOUR, LCD_COLOR_BLACK, |
JonFreeman | 12:a25bdf135348 | 38 | SPEEDO_X, SPEEDO_Y, SPEEDO_SIZE, 0.0, 12.0, 1.25 * PI, -0.25 * PI , 12, "MPH", ONE_DP, false); |
JonFreeman | 12:a25bdf135348 | 39 | // 3 instances of moving coil meter graphic |
JonFreeman | 4:67478861c670 | 40 | |
JonFreeman | 12:a25bdf135348 | 41 | error_handling_Jan_2019 Controller_Error ; // Provides array usable to store error codes. |
JonFreeman | 12:a25bdf135348 | 42 | STM3_ESC_Interface My_STM3_ESC_boards ; |
JonFreeman | 12:a25bdf135348 | 43 | |
JonFreeman | 12:a25bdf135348 | 44 | extern command_line_interpreter_core pcli, ploco; // pcli handles comms with pc, ploco handles comms with STM3_ESC boards |
JonFreeman | 4:67478861c670 | 45 | |
JonFreeman | 12:a25bdf135348 | 46 | /* |
JonFreeman | 12:a25bdf135348 | 47 | STRANGE BEHAVIOUR WARNING ! |
JonFreeman | 12:a25bdf135348 | 48 | This project requires two serial ports. |
JonFreeman | 12:a25bdf135348 | 49 | The following combination of one 'Serial' and one 'AsyncSerial' is the only combination found to work ! |
JonFreeman | 12:a25bdf135348 | 50 | MODSERIAL has not been adapted to F746NG, will not compile. |
JonFreeman | 12:a25bdf135348 | 51 | Does compile with BufferedSerial but crashes the whole thing. No startup. |
JonFreeman | 12:a25bdf135348 | 52 | */ |
JonFreeman | 4:67478861c670 | 53 | |
JonFreeman | 12:a25bdf135348 | 54 | Serial pc (USBTX, USBRX); // AsyncSerial does not work here. Comms to 'PuTTY' or similar comms programme on pc |
JonFreeman | 12:a25bdf135348 | 55 | AsyncSerial com2escs (A4, A5); // Com port to opto isolators on Twin BLDC Controller boards. Only AsyncSerial works here |
JonFreeman | 12:a25bdf135348 | 56 | |
JonFreeman | 12:a25bdf135348 | 57 | //DigitalOut reverse_pin (D7); // These pins no longer used to set mode and direction, now commands issued to com |
JonFreeman | 12:a25bdf135348 | 58 | //DigitalOut forward_pin (D9); //was D6, these two decode to fwd, rev, regen_braking and park |
JonFreeman | 12:a25bdf135348 | 59 | |
JonFreeman | 12:a25bdf135348 | 60 | DigitalOut I_sink1 (D14); // a horn |
JonFreeman | 12:a25bdf135348 | 61 | DigitalOut I_sink2 (D15); // lamp |
JonFreeman | 12:a25bdf135348 | 62 | DigitalOut I_sink3 (D3); // lamp |
JonFreeman | 12:a25bdf135348 | 63 | DigitalOut I_sink4 (D4); |
JonFreeman | 12:a25bdf135348 | 64 | DigitalOut I_sink5 (D5); |
JonFreeman | 12:a25bdf135348 | 65 | DigitalOut led_grn (LED1); // the only on board user led |
JonFreeman | 4:67478861c670 | 66 | |
JonFreeman | 5:21a8ac83142c | 67 | DigitalIn f_r_switch (D2); // was D0, Reads position of centre-off ignition switch |
JonFreeman | 4:67478861c670 | 68 | //DigitalIn spareio_d8 (D8); |
JonFreeman | 5:21a8ac83142c | 69 | //DigitalIn spareio_d9 (D9); |
JonFreeman | 4:67478861c670 | 70 | DigitalIn spareio_d10 (D10); // D8, D9, D10 wired to jumper on pcb - not used to Apr 2017 |
JonFreeman | 4:67478861c670 | 71 | |
JonFreeman | 4:67478861c670 | 72 | AnalogIn ht_volts_ain (A0); // Jan 2017 |
JonFreeman | 4:67478861c670 | 73 | AnalogIn ht_amps_ain (A1); // Jan 2017 |
JonFreeman | 5:21a8ac83142c | 74 | //AnalogIn spare_ain2 (A2); |
JonFreeman | 5:21a8ac83142c | 75 | //AnalogIn spare_ain3 (A3); |
JonFreeman | 4:67478861c670 | 76 | //AnalogIn spare_ain4 (A4); // hardware on pcb for these 3 spare analogue inputs - not used to Apr 2017 |
JonFreeman | 4:67478861c670 | 77 | //AnalogIn spare_ain5 (A5); // causes display flicker ! |
JonFreeman | 5:21a8ac83142c | 78 | |
JonFreeman | 12:a25bdf135348 | 79 | Servo servo1 (D6); // Model control servo used to adjust Honda engine speed |
JonFreeman | 4:67478861c670 | 80 | |
JonFreeman | 12:a25bdf135348 | 81 | extern bool test_qspi () ; |
JonFreeman | 4:67478861c670 | 82 | extern bool odometer_zero () ; // Returns true on success |
JonFreeman | 4:67478861c670 | 83 | extern bool odometer_update (uint32_t pulsetot, uint16_t pow, uint16_t volt) ; // Hall pulse total updated once per sec and saved in blocks of 4096 bytes on QSPI onboard memory |
JonFreeman | 4:67478861c670 | 84 | |
JonFreeman | 4:67478861c670 | 85 | extern void setup_buttons () ; |
JonFreeman | 12:a25bdf135348 | 86 | extern void rewrite_odometer () ; |
JonFreeman | 7:3b1f44cd4735 | 87 | |
JonFreeman | 4:67478861c670 | 88 | static const int |
JonFreeman | 4:67478861c670 | 89 | MAF_PTS = 140, // Moving Average Filter points. Filters reduce noise on volatage and current readings |
JonFreeman | 4:67478861c670 | 90 | FWD = 0, |
JonFreeman | 4:67478861c670 | 91 | REV = ~FWD; |
JonFreeman | 4:67478861c670 | 92 | |
JonFreeman | 12:a25bdf135348 | 93 | int32_t V_maf[MAF_PTS + 2], I_maf[MAF_PTS + 2], maf_ptr = 0; // |
JonFreeman | 12:a25bdf135348 | 94 | volatile uint32_t sys_timer_32Hz = 0; |
JonFreeman | 12:a25bdf135348 | 95 | double recent_distance = 0.0; |
adustm | 0:99e26e18b424 | 96 | |
JonFreeman | 12:a25bdf135348 | 97 | bool qtrsec_trig = false; |
JonFreeman | 12:a25bdf135348 | 98 | bool trigger_current_read = false; |
JonFreeman | 4:67478861c670 | 99 | volatile bool trigger_32ms = false; |
JonFreeman | 4:67478861c670 | 100 | |
JonFreeman | 12:a25bdf135348 | 101 | double read_voltmeter () |
JonFreeman | 4:67478861c670 | 102 | { |
JonFreeman | 7:3b1f44cd4735 | 103 | int32_t a = 0; |
JonFreeman | 4:67478861c670 | 104 | for (int b = 0; b < MAF_PTS; b++) |
JonFreeman | 12:a25bdf135348 | 105 | a += V_maf[b]; |
JonFreeman | 12:a25bdf135348 | 106 | a /= MAF_PTS; |
JonFreeman | 12:a25bdf135348 | 107 | double v = (double) a; |
JonFreeman | 12:a25bdf135348 | 108 | return (v / 932.0) + 0.0; // fiddled to suit resistor values |
JonFreeman | 12:a25bdf135348 | 109 | } |
JonFreeman | 12:a25bdf135348 | 110 | |
JonFreeman | 12:a25bdf135348 | 111 | double read_ammeter () // Returns amps taken by STM3escs - amps dumped due to over-voltage |
JonFreeman | 12:a25bdf135348 | 112 | { // Could make sense to read this at up to 32 times per second |
JonFreeman | 12:a25bdf135348 | 113 | int32_t a = 0; // MAF data almost completely renewed at this rate |
JonFreeman | 12:a25bdf135348 | 114 | for (int b = 0; b < MAF_PTS; b++) // MAF updated every 250us, MAF size = MAF_PTS (once set to 140, probably still is) |
JonFreeman | 4:67478861c670 | 115 | a += I_maf[b]; |
JonFreeman | 4:67478861c670 | 116 | a /= MAF_PTS; |
JonFreeman | 7:3b1f44cd4735 | 117 | a -= 0x4000; |
JonFreeman | 7:3b1f44cd4735 | 118 | double i = (double) (0 - a); |
JonFreeman | 7:3b1f44cd4735 | 119 | return i / 200.0; // Fiddled to get current reading close enough |
JonFreeman | 4:67478861c670 | 120 | } |
JonFreeman | 4:67478861c670 | 121 | |
JonFreeman | 12:a25bdf135348 | 122 | const int BIGMAFSIZ = 8; |
JonFreeman | 12:a25bdf135348 | 123 | |
JonFreeman | 12:a25bdf135348 | 124 | class ammeter_reading { |
JonFreeman | 12:a25bdf135348 | 125 | double bigImaf[BIGMAFSIZ]; |
JonFreeman | 12:a25bdf135348 | 126 | int bigImafptr; |
JonFreeman | 12:a25bdf135348 | 127 | double amps_longave, // internal use only |
JonFreeman | 12:a25bdf135348 | 128 | amps_latest, // update() called @ 32Hz. Value stored here is average over most recent 3125us |
JonFreeman | 12:a25bdf135348 | 129 | amps_filtered; // Average of the BIGMAFSIZ most recent samples stored in latest |
JonFreeman | 12:a25bdf135348 | 130 | public: |
JonFreeman | 12:a25bdf135348 | 131 | ammeter_reading () { // constructor |
JonFreeman | 12:a25bdf135348 | 132 | bigImafptr = 0; |
JonFreeman | 12:a25bdf135348 | 133 | amps_longave = amps_latest = amps_filtered = 0.0; |
JonFreeman | 12:a25bdf135348 | 134 | for (int i = 0; i < BIGMAFSIZ; i++) |
JonFreeman | 12:a25bdf135348 | 135 | bigImaf[i] = 0.0; |
JonFreeman | 12:a25bdf135348 | 136 | } |
JonFreeman | 12:a25bdf135348 | 137 | void update () ; // Read ammeter core, store most recent 32ms or so worth in amps_latest, 250ms average in amps_filtered |
JonFreeman | 12:a25bdf135348 | 138 | double latest () ; |
JonFreeman | 12:a25bdf135348 | 139 | double filtered() ; |
JonFreeman | 12:a25bdf135348 | 140 | } Ammeter ; |
JonFreeman | 12:a25bdf135348 | 141 | |
JonFreeman | 12:a25bdf135348 | 142 | double ammeter_reading::latest () { |
JonFreeman | 12:a25bdf135348 | 143 | return amps_latest; |
JonFreeman | 4:67478861c670 | 144 | } |
JonFreeman | 4:67478861c670 | 145 | |
JonFreeman | 12:a25bdf135348 | 146 | double ammeter_reading::filtered () { |
JonFreeman | 12:a25bdf135348 | 147 | return amps_filtered; |
JonFreeman | 12:a25bdf135348 | 148 | } |
JonFreeman | 12:a25bdf135348 | 149 | |
JonFreeman | 12:a25bdf135348 | 150 | void ammeter_reading::update () { |
JonFreeman | 12:a25bdf135348 | 151 | amps_latest = read_ammeter(); |
JonFreeman | 12:a25bdf135348 | 152 | amps_longave -= bigImaf[bigImafptr]; |
JonFreeman | 12:a25bdf135348 | 153 | bigImaf[bigImafptr] = amps_latest; |
JonFreeman | 12:a25bdf135348 | 154 | amps_longave += amps_latest; |
JonFreeman | 12:a25bdf135348 | 155 | bigImafptr++; |
JonFreeman | 12:a25bdf135348 | 156 | if (bigImafptr >= BIGMAFSIZ) |
JonFreeman | 12:a25bdf135348 | 157 | bigImafptr = 0; |
JonFreeman | 12:a25bdf135348 | 158 | amps_filtered = amps_longave / BIGMAFSIZ; |
JonFreeman | 12:a25bdf135348 | 159 | } |
JonFreeman | 12:a25bdf135348 | 160 | |
JonFreeman | 12:a25bdf135348 | 161 | |
JonFreeman | 4:67478861c670 | 162 | // Interrupt Service Routines |
JonFreeman | 4:67478861c670 | 163 | |
JonFreeman | 4:67478861c670 | 164 | void ISR_current_reader (void) // FIXED at 250us |
JonFreeman | 4:67478861c670 | 165 | { |
JonFreeman | 4:67478861c670 | 166 | static int ms32 = 0, ms250 = 0; |
JonFreeman | 4:67478861c670 | 167 | trigger_current_read = true; // every 250us, i.e. 4kHz NOTE only sets trigger here, readings taken in main loop |
JonFreeman | 4:67478861c670 | 168 | ms32++; |
JonFreeman | 12:a25bdf135348 | 169 | if (ms32 >= 125) { // 31.25ms, not 32ms, is 32Hz |
JonFreeman | 4:67478861c670 | 170 | ms32 = 0; |
JonFreeman | 5:21a8ac83142c | 171 | sys_timer_32Hz++; // , usable anywhere as general measure of elapsed time |
JonFreeman | 4:67478861c670 | 172 | trigger_32ms = true; |
JonFreeman | 4:67478861c670 | 173 | ms250++; |
JonFreeman | 12:a25bdf135348 | 174 | if (ms250 >= 8) { |
JonFreeman | 4:67478861c670 | 175 | ms250 = 0; |
JonFreeman | 4:67478861c670 | 176 | qtrsec_trig = true; |
JonFreeman | 4:67478861c670 | 177 | } |
JonFreeman | 4:67478861c670 | 178 | } |
JonFreeman | 4:67478861c670 | 179 | } |
JonFreeman | 4:67478861c670 | 180 | |
JonFreeman | 4:67478861c670 | 181 | // End of Interrupt Service Routines |
JonFreeman | 4:67478861c670 | 182 | |
JonFreeman | 5:21a8ac83142c | 183 | void throttle (double p) { // New Apr 2018 ; servo adjusts throttle lever on Honda GX120 |
JonFreeman | 12:a25bdf135348 | 184 | const double THR_MAX = 0.92; // Values tweaked to suit servo and linkage fitted to loco power unit |
JonFreeman | 12:a25bdf135348 | 185 | const double THR_MIN = 0.09; |
JonFreeman | 12:a25bdf135348 | 186 | const double RANGE = (THR_MAX - THR_MIN); |
JonFreeman | 5:21a8ac83142c | 187 | if (p > 1.0) |
JonFreeman | 5:21a8ac83142c | 188 | p = 1.0; |
JonFreeman | 5:21a8ac83142c | 189 | if (p < 0.0) |
JonFreeman | 5:21a8ac83142c | 190 | p = 0.0; |
JonFreeman | 5:21a8ac83142c | 191 | // p = 1.0 - p; // if direction needs swapping |
JonFreeman | 5:21a8ac83142c | 192 | p *= RANGE; |
JonFreeman | 5:21a8ac83142c | 193 | p += THR_MIN; |
JonFreeman | 5:21a8ac83142c | 194 | servo1 = p; |
adustm | 0:99e26e18b424 | 195 | } |
adustm | 0:99e26e18b424 | 196 | |
JonFreeman | 5:21a8ac83142c | 197 | |
JonFreeman | 12:a25bdf135348 | 198 | void horn (int which, int onoff) { |
JonFreeman | 12:a25bdf135348 | 199 | if (which == HI_HORN) |
JonFreeman | 12:a25bdf135348 | 200 | I_sink5 = onoff; |
JonFreeman | 12:a25bdf135348 | 201 | else |
JonFreeman | 12:a25bdf135348 | 202 | I_sink4 = onoff; |
JonFreeman | 12:a25bdf135348 | 203 | } |
JonFreeman | 12:a25bdf135348 | 204 | |
JonFreeman | 12:a25bdf135348 | 205 | |
JonFreeman | 7:3b1f44cd4735 | 206 | void lights (int onoff) { |
JonFreeman | 7:3b1f44cd4735 | 207 | I_sink2 = onoff; // lamp right |
JonFreeman | 7:3b1f44cd4735 | 208 | I_sink3 = onoff; // lamp left |
JonFreeman | 7:3b1f44cd4735 | 209 | } |
JonFreeman | 4:67478861c670 | 210 | |
JonFreeman | 12:a25bdf135348 | 211 | |
JonFreeman | 12:a25bdf135348 | 212 | void draw_normal_run_screen () { |
JonFreeman | 12:a25bdf135348 | 213 | lcd.Clear(LCD_COLOR_LIGHTGRAY); |
JonFreeman | 12:a25bdf135348 | 214 | setup_buttons(); // draws buttons |
JonFreeman | 12:a25bdf135348 | 215 | slider.DrawSlider (); |
JonFreeman | 12:a25bdf135348 | 216 | // Draw 3 analogue meter movements, speedo, voltmeter, ammeter |
JonFreeman | 12:a25bdf135348 | 217 | Speedo.redraw(); |
JonFreeman | 12:a25bdf135348 | 218 | Voltmeter.redraw(); |
JonFreeman | 12:a25bdf135348 | 219 | Powermeter.redraw(); |
JonFreeman | 12:a25bdf135348 | 220 | } |
JonFreeman | 12:a25bdf135348 | 221 | |
JonFreeman | 12:a25bdf135348 | 222 | |
JonFreeman | 12:a25bdf135348 | 223 | int main() // Programme entry point |
JonFreeman | 4:67478861c670 | 224 | { |
JonFreeman | 12:a25bdf135348 | 225 | int qtr_sec = 0, seconds = 0, minutes = 0; |
JonFreeman | 12:a25bdf135348 | 226 | double electrical_power_Watt = 0.0, volts = 0.0; |
JonFreeman | 12:a25bdf135348 | 227 | |
JonFreeman | 7:3b1f44cd4735 | 228 | pc.baud (9600); |
JonFreeman | 12:a25bdf135348 | 229 | com2escs.baud (19200); |
JonFreeman | 7:3b1f44cd4735 | 230 | |
JonFreeman | 7:3b1f44cd4735 | 231 | I_sink1 = 0; // turn outputs off |
JonFreeman | 7:3b1f44cd4735 | 232 | I_sink2 = 0; // lamp right |
JonFreeman | 7:3b1f44cd4735 | 233 | I_sink3 = 0; // lamp left |
JonFreeman | 12:a25bdf135348 | 234 | I_sink4 = 0; // low horn |
JonFreeman | 12:a25bdf135348 | 235 | I_sink5 = 0; // high horn |
JonFreeman | 7:3b1f44cd4735 | 236 | spareio_d10.mode(PullUp); |
JonFreeman | 7:3b1f44cd4735 | 237 | |
JonFreeman | 12:a25bdf135348 | 238 | Ticker tick250us; // Master 4kHz interrupt timebase |
JonFreeman | 7:3b1f44cd4735 | 239 | |
JonFreeman | 7:3b1f44cd4735 | 240 | // Setup User Interrupt Vectors |
JonFreeman | 12:a25bdf135348 | 241 | tick250us.attach_us (&ISR_current_reader, 250); // count 125 interrupts to trig 31.25ms |
JonFreeman | 4:67478861c670 | 242 | |
JonFreeman | 12:a25bdf135348 | 243 | // QSPI memory is now in constant use for odometer |
JonFreeman | 12:a25bdf135348 | 244 | if (!test_qspi()) |
JonFreeman | 12:a25bdf135348 | 245 | Controller_Error.set (FAULT_QSPI, -1); // pc.printf ("Problem with qspimemcheck\r\n"); |
JonFreeman | 4:67478861c670 | 246 | |
JonFreeman | 12:a25bdf135348 | 247 | slider.direction = f_r_switch ? REV : FWD; // Only place in the code where direction gets set. Centre-Off power switch REV-OFF-FWD. |
JonFreeman | 4:67478861c670 | 248 | |
JonFreeman | 12:a25bdf135348 | 249 | My_STM3_ESC_boards.set_I_limit (0.0); |
JonFreeman | 12:a25bdf135348 | 250 | My_STM3_ESC_boards.set_V_limit (0.0); |
JonFreeman | 12:a25bdf135348 | 251 | My_STM3_ESC_boards.message ("rb\r"); |
JonFreeman | 12:a25bdf135348 | 252 | throttle (0.0); // Set revs to idle. Start engine and warm up before powering up control |
JonFreeman | 12:a25bdf135348 | 253 | pc.printf ("\r\n\n\nJon's Loco_TS_2018 Loco Controller ver %s starting, direction %s\r\n", const_version_string, slider.direction ? "Forward":"Reverse"); |
JonFreeman | 4:67478861c670 | 254 | |
JonFreeman | 4:67478861c670 | 255 | uint8_t lcd_status = touch_screen.Init(lcd.GetXSize(), lcd.GetYSize()); |
JonFreeman | 4:67478861c670 | 256 | if (lcd_status != TS_OK) { |
JonFreeman | 12:a25bdf135348 | 257 | Controller_Error.set (FAULT_TS, -1); |
JonFreeman | 12:a25bdf135348 | 258 | } |
JonFreeman | 12:a25bdf135348 | 259 | lcd.Clear(LCD_COLOR_DARKBLUE); |
JonFreeman | 12:a25bdf135348 | 260 | lcd.SetBackColor(LCD_COLOR_GREEN); |
JonFreeman | 12:a25bdf135348 | 261 | lcd.SetTextColor(LCD_COLOR_WHITE); |
JonFreeman | 12:a25bdf135348 | 262 | lcd.DisplayStringAt(0, LINE(5), (uint8_t *)"TOUCHSCREEN INIT OK", CENTER_MODE); |
JonFreeman | 4:67478861c670 | 263 | |
JonFreeman | 7:3b1f44cd4735 | 264 | // if (odometer_zero ()) |
JonFreeman | 7:3b1f44cd4735 | 265 | // pc.printf ("TRUE from odometer_zero\r\n"); |
JonFreeman | 7:3b1f44cd4735 | 266 | // else |
JonFreeman | 7:3b1f44cd4735 | 267 | // pc.printf ("FALSE from odometer_zero\r\n"); |
JonFreeman | 5:21a8ac83142c | 268 | |
JonFreeman | 7:3b1f44cd4735 | 269 | lights (1); // Headlights ON! |
JonFreeman | 7:3b1f44cd4735 | 270 | |
JonFreeman | 12:a25bdf135348 | 271 | My_STM3_ESC_boards.search_for_escs (); // Build list of connected STM3_ESC IDs |
JonFreeman | 4:67478861c670 | 272 | |
JonFreeman | 12:a25bdf135348 | 273 | /* Controller_Error.set (3, 99); |
JonFreeman | 12:a25bdf135348 | 274 | pc.printf ("%lx red\r\n", LCD_COLOR_RED); //LCD_COLOR is 0xffrrggbb |
JonFreeman | 12:a25bdf135348 | 275 | pc.printf ("%lx grn\r\n", LCD_COLOR_GREEN); |
JonFreeman | 12:a25bdf135348 | 276 | pc.printf ("%lx blu\r\n", LCD_COLOR_BLUE); |
JonFreeman | 12:a25bdf135348 | 277 | pc.printf ("%lx blk\r\n", LCD_COLOR_BLACK); |
JonFreeman | 12:a25bdf135348 | 278 | pc.printf ("%lx white\r\n", LCD_COLOR_WHITE); |
JonFreeman | 12:a25bdf135348 | 279 | */ |
JonFreeman | 12:a25bdf135348 | 280 | draw_normal_run_screen (); |
JonFreeman | 4:67478861c670 | 281 | |
JonFreeman | 12:a25bdf135348 | 282 | pc.printf ("Controller_Error.all_good() ret'd %s\r\n", Controller_Error.all_good() ? "true" : "false"); |
JonFreeman | 4:67478861c670 | 283 | |
JonFreeman | 12:a25bdf135348 | 284 | while (1) { // main prog loop |
JonFreeman | 4:67478861c670 | 285 | |
JonFreeman | 12:a25bdf135348 | 286 | pcli.sniff (); // Do any actions from command line serial port via usb link |
JonFreeman | 4:67478861c670 | 287 | |
JonFreeman | 12:a25bdf135348 | 288 | if (trigger_current_read) { // flag set in interrupt handler every 250us |
JonFreeman | 12:a25bdf135348 | 289 | trigger_current_read = false; |
JonFreeman | 12:a25bdf135348 | 290 | I_maf[maf_ptr] = ht_amps_ain.read_u16(); // Read raw ACS709 ammeter module |
JonFreeman | 12:a25bdf135348 | 291 | V_maf[maf_ptr] = ht_volts_ain.read_u16(); // Read raw system voltage |
JonFreeman | 12:a25bdf135348 | 292 | maf_ptr++; |
JonFreeman | 12:a25bdf135348 | 293 | if (maf_ptr > MAF_PTS - 1) |
JonFreeman | 12:a25bdf135348 | 294 | maf_ptr = 0; |
JonFreeman | 12:a25bdf135348 | 295 | } // endof stuff to do every 250us |
JonFreeman | 4:67478861c670 | 296 | |
JonFreeman | 12:a25bdf135348 | 297 | if (trigger_32ms == true) { // Stuff to do every 31.25 milli secs (32Hz) |
JonFreeman | 12:a25bdf135348 | 298 | trigger_32ms = false; |
JonFreeman | 12:a25bdf135348 | 299 | ploco.sniff (); // Only call within main loop, checks message responses from STM3_ESC boards |
JonFreeman | 12:a25bdf135348 | 300 | Ammeter.update (); // This updates Ammeter 'latest' and 'filtered' variables every 31.25ms |
JonFreeman | 12:a25bdf135348 | 301 | slider.HandleFingerInput (); // Do everything concerning fingers on touch screen |
JonFreeman | 12:a25bdf135348 | 302 | } // endof doing 32Hz stuff |
JonFreeman | 4:67478861c670 | 303 | |
JonFreeman | 4:67478861c670 | 304 | if (qtrsec_trig == true) { // do every quarter second stuff here |
JonFreeman | 4:67478861c670 | 305 | qtrsec_trig = false; |
JonFreeman | 12:a25bdf135348 | 306 | volts = read_voltmeter(); // voltage and current readings updated @ 250us, these are averaged over 35ms or so |
JonFreeman | 12:a25bdf135348 | 307 | electrical_power_Watt = volts * Ammeter.filtered(); // visible throughout main |
JonFreeman | 12:a25bdf135348 | 308 | // Update meters |
JonFreeman | 12:a25bdf135348 | 309 | Powermeter.set_value(electrical_power_Watt); |
JonFreeman | 12:a25bdf135348 | 310 | Voltmeter.set_value (volts); |
JonFreeman | 12:a25bdf135348 | 311 | Speedo.set_value (My_STM3_ESC_boards.mph); |
JonFreeman | 12:a25bdf135348 | 312 | |
JonFreeman | 4:67478861c670 | 313 | led_grn = !led_grn; |
JonFreeman | 12:a25bdf135348 | 314 | /* |
JonFreeman | 12:a25bdf135348 | 315 | Handbrake more sensibly implemented on STM3_ESC boards ? |
JonFreeman | 12:a25bdf135348 | 316 | |
JonFreeman | 4:67478861c670 | 317 | if (slider.state == PARK) { |
JonFreeman | 12:a25bdf135348 | 318 | if (My_STM3_ESC_boards.mph > LOCO_HANDBRAKE_ESCAPE_SPEED / 4.0) { |
JonFreeman | 4:67478861c670 | 319 | slider.handbrake_effort *= 1.1; |
JonFreeman | 4:67478861c670 | 320 | if (slider.handbrake_effort > 0.55) slider.handbrake_effort = 0.55; |
JonFreeman | 4:67478861c670 | 321 | set_run_mode (PARK); |
JonFreeman | 4:67478861c670 | 322 | pc.printf ("Handbrake slipping, effort %.2f\r\n", slider.handbrake_effort); |
JonFreeman | 4:67478861c670 | 323 | } |
JonFreeman | 12:a25bdf135348 | 324 | if (My_STM3_ESC_boards.mph < 0.02) { |
JonFreeman | 4:67478861c670 | 325 | slider.handbrake_effort *= 0.9; |
JonFreeman | 4:67478861c670 | 326 | if (slider.handbrake_effort < 0.05) slider.handbrake_effort = 0.05; |
JonFreeman | 4:67478861c670 | 327 | set_run_mode (PARK); |
JonFreeman | 4:67478861c670 | 328 | pc.printf ("Handbrake not slipping, effort %.2f\r\n", slider.handbrake_effort); |
JonFreeman | 4:67478861c670 | 329 | } |
JonFreeman | 4:67478861c670 | 330 | } |
JonFreeman | 12:a25bdf135348 | 331 | */ |
JonFreeman | 12:a25bdf135348 | 332 | My_STM3_ESC_boards.request_mph (); // issues "'n'rpm\r", takes care of cycling through available boards in sequence |
JonFreeman | 7:3b1f44cd4735 | 333 | // switch (qtr_sec) { // Can do sequential stuff quarter second apart here |
JonFreeman | 7:3b1f44cd4735 | 334 | // } // End of switch qtr_sec |
JonFreeman | 4:67478861c670 | 335 | qtr_sec++; |
JonFreeman | 4:67478861c670 | 336 | // Can do stuff once per second here |
JonFreeman | 4:67478861c670 | 337 | if(qtr_sec > 3) { |
JonFreeman | 4:67478861c670 | 338 | qtr_sec = 0; |
JonFreeman | 4:67478861c670 | 339 | seconds++; |
JonFreeman | 4:67478861c670 | 340 | if (seconds > 59) { |
JonFreeman | 4:67478861c670 | 341 | seconds = 0; |
JonFreeman | 4:67478861c670 | 342 | minutes++; |
JonFreeman | 4:67478861c670 | 343 | // do once per minute stuff here |
JonFreeman | 12:a25bdf135348 | 344 | Controller_Error.report_any (); |
JonFreeman | 4:67478861c670 | 345 | } // fall back into once per second |
JonFreeman | 12:a25bdf135348 | 346 | if (seconds & 1) |
JonFreeman | 12:a25bdf135348 | 347 | Speedo.LED (0, LCD_COLOR_DARKGRAY); |
JonFreeman | 12:a25bdf135348 | 348 | else |
JonFreeman | 12:a25bdf135348 | 349 | Speedo.LED (0, LCD_COLOR_RED); |
JonFreeman | 12:a25bdf135348 | 350 | My_STM3_ESC_boards.message ("kd\r"); // Kick the WatchDog timers in the Twin BLDC drive boards |
JonFreeman | 12:a25bdf135348 | 351 | recent_distance += (My_STM3_ESC_boards.mph * (111.76 * 4.0)); // Convert mph to distance mm travelled in one second |
JonFreeman | 12:a25bdf135348 | 352 | uint32_t new_metres = ((uint32_t)recent_distance) / 1000; |
JonFreeman | 12:a25bdf135348 | 353 | recent_distance -= (double)(new_metres * 1000); |
JonFreeman | 12:a25bdf135348 | 354 | if (!odometer_update (new_metres, (uint16_t)electrical_power_Watt, (uint16_t)(volts * 500.0))) { |
JonFreeman | 12:a25bdf135348 | 355 | pc.printf ("Probs with odometer_update"); |
JonFreeman | 12:a25bdf135348 | 356 | Controller_Error.set (FAULT_ODOMETER, 1); |
JonFreeman | 12:a25bdf135348 | 357 | } |
JonFreeman | 12:a25bdf135348 | 358 | rewrite_odometer () ; // Update text on speedo dial face |
JonFreeman | 4:67478861c670 | 359 | } // endof if(qtr_sec > 3 |
JonFreeman | 4:67478861c670 | 360 | } // endof if (qtrsec_trig == true) { |
JonFreeman | 4:67478861c670 | 361 | } // endof while(1) main programme loop |
JonFreeman | 12:a25bdf135348 | 362 | } // endof main () |
JonFreeman | 4:67478861c670 | 363 |