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);
}
}