An attempt to build an Engine Control Unit based on stm32.
It's really not that hard.

Now that we have RPM value let's display it nicely. Instead of inventing a bicycle, we can use TunerStudio - it has a free Lite version, it's multi-platform and it's just the right tool for the job! Phil from EFI Analytics has helper me with a minimal configuration file:

[TunerStudio]
   queryCommand   = "H"
   signature    = "MShift v0.01" ; signature is expected to be 7 or more characters.

[Constants]
   endianness          = little
   nPages              = 1
   pageSize            = 128
   pageReadCommand     = "C"

[OutputChannels]
   ochGetCommand    = "O"
   ochBlockSize     =  4
   ;  name            = class,  type, offset,      shape,  units,       scale, translate,    lo,      hi, digits
      rpm             = scalar,  U32,      0,             "RPM",      1.00000,   0.00000,  0.00,  3000.0,      0 ; * (  4 bytes)

[TableEditor]

[FrontPage]
   ; Gauges are numbered left to right, top to bottom.
   ;    1  2  3  4
   ;    5  6  7  8
   ; currently a minimum of 6 gauges must be on the dash, this appears to be an old not needed limitation. next release 1 will work.
   gauge1 = tachometer
   gauge2 = tachometer
   gauge3 = tachometer
   gauge4 = tachometer
   gauge5 = tachometer
   gauge6 = tachometer

[GaugeConfigurations]
   ;Name               Var            Title                 Units     Lo     Hi     LoD    LoW   HiW   HiD vd ld
   tachometer        = rpm,           "Engine Speed",       "RPM",     0,  8000,    200,   500, 6000, 6000, 0, 0

[Menu]


Since we have already used serial-over-usb port for debug messages, we would need a $3 uart USB module to support the second communication channel.

Now with just a page of code we implemet the protocol
static SerialConfig tsSerialConfig = { TS_SERIAL_SPEED, 0, USART_CR2_STOP1_BITS | USART_CR2_LINEN, 0 };

typedef struct {
    int rpm;
} TunerStudioOutputChannels;

TunerStudioOutputChannels tsOutputChannels;
// values within this array are not used yet
static char constants[128];

static void handleHelloCommand() {
    chprintf(CONSOLE_DEVICE, "got H (Hello)\r\n");
    chSequentialStreamWrite(TS_SERIAL_DEVICE, SIGNATURE, strlen(SIGNATURE) + 1);
}

static void handleOutputChannelsCommand() {
    chSequentialStreamWrite(TS_SERIAL_DEVICE, &tsOutputChannels, sizeof(tsOutputChannels));
}

static void handleConstantsCommand() {
    chprintf(CONSOLE_DEVICE, "got C (Constants)\r\n");
    chSequentialStreamWrite(TS_SERIAL_DEVICE, constants, 128);
}

static void handleTSCommand(short code) {
    if (code == 'H') {
        handleHelloCommand();
    } else if (code == 'O') {
        handleOutputChannelsCommand();
    } else if (code == 'C') {
        handleConstantsCommand();
    } else {
        chprintf(CONSOLE_DEVICE, "got unexpected command %c:%d\r\n", code, code);
    }
}

static msg_t tsThreadEntryPoint(void *arg) {
    (void) arg;
    chRegSetThreadName("tunerstudio thread");

    while (true) {
        short code = (short) chSequentialStreamGet(TS_SERIAL_DEVICE);
        handleTSCommand(code);
    }
    return 0;
}

void startTunerStudioConnectivity(void) {
    palSetPadMode(TS_SERIAL_PORT, TS_SERIAL_RX_PIN, PAL_MODE_ALTERNATE(7));
    palSetPadMode(TS_SERIAL_PORT, TS_SERIAL_TX_PIN, PAL_MODE_ALTERNATE(7));

    sdStart(TS_SERIAL_DEVICE, &tsSerialConfig);

    chThdCreateStatic(TS_WORKING_AREA, sizeof(TS_WORKING_AREA), NORMALPRIO, tsThreadEntryPoint, NULL);
}

int main(void) {
    halInit();
    chSysInit();

    // serial-over-usb initialization
    usb_serial_start();

    // configure input signal pin
    palSetPadMode(CRANK_INPUT_PORT, CRANK_INPUT_PIN, PAL_MODE_ALTERNATE(GPIO_AF_TIM2));

    // start input capture - we will handle input events and calculate RPM based on the timestamps
    icuStart(&CRANK_DRIVER, &wave_icucfg);
    icuEnable(&CRANK_DRIVER);

    startTunerStudioConnectivity();

    while (TRUE) {
        // RPM value is updated by the input event handler
        chprintf(&SDU1, "rpm: %d\r\n", rpm);
        tsOutputChannels.rpm = rpm;
        chThdSleep(100);
    }

    return 0;
}

Voila, instant gratification


It really isn't that hard, right?
Here is the whole project source: tachometer_ts.zip


Comments?

Copyright (c) 2012-2013 Andrey