Timers and Interrupts (to output to Composite or VGA) #202
Replies: 15 comments 26 replies
-
So you say it needs to run at 55 kHz. 55 iterations per ms - 18us is like 430+ clock cycles, even limiting yourself to the rated maximum speed of 24 MHz, (and these parts overclock crazy well, particularly the extended temperature range ones. What do the signals you need to generate look like? I'm not familiar with that sort of video stuff. I've always been more of a fan of monochrome LCDs for microcontroller output, with nice digital interfaces and an absence of demanding timing constraints... BTW - a general rule is that if you're "looking for things to add" to a design, you should ask yourself why you're doing that. The impulse to add features is often something that is counterproductive. |
Beta Was this translation helpful? Give feedback.
-
You need to takeOverTCA0(); at the start - that does the hard reset, and tells the core to stop fucking with it. The core configures TCA0 for split mode, you're using it as if it were in single mode. , where it acts as two 8-bit timers that only downcount, run from the same oprescaled clock, but can have different periods. I suspect there are some ways that the hardware could be convinced to make your life a lot easier - do you have any scope tracces of what the signal youwant to get out of it looks liker? these parts have all kinds of ways to do cool stuff without CPU interaction through the event system... |
Beta Was this translation helpful? Give feedback.
-
two 8-bit downcounting timers with separate periods but same prescaler is better than a 16-bit one? okay then - I would have assumed the opposite, and that you'd want to use takeOverTCA0 to put it back into single mode. Depending on what the signal has to look like, there are probably ways that magic could be worked with the CCL (driven from internal sources) or maybe an SPI peripheral running as slave in buffered mode (in slave mode, if you control the clock, you effectively have a shift register and can write bits 8 at a time and shift them out on some other clock. I still haven't gotten around to trying that for neopixels.... I'm pretty confident it will work though. |
Beta Was this translation helpful? Give feedback.
-
I do have my timer -> interrupt example working for Low Undercount interrupt. Practical result is that the service routine runs at the start of and in sync with PD2 going high. Useful for resetting the pixel count on horizontal scan.
PA5 is on the bottom. |
Beta Was this translation helpful? Give feedback.
-
Here's the timer to Overflow interrupt in SINGLE mode. My frequency counter came up with 9.378KHz for PD1. Example 8 will be using a CMP1 interrupt (I hope).
|
Beta Was this translation helpful? Give feedback.
-
So Example 8....Timer in Single mode, now configured like an NTSC horizontal sync pulse. Interrupt should be firing when the pulse goes low. What use case this would be for I have no idea, but here you go....Interrupt at CMP1. Sorry that PA0 looks so messy, I bought this scope in 1984. Next up...two clocks...HSync and Pixel Clock...
|
Beta Was this translation helpful? Give feedback.
-
Example 9: HSync on PD2, and an interrupt to fire 5 times per HSync....I need a SPI clock however. Example 9 just shows a toggle on PA5...I'll add the SPI push for Example 10.
|
Beta Was this translation helpful? Give feedback.
-
Example 11: Creating an event that will "follow" PD3 that is running at 325KHz. This uses the "Simple Event" example in the Events library, modified so that it works on an AVR128DB28.
|
Beta Was this translation helpful? Give feedback.
-
You should TOTALLY check out the logic library..... it is in many ways more poweful Like, I think this will do much the same thing without the second pin. - only it also gives you two more inputs you could use for control... See also Logic examples like LatchNoSeq where you can use pulse event s to latch a logic block into one position or the other
|
Beta Was this translation helpful? Give feedback.
-
SPI0.CTRLB = 0b110000xx where xx is mode, drive SS low while you want to output bytes.... those first two bits enable buffered mode and turn off wairt for resceive so the first byte isn't a dummy byte, then either enable DREIE or poll DREIF to know when there's room in the SPI buffer.... |
Beta Was this translation helpful? Give feedback.
-
I'm going to wrapper
|
Beta Was this translation helpful? Give feedback.
-
Vertical Sync works, and I've established where I can start shuffling out bits that represent pixels, and storing it via making that array bigger.
|
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
I now have the C++ code rendering straight from memory, and now need to convert it to ASM so that I can control the timing. We'll see if I can increase the number of characters...best I can do is 14 columns.
|
Beta Was this translation helpful? Give feedback.
-
So after 3 weeks (spent reading up how to do and practicing inline ASM), here's is my first UNTESTED run at creating the bit-banging loop:
Note that I've removed the artifact of always writing TVCOMP as a high. I've also added the number of instruction cycles for each instruction, as I'll have to add NOPs to make sure there is no difference in timing as the next character is fetched. |
Beta Was this translation helpful? Give feedback.
-
I'm thoroughly hooked on the AVR128DB as a great upgrade to the now venerable ATMega328 and ATMega2560. I have a business card sized circuit board that mostly works, and I am looking to see what else I should put on it. What came immediately to mind was some sort of video output. I discovered quickly that the TVout and VGAx libraries would likely need to be significantly modified to work....so I need to now learn (or relearn) timers and interrupts.
This first sketch was modified from the Ref_Timers documentation, it creates a timer and links it to an interrupt service routine.
This works great as far as it goes as you can only change the period of the clock tick. The following code uses the COMPARE interrupt vector and also
kindadoesn't works, but not as I expected.You can change the PER and CMP value and the ISR fires at the same rate. I did also add the required "takeTCA0();"...no difference.I'm going to keep pecking away at it, but I am looking for a way to create a timer that I can use for a pixel clock. That's a pretty big ask, as the code in the ISR has to be fast enough to complete before the next pixel.
(Entry updated on 12/4/2021)
Beta Was this translation helpful? Give feedback.
All reactions