Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BSP_DISCO_F746NG FastPWM LCD_DISCO_F746NG SD_DISCO_F746NG TS_DISCO_F746NG mbed
Revision 1:8ef34deb5177, committed 2017-11-13
- Comitter:
- JonFreeman
- Date:
- Mon Nov 13 09:53:00 2017 +0000
- Parent:
- 0:23cc72b18e74
- Commit message:
- Brushless Motor electric locomotive congtrol system; Drives 4 motors using touch-screen control.; Displays speed MPH, system volts and power
Changed in this revision
--- a/BSP_DISCO_F746NG.lib Sun Nov 12 06:26:29 2017 +0000 +++ b/BSP_DISCO_F746NG.lib Mon Nov 13 09:53:00 2017 +0000 @@ -1,1 +1,1 @@ -https://developer.mbed.org/teams/ST/code/BSP_DISCO_F746NG/#5f0817e857ea +https://os.mbed.com/users/JonFreeman/code/BSP_DISCO_F746NG/#5f0817e857ea
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Electric_Loco.h Mon Nov 13 09:53:00 2017 +0000
@@ -0,0 +1,80 @@
+/* Updated 12 Nov 2017
+ Jon Freeman
+
+ 5" and 7.25" gauge Electric Locomotive Controller - ST DISCO-F746NG
+Uses built in display and touch screen.
+
+Display shows 'analogue' moving coil meter movements for :
+ Locomotive speed Miles per Hour
+ System voltage (range 20v - 90v or thereabouts)
+ Power Watts delivered to drive motors.
+
+Touch screen has three 'buttons', these are currently unused, and are where the meter movements show.
+Idea is to use two for two horns,
+
+Display has 'slider' touch control. This drives the loco.
+Control in central position when not driving or drfting.
+Moving towards bottom of screen applies regenerative braking - move further down applies harder braking.
+Moving towards top of screen powers drive motors, move further up applies more torque (current controller implemented)
+Take finger off and control drifts down to central 'neutral' position.
+*/
+#define MAX_TOUCHES 6 // Touch screen can decode up to this many simultaneous finger press positions
+#define NEUTRAL_VAL 150 // Number of pixels
+
+#define SLIDERX 418 // slider graphic x position
+#define SLIDERY 2 // slider graphic y position
+#define SLIDERW 50 // pixel width of slider
+#define SLIDERH 268 // pixel height of slider
+
+// To get speedo reading correctly, need to use correct gear ratio and wheel size info
+//#define BOGIE_5_INCH
+#define BOGIE_7_and_a_quarter_INCH
+
+const int
+
+ NUMBER_OF_MOTORS = 4, // 1 to 6 motors
+
+ BUTTON_RAD = (SLIDERW / 2) - 4, // radius of circular 'knob' in slider control
+ MIN_POS = BUTTON_RAD + 5, // top of screen
+ MAX_POS = SLIDERH - (BUTTON_RAD + 1), // bottom of screen
+ CIRC_CTR = SLIDERX + BUTTON_RAD + 4;
+
+static const double
+#ifdef BOGIE_7_and_a_quarter_INCH
+ MOTOR_PINION_T = 17.0, // motor pinion teeth, wheel gear teeth and wheel dia required to calculate speed and distance.
+ WHEEL_GEAR_T = 76.0,
+ WHEEL_DIA_MM = 147.0,
+#endif
+#ifdef BOGIE_5_INCH
+ MOTOR_PINION_T = 27.0, // motor pinion teeth, wheel gear teeth and wheel dia required to calculate speed and distance.
+ WHEEL_GEAR_T = 85.0,
+ WHEEL_DIA_MM = 98.0,
+#endif
+ PI = 4.0 * atan(1.0),
+ WHEEL_CIRCUMFERENCE_METRE = PI * WHEEL_DIA_MM / 1000.0,
+ PULSES_PER_WHEEL_REV = 32.0 * WHEEL_GEAR_T / MOTOR_PINION_T,
+ PULSES_PER_METRE = PULSES_PER_WHEEL_REV / WHEEL_CIRCUMFERENCE_METRE,
+ rpm2mph = 60.0 // = Motor Revs per hour;
+ * (MOTOR_PINION_T / WHEEL_GEAR_T) // = Wheel rev per hour
+ * WHEEL_CIRCUMFERENCE_METRE // = metres per hour
+ * 39.37 // = inches per hour
+ / (1760 * 36) // = miles per hour
+ ;
+
+const double LOCO_HANDBRAKE_ESCAPE_SPEED = 0.5;
+
+enum {NO_DPS, ONE_DP};
+// Assign unique number to every button we may use, and keep count of total number of them
+enum {
+ ENTER, SLIDER, SPEEDO_BUT, VMETER_BUT, AMETER_BUT,
+ NUMOF_BUTTONS} ; // button names
+enum {
+ STATES, INACTIVE, RUN, NEUTRAL_DRIFT, REGEN_BRAKE, PARK, HANDBRAKE_SLIPPING};
+
+struct slide { int position; int oldpos; int state; int direction; bool recalc_run; bool handbrake_slipping;
+ double handbrake_effort; double loco_speed; } ;
+struct point { int x; int y; } ;
+//struct rect { struct point a, b; } ;
+struct key { int keynum; int x; int y; bool pressed; } ;
+struct ky_bd { int count, slider_y; key ky[MAX_TOUCHES + 1]; bool sli; } ;
+
--- a/costab.cpp Sun Nov 12 06:26:29 2017 +0000 +++ b/costab.cpp Mon Nov 13 09:53:00 2017 +0000 @@ -1,4 +1,8 @@ #include "mbed.h" +/* +Purpose of this file is to provide sin and cos functions. Yes, C++ has these already, but using inbuilt sin and cos on +DISCO-F746NG causes display to flicker! Interrupt getting missed or whatever, these look-up functions solve the flicker ! +*/ static const double HALF_PI = 2.0 * atan(1.0); static const double TWO_PI = 8.0 * atan(1.0);
--- a/dro.h Sun Nov 12 06:26:29 2017 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/* Updated 12 Nov 2017
- Jon Freeman
-
- 5" and 7.25" gauge Electric Locomotive Controller - ST DISCO-F746NG
-Uses built in display and touch screen.
-
-Display shows 'analogue' moving coil meter movements for :
- Locomotive speed Miles per Hour
- System voltage (range 20v - 90v or thereabouts)
- Power Watts delivered to drive motors.
-
-Touch screen has three 'buttons', these are currently unused, and are where the meter movements show.
-Idea is to use two for two horns,
-
-Display has 'slider' touch control. This drives the loco.
-Control in central position when not driving or drfting.
-Moving towards bottom of screen applies regenerative braking - move further down applies harder braking.
-Moving towards top of screen powers drive motors, move further up applies more torque (current controller implemented)
-Take finger off and control drifts down to central 'neutral' position.
-*/
-#define MAX_TOUCHES 6 // Touch screen can decode up to this many simultaneous finger press positions
-#define NEUTRAL_VAL 150 // Number of pixels
-
-#define SLIDERX 418 // slider graphic x position
-#define SLIDERY 2 // slider graphic y position
-#define SLIDERW 50 // pixel width of slider
-#define SLIDERH 268 // pixel height of slider
-const int
-BUTTON_RAD = (SLIDERW / 2) - 4, // radius of circular 'knob' in slider control
-MIN_POS = BUTTON_RAD + 5, // top of screen
-MAX_POS = SLIDERH - (BUTTON_RAD + 1), // bottom of screen
-CIRC_CTR = SLIDERX + BUTTON_RAD + 4;
-
-static const double PI = 4.0 * atan(1.0);
-const double LOCO_HANDBRAKE_ESCAPE_SPEED = 0.5;
-
-enum {NO_DPS, ONE_DP};
-// Assign unique number to every button we may use, and keep count of total number of them
-enum {
- ENTER, SLIDER, SPEEDO_BUT, VMETER_BUT, AMETER_BUT,
- NUMOF_BUTTONS} ; // button names
-enum {
- STATES, INACTIVE, RUN, NEUTRAL_DRIFT, REGEN_BRAKE, PARK, HANDBRAKE_SLIPPING};
-
-struct slide { int position; int oldpos; int state; int direction; bool recalc_run; bool handbrake_slipping;
- double handbrake_effort; double loco_speed; } ;
-struct point { int x; int y; } ;
-//struct rect { struct point a, b; } ;
-struct key { int keynum; int x; int y; bool pressed; } ;
-struct ky_bd { int count, slider_y; key ky[MAX_TOUCHES + 1]; bool sli; } ;
-
--- a/graphics.cpp Sun Nov 12 06:26:29 2017 +0000
+++ b/graphics.cpp Mon Nov 13 09:53:00 2017 +0000
@@ -1,7 +1,7 @@
#include "mbed.h"
#include "TS_DISCO_F746NG.h"
#include "LCD_DISCO_F746NG.h"
-#include "dro.h"
+#include "Electric_Loco.h"
#define VOLTMETER_X 68 // Voltmeter screen position
#define VOLTMETER_Y 68
@@ -331,9 +331,11 @@
Powermeter.setup (AMMETER_X, AMMETER_Y, V_A_SIZE, -1400.0, 1400.0, 1.25 * PI, -0.25 * PI , 14, "Watt", NO_DPS);
}
-void update_meters (double speed, double current, double voltage)
+//void update_meters (double speed, double current, double voltage)
+void update_meters (double speed, double power, double voltage)
{
- Powermeter.set_value(voltage * current);
+// Powermeter.set_value(voltage * current);
+ Powermeter.set_value(power);
Voltmeter.set_value (voltage);
Speedo.set_value (speed);
}
--- a/main.cpp Sun Nov 12 06:26:29 2017 +0000
+++ b/main.cpp Mon Nov 13 09:53:00 2017 +0000
@@ -1,7 +1,8 @@
// Electric Locomotive Controller
// Jon Freeman B. Eng Hons
-// Last Updated 12 April 2017
+// Last Updated 13 November 2017
+
// Touch Screen Loco 2017 - WITH SD card data logger functions
// This code runs on STM 32F746NG DISCO module, high performance ARM Cortex with touch screen
@@ -16,15 +17,12 @@
// NOTE that when braking, the motor supply rail voltage will be lifted. Failure to design-in some type of 'surplus power dump'
// may result in over-voltage damage to batteries or power electronics.
-
#include "mbed.h"
#include "FastPWM.h"
#include "TS_DISCO_F746NG.h"
#include "LCD_DISCO_F746NG.h"
-#include "SD_DISCO_F746NG.h"
-#include "dro.h"
-
-
+//#include "SD_DISCO_F746NG.h" // SD card stuff now in separate file sd_card.cpp
+#include "Electric_Loco.h"
// Design Topology
// This F746NG is the single loco control computer.
@@ -57,7 +55,7 @@
LCD_DISCO_F746NG lcd;
TS_DISCO_F746NG touch_screen;
-SD_DISCO_F746NG sd;
+//SD_DISCO_F746NG sd; // SD card stuff now in sd_card.cpp
FastPWM maxv (D12, 1),
maxi (D11, 1); // pin, prescaler value
@@ -70,7 +68,8 @@
DigitalOut led_grn (LED1); // the only on board user led
DigitalIn f_r_switch (D0); // Reads position of centre-off ignition switch
-DigitalIn spareio_d8 (D8);
+//DigitalIn spareio_d8 (D8);
+//DigitalOut throttle_servo_pulse_out (D8); // now defined in throttle.cpp
DigitalIn spareio_d9 (D9);
DigitalIn spareio_d10 (D10); // D8, D9, D10 wired to jumper on pcb - not used to Apr 2017
@@ -100,50 +99,25 @@
extern void update_meters (double, double, double) ;
extern void command_line_interpreter () ;
-static const int NUMBER_OF_MOTORS = 4,
- SD_BLOCKSIZE = 512, /* SD card data Block Size in Bytes */
+extern int throttle (double, double) ; // called from main every 31ms
+
+extern void update_SD_card () ; // Hall pulse total updated once per sec and saved in blocks of 128 to SD card
+extern bool read_SD_state () ;
+extern bool mainSDtest();
+
+static const int
DAMPER_DECAY = 42, // Small num -> fast 'viscous damper' on dead-mans function with finger removed from panel
- MAF_PTS = 140, // Moving Average Filter points
- PWM_HZ = 13000,
+ MAF_PTS = 140, // Moving Average Filter points. Filters reduce noise on volatage and current readings
+ PWM_HZ = 16000, // chosen to be above cutoff frequency of average human ear
// PWM_HZ = 2000, // Used this to experiment on much bigger motor
MAX_PWM_TICKS = 108000000 / PWM_HZ, // 108000000 for F746N, due to cpu clock = 216 MHz
FWD = 0,
REV = ~FWD;
-static const double
- MOTOR_PINION_T = 17.0, // motor pinion teeth, wheel gear teeth and wheel dia required to calculate speed and distance.
- WHEEL_GEAR_T = 76.0,
- WHEEL_DIA_MM = 147.0,
- WHEEL_CIRCUMFERENCE_METRE = PI * WHEEL_DIA_MM / 1000.0,
- PULSES_PER_WHEEL_REV = 32.0 * WHEEL_GEAR_T / MOTOR_PINION_T,
- PULSES_PER_METRE = PULSES_PER_WHEEL_REV / WHEEL_CIRCUMFERENCE_METRE,
- rpm2mph = 60.0 // = Motor Revs per hour;
- * (MOTOR_PINION_T / WHEEL_GEAR_T) // = Wheel rev per hour
- * WHEEL_CIRCUMFERENCE_METRE // = metres per hour
- * 39.37 // = inches per hour
- / (1760 * 36) // = miles per hour
- ;
-
-// Assume SD card size is 4Gbyte, might be 8 Gbyte
-// Then can use 8388608 blocks (8 * 1024 * 1024)
-
-uint64_t SD_blockptr = 0;
-uint32_t SDBuffer[(SD_BLOCKSIZE >> 2)]; // = space for (512 / 4) uint32_t
-uint8_t SD_state = SD_OK, sd_jf = 0;
-
-static const uint64_t GIGAB = 1024 * 1024 * 1024;
-//static const uint64_t SDBLOCKS = (GIGAB / SD_BLOCKSIZE) * 4; // software drives SD up to 4Gbyte only - 8 M block
-static const uint64_t SDBLOCKS = (GIGAB / SD_BLOCKSIZE) * 2; // software drives SD up to 4Gbyte only - 8 M block
-// If data logger takes 2 minutes to fill 1 block, a 4G card takes 32 years run-time to fill
-// If system generates approx 320 pulses per metre travelled, max distance recordable in uint32_t is 65536 * 65536 / 320 = 13421.772 km
-
-//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 } ;
+//from .h struct slide { int position; int oldpos; int state; int direction; bool recalc_run; bool handbrake_slipping; double handbrake_effort; double loco_speed } ;
struct slide slider ;
-
-//static const double mph_2_mm_per_sec = 447.04; // exact
-
int V_maf[MAF_PTS + 2], I_maf[MAF_PTS + 2], maf_ptr = 0;
//uint32_t Hall_pulse[8] = {0,0,0,0,0,0,0,0}; // more than max number of motors
uint32_t Hall_pulse[8] = {1,1,1,1,1,1,1,1}; // more than max number of motors
@@ -155,163 +129,6 @@
double last_pwm = 0.0;
-bool sd_error () { // Test and Clear error code sd_jf, return true if any error bits set, false on 0
- bool retval = false;
- if (sd_jf != 0) {
- retval = true;
- sd_jf = 0;
- }
- return retval;
-}
-
-bool check_SD_block_clear (uint32_t block) {
- uint32_t b[(SD_BLOCKSIZE >> 2)];
- SD_state = sd.ReadBlocks(b, (uint64_t)(SD_BLOCKSIZE * block), SD_BLOCKSIZE, 1);
- if(SD_state != SD_OK) {
- sd_jf = 1;
- pc.printf ("Failed, not SD_OK, erasing block %d\r\n", block);
- return false;
- }
- for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++)
- if (b[i] != 0)
- return false;
- return true;
-}
-
-/*bool erase_block (uint32_t block2erase) {
- uint64_t addr = SD_BLOCKSIZE * (uint64_t)block2erase;
- SD_state = sd.Erase(addr, addr + SD_BLOCKSIZE);
- if (SD_state != SD_OK) {
- sd_jf = 1; // Assert error flag
- pc.printf ("Failed, not SD_OK, erasing block %d\r\n", block2erase);
- return false;
- }
- return check_SD_block_clear (block2erase);
-}*/
-
-bool SD_find_next_clear_block (uint64_t * blok) { // Successive approximation algorithm to quickly find next vacant SD card 512 byte block
- uint64_t toaddsub = SDBLOCKS / 2, stab = SDBLOCKS - 1;
- pc.printf ("At SD_find_next_clear_block \r\n");
- while (toaddsub) {
- pc.printf ("stab = %lld, toadsub = %lld\r\n", stab, toaddsub); // lld for long long int
- bool clear_block = true;
- SD_state = sd.ReadBlocks(SDBuffer, SD_BLOCKSIZE * stab, SD_BLOCKSIZE, 1);
- if(SD_state != SD_OK) {
- sd_jf = 1;
- pc.printf ("SD error in SD_find_next_clear_block, returning -1\r\n");
- return false;
- }
- for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++) {
- if (SDBuffer[i] != 0) {
- clear_block = false;
- pc.printf ("Buff at %d contains %x\r\n", i, SDBuffer[i]);
- i = SD_BLOCKSIZE; // to exit loop
- }
- }
- if (clear_block)
- stab -= toaddsub;
- else
- stab += toaddsub;
- toaddsub >>= 1;
- }
- if (!check_SD_block_clear(stab))
- stab++;
- if (sd_error()) { // sd_error() tests and clears error bits
- pc.printf ("check_SD_block_clear(%ld)returned ERROR in SD_find_next_clear_block\r\n", stab);
- sd_jf = 1; // reassert error flag
- return false;
- }
- pc.printf ("Completed find_next, stab = %d\r\n", stab);
- *blok = stab; // block number of next free block
- return true;
-}
-
-bool SD_card_erase_all (void) { // assumes sd card is 4 Gbyte, erases 4 Gbyte. Called from CLI
- uint64_t EndAddr = GIGAB * 4,
- StartAddr = 0LL;
- sd_jf = 0;
- pc.printf ("Erasing SD card ... ");
- // uint8_t Erase(uint64_t StartAddr, uint64_t EndAddr);
- SD_state = sd.Erase(StartAddr, EndAddr);
- if (SD_state != SD_OK) {
- pc.printf ("SD_card_erase_all FAILED\r\n");
- sd_jf = 1;
- return false;
- }
- pc.printf ("no error detected\r\n");
- return true;
-}
-
-
-bool mainSDtest()
-{
- SD_state = sd.Init();
- if(SD_state != SD_OK) {
- pc.printf ("sd.Init set SD_state to %0x\r\n", SD_state);
- if(SD_state == MSD_ERROR_SD_NOT_PRESENT) {
- pc.printf("SD shall be inserted before running test\r\n");
- } else {
- pc.printf("SD Initialization : FAIL.\r\n");
- }
- pc.printf("SD Test Aborted.\r\n");
- return false;
- }
-// else { // SD_state is SD_OK
- pc.printf("SD Initialization : OK.\r\n");
-
-
-
-// SD_card_erase_all();
-// if (sd_error())
-// pc.printf ("SD_card_erase_all() reports ERROR");
-
-
-
- SD_find_next_clear_block(& SD_blockptr);
- pc.printf ("SD_find_next_clear_block returned %lld\r\n\n\n", SD_blockptr);
- if (sd_error()) {
- pc.printf ("***** ERROR returned from SD_find_next_clear_block ***** SD ops aborted\r\n");
- return false;
- }
- pc.printf("SD_find_next_clear_block() returned %ld\r\n", SD_blockptr);
- if (SD_blockptr < 1) {
- pc.printf ("Looks like card newly erased, SD_blockptr value of %d\r\n", SD_blockptr);
- SD_blockptr = 0;
- historic_distance = 0;
- }
- else {
- SD_state = sd.ReadBlocks(SDBuffer, SD_BLOCKSIZE * (SD_blockptr - 1), SD_BLOCKSIZE, 1);
- if (SD_state != SD_OK) {
- pc.printf ("Error reading last block from SD block %d\r\n", SD_blockptr - 1);
- return false;
- }
- for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++)
- pc.printf ("%lx\t", SDBuffer[i]);
- historic_distance = SDBuffer[(SD_BLOCKSIZE >> 2) - 1];
- pc.printf ("\r\nAbove, data read from last filled SD block %lld, using historic_distance = %lx\r\n", SD_blockptr - 1, historic_distance);
- }
- if (SD_blockptr > 2) {
- for (int i = SD_blockptr - 2; i < SD_blockptr + 2; i++) {
- pc.printf ("check_SD_block_clear (%d) ", i);
- if (check_SD_block_clear(i))
- pc.printf ("block %ld is CLEAR\r\n", i);
- else
- pc.printf ("block %ld is NOT clear\r\n", i);
- if (sd_error()) {
- pc.printf ("ERROR from check_SD_block_clear ()\r\n");
- }
- }
- }
- return true;
-}
-
-
-
-
-
-
-
-
class speed_measurement // Interrupts at qtr sec cause read of Hall_pulse counters which are incremented by transitions of Hall inputs
{
static const int SPEED_AVE_PTS = 9; // AVE_PTS - points in moving average filters
@@ -393,6 +210,10 @@
return historic_distance + Hall_pulse[0] + Hall_pulse[1] + Hall_pulse[2] + Hall_pulse[3];
}
+uint32_t get_pulse_total () { // called by SD card code
+ return speed.pulse_total();
+}
+
void set_V_limit (double p) // Sets max motor voltage
{
if (p < 0.0)
@@ -458,22 +279,33 @@
{
Hall_pulse[3]++;
}
-/*void ISR_mot5_hall_handler ()
+void ISR_mot5_hall_handler () // If only 4 motors this never gets used, there is no fifth motor
{
Hall_pulse[4]++;
}
-void ISR_mot6_hall_handler ()
+void ISR_mot6_hall_handler () // As one above
{
Hall_pulse[5]++;
}
-*/
+
void ISR_current_reader (void) // FIXED at 250us
{
+ static int ms32 = 0, ms250 = 0;
trigger_current_read = true; // every 250us, i.e. 4kHz NOTE only sets trigger here, readings taken in main loop
+ ms32++;
+ if (ms32 > 124) {
+ ms32 = 0;
+ trigger_32ms = true;
+ ms250++;
+ if (ms250 > 7) {
+ ms250 = 0;
+ qtrsec_trig = true;
+ }
+ }
}
-void ISR_tick_32ms (void) //
+/*void ISR_tick_32ms (void) //
{
trigger_32ms = true;
}
@@ -481,7 +313,7 @@
{
qtrsec_trig = true;
}
-
+*/
// End of Interrupt Service Routines
@@ -521,7 +353,7 @@
1 1 1 Regen Braking
*/
void set_run_mode (int mode)
-{
+{ // NOTE Nov 2017 - Handbrake not implemented
if (mode == HANDBRAKE_SLIPPING) slider.handbrake_slipping = true;
else slider.handbrake_slipping = false;
switch (mode) {
@@ -560,36 +392,21 @@
}
}
-void update_SD_card () { // Hall pulse total updated once per sec and saved in blocks of 128 to SD card
- static int index = 0;
- static uint32_t buff[(SD_BLOCKSIZE >> 2) + 2];
- buff[index++] = speed.pulse_total(); // pulse_total for all time, add this to buffer to write to SD
- if (index >= (SD_BLOCKSIZE >> 2)) {
- pc.printf ("Writing new SD block %d ... ", SD_blockptr);
- SD_state = sd.WriteBlocks(buff, SD_BLOCKSIZE * SD_blockptr, SD_BLOCKSIZE, 1);
- SD_blockptr++;
- if (SD_state == SD_OK)
- pc.printf ("OK, distance %d\r\n", buff[index - 1] / (int)PULSES_PER_METRE);
- else
- pc.printf ("ERROR\r\n");
- index = 0;
- }
-}
-
int main()
{
int c_5 = 0, seconds = 0, minutes = 0;
+ double electrical_power_Watt = 0.0;
ky_bd kybd_a, kybd_b;
memset (&kybd_a, 0, sizeof(kybd_a));
memset (&kybd_b, 0, sizeof(kybd_b));
- spareio_d8.mode (PullUp);
+// spareio_d8.mode (PullUp); now output driving throttle servo
spareio_d9.mode (PullUp);
spareio_d10.mode(PullUp);
Ticker tick250us;
- Ticker tick32ms;
- Ticker tick250ms;
+// Ticker tick32ms;
+// Ticker tick250ms;
// Setup User Interrupt Vectors
mot1hall.fall (&ISR_mot1_hall_handler);
@@ -601,9 +418,10 @@
mot4hall.fall (&ISR_mot4_hall_handler);
mot4hall.rise (&ISR_mot4_hall_handler);
- tick250us.attach_us (&ISR_current_reader, 250); // set to longer time to test
- tick32ms.attach_us (&ISR_tick_32ms, 32001);
- tick250ms.attach_us (&ISR_tick_250ms, 250002);
+ tick250us.attach_us (&ISR_current_reader, 250); // count 125 of these to trig 31.25ms
+// tick32ms.attach_us (&ISR_tick_32ms, 32001);
+// tick32ms.attach_us (&ISR_tick_32ms, 31250); // then count 8 pulses per 250ms
+// tick250ms.attach_us (&ISR_tick_250ms, 250002);
pc.baud (9600);
GfetT1 = 0;
GfetT2 = 0; // two output bits for future use driving horns
@@ -650,6 +468,7 @@
mainSDtest();
+ double torque_req = 0.0;
bool toggle32ms = false;
// Main loop
while(1) { //
@@ -660,6 +479,10 @@
if (trigger_32ms == true) { // Stuff to do every 32 milli secs
trigger_32ms = false;
+
+// CALL THROTTLE HERE - why here ? Ah yes, this initiates servo pulse. Need steady stream of servo pulses even when nothing changes.
+ throttle (torque_req, 2.3);
+
toggle32ms = !toggle32ms;
if (toggle32ms) {
present_kybd = &kybd_a;
@@ -690,7 +513,7 @@
else { // nice slow non-jerky glidey movement required
dbl = (double)(k - slider.position);
- dbl /= 13.179;
+ dbl /= 13.179; // Where did 13.179 come from ?
if (dbl < 0.0)
dbl -= 1.0;
if (dbl > 0.0)
@@ -767,7 +590,7 @@
if (slider.recalc_run) { // range of slider.position in RUN mode is min_pos_() to NEUTRAL_VAL - 1
slider.recalc_run = false; // All RUN power and pwm calcs done here
int b = slider.position;
- double torque_req;
+// double torque_req; // now declared above to be used as parameter for throttle
if (b > NEUTRAL_VAL)
b = NEUTRAL_VAL;
if (b < MIN_POS) // if finger position is above top of slider limit
@@ -793,7 +616,8 @@
//static const double mph_2_mm_per_sec = 447.04; // exact
// double mm_travelled_in_qtrsec = speedmph * mph_2_mm_per_sec / 4.0;
slider.loco_speed = speedmph;
- update_meters (speedmph, amps, volts) ;
+ electrical_power_Watt = volts * amps; // visible throughout main
+ update_meters (speedmph, electrical_power_Watt, volts) ; // displays speed, volts and power (volts times amps)
// update_meters (7.5, amps, volts) ;
led_grn = !led_grn;
if (slider.state == PARK) {
@@ -820,7 +644,8 @@
minutes++;
// do once per minute stuff here
} // fall back into once per second
- if(SD_state == SD_OK) {
+// if(SD_state == SD_OK) {
+ if(read_SD_state() == true) {
uint32_t distance = speed.metres_travelled();
char dist[20];
sprintf (dist, "%05d m", distance);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sd_card.cpp Mon Nov 13 09:53:00 2017 +0000
@@ -0,0 +1,204 @@
+#include "mbed.h"
+#include "Electric_Loco.h"
+#include "SD_DISCO_F746NG.h"
+/*
+SD card used only to keep log of total distance travelled.
+Odometer is trivial.
+This file treats SD card as random access memory.
+A better implementation would use library functions for FAT file system etc.
+
+May revisit this.
+
+*/
+SD_DISCO_F746NG sd;
+extern Serial pc;
+extern uint32_t historic_distance;
+extern uint32_t get_pulse_total () ;
+
+static const int
+ SD_BLOCKSIZE = 512; /* SD card data Block Size in Bytes */
+// Assume SD card size is 4Gbyte, might be 8 Gbyte
+// Then can use 8388608 blocks (8 * 1024 * 1024)
+
+uint64_t SD_blockptr = 0;
+uint32_t SDBuffer[(SD_BLOCKSIZE >> 2)]; // = space for (512 / 4) uint32_t
+uint8_t SD_state = SD_OK, sd_jf = 0;
+
+static const uint64_t GIGAB = 1024 * 1024 * 1024;
+//static const uint64_t SDBLOCKS = (GIGAB / SD_BLOCKSIZE) * 4; // software drives SD up to 4Gbyte only - 8 M block
+static const uint64_t SDBLOCKS = (GIGAB / SD_BLOCKSIZE) * 2; // software drives SD up to 4Gbyte only - 8 M block
+// If data logger takes 2 minutes to fill 1 block, a 4G card takes 32 years run-time to fill
+// If system generates approx 320 pulses per metre travelled, max distance recordable in uint32_t is 65536 * 65536 / 320 = 13421.772 km
+bool sd_error () { // Test and Clear error code sd_jf, return true if any error bits set, false on 0
+ bool retval = false;
+ if (sd_jf != 0) {
+ retval = true;
+ sd_jf = 0;
+ }
+ return retval;
+}
+
+bool check_SD_block_clear (uint32_t block) {
+ uint32_t b[(SD_BLOCKSIZE >> 2)];
+ SD_state = sd.ReadBlocks(b, (uint64_t)(SD_BLOCKSIZE * block), SD_BLOCKSIZE, 1);
+ if(SD_state != SD_OK) {
+ sd_jf = 1;
+ pc.printf ("Failed, not SD_OK, erasing block %d\r\n", block);
+ return false;
+ }
+ for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++)
+ if (b[i] != 0)
+ return false;
+ return true;
+}
+
+bool read_SD_state () {
+ if (SD_state == SD_OK)
+ return true;
+ return false;
+}
+/*bool erase_block (uint32_t block2erase) {
+ uint64_t addr = SD_BLOCKSIZE * (uint64_t)block2erase;
+ SD_state = sd.Erase(addr, addr + SD_BLOCKSIZE);
+ if (SD_state != SD_OK) {
+ sd_jf = 1; // Assert error flag
+ pc.printf ("Failed, not SD_OK, erasing block %d\r\n", block2erase);
+ return false;
+ }
+ return check_SD_block_clear (block2erase);
+}*/
+
+bool SD_find_next_clear_block (uint64_t * blok) { // Successive approximation algorithm to quickly find next vacant SD card 512 byte block
+ uint64_t toaddsub = SDBLOCKS / 2, stab = SDBLOCKS - 1;
+ pc.printf ("At SD_find_next_clear_block \r\n");
+ while (toaddsub) {
+ pc.printf ("stab = %lld, toadsub = %lld\r\n", stab, toaddsub); // lld for long long int
+ bool clear_block = true;
+ SD_state = sd.ReadBlocks(SDBuffer, SD_BLOCKSIZE * stab, SD_BLOCKSIZE, 1);
+ if(SD_state != SD_OK) {
+ sd_jf = 1;
+ pc.printf ("SD error in SD_find_next_clear_block, returning -1\r\n");
+ return false;
+ }
+ for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++) {
+ if (SDBuffer[i] != 0) {
+ clear_block = false;
+ pc.printf ("Buff at %d contains %x\r\n", i, SDBuffer[i]);
+ i = SD_BLOCKSIZE; // to exit loop
+ }
+ }
+ if (clear_block)
+ stab -= toaddsub;
+ else
+ stab += toaddsub;
+ toaddsub >>= 1;
+ }
+ if (!check_SD_block_clear(stab))
+ stab++;
+ if (sd_error()) { // sd_error() tests and clears error bits
+ pc.printf ("check_SD_block_clear(%ld)returned ERROR in SD_find_next_clear_block\r\n", stab);
+ sd_jf = 1; // reassert error flag
+ return false;
+ }
+ pc.printf ("Completed find_next, stab = %d\r\n", stab);
+ *blok = stab; // block number of next free block
+ return true;
+}
+
+bool SD_card_erase_all (void) { // assumes sd card is 4 Gbyte, erases 4 Gbyte. Called from CLI
+ uint64_t EndAddr = GIGAB * 4,
+ StartAddr = 0LL;
+ sd_jf = 0;
+ pc.printf ("Erasing SD card ... ");
+ // uint8_t Erase(uint64_t StartAddr, uint64_t EndAddr);
+ SD_state = sd.Erase(StartAddr, EndAddr);
+ if (SD_state != SD_OK) {
+ pc.printf ("SD_card_erase_all FAILED\r\n");
+ sd_jf = 1;
+ return false;
+ }
+ pc.printf ("no error detected\r\n");
+ return true;
+}
+
+
+bool mainSDtest()
+{
+ SD_state = sd.Init();
+ if(SD_state != SD_OK) {
+ pc.printf ("sd.Init set SD_state to %0x\r\n", SD_state);
+ if(SD_state == MSD_ERROR_SD_NOT_PRESENT) {
+ pc.printf("SD shall be inserted before running test\r\n");
+ } else {
+ pc.printf("SD Initialization : FAIL.\r\n");
+ }
+ pc.printf("SD Test Aborted.\r\n");
+ return false;
+ }
+// else { // SD_state is SD_OK
+ pc.printf("SD Initialization : OK.\r\n");
+
+
+
+// SD_card_erase_all();
+// if (sd_error())
+// pc.printf ("SD_card_erase_all() reports ERROR");
+
+
+
+ SD_find_next_clear_block(& SD_blockptr);
+ pc.printf ("SD_find_next_clear_block returned %lld\r\n\n\n", SD_blockptr);
+ if (sd_error()) {
+ pc.printf ("***** ERROR returned from SD_find_next_clear_block ***** SD ops aborted\r\n");
+ return false;
+ }
+ pc.printf("SD_find_next_clear_block() returned %ld\r\n", SD_blockptr);
+ if (SD_blockptr < 1) {
+ pc.printf ("Looks like card newly erased, SD_blockptr value of %d\r\n", SD_blockptr);
+ SD_blockptr = 0;
+ historic_distance = 0;
+ }
+ else {
+ SD_state = sd.ReadBlocks(SDBuffer, SD_BLOCKSIZE * (SD_blockptr - 1), SD_BLOCKSIZE, 1);
+ if (SD_state != SD_OK) {
+ pc.printf ("Error reading last block from SD block %d\r\n", SD_blockptr - 1);
+ return false;
+ }
+ for (int i = 0; i < (SD_BLOCKSIZE >> 2); i++)
+ pc.printf ("%lx\t", SDBuffer[i]);
+ historic_distance = SDBuffer[(SD_BLOCKSIZE >> 2) - 1];
+ pc.printf ("\r\nAbove, data read from last filled SD block %lld, using historic_distance = %lx\r\n", SD_blockptr - 1, historic_distance);
+ }
+ if (SD_blockptr > 2) {
+ for (int i = SD_blockptr - 2; i < SD_blockptr + 2; i++) {
+ pc.printf ("check_SD_block_clear (%d) ", i);
+ if (check_SD_block_clear(i))
+ pc.printf ("block %ld is CLEAR\r\n", i);
+ else
+ pc.printf ("block %ld is NOT clear\r\n", i);
+ if (sd_error()) {
+ pc.printf ("ERROR from check_SD_block_clear ()\r\n");
+ }
+ }
+ }
+ return true;
+}
+
+void update_SD_card () { // Hall pulse total updated once per sec and saved in blocks of 128 to SD card
+ static int index = 0;
+ static uint32_t buff[(SD_BLOCKSIZE >> 2) + 2];
+// buff[index++] = speed.pulse_total(); // pulse_total for all time, add this to buffer to write to SD
+ buff[index++] = get_pulse_total(); // pulse_total for all time, add this to buffer to write to SD
+ if (index >= (SD_BLOCKSIZE >> 2)) {
+ pc.printf ("Writing new SD block %d ... ", SD_blockptr);
+ SD_state = sd.WriteBlocks(buff, SD_BLOCKSIZE * SD_blockptr, SD_BLOCKSIZE, 1);
+ SD_blockptr++;
+ if (SD_state == SD_OK)
+ pc.printf ("OK, distance %d\r\n", buff[index - 1] / (int)PULSES_PER_METRE);
+ else
+ pc.printf ("ERROR\r\n");
+ index = 0;
+ }
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/throttle.cpp Mon Nov 13 09:53:00 2017 +0000
@@ -0,0 +1,56 @@
+/*
+This file about using model control servo to drive the throttle of Honda GX120 engine
+
+Using a model control servo to set the throttle of Honda GX120 petrol engine
+First thoughts 12 Nov 2017.
+
+Servo driven by positive pulse of duration 1000 to 2000 micro sec. Repetition rate 50Hz
+Will first try repeating in 32ms loop giving repetirion rate approx 30 Hz.
+Pos pulse generated by setting to 1 in 32ms handler and starting a 'timeout'
+
+ ... as part of 32ms code
+ if (torque_demand < 0.01) {
+ throttle (TICKOVER);
+ }
+ else { // got positive torque demand
+ throttle (MID_REVS);
+ }
+ throttle_servo_pulse_out = 1;
+ throttle_servo_pulse_width.attach_us (&servo_pulse_lo, global_throttle_us);
+*/
+#include "mbed.h"
+#include "Electric_Loco.h"
+
+static const int
+ SERVO_RANGE = 1000, // micro sec difference between max and min
+ SERVO_OFFSET = 1000, // min servo pulse width micro sec
+ TICKOVER = SERVO_OFFSET + 0,
+ MID_REVS = SERVO_OFFSET + 500,
+ RANGE_MULTIPLIER = SERVO_RANGE + SERVO_OFFSET - MID_REVS;
+
+DigitalOut throttle_servo_pulse_out (D8); // now defined in throttle.cpp
+
+Timeout throttle_servo_pulse_width;
+
+void throttle_servo_pulse_lo () { // Interrupt handler called at end of 'Timeout'
+ throttle_servo_pulse_out = 0; // end servo positive pulse
+}
+
+int throttle (double torque_demand, double speed_mph) { // called from main every 31ms
+ int duration_us;
+ if (throttle_servo_pulse_out != 0)
+ return -1; // pulse positive already
+ if (torque_demand < 0.01) {
+ duration_us = TICKOVER;
+ }
+ else { // got positive torque demand
+ double tmpd = torque_demand * RANGE_MULTIPLIER;
+ duration_us = MID_REVS + (int) tmpd;
+ }
+ throttle_servo_pulse_out = 1; // start servo positive pulse
+ throttle_servo_pulse_width.attach_us (&throttle_servo_pulse_lo, duration_us);
+ return 0;
+}
+// endof New Nov 2017 Controlling throttle of Honda engine
+
+