Hello all you FlexIO people. I've started diving into this, and I believe I understand about half of how to use this subsystem.
I could use some help because I can't quite figure out how to accomplish a certain task.
The goal:
Detect a high-to-low transition on a pin and trigger a timer output that stays asserted when the input stays low for at least 50us.
I figured that these must be the details for a FlexIO timer configuration (these are my working assumptions):
1. Enable on negative input edge (i.e. reverse trigger polarity)
2. Disable on positive input edge (i.e. reverse trigger polarity)
3. Use a 20MHz frequency (480MHz / 8 / 3) (50ns cycle time)
4. 50us is 1000 timer cycles (that's 20000 complete iterations a second)
I wrote a program that watches interrupts so that each time the timer status flag is set due to a timer reset, a counter is incremented. In the main loop, I print the interrupt count and I'm seeing the number increment by about 20000 per second, which is expected if the timer keeps running when the input signal is low, but I'd rather have the interrupt trigger once, once the input low time reached 50us.
What my program does correctly:
1. Start the timer on negative input edge
2. Stop the timer on positive input edge
3. Each second shows about 20000 interrupt counts (correct if I wanted the timer to keep running, and I don't). The count should be 1 if there's been one pulse >= 50us.
What my program does not do correctly:
1. Interrupts are triggered every 50us (i.e. every complete timer cycle) and I want it to be one-shot until the input goes low again. i.e. if the low pulse only happens once, even if it's longer than 50us, then the interrupt count should be 1.
What I don't understand:
1. The FLEXIO_TIMCFG_TIMOUT configuration talks about things like "Timer output is logic zero when enabled and is not affected by timer reset" and "Timer output is logic zero when enabled and on timer reset". This is confusing language because the "Timer 16-bit Counter Mode" section says that "When the 16-bit counter equals zero and decrements, the timer output toggles and the counter reloads from the compare register. A timer compare event occurs when the 16-bit counter equals zero and decrements. The timer status flag is set on a timer compare event."
If the timer output toggles, then what does "Timer output is logic zero when enabled and on timer reset" mean? Does it mean the output is logic zero on reset, or is that sentence supposed to read "Timer output is logic zero when enabled and toggles on timer reset"? Also, should "Timer output is logic zero when enabled and is not affected by timer reset" read as: "Timer output is logic zero when enabled and is not toggled by timer reset"?
In other words, how does a timer reset affect toggling its output? I'm confused by how TIMOUT is supposed to work.
2. Shouldn't TIMRST set to "Never reset" stop the timer from resetting?
3. Is it possible to treat the timer as a one-shot and to somehow disable it when a condition is met, such as the timer running out? How do I get the status to stop triggering the interrupt?
Here's my test code:
Note: Setting TIMOUT to this doesn't work either:
Thank you in advance for any suggestions or assistance.
I could use some help because I can't quite figure out how to accomplish a certain task.
The goal:
Detect a high-to-low transition on a pin and trigger a timer output that stays asserted when the input stays low for at least 50us.
I figured that these must be the details for a FlexIO timer configuration (these are my working assumptions):
1. Enable on negative input edge (i.e. reverse trigger polarity)
2. Disable on positive input edge (i.e. reverse trigger polarity)
3. Use a 20MHz frequency (480MHz / 8 / 3) (50ns cycle time)
4. 50us is 1000 timer cycles (that's 20000 complete iterations a second)
I wrote a program that watches interrupts so that each time the timer status flag is set due to a timer reset, a counter is incremented. In the main loop, I print the interrupt count and I'm seeing the number increment by about 20000 per second, which is expected if the timer keeps running when the input signal is low, but I'd rather have the interrupt trigger once, once the input low time reached 50us.
What my program does correctly:
1. Start the timer on negative input edge
2. Stop the timer on positive input edge
3. Each second shows about 20000 interrupt counts (correct if I wanted the timer to keep running, and I don't). The count should be 1 if there's been one pulse >= 50us.
What my program does not do correctly:
1. Interrupts are triggered every 50us (i.e. every complete timer cycle) and I want it to be one-shot until the input goes low again. i.e. if the low pulse only happens once, even if it's longer than 50us, then the interrupt count should be 1.
What I don't understand:
1. The FLEXIO_TIMCFG_TIMOUT configuration talks about things like "Timer output is logic zero when enabled and is not affected by timer reset" and "Timer output is logic zero when enabled and on timer reset". This is confusing language because the "Timer 16-bit Counter Mode" section says that "When the 16-bit counter equals zero and decrements, the timer output toggles and the counter reloads from the compare register. A timer compare event occurs when the 16-bit counter equals zero and decrements. The timer status flag is set on a timer compare event."
If the timer output toggles, then what does "Timer output is logic zero when enabled and on timer reset" mean? Does it mean the output is logic zero on reset, or is that sentence supposed to read "Timer output is logic zero when enabled and toggles on timer reset"? Also, should "Timer output is logic zero when enabled and is not affected by timer reset" read as: "Timer output is logic zero when enabled and is not toggled by timer reset"?
In other words, how does a timer reset affect toggling its output? I'm confused by how TIMOUT is supposed to work.
2. Shouldn't TIMRST set to "Never reset" stop the timer from resetting?
3. Is it possible to treat the timer as a one-shot and to somehow disable it when a condition is met, such as the timer running out? How do I get the status to stop triggering the interrupt?
Here's my test code:
Code:
// See also:
// * https://forum.pjrc.com/threads/66201-Teensy-4-1-How-to-start-using-FlexIO
// Goal:
// When an input goes low for a certain number of cycles, have a timer
// assert and stay asserted until the input goes high.
// Details:
// 1. Use FlexIO2 pin 0 (Teensy 4.1 pin 10)
// 2. Want to detect low for at least 1000 cycles at 20MHz
// (That's 20000 interrupts a second if the timer was
// continuously resetting)
// 3. Enable the timer when the pin goes low
// 4. Disable the timer when the pin goes high
// 5. Keep timer asserted and stop triggering interrupts after timer
// output goes high, and before the input pin goes high
#define CLRSET(reg, clear, set) ((reg) = ((reg) & ~(clear)) | (set))
// Forward declarations
void isr();
// Main program setup.
void setup() {
Serial.begin(115200);
while (!Serial && millis() < 4000) {
// Wait for serial
}
delay(2000);
printf("Starting...\r\n");
// Configure frequency for 20MHz (480MHz/24)
CLRSET(CCM_CS1CDR,
CCM_CS1CDR_FLEXIO2_CLK_PODF(7) | CCM_CS1CDR_FLEXIO2_CLK_PRED(7),
CCM_CS1CDR_FLEXIO2_CLK_PODF(7) | CCM_CS1CDR_FLEXIO2_CLK_PRED(2)); // /3 then /8
// Turn on FlexIO2 clock
CCM_CCGR3 |= CCM_CCGR3_FLEXIO2(CCM_CCGR_ON);
// Configure Timer 4
FLEXIO2_TIMCTL4 = FLEXIO_TIMCTL_TRGSEL(0) | // Pin 0 trigger
FLEXIO_TIMCTL_TRGSRC | // Internal trigger
FLEXIO_TIMCTL_TRGPOL | // Trigger active low
FLEXIO_TIMCTL_PINCFG(0) | // Pin output disabled
FLEXIO_TIMCTL_PINSEL(0) | // Which pin
FLEXIO_TIMCTL_TIMOD(3); // Single 16-bit counter
FLEXIO2_TIMCFG4 = FLEXIO_TIMCFG_TIMOUT(3) | // Zero when enabled, and on reset (is this correct?)
FLEXIO_TIMCFG_TIMDEC(0) | // Decrement on clock
FLEXIO_TIMCFG_TIMRST(0) | // Never reset
FLEXIO_TIMCFG_TIMDIS(6) | // Disabled on trigger falling edge (low->high for inverted)
FLEXIO_TIMCFG_TIMENA(6); // Enabled on trigger rising edge (high->low for inverted)
FLEXIO2_TIMCMP4 = 1000;
CLRSET(FLEXIO2_TIMIEN, 0xff, (1 << 4)); // Enable interrupts for Timer 4
// Pin control - configure Teensy pin 10 as FlexIO2 pin 0
// Start experiment with nothing connected and with the pin at high
// There's no interrupts when the pin is high, as expected
// There are regular interrupts when the pin is low. Why do
// interrupts keep getting generated if the timer is configured to
// never reset?
pinMode(10, INPUT_PULLUP);
IOMUXC_SW_MUX_CTL_PAD_GPIO_B0_00 = 4; // ALT4, FLEXIO2_FLEXIO00
// Attach FlexIO2 interrupt
attachInterruptVector(IRQ_FLEXIO2, isr);
NVIC_ENABLE_IRQ(IRQ_FLEXIO2);
// Turn FlexIO2 on
FLEXIO2_CTRL |= FLEXIO_CTRL_FLEXEN;
}
// Interrupt counter.
static volatile uint32_t counter = 0;
// Handles FlexIO interrupt.
void isr() {
uint32_t status = FLEXIO2_TIMSTAT & 0xff;
FLEXIO2_TIMSTAT = status; // Clear all the interrupts
if (status & (1 << 4)) { // Timer 4 triggered?
counter++;
}
asm volatile ("dsb");
}
// Main program loop.
void loop() {
// Print the interrupt count every second
printf("%" PRIu32 "\r\n", counter);
delay(1000);
}
Note: Setting TIMOUT to this doesn't work either:
Code:
FLEXIO_TIMCFG_TIMOUT(1) | // Zero when enabled, not affected by reset
Thank you in advance for any suggestions or assistance.
Last edited: