From a406e4031c7f55c626e1e2cf984a8c71b7ab1abf Mon Sep 17 00:00:00 2001 From: Sam Anthony Date: Mon, 10 Nov 2025 14:20:19 -0500 Subject: generate tachometer signal --- fw/main.c | 45 ++++++++++++++++++++++++++++++++------ fw/system.c | 4 ++++ fw/system.h | 4 ++++ fw/tests/system/tach_systest.c | 49 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 7 deletions(-) create mode 100644 fw/tests/system/tach_systest.c diff --git a/fw/main.c b/fw/main.c index d04b6d0..512a881 100644 --- a/fw/main.c +++ b/fw/main.c @@ -14,6 +14,8 @@ #include "serial.h" #include "table.h" +#define ERR __LINE__ + // TODO: auto baud detection #define CAN_TIMING CAN_TIMING_10K @@ -21,7 +23,12 @@ #define SIG_CTRL_CAN_ID 0x1272100 // Signal Control Frame ID #define ERR_CAN_ID 0x1272F00 -#define ERR __LINE__ +// (pulse/min) = 60 * (Fosc/4) / ((pre)*(post)*(2^16 - TMR1)) +// = 60 * (48e6/4) / (8*6*(2^16 - TMR1)) +// = 15000000 / (2^16 - TMR1) +#define TACH_FACTOR 15000000ul +#define TMR1_POST 6u // TMR1 postscaler -- must be multiple of 2 +#define EDGE_PER_PULSE 2u // rising and falling edge // Signals typedef enum { @@ -87,6 +94,8 @@ static const EepromAddr sigFmtAddrs[NSIG] = { // Encoding format and CAN ID of each signal static volatile SigFmt sigFmts[NSIG]; +static volatile U16 tmr1Start = 0u; + // Load signals' encoding formats and CAN IDs from EEPROM static Status loadSigFmts(void) { @@ -157,12 +166,16 @@ main(void) { reset(); } + // Setup TMR1 for tachometer + T1CON = 0x31; // source=Fosc/4, prescaler=1:8, enable=1 + // Enable interrupts INTCON = 0x00; // clear flags OPTION_REGbits.INTEDG = 0; // interrupt on falling edge of INT pin - INTCONbits.INTE = 1; // enable INT pin - INTCONbits.PEIE = 1; // enable peripheral interrupts - INTCONbits.GIE = 1; // enable global interrupts + INTE = 1; // enable INT pin + TMR1IE = 1; // enable TMR1 interrupts + PEIE = 1; // enable peripheral interrupts + GIE = 1; // enable global interrupts for (;;) { @@ -309,6 +322,12 @@ handleSigCtrlFrame(const CanFrame *frame) { } } +// Set frequency of tachometer output signal. +static void +driveTach(U16 pulsePerMin) { + tmr1Start = (((U32)1ul<<16u) - (U32)TACH_FACTOR / (U32)pulsePerMin) & 0xFFFF; +} + // Generate the output signal being sent to one of the gauges. // Raw is the raw signal value extracted from a CAN frame. static Status @@ -339,7 +358,7 @@ driveGauge(Signal sig, I32 raw) { switch (sig) { case SIG_TACH: - // TODO + driveTach(val); break; case SIG_SPEED: // TODO @@ -361,6 +380,7 @@ driveGauge(Signal sig, I32 raw) { } // TODO + return OK; } // Handle a frame potentially holding a signal value. @@ -390,11 +410,13 @@ handleSigFrame(const CanFrame *frame) { void __interrupt() isr(void) { + static U8 tmr1Ctr = 0u; + U8 rxStatus; CanFrame frame; Status status; - if (INTCONbits.INTF) { // CAN interrupt + if (INTF) { // CAN interrupt rxStatus = canRxStatus(); switch (rxStatus & 0x7) { // check filter hit case 0u: // RXF0: calibration table control @@ -415,6 +437,15 @@ __interrupt() isr(void) { canReadRxb1(&frame); (void)handleSigFrame(&frame); } - INTCONbits.INTF = 0; // clear flag + INTF = 0; // clear flag + } + if (TMR1IF) { // tachometer + if (++tmr1Ctr == (TMR1_POST/EDGE_PER_PULSE)) { + tmr1Ctr = 0u; + TACH_PIN ^= 1; // toggle tach output + } + TMR1H = (tmr1Start>>8u)&0xFF; // reset timer + TMR1L = (tmr1Start>>0u)&0xFF; + TMR1IF = 0; } } diff --git a/fw/system.c b/fw/system.c index 5f7bbb4..7921d5a 100644 --- a/fw/system.c +++ b/fw/system.c @@ -33,4 +33,8 @@ sysInit(void) { ANSELA = 0; ANSELB = 0; ANSELC = 0; + + // Init pins + TACH_TRIS = OUT; + TACH_PIN = 0; } diff --git a/fw/system.h b/fw/system.h index acd59df..897a4b4 100644 --- a/fw/system.h +++ b/fw/system.h @@ -3,6 +3,10 @@ #include "fixed_address_memory.h" +// Pins +#define TACH_PIN RC3 +#define TACH_TRIS TRISC3 + // TRIS enum { OUT = 0, diff --git a/fw/tests/system/tach_systest.c b/fw/tests/system/tach_systest.c new file mode 100644 index 0000000..db65500 --- /dev/null +++ b/fw/tests/system/tach_systest.c @@ -0,0 +1,49 @@ +#include + +#include + +#include "system.h" +#include "types.h" + +// (pulse/min) = 60 * (Fosc/4) / ((pre)*(post)*(2^16 - TMR1)) +// = 60 * (48e6/4) / (8*6*(2^16 - TMR1)) +// = 15000000 / (2^16 - TMR1) +#define TACH_FACTOR 15000000ul +#define TMR1_POST 6u // TMR1 postscaler -- must be multiple of 2 +#define EDGE_PER_PULSE 2u // rising and falling edge + +static volatile U16 tmr1Start = 0u; + +void +main(void) { + sysInit(); + + U16 pulsePerMin = 2500u; + tmr1Start = (((U32)1ul<<16u) - (U32)TACH_FACTOR / (U32)pulsePerMin) & 0xFFFF; + + T1CON = 0x31; // source=Fosc/4, prescaler=1:8, enable=1 + + INTCON = 0x00; + PIE1bits.TMR1IE = 1; + INTCONbits.PEIE = 1; + INTCONbits.GIE = 1; + + for (;;) { + + } +} + +void __interrupt() +isr(void) { + static U8 tmr1Ctr = 0u; + + if (TMR1IF) { // tachometer + if (++tmr1Ctr == (TMR1_POST/EDGE_PER_PULSE)) { + tmr1Ctr = 0u; + TACH_PIN ^= 1; // toggle tachometer output + } + TMR1H = (tmr1Start>>8u)&0xFF; // reset timer + TMR1L = (tmr1Start>>0u)&0xFF; + TMR1IF = 0; + } +} -- cgit v1.2.3