Using an ATtiny MCU to measure video signal timings (questions about Comparator, Interrupts and Timers) #1132
Replies: 1 comment
-
I've spent some time re-reading the documentation and finding snippets of code to figure out how to some of the things I've mentioned above. I've managed to have something that starts approaching what I want to achieve. The following code measures the length of the horizontal sync pulses (with some code to deal with small variations in the measured times), and transmits the values over serial. #include <Comparator.h>
void setup() {
pinMode(PIN_PA1, OUTPUT);
digitalWriteFast(PIN_PA1, LOW);
Serial.begin(230400);
Comparator.input_p = comparator::in_p::in0;
Comparator.input_n = comparator::in_n::in0;
Comparator.output = out::enable;
Comparator.output_initval = out::init_low;
EVSYS.ASYNCCH0 = EVSYS_ASYNCCH0_AC0_OUT_gc;
EVSYS.ASYNCUSER0 = EVSYS_ASYNCUSER0_ASYNCCH0_gc;
TCB0.CTRLA = TCB_CLKSEL_CLKDIV1_gc | TCB_ENABLE_bm;
TCB0.CNT = 0;
TCB0.CTRLB |= TCB_CNTMODE_FRQ_gc;
TCB0.CCMP = 0xFFFFu;
TCB0.EVCTRL |= TCB_EDGE_bm | TCB_CAPTEI_bm;
TCB0.INTCTRL |= TCB_CAPT_bm;
TCB0.CTRLA |= 0x01;
Comparator.init();
Comparator.start();
}
volatile bool changed = false;
volatile uint16_t time = 0;
volatile uint16_t current = 0;
volatile uint16_t lines = 0;
volatile uint16_t prev_time = 0;
volatile uint16_t prev_lines = 0;
void loop() {
if (changed) {
Serial.print("t: ");
Serial.print(prev_time);
Serial.print("\tl: ");
Serial.println(prev_lines);
changed = false;
}
}
ISR(TCB0_INT_vect) {
time = TCB0_CCMP;
uint16_t test = ((time + 0x7) - current) >> 4; // To consider equal values that are within ±7 of 'current'
if (test != 0) {
prev_time = current;
prev_lines = lines;
current = time;
lines = 1;
changed = true;
} else {
lines++;
}
} This is the output I get for this code and a valid 576i PAL video signal:
For a full frame, I have 305 + 305 + (14 + 16) / 2 = 625. Next I'll have to check if this works with other / higher resolution signals, figure out a way to know if we are currently during vsync, and detect if it is an interlaced signal (differentiate odd and even lines). |
Beta Was this translation helpful? Give feedback.
-
Hello,
First, thanks to @SpenceKonde and all the other contributors for this incredible core. It makes people such as me that don't have any experience programming microcontrollers less daunting.
I'm trying to use an ATtiny MCU to detect a valid analog video composite sync signal (a composite sync signal is just horizontal and vertical sync combined with a few tricks). I'm currently using an ATtiny404 running at 20MHz.
For those that don't know how it looks like, here are examples of an analog video signal with composite sync for SD and HD (in order from top to bottom: 480i, 480p and 720/1080p):
The sync pulse having a negative voltage (the positive part of the signal being the video lines themselves), I've made a small circuit to adapt the signal to be fully positive, then I use the analog comparator from the MCU to detect changes in the sync signal.
As a start I've tried the following code:
I got this result (screenshot from an oscilloscope, the yellow signal is the video signal, the blue signal is the output from the GPIO):
So I know that my circuit and the analog comparator work.
Then I've tried this, but it doesn't seem to work, I guess having separate interrupts for
RISING
andFALLING
is not allowed by the hardware? :Next I tried a different method:
However, it wouldn't work for some of the shorter pulses during vertical sync (but not all of them, it's strange):
I've read that using
attachInterrupt()
is supposed to be slower than using theISR
macro. How can I use the faster macro instead with the comparator? Will it be fast enough? Is the fastest code to just poll the comparator state as in my initial code and detect signal rise and fall manually? What is the most appropriate way?Ideally, what I'd like, is to detect if it is some kind of valid video sync signal and measure the horizontal and vertical sync frequencies (that way I can know the resolution and refresh rate of the signal).
I guess the first thing to do would be to measure the time between each pulse. To have an idea of the actual timings to measure, the duration of each line (
H
) goes from ~64 usecs (~1280 clock cycles) for 480i to ~15 usecs (~300 clock cycles) for 1080p.Instead of using
micros()
, I need a more precise way to measure the timings. From my understanding, the maximum precision I can have with the MCU running at 20MHz is the time of one clock cycle, which is 0.05 usec. Is there a way to set up one of the timers to count clock cycles, reset it to 0 when I want to start measuring again and to know if it overflowed?In the datasheet, it says it should be even possible to use the event system to combine the output of the analog comparator with one of the timers. The problem is that I can't find any code examples doing this kind of stuff, I don't even know where to begin.
Thank you for your help.
Beta Was this translation helpful? Give feedback.
All reactions