Electric Locomotive control system. Touch screen driver control, includes regenerative braking, drives 4 brushless motors, displays speed MPH, system volts and power

Dependencies:   BSP_DISCO_F746NG FastPWM LCD_DISCO_F746NG SD_DISCO_F746NG TS_DISCO_F746NG mbed

Committer:
JonFreeman
Date:
Sun Nov 12 06:26:29 2017 +0000
Revision:
0:23cc72b18e74
Child:
1:8ef34deb5177
Electric loco controller up to Nov 2017 includes SD odometer

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 0:23cc72b18e74 1 // Electric Locomotive Controller
JonFreeman 0:23cc72b18e74 2 // Jon Freeman B. Eng Hons
JonFreeman 0:23cc72b18e74 3
JonFreeman 0:23cc72b18e74 4 // Last Updated 12 April 2017
JonFreeman 0:23cc72b18e74 5 // Touch Screen Loco 2017 - WITH SD card data logger functions
JonFreeman 0:23cc72b18e74 6
JonFreeman 0:23cc72b18e74 7 // This code runs on STM 32F746NG DISCO module, high performance ARM Cortex with touch screen
JonFreeman 0:23cc72b18e74 8 // ffi on ST module -> https://developer.mbed.org/platforms/ST-Discovery-F746NG/
JonFreeman 0:23cc72b18e74 9 // Board plugs onto simple mother-board containing low voltage power supplies, interfacing buffers, connectors etc.
JonFreeman 0:23cc72b18e74 10 // See www.jons-workshop.com ffi on hardware.
JonFreeman 0:23cc72b18e74 11
JonFreeman 0:23cc72b18e74 12 // Design provides PWM outputs to drive up to four brushless motor drive modules, each able to return speed information.
JonFreeman 0:23cc72b18e74 13 // Output signals are dual PWM, one to set max motor voltage, other to set max motor current.
JonFreeman 0:23cc72b18e74 14 // This code as supplied uses current control to drive locomotive. This means that drive fader acts as a Torque, not Speed, Demand control.
JonFreeman 0:23cc72b18e74 15 // Regenerative braking is included in the design.
JonFreeman 0:23cc72b18e74 16 // NOTE that when braking, the motor supply rail voltage will be lifted. Failure to design-in some type of 'surplus power dump'
JonFreeman 0:23cc72b18e74 17 // may result in over-voltage damage to batteries or power electronics.
JonFreeman 0:23cc72b18e74 18
JonFreeman 0:23cc72b18e74 19
JonFreeman 0:23cc72b18e74 20 #include "mbed.h"
JonFreeman 0:23cc72b18e74 21 #include "FastPWM.h"
JonFreeman 0:23cc72b18e74 22 #include "TS_DISCO_F746NG.h"
JonFreeman 0:23cc72b18e74 23 #include "LCD_DISCO_F746NG.h"
JonFreeman 0:23cc72b18e74 24 #include "SD_DISCO_F746NG.h"
JonFreeman 0:23cc72b18e74 25 #include "dro.h"
JonFreeman 0:23cc72b18e74 26
JonFreeman 0:23cc72b18e74 27
JonFreeman 0:23cc72b18e74 28
JonFreeman 0:23cc72b18e74 29 // Design Topology
JonFreeman 0:23cc72b18e74 30 // This F746NG is the single loco control computer.
JonFreeman 0:23cc72b18e74 31 // Assumed 4 motor controllers driven from same signal set via multiple opto / buffers
JonFreeman 0:23cc72b18e74 32 // Outputs are : -
JonFreeman 0:23cc72b18e74 33 // FastPWM maxv on D12 - in drive, sets motor volts to pwm proportion of available volts. Also used in regen braking
JonFreeman 0:23cc72b18e74 34 // FastPWM maxi on D11 - used to set upper bound on motor current, used as analogue out to set current limit on motor driver
JonFreeman 0:23cc72b18e74 35 // DigitalOut reverse (D7) - D6,7 select fwd, rev, brake, parking brake
JonFreeman 0:23cc72b18e74 36 // DigitalOut forward (D6)
JonFreeman 0:23cc72b18e74 37 // Inputs are : -
JonFreeman 0:23cc72b18e74 38 // AnalogIn ht_amps_ain (A0); // Jan 2017
JonFreeman 0:23cc72b18e74 39 // AnalogIn ht_volts_ain (A1); // Jan 2017
JonFreeman 0:23cc72b18e74 40 // InterruptIn mot4hall (D2);
JonFreeman 0:23cc72b18e74 41 // InterruptIn mot3hall (D3);
JonFreeman 0:23cc72b18e74 42 // InterruptIn mot2hall (D4);
JonFreeman 0:23cc72b18e74 43 // InterruptIn mot1hall (D5);
JonFreeman 0:23cc72b18e74 44
JonFreeman 0:23cc72b18e74 45 /* Feb 2017, re-thought use of FR and SG signals. Rename these FWD and REV. Truth table for actions required now : -
JonFreeman 0:23cc72b18e74 46 FWD(A5) REV(A4) PWM Action
JonFreeman 0:23cc72b18e74 47 0 0 0 'Handbrake' - energises motor to not move
JonFreeman 0:23cc72b18e74 48 0 0 1 'Handbrake' - energises motor to not move
JonFreeman 0:23cc72b18e74 49 0 1 0 Reverse0
JonFreeman 0:23cc72b18e74 50 0 1 1 Reverse1
JonFreeman 0:23cc72b18e74 51
JonFreeman 0:23cc72b18e74 52 1 0 0 Forward0
JonFreeman 0:23cc72b18e74 53 1 0 1 Forward1
JonFreeman 0:23cc72b18e74 54 1 1 0 Regen Braking
JonFreeman 0:23cc72b18e74 55 1 1 1 Regen Braking
JonFreeman 0:23cc72b18e74 56 */
JonFreeman 0:23cc72b18e74 57
JonFreeman 0:23cc72b18e74 58 LCD_DISCO_F746NG lcd;
JonFreeman 0:23cc72b18e74 59 TS_DISCO_F746NG touch_screen;
JonFreeman 0:23cc72b18e74 60 SD_DISCO_F746NG sd;
JonFreeman 0:23cc72b18e74 61
JonFreeman 0:23cc72b18e74 62 FastPWM maxv (D12, 1),
JonFreeman 0:23cc72b18e74 63 maxi (D11, 1); // pin, prescaler value
JonFreeman 0:23cc72b18e74 64 Serial pc (USBTX, USBRX); // Comms to 'PuTTY' or similar comms programme on pc
JonFreeman 0:23cc72b18e74 65
JonFreeman 0:23cc72b18e74 66 DigitalOut reverse_pin (D7); //
JonFreeman 0:23cc72b18e74 67 DigitalOut forward_pin (D6); //these two decode to fwd, rev, regen_braking and park
JonFreeman 0:23cc72b18e74 68 DigitalOut GfetT2 (D14); // a horn
JonFreeman 0:23cc72b18e74 69 DigitalOut GfetT1 (D15); // another horn
JonFreeman 0:23cc72b18e74 70 DigitalOut led_grn (LED1); // the only on board user led
JonFreeman 0:23cc72b18e74 71
JonFreeman 0:23cc72b18e74 72 DigitalIn f_r_switch (D0); // Reads position of centre-off ignition switch
JonFreeman 0:23cc72b18e74 73 DigitalIn spareio_d8 (D8);
JonFreeman 0:23cc72b18e74 74 DigitalIn spareio_d9 (D9);
JonFreeman 0:23cc72b18e74 75 DigitalIn spareio_d10 (D10); // D8, D9, D10 wired to jumper on pcb - not used to Apr 2017
JonFreeman 0:23cc72b18e74 76
JonFreeman 0:23cc72b18e74 77 AnalogIn ht_volts_ain (A0); // Jan 2017
JonFreeman 0:23cc72b18e74 78 AnalogIn ht_amps_ain (A1); // Jan 2017
JonFreeman 0:23cc72b18e74 79 AnalogIn spare_ain2 (A2);
JonFreeman 0:23cc72b18e74 80 AnalogIn spare_ain3 (A3);
JonFreeman 0:23cc72b18e74 81 AnalogIn spare_ain4 (A4); // hardware on pcb for these 3 spare analogue inputs - not used to Apr 2017
JonFreeman 0:23cc72b18e74 82 //AnalogIn spare_ain5 (A5); // causes display flicker !
JonFreeman 0:23cc72b18e74 83
JonFreeman 0:23cc72b18e74 84 InterruptIn mot4hall (D2); // One Hall sensor signal from each motor fed back to measure speed
JonFreeman 0:23cc72b18e74 85 InterruptIn mot3hall (D3);
JonFreeman 0:23cc72b18e74 86 InterruptIn mot2hall (D4);
JonFreeman 0:23cc72b18e74 87 InterruptIn mot1hall (D5);
JonFreeman 0:23cc72b18e74 88
JonFreeman 0:23cc72b18e74 89 extern int get_button_press (struct point & pt) ;
JonFreeman 0:23cc72b18e74 90 extern void displaytext (int x, int y, const int font, uint32_t BCol, uint32_t TCol, char * txt) ;
JonFreeman 0:23cc72b18e74 91 extern void displaytext (int x, int y, const int font, char * txt) ;
JonFreeman 0:23cc72b18e74 92 extern void displaytext (int x, int y, char * txt) ;
JonFreeman 0:23cc72b18e74 93 extern void setup_buttons () ;
JonFreeman 0:23cc72b18e74 94 extern void draw_numeric_keypad (int colour) ;
JonFreeman 0:23cc72b18e74 95 extern void draw_button_hilight (int bu, int colour) ;
JonFreeman 0:23cc72b18e74 96 extern void read_presses (int * a) ;
JonFreeman 0:23cc72b18e74 97 extern void read_keypresses (struct ky_bd & a) ;
JonFreeman 0:23cc72b18e74 98 extern void SliderGraphic (struct slide & q) ;
JonFreeman 0:23cc72b18e74 99 extern void vm_set () ;
JonFreeman 0:23cc72b18e74 100 extern void update_meters (double, double, double) ;
JonFreeman 0:23cc72b18e74 101 extern void command_line_interpreter () ;
JonFreeman 0:23cc72b18e74 102
JonFreeman 0:23cc72b18e74 103 static const int NUMBER_OF_MOTORS = 4,
JonFreeman 0:23cc72b18e74 104 SD_BLOCKSIZE = 512, /* SD card data Block Size in Bytes */
JonFreeman 0:23cc72b18e74 105 DAMPER_DECAY = 42, // Small num -> fast 'viscous damper' on dead-mans function with finger removed from panel
JonFreeman 0:23cc72b18e74 106 MAF_PTS = 140, // Moving Average Filter points
JonFreeman 0:23cc72b18e74 107 PWM_HZ = 13000,
JonFreeman 0:23cc72b18e74 108 // PWM_HZ = 2000, // Used this to experiment on much bigger motor
JonFreeman 0:23cc72b18e74 109 MAX_PWM_TICKS = 108000000 / PWM_HZ, // 108000000 for F746N, due to cpu clock = 216 MHz
JonFreeman 0:23cc72b18e74 110 FWD = 0,
JonFreeman 0:23cc72b18e74 111 REV = ~FWD;
JonFreeman 0:23cc72b18e74 112
JonFreeman 0:23cc72b18e74 113 static const double
JonFreeman 0:23cc72b18e74 114 MOTOR_PINION_T = 17.0, // motor pinion teeth, wheel gear teeth and wheel dia required to calculate speed and distance.
JonFreeman 0:23cc72b18e74 115 WHEEL_GEAR_T = 76.0,
JonFreeman 0:23cc72b18e74 116 WHEEL_DIA_MM = 147.0,
JonFreeman 0:23cc72b18e74 117 WHEEL_CIRCUMFERENCE_METRE = PI * WHEEL_DIA_MM / 1000.0,
JonFreeman 0:23cc72b18e74 118 PULSES_PER_WHEEL_REV = 32.0 * WHEEL_GEAR_T / MOTOR_PINION_T,
JonFreeman 0:23cc72b18e74 119 PULSES_PER_METRE = PULSES_PER_WHEEL_REV / WHEEL_CIRCUMFERENCE_METRE,
JonFreeman 0:23cc72b18e74 120 rpm2mph = 60.0 // = Motor Revs per hour;
JonFreeman 0:23cc72b18e74 121 * (MOTOR_PINION_T / WHEEL_GEAR_T) // = Wheel rev per hour
JonFreeman 0:23cc72b18e74 122 * WHEEL_CIRCUMFERENCE_METRE // = metres per hour
JonFreeman 0:23cc72b18e74 123 * 39.37 // = inches per hour
JonFreeman 0:23cc72b18e74 124 / (1760 * 36) // = miles per hour
JonFreeman 0:23cc72b18e74 125 ;
JonFreeman 0:23cc72b18e74 126
JonFreeman 0:23cc72b18e74 127 // Assume SD card size is 4Gbyte, might be 8 Gbyte
JonFreeman 0:23cc72b18e74 128 // Then can use 8388608 blocks (8 * 1024 * 1024)
JonFreeman 0:23cc72b18e74 129
JonFreeman 0:23cc72b18e74 130 uint64_t SD_blockptr = 0;
JonFreeman 0:23cc72b18e74 131 uint32_t SDBuffer[(SD_BLOCKSIZE >> 2)]; // = space for (512 / 4) uint32_t
JonFreeman 0:23cc72b18e74 132 uint8_t SD_state = SD_OK, sd_jf = 0;
JonFreeman 0:23cc72b18e74 133
JonFreeman 0:23cc72b18e74 134 static const uint64_t GIGAB = 1024 * 1024 * 1024;
JonFreeman 0:23cc72b18e74 135 //static const uint64_t SDBLOCKS = (GIGAB / SD_BLOCKSIZE) * 4; // software drives SD up to 4Gbyte only - 8 M block
JonFreeman 0:23cc72b18e74 136 static const uint64_t SDBLOCKS = (GIGAB / SD_BLOCKSIZE) * 2; // software drives SD up to 4Gbyte only - 8 M block
JonFreeman 0:23cc72b18e74 137 // If data logger takes 2 minutes to fill 1 block, a 4G card takes 32 years run-time to fill
JonFreeman 0:23cc72b18e74 138 // If system generates approx 320 pulses per metre travelled, max distance recordable in uint32_t is 65536 * 65536 / 320 = 13421.772 km
JonFreeman 0:23cc72b18e74 139
JonFreeman 0:23cc72b18e74 140 //from dro.h struct slide { int position; int oldpos; int state; int direction; bool recalc_run; bool handbrake_slipping; double handbrake_effort; double loco_speed } ;
JonFreeman 0:23cc72b18e74 141 struct slide slider ;
JonFreeman 0:23cc72b18e74 142
JonFreeman 0:23cc72b18e74 143
JonFreeman 0:23cc72b18e74 144
JonFreeman 0:23cc72b18e74 145 //static const double mph_2_mm_per_sec = 447.04; // exact
JonFreeman 0:23cc72b18e74 146
JonFreeman 0:23cc72b18e74 147 int V_maf[MAF_PTS + 2], I_maf[MAF_PTS + 2], maf_ptr = 0;
JonFreeman 0:23cc72b18e74 148 //uint32_t Hall_pulse[8] = {0,0,0,0,0,0,0,0}; // more than max number of motors
JonFreeman 0:23cc72b18e74 149 uint32_t Hall_pulse[8] = {1,1,1,1,1,1,1,1}; // more than max number of motors
JonFreeman 0:23cc72b18e74 150 uint32_t historic_distance = 0;
JonFreeman 0:23cc72b18e74 151
JonFreeman 0:23cc72b18e74 152 bool qtrsec_trig = false;
JonFreeman 0:23cc72b18e74 153 bool trigger_current_read = false;
JonFreeman 0:23cc72b18e74 154 volatile bool trigger_32ms = false;
JonFreeman 0:23cc72b18e74 155
JonFreeman 0:23cc72b18e74 156 double last_pwm = 0.0;
JonFreeman 0:23cc72b18e74 157
JonFreeman 0:23cc72b18e74 158 bool sd_error () { // Test and Clear error code sd_jf, return true if any error bits set, false on 0
JonFreeman 0:23cc72b18e74 159 bool retval = false;
JonFreeman 0:23cc72b18e74 160 if (sd_jf != 0) {
JonFreeman 0:23cc72b18e74 161 retval = true;
JonFreeman 0:23cc72b18e74 162 sd_jf = 0;
JonFreeman 0:23cc72b18e74 163 }
JonFreeman 0:23cc72b18e74 164 return retval;
JonFreeman 0:23cc72b18e74 165 }
JonFreeman 0:23cc72b18e74 166
JonFreeman 0:23cc72b18e74 167 bool check_SD_block_clear (uint32_t block) {
JonFreeman 0:23cc72b18e74 168 uint32_t b[(SD_BLOCKSIZE >> 2)];
JonFreeman 0:23cc72b18e74 169 SD_state = sd.ReadBlocks(b, (uint64_t)(SD_BLOCKSIZE * block), SD_BLOCKSIZE, 1);
JonFreeman 0:23cc72b18e74 170 if(SD_state != SD_OK) {
JonFreeman 0:23cc72b18e74 171 sd_jf = 1;
JonFreeman 0:23cc72b18e74 172 pc.printf ("Failed, not SD_OK, erasing block %d\r\n", block);
JonFreeman 0:23cc72b18e74 173 return false;
JonFreeman 0:23cc72b18e74 174 }
JonFreeman 0:23cc72b18e74 175 for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++)
JonFreeman 0:23cc72b18e74 176 if (b[i] != 0)
JonFreeman 0:23cc72b18e74 177 return false;
JonFreeman 0:23cc72b18e74 178 return true;
JonFreeman 0:23cc72b18e74 179 }
JonFreeman 0:23cc72b18e74 180
JonFreeman 0:23cc72b18e74 181 /*bool erase_block (uint32_t block2erase) {
JonFreeman 0:23cc72b18e74 182 uint64_t addr = SD_BLOCKSIZE * (uint64_t)block2erase;
JonFreeman 0:23cc72b18e74 183 SD_state = sd.Erase(addr, addr + SD_BLOCKSIZE);
JonFreeman 0:23cc72b18e74 184 if (SD_state != SD_OK) {
JonFreeman 0:23cc72b18e74 185 sd_jf = 1; // Assert error flag
JonFreeman 0:23cc72b18e74 186 pc.printf ("Failed, not SD_OK, erasing block %d\r\n", block2erase);
JonFreeman 0:23cc72b18e74 187 return false;
JonFreeman 0:23cc72b18e74 188 }
JonFreeman 0:23cc72b18e74 189 return check_SD_block_clear (block2erase);
JonFreeman 0:23cc72b18e74 190 }*/
JonFreeman 0:23cc72b18e74 191
JonFreeman 0:23cc72b18e74 192 bool SD_find_next_clear_block (uint64_t * blok) { // Successive approximation algorithm to quickly find next vacant SD card 512 byte block
JonFreeman 0:23cc72b18e74 193 uint64_t toaddsub = SDBLOCKS / 2, stab = SDBLOCKS - 1;
JonFreeman 0:23cc72b18e74 194 pc.printf ("At SD_find_next_clear_block \r\n");
JonFreeman 0:23cc72b18e74 195 while (toaddsub) {
JonFreeman 0:23cc72b18e74 196 pc.printf ("stab = %lld, toadsub = %lld\r\n", stab, toaddsub); // lld for long long int
JonFreeman 0:23cc72b18e74 197 bool clear_block = true;
JonFreeman 0:23cc72b18e74 198 SD_state = sd.ReadBlocks(SDBuffer, SD_BLOCKSIZE * stab, SD_BLOCKSIZE, 1);
JonFreeman 0:23cc72b18e74 199 if(SD_state != SD_OK) {
JonFreeman 0:23cc72b18e74 200 sd_jf = 1;
JonFreeman 0:23cc72b18e74 201 pc.printf ("SD error in SD_find_next_clear_block, returning -1\r\n");
JonFreeman 0:23cc72b18e74 202 return false;
JonFreeman 0:23cc72b18e74 203 }
JonFreeman 0:23cc72b18e74 204 for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++) {
JonFreeman 0:23cc72b18e74 205 if (SDBuffer[i] != 0) {
JonFreeman 0:23cc72b18e74 206 clear_block = false;
JonFreeman 0:23cc72b18e74 207 pc.printf ("Buff at %d contains %x\r\n", i, SDBuffer[i]);
JonFreeman 0:23cc72b18e74 208 i = SD_BLOCKSIZE; // to exit loop
JonFreeman 0:23cc72b18e74 209 }
JonFreeman 0:23cc72b18e74 210 }
JonFreeman 0:23cc72b18e74 211 if (clear_block)
JonFreeman 0:23cc72b18e74 212 stab -= toaddsub;
JonFreeman 0:23cc72b18e74 213 else
JonFreeman 0:23cc72b18e74 214 stab += toaddsub;
JonFreeman 0:23cc72b18e74 215 toaddsub >>= 1;
JonFreeman 0:23cc72b18e74 216 }
JonFreeman 0:23cc72b18e74 217 if (!check_SD_block_clear(stab))
JonFreeman 0:23cc72b18e74 218 stab++;
JonFreeman 0:23cc72b18e74 219 if (sd_error()) { // sd_error() tests and clears error bits
JonFreeman 0:23cc72b18e74 220 pc.printf ("check_SD_block_clear(%ld)returned ERROR in SD_find_next_clear_block\r\n", stab);
JonFreeman 0:23cc72b18e74 221 sd_jf = 1; // reassert error flag
JonFreeman 0:23cc72b18e74 222 return false;
JonFreeman 0:23cc72b18e74 223 }
JonFreeman 0:23cc72b18e74 224 pc.printf ("Completed find_next, stab = %d\r\n", stab);
JonFreeman 0:23cc72b18e74 225 *blok = stab; // block number of next free block
JonFreeman 0:23cc72b18e74 226 return true;
JonFreeman 0:23cc72b18e74 227 }
JonFreeman 0:23cc72b18e74 228
JonFreeman 0:23cc72b18e74 229 bool SD_card_erase_all (void) { // assumes sd card is 4 Gbyte, erases 4 Gbyte. Called from CLI
JonFreeman 0:23cc72b18e74 230 uint64_t EndAddr = GIGAB * 4,
JonFreeman 0:23cc72b18e74 231 StartAddr = 0LL;
JonFreeman 0:23cc72b18e74 232 sd_jf = 0;
JonFreeman 0:23cc72b18e74 233 pc.printf ("Erasing SD card ... ");
JonFreeman 0:23cc72b18e74 234 // uint8_t Erase(uint64_t StartAddr, uint64_t EndAddr);
JonFreeman 0:23cc72b18e74 235 SD_state = sd.Erase(StartAddr, EndAddr);
JonFreeman 0:23cc72b18e74 236 if (SD_state != SD_OK) {
JonFreeman 0:23cc72b18e74 237 pc.printf ("SD_card_erase_all FAILED\r\n");
JonFreeman 0:23cc72b18e74 238 sd_jf = 1;
JonFreeman 0:23cc72b18e74 239 return false;
JonFreeman 0:23cc72b18e74 240 }
JonFreeman 0:23cc72b18e74 241 pc.printf ("no error detected\r\n");
JonFreeman 0:23cc72b18e74 242 return true;
JonFreeman 0:23cc72b18e74 243 }
JonFreeman 0:23cc72b18e74 244
JonFreeman 0:23cc72b18e74 245
JonFreeman 0:23cc72b18e74 246 bool mainSDtest()
JonFreeman 0:23cc72b18e74 247 {
JonFreeman 0:23cc72b18e74 248 SD_state = sd.Init();
JonFreeman 0:23cc72b18e74 249 if(SD_state != SD_OK) {
JonFreeman 0:23cc72b18e74 250 pc.printf ("sd.Init set SD_state to %0x\r\n", SD_state);
JonFreeman 0:23cc72b18e74 251 if(SD_state == MSD_ERROR_SD_NOT_PRESENT) {
JonFreeman 0:23cc72b18e74 252 pc.printf("SD shall be inserted before running test\r\n");
JonFreeman 0:23cc72b18e74 253 } else {
JonFreeman 0:23cc72b18e74 254 pc.printf("SD Initialization : FAIL.\r\n");
JonFreeman 0:23cc72b18e74 255 }
JonFreeman 0:23cc72b18e74 256 pc.printf("SD Test Aborted.\r\n");
JonFreeman 0:23cc72b18e74 257 return false;
JonFreeman 0:23cc72b18e74 258 }
JonFreeman 0:23cc72b18e74 259 // else { // SD_state is SD_OK
JonFreeman 0:23cc72b18e74 260 pc.printf("SD Initialization : OK.\r\n");
JonFreeman 0:23cc72b18e74 261
JonFreeman 0:23cc72b18e74 262
JonFreeman 0:23cc72b18e74 263
JonFreeman 0:23cc72b18e74 264 // SD_card_erase_all();
JonFreeman 0:23cc72b18e74 265 // if (sd_error())
JonFreeman 0:23cc72b18e74 266 // pc.printf ("SD_card_erase_all() reports ERROR");
JonFreeman 0:23cc72b18e74 267
JonFreeman 0:23cc72b18e74 268
JonFreeman 0:23cc72b18e74 269
JonFreeman 0:23cc72b18e74 270 SD_find_next_clear_block(& SD_blockptr);
JonFreeman 0:23cc72b18e74 271 pc.printf ("SD_find_next_clear_block returned %lld\r\n\n\n", SD_blockptr);
JonFreeman 0:23cc72b18e74 272 if (sd_error()) {
JonFreeman 0:23cc72b18e74 273 pc.printf ("***** ERROR returned from SD_find_next_clear_block ***** SD ops aborted\r\n");
JonFreeman 0:23cc72b18e74 274 return false;
JonFreeman 0:23cc72b18e74 275 }
JonFreeman 0:23cc72b18e74 276 pc.printf("SD_find_next_clear_block() returned %ld\r\n", SD_blockptr);
JonFreeman 0:23cc72b18e74 277 if (SD_blockptr < 1) {
JonFreeman 0:23cc72b18e74 278 pc.printf ("Looks like card newly erased, SD_blockptr value of %d\r\n", SD_blockptr);
JonFreeman 0:23cc72b18e74 279 SD_blockptr = 0;
JonFreeman 0:23cc72b18e74 280 historic_distance = 0;
JonFreeman 0:23cc72b18e74 281 }
JonFreeman 0:23cc72b18e74 282 else {
JonFreeman 0:23cc72b18e74 283 SD_state = sd.ReadBlocks(SDBuffer, SD_BLOCKSIZE * (SD_blockptr - 1), SD_BLOCKSIZE, 1);
JonFreeman 0:23cc72b18e74 284 if (SD_state != SD_OK) {
JonFreeman 0:23cc72b18e74 285 pc.printf ("Error reading last block from SD block %d\r\n", SD_blockptr - 1);
JonFreeman 0:23cc72b18e74 286 return false;
JonFreeman 0:23cc72b18e74 287 }
JonFreeman 0:23cc72b18e74 288 for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++)
JonFreeman 0:23cc72b18e74 289 pc.printf ("%lx\t", SDBuffer[i]);
JonFreeman 0:23cc72b18e74 290 historic_distance = SDBuffer[(SD_BLOCKSIZE >> 2) - 1];
JonFreeman 0:23cc72b18e74 291 pc.printf ("\r\nAbove, data read from last filled SD block %lld, using historic_distance = %lx\r\n", SD_blockptr - 1, historic_distance);
JonFreeman 0:23cc72b18e74 292 }
JonFreeman 0:23cc72b18e74 293 if (SD_blockptr > 2) {
JonFreeman 0:23cc72b18e74 294 for (int i = SD_blockptr - 2; i < SD_blockptr + 2; i++) {
JonFreeman 0:23cc72b18e74 295 pc.printf ("check_SD_block_clear (%d) ", i);
JonFreeman 0:23cc72b18e74 296 if (check_SD_block_clear(i))
JonFreeman 0:23cc72b18e74 297 pc.printf ("block %ld is CLEAR\r\n", i);
JonFreeman 0:23cc72b18e74 298 else
JonFreeman 0:23cc72b18e74 299 pc.printf ("block %ld is NOT clear\r\n", i);
JonFreeman 0:23cc72b18e74 300 if (sd_error()) {
JonFreeman 0:23cc72b18e74 301 pc.printf ("ERROR from check_SD_block_clear ()\r\n");
JonFreeman 0:23cc72b18e74 302 }
JonFreeman 0:23cc72b18e74 303 }
JonFreeman 0:23cc72b18e74 304 }
JonFreeman 0:23cc72b18e74 305 return true;
JonFreeman 0:23cc72b18e74 306 }
JonFreeman 0:23cc72b18e74 307
JonFreeman 0:23cc72b18e74 308
JonFreeman 0:23cc72b18e74 309
JonFreeman 0:23cc72b18e74 310
JonFreeman 0:23cc72b18e74 311
JonFreeman 0:23cc72b18e74 312
JonFreeman 0:23cc72b18e74 313
JonFreeman 0:23cc72b18e74 314
JonFreeman 0:23cc72b18e74 315 class speed_measurement // Interrupts at qtr sec cause read of Hall_pulse counters which are incremented by transitions of Hall inputs
JonFreeman 0:23cc72b18e74 316 {
JonFreeman 0:23cc72b18e74 317 static const int SPEED_AVE_PTS = 9; // AVE_PTS - points in moving average filters
JonFreeman 0:23cc72b18e74 318 int speed_maf_mem [(SPEED_AVE_PTS + 1) * 2][NUMBER_OF_MOTORS],
JonFreeman 0:23cc72b18e74 319 latest_counter_read[NUMBER_OF_MOTORS],
JonFreeman 0:23cc72b18e74 320 prev_counter_read[NUMBER_OF_MOTORS],
JonFreeman 0:23cc72b18e74 321 mafptr;
JonFreeman 0:23cc72b18e74 322 int raw_filtered () ; // sum of count for all motors
JonFreeman 0:23cc72b18e74 323
JonFreeman 0:23cc72b18e74 324 public:
JonFreeman 0:23cc72b18e74 325
JonFreeman 0:23cc72b18e74 326 speed_measurement () {
JonFreeman 0:23cc72b18e74 327 memset(speed_maf_mem, 0, sizeof(speed_maf_mem));
JonFreeman 0:23cc72b18e74 328 mafptr = 0;
JonFreeman 0:23cc72b18e74 329 memset (latest_counter_read, 0, sizeof(latest_counter_read));
JonFreeman 0:23cc72b18e74 330 memset (prev_counter_read, 0, sizeof(prev_counter_read));
JonFreeman 0:23cc72b18e74 331 } // constructor
JonFreeman 0:23cc72b18e74 332 int raw_filtered (int) ; // count for one motor
JonFreeman 0:23cc72b18e74 333 int RPM () ;
JonFreeman 0:23cc72b18e74 334 double MPH () ;
JonFreeman 0:23cc72b18e74 335 void qtr_sec_update () ;
JonFreeman 0:23cc72b18e74 336 uint32_t metres_travelled ();
JonFreeman 0:23cc72b18e74 337 uint32_t pulse_total ();
JonFreeman 0:23cc72b18e74 338 }
JonFreeman 0:23cc72b18e74 339 speed ;
JonFreeman 0:23cc72b18e74 340
JonFreeman 0:23cc72b18e74 341 int speed_measurement::raw_filtered () // sum of count for all motors
JonFreeman 0:23cc72b18e74 342 {
JonFreeman 0:23cc72b18e74 343 int result = 0, a, b;
JonFreeman 0:23cc72b18e74 344 for (b = 0; b < NUMBER_OF_MOTORS; b++) {
JonFreeman 0:23cc72b18e74 345 for (a = 0; a < SPEED_AVE_PTS; a++) {
JonFreeman 0:23cc72b18e74 346 result += speed_maf_mem[a][b];
JonFreeman 0:23cc72b18e74 347 }
JonFreeman 0:23cc72b18e74 348 }
JonFreeman 0:23cc72b18e74 349 return result;
JonFreeman 0:23cc72b18e74 350 }
JonFreeman 0:23cc72b18e74 351
JonFreeman 0:23cc72b18e74 352 int speed_measurement::raw_filtered (int motor) // count for one motor
JonFreeman 0:23cc72b18e74 353 {
JonFreeman 0:23cc72b18e74 354 int result = 0, a;
JonFreeman 0:23cc72b18e74 355 for (a = 0; a < SPEED_AVE_PTS; a++) {
JonFreeman 0:23cc72b18e74 356 result += speed_maf_mem[a][motor];
JonFreeman 0:23cc72b18e74 357 }
JonFreeman 0:23cc72b18e74 358 return result;
JonFreeman 0:23cc72b18e74 359 }
JonFreeman 0:23cc72b18e74 360
JonFreeman 0:23cc72b18e74 361 double speed_measurement::MPH ()
JonFreeman 0:23cc72b18e74 362 {
JonFreeman 0:23cc72b18e74 363 return rpm2mph * (double)RPM();
JonFreeman 0:23cc72b18e74 364 }
JonFreeman 0:23cc72b18e74 365
JonFreeman 0:23cc72b18e74 366 int speed_measurement::RPM ()
JonFreeman 0:23cc72b18e74 367 {
JonFreeman 0:23cc72b18e74 368 int rpm = raw_filtered ();
JonFreeman 0:23cc72b18e74 369 rpm *= 60 * 4; // 60 sec per min, 4 quarters per sec, result pulses per min
JonFreeman 0:23cc72b18e74 370 rpm /= (SPEED_AVE_PTS * NUMBER_OF_MOTORS * 8); // 8 transitions counted per rev
JonFreeman 0:23cc72b18e74 371 return rpm;
JonFreeman 0:23cc72b18e74 372 }
JonFreeman 0:23cc72b18e74 373
JonFreeman 0:23cc72b18e74 374 void speed_measurement::qtr_sec_update () // this to be called every quarter sec to read counters and update maf
JonFreeman 0:23cc72b18e74 375 {
JonFreeman 0:23cc72b18e74 376 mafptr++;
JonFreeman 0:23cc72b18e74 377 if (mafptr >= SPEED_AVE_PTS)
JonFreeman 0:23cc72b18e74 378 mafptr = 0;
JonFreeman 0:23cc72b18e74 379 for (int a = 0; a < NUMBER_OF_MOTORS; a++) {
JonFreeman 0:23cc72b18e74 380 prev_counter_read[a] = latest_counter_read[a];
JonFreeman 0:23cc72b18e74 381 latest_counter_read[a] = Hall_pulse[a];
JonFreeman 0:23cc72b18e74 382 speed_maf_mem[mafptr][a] = latest_counter_read[a] - prev_counter_read[a];
JonFreeman 0:23cc72b18e74 383 }
JonFreeman 0:23cc72b18e74 384 }
JonFreeman 0:23cc72b18e74 385
JonFreeman 0:23cc72b18e74 386 uint32_t speed_measurement::metres_travelled ()
JonFreeman 0:23cc72b18e74 387 {
JonFreeman 0:23cc72b18e74 388 return pulse_total() / (int)PULSES_PER_METRE;
JonFreeman 0:23cc72b18e74 389 }
JonFreeman 0:23cc72b18e74 390
JonFreeman 0:23cc72b18e74 391 uint32_t speed_measurement::pulse_total ()
JonFreeman 0:23cc72b18e74 392 {
JonFreeman 0:23cc72b18e74 393 return historic_distance + Hall_pulse[0] + Hall_pulse[1] + Hall_pulse[2] + Hall_pulse[3];
JonFreeman 0:23cc72b18e74 394 }
JonFreeman 0:23cc72b18e74 395
JonFreeman 0:23cc72b18e74 396 void set_V_limit (double p) // Sets max motor voltage
JonFreeman 0:23cc72b18e74 397 {
JonFreeman 0:23cc72b18e74 398 if (p < 0.0)
JonFreeman 0:23cc72b18e74 399 p = 0.0;
JonFreeman 0:23cc72b18e74 400 if (p > 1.0)
JonFreeman 0:23cc72b18e74 401 p = 1.0;
JonFreeman 0:23cc72b18e74 402 last_pwm = p;
JonFreeman 0:23cc72b18e74 403 p *= 0.95; // need limit, ffi see MCP1630 data
JonFreeman 0:23cc72b18e74 404 p = 1.0 - p; // because pwm is wrong way up
JonFreeman 0:23cc72b18e74 405 maxv.pulsewidth_ticks ((int)(p * MAX_PWM_TICKS)); // PWM output on pin D12 inverted motor pwm
JonFreeman 0:23cc72b18e74 406 }
JonFreeman 0:23cc72b18e74 407
JonFreeman 0:23cc72b18e74 408 void set_I_limit (double p) // Sets max motor current
JonFreeman 0:23cc72b18e74 409 {
JonFreeman 0:23cc72b18e74 410 int a;
JonFreeman 0:23cc72b18e74 411 if (p < 0.0)
JonFreeman 0:23cc72b18e74 412 p = 0.0;
JonFreeman 0:23cc72b18e74 413 if (p > 1.0)
JonFreeman 0:23cc72b18e74 414 p = 1.0;
JonFreeman 0:23cc72b18e74 415 a = (int)(p * MAX_PWM_TICKS);
JonFreeman 0:23cc72b18e74 416 if (a > MAX_PWM_TICKS)
JonFreeman 0:23cc72b18e74 417 a = MAX_PWM_TICKS;
JonFreeman 0:23cc72b18e74 418 if (a < 0)
JonFreeman 0:23cc72b18e74 419 a = 0;
JonFreeman 0:23cc72b18e74 420 maxi.pulsewidth_ticks (a); // PWM output on pin D12 inverted motor pwm
JonFreeman 0:23cc72b18e74 421 }
JonFreeman 0:23cc72b18e74 422
JonFreeman 0:23cc72b18e74 423 double read_ammeter ()
JonFreeman 0:23cc72b18e74 424 {
JonFreeman 0:23cc72b18e74 425 int a = 0;
JonFreeman 0:23cc72b18e74 426 for (int b = 0; b < MAF_PTS; b++)
JonFreeman 0:23cc72b18e74 427 a += I_maf[b];
JonFreeman 0:23cc72b18e74 428 a /= MAF_PTS;
JonFreeman 0:23cc72b18e74 429 double i = (double) a;
JonFreeman 0:23cc72b18e74 430 return (i * 95.0 / 32768.0) - 95.0 + 0.46; // fiddled to suit current module
JonFreeman 0:23cc72b18e74 431 }
JonFreeman 0:23cc72b18e74 432
JonFreeman 0:23cc72b18e74 433 double read_voltmeter ()
JonFreeman 0:23cc72b18e74 434 {
JonFreeman 0:23cc72b18e74 435 int a = 0;
JonFreeman 0:23cc72b18e74 436 for (int b = 0; b < MAF_PTS; b++)
JonFreeman 0:23cc72b18e74 437 a += V_maf[b];
JonFreeman 0:23cc72b18e74 438 a /= MAF_PTS;
JonFreeman 0:23cc72b18e74 439 double i = (double) a;
JonFreeman 0:23cc72b18e74 440 return (i / 617.75) + 0.3; // fiddled to suit current module
JonFreeman 0:23cc72b18e74 441 }
JonFreeman 0:23cc72b18e74 442
JonFreeman 0:23cc72b18e74 443 // Interrupt Service Routines
JonFreeman 0:23cc72b18e74 444
JonFreeman 0:23cc72b18e74 445 void ISR_mot1_hall_handler () // read motor position pulse signals from up to six motors
JonFreeman 0:23cc72b18e74 446 {
JonFreeman 0:23cc72b18e74 447 Hall_pulse[0]++;
JonFreeman 0:23cc72b18e74 448 }
JonFreeman 0:23cc72b18e74 449 void ISR_mot2_hall_handler ()
JonFreeman 0:23cc72b18e74 450 {
JonFreeman 0:23cc72b18e74 451 Hall_pulse[1]++;
JonFreeman 0:23cc72b18e74 452 }
JonFreeman 0:23cc72b18e74 453 void ISR_mot3_hall_handler ()
JonFreeman 0:23cc72b18e74 454 {
JonFreeman 0:23cc72b18e74 455 Hall_pulse[2]++;
JonFreeman 0:23cc72b18e74 456 }
JonFreeman 0:23cc72b18e74 457 void ISR_mot4_hall_handler ()
JonFreeman 0:23cc72b18e74 458 {
JonFreeman 0:23cc72b18e74 459 Hall_pulse[3]++;
JonFreeman 0:23cc72b18e74 460 }
JonFreeman 0:23cc72b18e74 461 /*void ISR_mot5_hall_handler ()
JonFreeman 0:23cc72b18e74 462 {
JonFreeman 0:23cc72b18e74 463 Hall_pulse[4]++;
JonFreeman 0:23cc72b18e74 464 }
JonFreeman 0:23cc72b18e74 465 void ISR_mot6_hall_handler ()
JonFreeman 0:23cc72b18e74 466 {
JonFreeman 0:23cc72b18e74 467 Hall_pulse[5]++;
JonFreeman 0:23cc72b18e74 468 }
JonFreeman 0:23cc72b18e74 469 */
JonFreeman 0:23cc72b18e74 470
JonFreeman 0:23cc72b18e74 471 void ISR_current_reader (void) // FIXED at 250us
JonFreeman 0:23cc72b18e74 472 {
JonFreeman 0:23cc72b18e74 473 trigger_current_read = true; // every 250us, i.e. 4kHz NOTE only sets trigger here, readings taken in main loop
JonFreeman 0:23cc72b18e74 474 }
JonFreeman 0:23cc72b18e74 475
JonFreeman 0:23cc72b18e74 476 void ISR_tick_32ms (void) //
JonFreeman 0:23cc72b18e74 477 {
JonFreeman 0:23cc72b18e74 478 trigger_32ms = true;
JonFreeman 0:23cc72b18e74 479 }
JonFreeman 0:23cc72b18e74 480 void ISR_tick_250ms (void)
JonFreeman 0:23cc72b18e74 481 {
JonFreeman 0:23cc72b18e74 482 qtrsec_trig = true;
JonFreeman 0:23cc72b18e74 483 }
JonFreeman 0:23cc72b18e74 484
JonFreeman 0:23cc72b18e74 485 // End of Interrupt Service Routines
JonFreeman 0:23cc72b18e74 486
JonFreeman 0:23cc72b18e74 487
JonFreeman 0:23cc72b18e74 488 bool inlist (struct ky_bd & a, int key)
JonFreeman 0:23cc72b18e74 489 {
JonFreeman 0:23cc72b18e74 490 int i = 0;
JonFreeman 0:23cc72b18e74 491 while (i < a.count) {
JonFreeman 0:23cc72b18e74 492 if (key == a.ky[i].keynum)
JonFreeman 0:23cc72b18e74 493 return true;
JonFreeman 0:23cc72b18e74 494 i++;
JonFreeman 0:23cc72b18e74 495 }
JonFreeman 0:23cc72b18e74 496 return false;
JonFreeman 0:23cc72b18e74 497 }
JonFreeman 0:23cc72b18e74 498
JonFreeman 0:23cc72b18e74 499
JonFreeman 0:23cc72b18e74 500 void stuff_to_do_every_250us () // Take readings of system voltage and current
JonFreeman 0:23cc72b18e74 501 {
JonFreeman 0:23cc72b18e74 502 if (!trigger_current_read)
JonFreeman 0:23cc72b18e74 503 return;
JonFreeman 0:23cc72b18e74 504 trigger_current_read = false;
JonFreeman 0:23cc72b18e74 505 I_maf[maf_ptr] = ht_amps_ain.read_u16();
JonFreeman 0:23cc72b18e74 506 V_maf[maf_ptr] = ht_volts_ain.read_u16();
JonFreeman 0:23cc72b18e74 507 maf_ptr++;
JonFreeman 0:23cc72b18e74 508 if (maf_ptr > MAF_PTS - 1)
JonFreeman 0:23cc72b18e74 509 maf_ptr = 0;
JonFreeman 0:23cc72b18e74 510 }
JonFreeman 0:23cc72b18e74 511 /* Feb 2017, re-thought use of FR and SG signals. Rename these FWD and REV. Truth table for actions required now : -
JonFreeman 0:23cc72b18e74 512 FWD(A5) REV(A4) PWM Action
JonFreeman 0:23cc72b18e74 513 0 0 0 'Handbrake' - energises motor to not move
JonFreeman 0:23cc72b18e74 514 0 0 1 'Handbrake' - energises motor to not move
JonFreeman 0:23cc72b18e74 515 0 1 0 Reverse0
JonFreeman 0:23cc72b18e74 516 0 1 1 Reverse1
JonFreeman 0:23cc72b18e74 517
JonFreeman 0:23cc72b18e74 518 1 0 0 Forward0
JonFreeman 0:23cc72b18e74 519 1 0 1 Forward1
JonFreeman 0:23cc72b18e74 520 1 1 0 Regen Braking
JonFreeman 0:23cc72b18e74 521 1 1 1 Regen Braking
JonFreeman 0:23cc72b18e74 522 */
JonFreeman 0:23cc72b18e74 523 void set_run_mode (int mode)
JonFreeman 0:23cc72b18e74 524 {
JonFreeman 0:23cc72b18e74 525 if (mode == HANDBRAKE_SLIPPING) slider.handbrake_slipping = true;
JonFreeman 0:23cc72b18e74 526 else slider.handbrake_slipping = false;
JonFreeman 0:23cc72b18e74 527 switch (mode) {
JonFreeman 0:23cc72b18e74 528 // STATES, INACTIVE, RUN, NEUTRAL_DRIFT, REGEN_BRAKE, PARK};
JonFreeman 0:23cc72b18e74 529 // case HANDBRAKE_SLIPPING:
JonFreeman 0:23cc72b18e74 530 // break;
JonFreeman 0:23cc72b18e74 531 case PARK: // PARKED new rom code IS now finished.
JonFreeman 0:23cc72b18e74 532 forward_pin = 0;
JonFreeman 0:23cc72b18e74 533 reverse_pin = 0;
JonFreeman 0:23cc72b18e74 534 slider.state = mode;
JonFreeman 0:23cc72b18e74 535 set_V_limit (0.075); // was 0.1
JonFreeman 0:23cc72b18e74 536 set_I_limit (slider.handbrake_effort);
JonFreeman 0:23cc72b18e74 537 break;
JonFreeman 0:23cc72b18e74 538 case REGEN_BRAKE: // BRAKING, pwm affects degree
JonFreeman 0:23cc72b18e74 539 forward_pin = 1;
JonFreeman 0:23cc72b18e74 540 reverse_pin = 1;
JonFreeman 0:23cc72b18e74 541 slider.state = mode;
JonFreeman 0:23cc72b18e74 542 break;
JonFreeman 0:23cc72b18e74 543 case NEUTRAL_DRIFT:
JonFreeman 0:23cc72b18e74 544 slider.state = mode;
JonFreeman 0:23cc72b18e74 545 set_I_limit (0.0); // added after first test runs, looking for cause of mechanical startup snatch
JonFreeman 0:23cc72b18e74 546 set_V_limit (0.0); // added after first test runs, looking for cause of mechanical startup snatch
JonFreeman 0:23cc72b18e74 547 break;
JonFreeman 0:23cc72b18e74 548 case RUN:
JonFreeman 0:23cc72b18e74 549 if (slider.direction) {
JonFreeman 0:23cc72b18e74 550 forward_pin = 0;
JonFreeman 0:23cc72b18e74 551 reverse_pin = 1;
JonFreeman 0:23cc72b18e74 552 } else {
JonFreeman 0:23cc72b18e74 553 forward_pin = 1;
JonFreeman 0:23cc72b18e74 554 reverse_pin = 0;
JonFreeman 0:23cc72b18e74 555 }
JonFreeman 0:23cc72b18e74 556 slider.state = mode;
JonFreeman 0:23cc72b18e74 557 break;
JonFreeman 0:23cc72b18e74 558 default:
JonFreeman 0:23cc72b18e74 559 break;
JonFreeman 0:23cc72b18e74 560 }
JonFreeman 0:23cc72b18e74 561 }
JonFreeman 0:23cc72b18e74 562
JonFreeman 0:23cc72b18e74 563 void update_SD_card () { // Hall pulse total updated once per sec and saved in blocks of 128 to SD card
JonFreeman 0:23cc72b18e74 564 static int index = 0;
JonFreeman 0:23cc72b18e74 565 static uint32_t buff[(SD_BLOCKSIZE >> 2) + 2];
JonFreeman 0:23cc72b18e74 566 buff[index++] = speed.pulse_total(); // pulse_total for all time, add this to buffer to write to SD
JonFreeman 0:23cc72b18e74 567 if (index >= (SD_BLOCKSIZE >> 2)) {
JonFreeman 0:23cc72b18e74 568 pc.printf ("Writing new SD block %d ... ", SD_blockptr);
JonFreeman 0:23cc72b18e74 569 SD_state = sd.WriteBlocks(buff, SD_BLOCKSIZE * SD_blockptr, SD_BLOCKSIZE, 1);
JonFreeman 0:23cc72b18e74 570 SD_blockptr++;
JonFreeman 0:23cc72b18e74 571 if (SD_state == SD_OK)
JonFreeman 0:23cc72b18e74 572 pc.printf ("OK, distance %d\r\n", buff[index - 1] / (int)PULSES_PER_METRE);
JonFreeman 0:23cc72b18e74 573 else
JonFreeman 0:23cc72b18e74 574 pc.printf ("ERROR\r\n");
JonFreeman 0:23cc72b18e74 575 index = 0;
JonFreeman 0:23cc72b18e74 576 }
JonFreeman 0:23cc72b18e74 577 }
JonFreeman 0:23cc72b18e74 578
JonFreeman 0:23cc72b18e74 579 int main()
JonFreeman 0:23cc72b18e74 580 {
JonFreeman 0:23cc72b18e74 581 int c_5 = 0, seconds = 0, minutes = 0;
JonFreeman 0:23cc72b18e74 582 ky_bd kybd_a, kybd_b;
JonFreeman 0:23cc72b18e74 583 memset (&kybd_a, 0, sizeof(kybd_a));
JonFreeman 0:23cc72b18e74 584 memset (&kybd_b, 0, sizeof(kybd_b));
JonFreeman 0:23cc72b18e74 585
JonFreeman 0:23cc72b18e74 586 spareio_d8.mode (PullUp);
JonFreeman 0:23cc72b18e74 587 spareio_d9.mode (PullUp);
JonFreeman 0:23cc72b18e74 588 spareio_d10.mode(PullUp);
JonFreeman 0:23cc72b18e74 589
JonFreeman 0:23cc72b18e74 590 Ticker tick250us;
JonFreeman 0:23cc72b18e74 591 Ticker tick32ms;
JonFreeman 0:23cc72b18e74 592 Ticker tick250ms;
JonFreeman 0:23cc72b18e74 593
JonFreeman 0:23cc72b18e74 594 // Setup User Interrupt Vectors
JonFreeman 0:23cc72b18e74 595 mot1hall.fall (&ISR_mot1_hall_handler);
JonFreeman 0:23cc72b18e74 596 mot1hall.rise (&ISR_mot1_hall_handler);
JonFreeman 0:23cc72b18e74 597 mot2hall.fall (&ISR_mot2_hall_handler);
JonFreeman 0:23cc72b18e74 598 mot2hall.rise (&ISR_mot2_hall_handler);
JonFreeman 0:23cc72b18e74 599 mot3hall.fall (&ISR_mot3_hall_handler);
JonFreeman 0:23cc72b18e74 600 mot3hall.rise (&ISR_mot3_hall_handler);
JonFreeman 0:23cc72b18e74 601 mot4hall.fall (&ISR_mot4_hall_handler);
JonFreeman 0:23cc72b18e74 602 mot4hall.rise (&ISR_mot4_hall_handler);
JonFreeman 0:23cc72b18e74 603
JonFreeman 0:23cc72b18e74 604 tick250us.attach_us (&ISR_current_reader, 250); // set to longer time to test
JonFreeman 0:23cc72b18e74 605 tick32ms.attach_us (&ISR_tick_32ms, 32001);
JonFreeman 0:23cc72b18e74 606 tick250ms.attach_us (&ISR_tick_250ms, 250002);
JonFreeman 0:23cc72b18e74 607 pc.baud (9600);
JonFreeman 0:23cc72b18e74 608 GfetT1 = 0;
JonFreeman 0:23cc72b18e74 609 GfetT2 = 0; // two output bits for future use driving horns
JonFreeman 0:23cc72b18e74 610 if (f_r_switch)
JonFreeman 0:23cc72b18e74 611 slider.direction = FWD; // make decision from key switch position here
JonFreeman 0:23cc72b18e74 612 else
JonFreeman 0:23cc72b18e74 613 slider.direction = REV; // make decision from key switch position here
JonFreeman 0:23cc72b18e74 614
JonFreeman 0:23cc72b18e74 615 // max_pwm_ticks = SystemCoreClock / (2 * PWM_HZ); // prescaler min value is 2, or so it would seem. SystemCoreClock returns 216000000 on F746NG board
JonFreeman 0:23cc72b18e74 616 maxv.period_ticks (MAX_PWM_TICKS + 1); // around 18 kHz
JonFreeman 0:23cc72b18e74 617 maxi.period_ticks (MAX_PWM_TICKS + 1);
JonFreeman 0:23cc72b18e74 618 set_I_limit (0.0);
JonFreeman 0:23cc72b18e74 619 set_V_limit (0.0);
JonFreeman 0:23cc72b18e74 620
JonFreeman 0:23cc72b18e74 621 pc.printf ("Jon's Touch Screen Loco 2017 sytem starting up %s\r\n", slider.direction ? "Forward":"Reverse");
JonFreeman 0:23cc72b18e74 622 uint8_t lcd_status = touch_screen.Init(lcd.GetXSize(), lcd.GetYSize());
JonFreeman 0:23cc72b18e74 623 if (lcd_status != TS_OK) {
JonFreeman 0:23cc72b18e74 624 lcd.Clear(LCD_COLOR_RED);
JonFreeman 0:23cc72b18e74 625 lcd.SetBackColor(LCD_COLOR_RED);
JonFreeman 0:23cc72b18e74 626 lcd.SetTextColor(LCD_COLOR_WHITE);
JonFreeman 0:23cc72b18e74 627 lcd.DisplayStringAt(0, LINE(5), (uint8_t *)"TOUCHSCREEN INIT FAIL", CENTER_MODE);
JonFreeman 0:23cc72b18e74 628 wait (20);
JonFreeman 0:23cc72b18e74 629 } else {
JonFreeman 0:23cc72b18e74 630 lcd.Clear(LCD_COLOR_DARKBLUE);
JonFreeman 0:23cc72b18e74 631 lcd.SetBackColor(LCD_COLOR_GREEN);
JonFreeman 0:23cc72b18e74 632 lcd.SetTextColor(LCD_COLOR_WHITE);
JonFreeman 0:23cc72b18e74 633 lcd.DisplayStringAt(0, LINE(5), (uint8_t *)"TOUCHSCREEN INIT OK", CENTER_MODE);
JonFreeman 0:23cc72b18e74 634 }
JonFreeman 0:23cc72b18e74 635
JonFreeman 0:23cc72b18e74 636 lcd.SetFont(&Font16);
JonFreeman 0:23cc72b18e74 637 lcd.Clear(LCD_COLOR_LIGHTGRAY);
JonFreeman 0:23cc72b18e74 638 setup_buttons(); // draws buttons
JonFreeman 0:23cc72b18e74 639
JonFreeman 0:23cc72b18e74 640 slider.oldpos = 0;
JonFreeman 0:23cc72b18e74 641 slider.loco_speed = 0.0;
JonFreeman 0:23cc72b18e74 642 slider.handbrake_effort = 0.1;
JonFreeman 0:23cc72b18e74 643 slider.position = MAX_POS - 2; // Low down in REGEN_BRAKE position - NOT to power-up in PARK
JonFreeman 0:23cc72b18e74 644 SliderGraphic (slider); // sets slider.state to value determined by slider.position
JonFreeman 0:23cc72b18e74 645 set_run_mode (REGEN_BRAKE); // sets slider.mode
JonFreeman 0:23cc72b18e74 646
JonFreeman 0:23cc72b18e74 647 lcd.SetBackColor(LCD_COLOR_DARKBLUE);
JonFreeman 0:23cc72b18e74 648
JonFreeman 0:23cc72b18e74 649 vm_set(); // Draw 3 analogue meter movements, speedo, voltmeter, ammeter
JonFreeman 0:23cc72b18e74 650
JonFreeman 0:23cc72b18e74 651 mainSDtest();
JonFreeman 0:23cc72b18e74 652
JonFreeman 0:23cc72b18e74 653 bool toggle32ms = false;
JonFreeman 0:23cc72b18e74 654 // Main loop
JonFreeman 0:23cc72b18e74 655 while(1) { //
JonFreeman 0:23cc72b18e74 656 struct ky_bd * present_kybd, * previous_kybd;
JonFreeman 0:23cc72b18e74 657 bool sliderpress = false;
JonFreeman 0:23cc72b18e74 658 command_line_interpreter () ; // Do any actions from command line via usb link
JonFreeman 0:23cc72b18e74 659 stuff_to_do_every_250us () ;
JonFreeman 0:23cc72b18e74 660
JonFreeman 0:23cc72b18e74 661 if (trigger_32ms == true) { // Stuff to do every 32 milli secs
JonFreeman 0:23cc72b18e74 662 trigger_32ms = false;
JonFreeman 0:23cc72b18e74 663 toggle32ms = !toggle32ms;
JonFreeman 0:23cc72b18e74 664 if (toggle32ms) {
JonFreeman 0:23cc72b18e74 665 present_kybd = &kybd_a;
JonFreeman 0:23cc72b18e74 666 previous_kybd = &kybd_b;
JonFreeman 0:23cc72b18e74 667 } else {
JonFreeman 0:23cc72b18e74 668 present_kybd = &kybd_b;
JonFreeman 0:23cc72b18e74 669 previous_kybd = &kybd_a;
JonFreeman 0:23cc72b18e74 670 }
JonFreeman 0:23cc72b18e74 671 read_keypresses (*present_kybd);
JonFreeman 0:23cc72b18e74 672 sliderpress = false;
JonFreeman 0:23cc72b18e74 673 slider.recalc_run = false;
JonFreeman 0:23cc72b18e74 674 int j = 0;
JonFreeman 0:23cc72b18e74 675 // if (present2->count > previous_kybd->count) pc.printf ("More presses\r\n");
JonFreeman 0:23cc72b18e74 676 // if (present2->count < previous_kybd->count) pc.printf ("Fewer presses\r\n");
JonFreeman 0:23cc72b18e74 677 if (present_kybd->count || previous_kybd->count) { // at least one key pressed this time or last time
JonFreeman 0:23cc72b18e74 678 int k;
JonFreeman 0:23cc72b18e74 679 double dbl;
JonFreeman 0:23cc72b18e74 680 // pc.printf ("Keys action may be required");
JonFreeman 0:23cc72b18e74 681 // if key in present and ! in previous, found new key press to handle
JonFreeman 0:23cc72b18e74 682 // if key ! in present and in previous, found new key release to handle
JonFreeman 0:23cc72b18e74 683 if (inlist(*present_kybd, SLIDER)) { // Finger is on slider, so Update slider graphic here
JonFreeman 0:23cc72b18e74 684 sliderpress = true;
JonFreeman 0:23cc72b18e74 685 k = present_kybd->slider_y; // get position of finger on slider
JonFreeman 0:23cc72b18e74 686 if (slider.state == RUN && k != slider.position) // Finger has moved within RUN range
JonFreeman 0:23cc72b18e74 687 slider.recalc_run = true;
JonFreeman 0:23cc72b18e74 688 if (slider.state == RUN && k >= NEUTRAL_VAL) // Finger has moved from RUN to BRAKE range
JonFreeman 0:23cc72b18e74 689 slider.position = k = NEUTRAL_VAL; // kill drive for rapid reaction to braking
JonFreeman 0:23cc72b18e74 690
JonFreeman 0:23cc72b18e74 691 else { // nice slow non-jerky glidey movement required
JonFreeman 0:23cc72b18e74 692 dbl = (double)(k - slider.position);
JonFreeman 0:23cc72b18e74 693 dbl /= 13.179;
JonFreeman 0:23cc72b18e74 694 if (dbl < 0.0)
JonFreeman 0:23cc72b18e74 695 dbl -= 1.0;
JonFreeman 0:23cc72b18e74 696 if (dbl > 0.0)
JonFreeman 0:23cc72b18e74 697 dbl += 1.0;
JonFreeman 0:23cc72b18e74 698 slider.position += (int)dbl;
JonFreeman 0:23cc72b18e74 699 }
JonFreeman 0:23cc72b18e74 700 SliderGraphic (slider); // sets slider.state to value determined by slider.position
JonFreeman 0:23cc72b18e74 701 set_run_mode (slider.state);
JonFreeman 0:23cc72b18e74 702 draw_button_hilight (SLIDER, LCD_COLOR_YELLOW) ;
JonFreeman 0:23cc72b18e74 703
JonFreeman 0:23cc72b18e74 704 if (slider.state == REGEN_BRAKE) {
JonFreeman 0:23cc72b18e74 705 double brake_effort = ((double)(slider.position - NEUTRAL_VAL)
JonFreeman 0:23cc72b18e74 706 / (double)(MAX_POS - NEUTRAL_VAL));
JonFreeman 0:23cc72b18e74 707 // brake_effort normalised to range 0.0 to 1.0
JonFreeman 0:23cc72b18e74 708 brake_effort *= 0.97; // upper limit to braking effort, observed effect before was quite fierce
JonFreeman 0:23cc72b18e74 709 pc.printf ("Brake effort %.2f\r\n", brake_effort);
JonFreeman 0:23cc72b18e74 710 /* set_pwm (brake_effort); */
JonFreeman 0:23cc72b18e74 711 set_V_limit (sqrt(brake_effort)); // sqrt gives more linear feel to control
JonFreeman 0:23cc72b18e74 712 set_I_limit (1.0);
JonFreeman 0:23cc72b18e74 713 }
JonFreeman 0:23cc72b18e74 714 } else { // pc.printf ("Slider not touched\r\n");
JonFreeman 0:23cc72b18e74 715 }
JonFreeman 0:23cc72b18e74 716
JonFreeman 0:23cc72b18e74 717 j = 0;
JonFreeman 0:23cc72b18e74 718 while (j < present_kybd->count) { // handle new key presses
JonFreeman 0:23cc72b18e74 719 k = present_kybd->ky[j++].keynum;
JonFreeman 0:23cc72b18e74 720 if (inlist(*present_kybd, k)) {
JonFreeman 0:23cc72b18e74 721 switch (k) { // Here for auto-repeat type key behaviour
JonFreeman 0:23cc72b18e74 722 case 21: // key is 'voltmeter'
JonFreeman 0:23cc72b18e74 723 // set_V_limit (last_pwm * 1.002 + 0.001);
JonFreeman 0:23cc72b18e74 724 break;
JonFreeman 0:23cc72b18e74 725 case 22: // key is 'ammeter'
JonFreeman 0:23cc72b18e74 726 // set_V_limit (last_pwm * 0.99);
JonFreeman 0:23cc72b18e74 727 break;
JonFreeman 0:23cc72b18e74 728 } // endof switch (k)
JonFreeman 0:23cc72b18e74 729 } // endof if (inlist(*present2, k)) {
JonFreeman 0:23cc72b18e74 730 if (inlist(*present_kybd, k) && !inlist(*previous_kybd, k)) {
JonFreeman 0:23cc72b18e74 731 pc.printf ("Handle Press %d\r\n", k);
JonFreeman 0:23cc72b18e74 732 draw_button_hilight (k, LCD_COLOR_YELLOW) ;
JonFreeman 0:23cc72b18e74 733 switch (k) { // Handle new touch screen button presses here - single action per press, not autorepeat
JonFreeman 0:23cc72b18e74 734 case SPEEDO_BUT: //
JonFreeman 0:23cc72b18e74 735 pc.printf ("Speedometer key pressed %d\r\n", k);
JonFreeman 0:23cc72b18e74 736 break;
JonFreeman 0:23cc72b18e74 737 case VMETER_BUT: //
JonFreeman 0:23cc72b18e74 738 pc.printf ("Voltmeter key pressed %d\r\n", k);
JonFreeman 0:23cc72b18e74 739 break;
JonFreeman 0:23cc72b18e74 740 case AMETER_BUT: //
JonFreeman 0:23cc72b18e74 741 pc.printf ("Ammeter key pressed %d\r\n", k);
JonFreeman 0:23cc72b18e74 742 break;
JonFreeman 0:23cc72b18e74 743 default:
JonFreeman 0:23cc72b18e74 744 pc.printf ("Unhandled keypress %d\r\n", k);
JonFreeman 0:23cc72b18e74 745 break;
JonFreeman 0:23cc72b18e74 746 } // endof switch (button)
JonFreeman 0:23cc72b18e74 747 }
JonFreeman 0:23cc72b18e74 748 } // endof while - handle new key presses
JonFreeman 0:23cc72b18e74 749 j = 0;
JonFreeman 0:23cc72b18e74 750 while (j < previous_kybd->count) { // handle new key releases
JonFreeman 0:23cc72b18e74 751 k = previous_kybd->ky[j++].keynum;
JonFreeman 0:23cc72b18e74 752 if (inlist(*previous_kybd, k) && !inlist(*present_kybd, k)) {
JonFreeman 0:23cc72b18e74 753 pc.printf ("Handle Release %d\r\n", k);
JonFreeman 0:23cc72b18e74 754 draw_button_hilight (k, LCD_COLOR_DARKBLUE) ;
JonFreeman 0:23cc72b18e74 755 }
JonFreeman 0:23cc72b18e74 756 } // endof while - handle new key releases
JonFreeman 0:23cc72b18e74 757 } // endof at least one key pressed this time or last time
JonFreeman 0:23cc72b18e74 758
JonFreeman 0:23cc72b18e74 759 if (sliderpress == false) { // need to glide dead-mans function towards neutral here
JonFreeman 0:23cc72b18e74 760 if (slider.position < NEUTRAL_VAL) {
JonFreeman 0:23cc72b18e74 761 slider.position += 1 + (NEUTRAL_VAL - slider.position) / DAMPER_DECAY;
JonFreeman 0:23cc72b18e74 762 SliderGraphic (slider);
JonFreeman 0:23cc72b18e74 763 slider.recalc_run = true;
JonFreeman 0:23cc72b18e74 764 }
JonFreeman 0:23cc72b18e74 765 }
JonFreeman 0:23cc72b18e74 766
JonFreeman 0:23cc72b18e74 767 if (slider.recalc_run) { // range of slider.position in RUN mode is min_pos_() to NEUTRAL_VAL - 1
JonFreeman 0:23cc72b18e74 768 slider.recalc_run = false; // All RUN power and pwm calcs done here
JonFreeman 0:23cc72b18e74 769 int b = slider.position;
JonFreeman 0:23cc72b18e74 770 double torque_req;
JonFreeman 0:23cc72b18e74 771 if (b > NEUTRAL_VAL)
JonFreeman 0:23cc72b18e74 772 b = NEUTRAL_VAL;
JonFreeman 0:23cc72b18e74 773 if (b < MIN_POS) // if finger position is above top of slider limit
JonFreeman 0:23cc72b18e74 774 b = MIN_POS;
JonFreeman 0:23cc72b18e74 775 b = NEUTRAL_VAL - b; // now got integer going positive for increasing power demand
JonFreeman 0:23cc72b18e74 776 torque_req = (double) b;
JonFreeman 0:23cc72b18e74 777 torque_req /= (NEUTRAL_VAL - MIN_POS); // in range 0.0 to 1.0
JonFreeman 0:23cc72b18e74 778 pc.printf ("torque_rec = %.3f, last_pwm = %.3f\r\n", torque_req, last_pwm);
JonFreeman 0:23cc72b18e74 779 set_I_limit (torque_req);
JonFreeman 0:23cc72b18e74 780 if (torque_req < 0.05)
JonFreeman 0:23cc72b18e74 781 set_V_limit (last_pwm / 2.0);
JonFreeman 0:23cc72b18e74 782 else {
JonFreeman 0:23cc72b18e74 783 if (last_pwm < 0.99)
JonFreeman 0:23cc72b18e74 784 set_V_limit (last_pwm + 0.05); // ramp voltage up rather than slam to max
JonFreeman 0:23cc72b18e74 785 }
JonFreeman 0:23cc72b18e74 786 }
JonFreeman 0:23cc72b18e74 787 } // endof doing 32ms stuff
JonFreeman 0:23cc72b18e74 788
JonFreeman 0:23cc72b18e74 789 if (qtrsec_trig == true) { // do every quarter second stuff here
JonFreeman 0:23cc72b18e74 790 qtrsec_trig = false;
JonFreeman 0:23cc72b18e74 791 speed.qtr_sec_update ();
JonFreeman 0:23cc72b18e74 792 double speedmph = speed.MPH(), amps = 0.0 - read_ammeter(), volts = read_voltmeter();
JonFreeman 0:23cc72b18e74 793 //static const double mph_2_mm_per_sec = 447.04; // exact
JonFreeman 0:23cc72b18e74 794 // double mm_travelled_in_qtrsec = speedmph * mph_2_mm_per_sec / 4.0;
JonFreeman 0:23cc72b18e74 795 slider.loco_speed = speedmph;
JonFreeman 0:23cc72b18e74 796 update_meters (speedmph, amps, volts) ;
JonFreeman 0:23cc72b18e74 797 // update_meters (7.5, amps, volts) ;
JonFreeman 0:23cc72b18e74 798 led_grn = !led_grn;
JonFreeman 0:23cc72b18e74 799 if (slider.state == PARK) {
JonFreeman 0:23cc72b18e74 800 if (speedmph > LOCO_HANDBRAKE_ESCAPE_SPEED / 4.0) {
JonFreeman 0:23cc72b18e74 801 slider.handbrake_effort *= 1.1;
JonFreeman 0:23cc72b18e74 802 if (slider.handbrake_effort > 0.55) slider.handbrake_effort = 0.55;
JonFreeman 0:23cc72b18e74 803 set_run_mode (PARK);
JonFreeman 0:23cc72b18e74 804 pc.printf ("Handbrake slipping, effort %.2f\r\n", slider.handbrake_effort);
JonFreeman 0:23cc72b18e74 805 }
JonFreeman 0:23cc72b18e74 806 if (speedmph < 0.02) {
JonFreeman 0:23cc72b18e74 807 slider.handbrake_effort *= 0.9;
JonFreeman 0:23cc72b18e74 808 if (slider.handbrake_effort < 0.05) slider.handbrake_effort = 0.05;
JonFreeman 0:23cc72b18e74 809 set_run_mode (PARK);
JonFreeman 0:23cc72b18e74 810 pc.printf ("Handbrake not slipping, effort %.2f\r\n", slider.handbrake_effort);
JonFreeman 0:23cc72b18e74 811 }
JonFreeman 0:23cc72b18e74 812 }
JonFreeman 0:23cc72b18e74 813 c_5++;
JonFreeman 0:23cc72b18e74 814 // Can do stuff once per second here
JonFreeman 0:23cc72b18e74 815 if(c_5 > 3) {
JonFreeman 0:23cc72b18e74 816 c_5 = 0;
JonFreeman 0:23cc72b18e74 817 seconds++;
JonFreeman 0:23cc72b18e74 818 if (seconds > 59) {
JonFreeman 0:23cc72b18e74 819 seconds = 0;
JonFreeman 0:23cc72b18e74 820 minutes++;
JonFreeman 0:23cc72b18e74 821 // do once per minute stuff here
JonFreeman 0:23cc72b18e74 822 } // fall back into once per second
JonFreeman 0:23cc72b18e74 823 if(SD_state == SD_OK) {
JonFreeman 0:23cc72b18e74 824 uint32_t distance = speed.metres_travelled();
JonFreeman 0:23cc72b18e74 825 char dist[20];
JonFreeman 0:23cc72b18e74 826 sprintf (dist, "%05d m", distance);
JonFreeman 0:23cc72b18e74 827 displaytext (236, 226, 2, dist);
JonFreeman 0:23cc72b18e74 828 update_SD_card (); // Buffers data for SD card, writes when buffer filled
JonFreeman 0:23cc72b18e74 829 }
JonFreeman 0:23cc72b18e74 830 // calc_motor_amps( mva);
JonFreeman 0:23cc72b18e74 831 } // endof if(c_5 > 3
JonFreeman 0:23cc72b18e74 832 } // endof if (qtrsec_trig == true) {
JonFreeman 0:23cc72b18e74 833 } // endof while(1) main programme loop
JonFreeman 0:23cc72b18e74 834 } // endof int main() {
JonFreeman 0:23cc72b18e74 835
JonFreeman 0:23cc72b18e74 836