0
\$\begingroup\$

Ive made a code for reading SENT sensor using TCB interrupt with event system. It works 90% of the time, but those 10% seems like it doesnt read correct high pulse duration, mby someone will see, what Im missing or have done incorretly

#define SAMPLES 40
#define TIMER_RESOLUTION 0.04166666666  // Timer resolution in microseconds
#define NEXT_PULSES_TO_PRINT 8    // Number of subsequent high and low pulses to print

volatile float highPulseBuff[SAMPLES] = {0};
volatile float lowPulseBuff[SAMPLES] = {0};
volatile bool pulseCaptured = false;
float oneTick = 0;

void TCB_init(void) {
    TCB0.CTRLB = TCB_CNTMODE_CAPT_gc;

// Enable input capture
TCB0.EVCTRL = TCB_CAPTEI_bm; // Enable Event Input

// Configure Event System to connect the PA6 pin to TCB
EVSYS.CHANNEL0 = EVSYS_CHANNEL0_PORTA_PIN6_gc;
EVSYS.USERTCB0CAPT = 0x01;

// Enable TCB interrupt
TCB0.INTCTRL = TCB_CAPT_bm;

// Enable TCB
TCB0.CTRLA = TCB_ENABLE_bm;

// Enable global interrupts
sei();
}

 // Interrupt Service Routine for TCB0 Capture interrupt

 ISR(TCB0_INT_vect) {
static uint16_t lastCapture = 0;
static uint8_t idx = 0;
uint16_t capture = TCB0.CNT; // Read the input capture register of TCB0
uint16_t duration;

// Handle overflow
if (capture >= lastCapture) {
    duration = capture - lastCapture;
} else {
    duration = (0xFFFF - lastCapture) + capture + 1; // Assuming a 16-bit counter
}

lastCapture = capture;

if (TCB0.EVCTRL & TCB_EDGE_bm) {
    // Rising edge detected, so this is the end of the low pulse
    if (idx < SAMPLES) {
        highPulseBuff[idx] = duration;
    }
} else {
    // Falling edge detected, so this is the end of the high pulse
    if (idx < SAMPLES) {
        lowPulseBuff[idx] = duration;
        idx++;
        if (idx >= SAMPLES) {
            pulseCaptured = true;
            idx = 0; // Reset index to prevent overflow
        }
    }
}

// Toggle edge detection
TCB0.EVCTRL ^= TCB_EDGE_bm;
TCB0.INTFLAGS = TCB_CAPT_bm; // Clear the interrupt flag
}

 unsigned int combineDataNibbles(unsigned int d4, unsigned int d5, unsigned int d6) {
return (d4 << 8) | (d5 << 4) | d6;
}

