pebisoft
19.04.2005, 21:54
hallo, ich möchte mit dem unteren programm ein videobild (einfache linien) in fbas-format darstellen mit dem avr16 8mhz. es klappt nicht.
es hatten schon einige aus diesem forum probiert, es geht aber noch nicht.
robert, vielleicht weist du weiter. vielleicht könnte man den compare-aufruf mit einem SIGNAL (SIG_OVERFLOW0) ersetzen (64us).
ich schaffe es nicht.
mfg pebisoft
// ---------------------------------------------------------------------------
//PORTC.4 is sync :1000 ohm to 75 ohm resistor
//PORTC.5 is video :330 ohm to 75 ohm resistor
// ---------------------------------------------------------------------------
#include <inttypes.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
// cycles = 63.625 Also fits for PAL (8 MHZ) / 1 * 509 no prescaler
// Frames 1/50 sec (non overlapped)
// --------------------------------------------------
// LINES
// --------------------------------------------------
//NTSC PAL
// 1 1 standard sync normaler Sync (5 uS Puls 0.3V auf 0V)
// ............. black schwarz
// 30 35
// ............. Visible part of Frame sichtbarer Bereich vertikal
//230 274
// ............. black
//248 295 reverted sync verkehrter Sync (5 uS Puls 0V auf 0.3V)
// .............
//251 299 standard sync wieder normal
// .............
//263 313 Bottom Line -> back to top 1/50 sec
// zurück nach oben
#define lineTime 509 // Timer1 Match Value (8 MHz /1 --> 0.000000125 s/cyc
// * 509 ---> 0,000063625 s
// 8 MHZ ohne PRescale gibt 0.125 uS
// auf 509 raufzählen ergibt ca 64 uS Interrupt
#define ScreenTop 40 // first visible line
#define ScreenBot 240 // last visible line gibt 200 sichtbare Zeilen pro Bild
#define SCREEN_MEM (ScreenBot - ScreenTop) * 8 // dafür brauchen wa 800 Byte
#define synONE 0x10 // syn (pin 4)
#define synNUL 0x00 // syn (pin 4)
#define VIDONE 0x20 // VIdeo (pin 5)
// --------------------------------------------------
// TESTING
// --------------------------------------------------
#define BAR_TOP 100 // first BAR line
#define BAR_BOT 150 // last BAR line
// --------------------------------------------------
// Register definition for faster access
// --------------------------------------------------
register unsigned char syncON asm ("r3");
register unsigned char syncOFF asm ("r4");
register unsigned char v1 asm ("r5");
register unsigned char v2 asm ("r6");
register unsigned char v3 asm ("r7");
register unsigned char v4 asm ("r8");
register unsigned char v5 asm ("r9");
register unsigned char v6 asm ("r10");
register unsigned char v7 asm ("r11");
register unsigned char v8 asm ("r12");
// --------------------------------------------------
static int LineCount; // Interrupt Linecounter
static int LineC; // main() Linecounter
// --------------------------------------------------
unsigned char screen[SCREEN_MEM]; // für den TEST überflüssig, egal
// --------------------------------------------------
// ---------------------------------------------------------------------
// Sync Interrupt every 64 uS Width ~4.7 uS 40 Cpu-Cycles
// wird alle 64 uS angesprungen .
// der Interrupt muß 5 uS lang den Sync Impuls auf die Leitung zu legen
// inzwischen zählt er die Bildzeilen und dreht ggf. den Impuls um (Bild Sync)
// oder schaltet wieder auf Bildanfang
// diese Zahl 313 kann nicht sinnvoll geändert werden, da ein PAL-Bild nunmal
// 625 Zeilen hat, ein Halbbild also 313 (komma fünf ist unisant)
// alles andere liefert UNFUG
// ---------------------------------------------------------------------
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
PORTC =syncON; // Beginn aktueller horz. sync
TCNT0 =0; // count timer 0 at 1/usec (eigentlich überflüssig)
LineCount++ ; // nächste Zeile
switch (LineCount)
{
case 295: // ab hier sync invertiert (Kennz.Bild ende)
syncON = synONE;
syncOFF = synNUL;
break;
case 299: // wieder zurück auf normal (Kennz.nächstes Bild start)
syncON = synNUL;
syncOFF = synONE;
break;
case 313: // PAL Zeilen 625 halbe --> 313
LineCount = 1; // wieder von vorne
break;
default:
break;
}
PORTC = syncOFF; // Ende aktueller sync pulse
}
// ---------------------------------------------------------------------
// set up the ports and timers M A I N
// ---------------------------------------------------------------------
int main(void)
{
//init timer 1 to generate sync
OCR1A = lineTime; //One NTSC & PAL line (509) --> 64 uS
TCCR1B = 0x09; //full speed, no prescale ; clear-on-match
TCCR1A= 0x00; //turn off pwm and oc lines
TIMSK = 0x10; //enable interrupt T1 cmp
//init port C Pin 4 u. 5 as Output
DDRC = 0x30; //video out and switches
// c.4 syn OUTPUT
// c.5 video OUTPUT
// der Rest bleibt INPUT
//init timer 0 to 1/uSec 1 MHZ
TCCR0 = 2; // (eigentlich überflüssig)
//initialize synch constants
syncON = synNUL; // initial standard sync anfang 0.3V -> 0V
syncOFF= synONE; // initial standard sync ende 0V -> 0.3V
LineCount= 1; // anfangswert interruptzähler
LineC= 1; // anfangswert main() zähler
//enable sleep mode
MCUCR = 0b10000000; // nach dem SLEEP geht's bei einem Interrupt
// direkt wieder weiter
sei(); // enable alle interrupts
// -----------------------------------------------------------------------
// ONE LINE WORKOUT
// -----------------------------------------------------------------------
while(1) // auf immer und ewig
{
// Sleep, bis ein Interrupt kommt (wir haben nur einen, ev. aufpassen)
asm volatile ("sleep"); // wait for Line-Sync Interrupt
// START Black Porch Time (Schwarzschulter & PAL Burst ) ~6 uS 48 Cpu-Cycles
// der Sync Impuls wurde von der Interrupt routine abgegeben.
// jetzt haben wir ~6 uS oder 48 CPU-Zyklen Zeit, entweder die Pixel zu schicken,
// oder nix oder auch was anderes zu tun. Auf jeden Fall müssen wir in 50 uS fertig sein
// und wieder bein SLEEP gelandet sein.
LineC++; // nächste Zeile
if (LineC >= 313) // (Halb-)Bildende ?
LineC = 1; // dann auf ein neues
// TEST: von Zeile 100 bis 150 zeichnen wir ein x-beliebiges Muster
if ((LineC < BAR_BOT) && (LineC > BAR_TOP))
{
v1 = screen[1]; // get 1st 8 Pixel from screenmemory
v2 = screen[1]; // get 2nd 8 Pixel from screenmemory
v3 = screen[1]; // get 3rd 8 Pixel from screenmemory
v4 = screen[1]; // get 4th 8 Pixel from screenmemory
v5 = screen[1]; // get 5th 8 Pixel from screenmemory
v6 = screen[1]; // get 6th 8 Pixel from screenmemory
v7 = screen[1]; // get 7th 8 Pixel from screenmemory
v8 = screen[1]; // get 8th 8 Pixel from screenmemory
// Jetzt sollten seit dem Sleep im Idealfall 6 uS vergangen sein, wir schicken
// jetzt die Pixel raus.
// wie haben ca 50 uS oder ~400 CPU Zyklen zeit, Tupfen auf den Schirm zu zaubern
// OHne "IF" geht das natürlich viel schneller, is aber nur'n TEST
// PIXEL 1-8 (V1)
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
// PIXEL 9-16 (V2)
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
// PIXEL 17-24 (V3)
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
// PIXEL 25-32 (V4)
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC &= ~VIDONE; // black Abwechslung
PORTC |= VIDONE; // white Pixel
PORTC &= ~VIDONE; // black Abwechslung
PORTC |= VIDONE; // white Pixel
// PIXEL 33-40 (V5)
PORTC &= ~VIDONE; // black Abwechslung
PORTC |= VIDONE; // white Pixel
PORTC &= ~VIDONE; // black Abwechslung
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
// PIXEL 41-48 (V6)
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
// PIXEL 49-56 (V7)
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
// PIXEL 57-64 (V8)
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
// ------------------------------------------------------------------------
PORTC &= ~VIDONE; // Video OFF that's it
}
else
{
// Black lines: Time to do something different
// wenn nix zu zeichnen ist, können wir was anderes Tun, es sollt halt
// nicht länger als 55 uS dauern, damit wir rechtzeitig wieder beim Sleep sind
}
} //while ENDLOS
return(0); // da kommen wir NIE hin
} //main
es hatten schon einige aus diesem forum probiert, es geht aber noch nicht.
robert, vielleicht weist du weiter. vielleicht könnte man den compare-aufruf mit einem SIGNAL (SIG_OVERFLOW0) ersetzen (64us).
ich schaffe es nicht.
mfg pebisoft
// ---------------------------------------------------------------------------
//PORTC.4 is sync :1000 ohm to 75 ohm resistor
//PORTC.5 is video :330 ohm to 75 ohm resistor
// ---------------------------------------------------------------------------
#include <inttypes.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
// cycles = 63.625 Also fits for PAL (8 MHZ) / 1 * 509 no prescaler
// Frames 1/50 sec (non overlapped)
// --------------------------------------------------
// LINES
// --------------------------------------------------
//NTSC PAL
// 1 1 standard sync normaler Sync (5 uS Puls 0.3V auf 0V)
// ............. black schwarz
// 30 35
// ............. Visible part of Frame sichtbarer Bereich vertikal
//230 274
// ............. black
//248 295 reverted sync verkehrter Sync (5 uS Puls 0V auf 0.3V)
// .............
//251 299 standard sync wieder normal
// .............
//263 313 Bottom Line -> back to top 1/50 sec
// zurück nach oben
#define lineTime 509 // Timer1 Match Value (8 MHz /1 --> 0.000000125 s/cyc
// * 509 ---> 0,000063625 s
// 8 MHZ ohne PRescale gibt 0.125 uS
// auf 509 raufzählen ergibt ca 64 uS Interrupt
#define ScreenTop 40 // first visible line
#define ScreenBot 240 // last visible line gibt 200 sichtbare Zeilen pro Bild
#define SCREEN_MEM (ScreenBot - ScreenTop) * 8 // dafür brauchen wa 800 Byte
#define synONE 0x10 // syn (pin 4)
#define synNUL 0x00 // syn (pin 4)
#define VIDONE 0x20 // VIdeo (pin 5)
// --------------------------------------------------
// TESTING
// --------------------------------------------------
#define BAR_TOP 100 // first BAR line
#define BAR_BOT 150 // last BAR line
// --------------------------------------------------
// Register definition for faster access
// --------------------------------------------------
register unsigned char syncON asm ("r3");
register unsigned char syncOFF asm ("r4");
register unsigned char v1 asm ("r5");
register unsigned char v2 asm ("r6");
register unsigned char v3 asm ("r7");
register unsigned char v4 asm ("r8");
register unsigned char v5 asm ("r9");
register unsigned char v6 asm ("r10");
register unsigned char v7 asm ("r11");
register unsigned char v8 asm ("r12");
// --------------------------------------------------
static int LineCount; // Interrupt Linecounter
static int LineC; // main() Linecounter
// --------------------------------------------------
unsigned char screen[SCREEN_MEM]; // für den TEST überflüssig, egal
// --------------------------------------------------
// ---------------------------------------------------------------------
// Sync Interrupt every 64 uS Width ~4.7 uS 40 Cpu-Cycles
// wird alle 64 uS angesprungen .
// der Interrupt muß 5 uS lang den Sync Impuls auf die Leitung zu legen
// inzwischen zählt er die Bildzeilen und dreht ggf. den Impuls um (Bild Sync)
// oder schaltet wieder auf Bildanfang
// diese Zahl 313 kann nicht sinnvoll geändert werden, da ein PAL-Bild nunmal
// 625 Zeilen hat, ein Halbbild also 313 (komma fünf ist unisant)
// alles andere liefert UNFUG
// ---------------------------------------------------------------------
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
PORTC =syncON; // Beginn aktueller horz. sync
TCNT0 =0; // count timer 0 at 1/usec (eigentlich überflüssig)
LineCount++ ; // nächste Zeile
switch (LineCount)
{
case 295: // ab hier sync invertiert (Kennz.Bild ende)
syncON = synONE;
syncOFF = synNUL;
break;
case 299: // wieder zurück auf normal (Kennz.nächstes Bild start)
syncON = synNUL;
syncOFF = synONE;
break;
case 313: // PAL Zeilen 625 halbe --> 313
LineCount = 1; // wieder von vorne
break;
default:
break;
}
PORTC = syncOFF; // Ende aktueller sync pulse
}
// ---------------------------------------------------------------------
// set up the ports and timers M A I N
// ---------------------------------------------------------------------
int main(void)
{
//init timer 1 to generate sync
OCR1A = lineTime; //One NTSC & PAL line (509) --> 64 uS
TCCR1B = 0x09; //full speed, no prescale ; clear-on-match
TCCR1A= 0x00; //turn off pwm and oc lines
TIMSK = 0x10; //enable interrupt T1 cmp
//init port C Pin 4 u. 5 as Output
DDRC = 0x30; //video out and switches
// c.4 syn OUTPUT
// c.5 video OUTPUT
// der Rest bleibt INPUT
//init timer 0 to 1/uSec 1 MHZ
TCCR0 = 2; // (eigentlich überflüssig)
//initialize synch constants
syncON = synNUL; // initial standard sync anfang 0.3V -> 0V
syncOFF= synONE; // initial standard sync ende 0V -> 0.3V
LineCount= 1; // anfangswert interruptzähler
LineC= 1; // anfangswert main() zähler
//enable sleep mode
MCUCR = 0b10000000; // nach dem SLEEP geht's bei einem Interrupt
// direkt wieder weiter
sei(); // enable alle interrupts
// -----------------------------------------------------------------------
// ONE LINE WORKOUT
// -----------------------------------------------------------------------
while(1) // auf immer und ewig
{
// Sleep, bis ein Interrupt kommt (wir haben nur einen, ev. aufpassen)
asm volatile ("sleep"); // wait for Line-Sync Interrupt
// START Black Porch Time (Schwarzschulter & PAL Burst ) ~6 uS 48 Cpu-Cycles
// der Sync Impuls wurde von der Interrupt routine abgegeben.
// jetzt haben wir ~6 uS oder 48 CPU-Zyklen Zeit, entweder die Pixel zu schicken,
// oder nix oder auch was anderes zu tun. Auf jeden Fall müssen wir in 50 uS fertig sein
// und wieder bein SLEEP gelandet sein.
LineC++; // nächste Zeile
if (LineC >= 313) // (Halb-)Bildende ?
LineC = 1; // dann auf ein neues
// TEST: von Zeile 100 bis 150 zeichnen wir ein x-beliebiges Muster
if ((LineC < BAR_BOT) && (LineC > BAR_TOP))
{
v1 = screen[1]; // get 1st 8 Pixel from screenmemory
v2 = screen[1]; // get 2nd 8 Pixel from screenmemory
v3 = screen[1]; // get 3rd 8 Pixel from screenmemory
v4 = screen[1]; // get 4th 8 Pixel from screenmemory
v5 = screen[1]; // get 5th 8 Pixel from screenmemory
v6 = screen[1]; // get 6th 8 Pixel from screenmemory
v7 = screen[1]; // get 7th 8 Pixel from screenmemory
v8 = screen[1]; // get 8th 8 Pixel from screenmemory
// Jetzt sollten seit dem Sleep im Idealfall 6 uS vergangen sein, wir schicken
// jetzt die Pixel raus.
// wie haben ca 50 uS oder ~400 CPU Zyklen zeit, Tupfen auf den Schirm zu zaubern
// OHne "IF" geht das natürlich viel schneller, is aber nur'n TEST
// PIXEL 1-8 (V1)
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
// PIXEL 9-16 (V2)
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
// PIXEL 17-24 (V3)
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
PORTC &= ~VIDONE; // black Pixel
// PIXEL 25-32 (V4)
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC &= ~VIDONE; // black Abwechslung
PORTC |= VIDONE; // white Pixel
PORTC &= ~VIDONE; // black Abwechslung
PORTC |= VIDONE; // white Pixel
// PIXEL 33-40 (V5)
PORTC &= ~VIDONE; // black Abwechslung
PORTC |= VIDONE; // white Pixel
PORTC &= ~VIDONE; // black Abwechslung
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
// PIXEL 41-48 (V6)
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
// PIXEL 49-56 (V7)
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
// PIXEL 57-64 (V8)
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
PORTC |= VIDONE; // white Pixel
// ------------------------------------------------------------------------
PORTC &= ~VIDONE; // Video OFF that's it
}
else
{
// Black lines: Time to do something different
// wenn nix zu zeichnen ist, können wir was anderes Tun, es sollt halt
// nicht länger als 55 uS dauern, damit wir rechtzeitig wieder beim Sleep sind
}
} //while ENDLOS
return(0); // da kommen wir NIE hin
} //main