I've been working on code that performs "animation" on an MCF5329 LCD Controller.
We're using standard double-buffering. Display one video buffer while writing to the next, then swapping them. This has to be done during the "vertical retrace" period.
This is a lot harder than it should be, as the LCDC doesn't have a signal or interrupt that uniquely tells you that the LCDC has obeyed the command to swap to the other buffer.
So I've been reverse engineering the timing, and when I hear back from Freescale on this I'll publish details.
Meanwhile I wrote some code to reverse-engineer the timing by reading the LCDC_ISR and Interrupt Controller registers.
It didn't go well. The LCD_ISR register contains status bits, two of interest being "BOF" and "EOF" (Beginning and End of Field). With the frame and memory timing I expect to see the following:
0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 16760us, 4us
That means the time from BOF to EOF was 16760us, and then the time to the next BOF was 4us. What I'm actually getting is this:
0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 117344us, 4us Multiple EOF Missed0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 16760us, 16768us BOF Missed0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 83816us, 16768us EOF and then BOF missed0 -> 2 -> 1, 16760us, 16768us0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 67052us, 16768us0 -> 2 -> 1, 16760us, 16768us0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 16760us, 4us0 -> 2 -> 1, 83816us, 16768us
The LCD_ISR register is documented as:
22.3.17 LCDC Interrupt Status Register (LCD_ISR)
The read-only interrupt status register indicates whether an interrupthas occurred. The status bit is set when the interrupt condition is met.If any bit in this register is set and the corresponding bit in theLCD_IER register is set, an LCD interrupt is asserted to the interruptcontroller.The status bit is cleared by reading the register.
In order to measure the timing, my code is in a loop continuously reading the register.
Which is sometimes CLEARING the bits before they can be read as being set!
It seems to be that a read of this register happening at the same time as the hardware trying to set bits in this register results in the "clear the bits on read" operation winning.
If I put delays in the loops so they read less often, then the missed-reads of the bits happens less often, but it still happens.
This register is provided to be read by an interrupt service routine to determine which interrupt source happened, and to clear that source. When used "synchronously" like this it should work OK, with the risk of missing interrupts if there are multiple ones being used (like both Frame and Graphics Window interrupts).
It doesn't look to support "asynchronous reading" though.
This is an unusual interrupt status register. Most of the ones in other peripherals are "write one to clear" rather than "read to clear". What is happening here shows why "write one to clear" is such a good design.
Watch out for any other registers in other peripherals that are "read to clear". They might be causing problems for other design with "missed events".