void decode_sent() {
static uint8_t dataFrame[8] = {0};
static float oneTickPeriods = 0;

if (pulseCaptured) {
    // Disable interrupts temporarily to safely read shared variables
    TCB0.EVCTRL &= ~TCB_CAPTEI_bm;
    TCB0.CTRLA &= ~TCB_ENABLE_bm;

    static bool foundSync = false;
    int syncIndex = -1;

    print("\r\n");
    print("pulseCaptured!");
    print("\r\n");

    // Search for the sync pulse based on duty ratio criteria
    for (int i = 0; i < SAMPLES; i++) {
        // Calculate duty ratio (high / (high + low))
        float dutyRatio = (float) highPulseBuff[i] / ((float) highPulseBuff[i] + (float)         lowPulseBuff[i]);

        print("H: ");
        print_float(highPulseBuff[i] * TIMER_RESOLUTION);
        print(" L: ");
        print_float(lowPulseBuff[i] * TIMER_RESOLUTION);
        print("\r\n");

        // Check if duty ratio meets criteria (approx. 0.89 with wiggle room)
        if (dutyRatio >= 0.90 * 0.99 && dutyRatio <= 0.90 * 1.01 && ((float) highPulseBuff[i] * TIMER_RESOLUTION) + ((float) lowPulseBuff[i]) * TIMER_RESOLUTION < 180) { // Adding a 1% wiggle room
            float totalPulseDurations = ((float) highPulseBuff[i] * TIMER_RESOLUTION) + ((float) lowPulseBuff[i] * TIMER_RESOLUTION);
            oneTickPeriods = totalPulseDurations / 56.0f;

            if (i < 11) {
                print("---Sync--- ");
                print_float(dutyRatio);
                print("\r\n");
                foundSync = true;
                syncIndex = i;
                break;
            } else {
                print("----------");
                print("\r\n");
            }
        }
    }

    //        print("\r\n");

    if (foundSync && syncIndex != -1) {
        // Print the next 8 sets of high and low pulses
        for (int j = syncIndex + 1; j < syncIndex + 1 + NEXT_PULSES_TO_PRINT && j < SAMPLES; j++) {
            float totalPulseDuration = ((float) highPulseBuff[j] * TIMER_RESOLUTION) + ((float) lowPulseBuff[j] * TIMER_RESOLUTION);
            float ticks = (totalPulseDuration / oneTickPeriods) - 12.0f;

            print("H: ");
            print_float(highPulseBuff[j] * TIMER_RESOLUTION);
            print(" L: ");
            print_float(lowPulseBuff[j] * TIMER_RESOLUTION);
            print(" D: ");
            print_float(totalPulseDuration);
            print(" T: ");
            print_float(oneTickPeriods);


            if ((uint8_t) round(ticks) < 16) {
                dataFrame[j - syncIndex - 1] = (uint8_t) round(ticks);
            }
            print(" HEX: ");
            print_hex(dataFrame[j - syncIndex - 1]);
            print("\r\n");

        }

        print(" D1: ");
        sent_pressure = combineDataNibbles(dataFrame[1], dataFrame[2], dataFrame[3]);
        print_int(sent_pressure);
        print(" D2: ");
        sent_temperature = combineDataNibbles(dataFrame[6], dataFrame[5], dataFrame[4]);
        print_int(sent_temperature);
        print("\r\n");
        //            }
    } else {
        foundSync = false;
    }

    // Reset variables and enable interrupts
    cli();
    TCB0.CNT = 0;
    pulseCaptured = false;
    TCB0.CTRLA = TCB_ENABLE_bm;
    TCB0.EVCTRL = TCB_CAPTEI_bm;
    sei();
}
}

 int main(void) {
// Initialize PA6 and TCB
/* Set OSCHF as main clock source */
_PROTECTED_WRITE(CLKCTRL.MCLKCTRLA, CLKCTRL_CLKSEL_OSCHF_gc);

/* Wait for main clock oscillator changing to finish */
while (CLKCTRL.MCLKSTATUS & CLKCTRL_SOSC_bm) {
    ;
}

/* Change OSCHF frequency to 24 MHz */
_PROTECTED_WRITE(CLKCTRL.OSCHFCTRLA, CLKCTRL_FRQSEL_24M_gc);

PA6_init();
TCB_init();
USART2_init(1000000);
while (1) {
    decode_sent();
    _delay_ms(10);
}
 }
\$\endgroup\$
4
  • \$\begingroup\$ Rule #1 for ISR, keep it as short as possible. Rule#2, don't do print to USART within ISR. \$\endgroup\$
    – hcheung
    Commented Jul 5 at 14:27
  • \$\begingroup\$ Where do i print in ISR? \$\endgroup\$ Commented Jul 9 at 19:07
  • \$\begingroup\$ If you ask such an question, then maybe you need to read Nick Gammon on interrupts. \$\endgroup\$
    – hcheung
    Commented Jul 9 at 23:07
  • \$\begingroup\$ Use TCB in "Input Capture Pulse-Width Measurement mode". It significantly simplifies your code and removes many potential problems (race conditions etc.) coming from your actual approach (using pure input capture). \$\endgroup\$ Commented Jul 11 at 16:00

0

Browse other questions tagged or ask your own question.