Kampis Elektroecke

Videoausgabe: Steuersignale erzeugen

Im ersten Teil dieses Tutorials habe ich die benötigte Hardware für ein Videointerface vorgestellt und erklärt. Als nächstes muss die Software für die Ansteuerung der verwendeten Hardware entwickelt werden. Die komplette Software unterteile ich in drei Funktionsgruppen:

  1. Die Ansteuerung des Video Timing Controllers und des Clocking Wizards (dieser Artikel)
  2. Die Ansteuerung des Video DMA (der nächste Artikel)
  3. Die Anwendung für die Erzeugung des Bildes (der übernächste Artikel)

Über den Video Timing Controller wird die Auflösung des Videobildes bestimmt. Dazu erzeugt der Controller die für den Video Out IP-Core notwendigen Steuersignale HSync, VSync, HBlank, VBlank und Active_Video, wobei letzteres kein Steuersignal für den Monitor darstellt, sondern nur die sichtbaren Pixel markiert. Für die Erzeugung der Steuersignale benötigt der Video Timing Controller einen Basistakt, wobei die Höhe dieses Basistakt von der Bildauflösung und der Bildwiederholrate abhängig ist. 

In diesem Beispiel sollen drei Auflösungen implementiert werden:

Auflösung Takt Bildwiederholrate
640 x 480 25,175 MHz 70 Hz
800 x 600 40 MHz 60 Hz
1024 x 768 65 MHz 60 Hz

Der Eingangstakt für den Video Timing Controller wird über den Clocking Wizard erzeugt. Die Ausgangsfrequenz des Clocking Wizards wird über ein AXI-Lite Interface eingestellt und umgeschaltet.


Info:

Eine detailliertere Beschreibung zur Ansteuerung des Clocking Wizards und des Treibers ist hier zu finden.


Für die verschiedenen Taktfrequenzen müssen die Parameter CLKBOUT_MULT_F, DIVCLK_DIVIDE und DIVIDE ermittelt werden, wobei der Wert dieser Faktoren von der Frequenz des Eingangstaktes des Clocking Wizards abhängt. Die Parameter können direkt aus dem Konfigurationsmenü in Vivado entnommen werden, indem die einzelnen Ausgangsfrequenzen eingestellt und die berechneten Werte kopiert werden.

Es ergeben sich für eine Frequenz von 125 MHz die folgenden Werte:

Auflösung CLKBOUT_MULT_F DIVCLK_DIVIDE DIVIDE
640 x 480 61,5 7 43,625
800 x 600 8 1 25
1024 x 768 8,125 1 15,625

Den Code für das Video-Timing habe ich in einen separaten Treiber ausgelagert, wobei sämtliche Informationen zu dem Treiber in der Struktur VideoTiming_t gespeichert werden:

Feld Beschreibung
VTC_ID Geräte-ID des verwendeten Video Timing Controllers
VTC Geräteinstanz des verwendeten Video Timing Controllers
Wizard Geräteinstanz des verwendeten Clocking Wizards
VideoClock Die aktuellen Einstellungen des verwendeten Ausgangskanals vom Clocking Wizard

Während der Initialisierung des Video-Timing Treibers werden der Clocking Wizard und der Video Timing Controller initialisiert und in der Struktur gespeichert:

u32 VideoTiming_Init(VideoTiming_t* Config, const u32 Channel, const u32 VTCID, const UINTPTR ClockAddr)
{
    XVtc_Config* VTC_Config;

    if((Config == NULL) || (!ClockAddr) || (Channel > 0x06))
    {
        return XST_INVALID_PARAM;
    }

    if((ClockingWizard_Init(&Config->Wizard, ClockAddr) & ClockingWizard_GetOutput(&Config->Wizard, &Config->VideoClock)) != XST_SUCCESS)
    {
        return XST_FAILURE;
    }

    VTC_Config = XVtc_LookupConfig(VTCID);
    if(!Config)
    {
        return XST_FAILURE;
    }

    return XVtc_CfgInitialize(&Config->VTC, VTC_Config, VTC_Config->BaseAddress);
}

Über die Funktion VideoTiming_SwitchMode wird die Auflösung geändert. Dazu werden die Einstellungen für den Clocking Wizard in die Konfiguration geladen und die Auflösung im Video Timing Controller umgeschaltet:

u32 VideoTiming_SwitchMode(VideoTiming_t* Config, const VideoMode_t Mode)
{
    u16 VGA_Mode;

    if(Config == NULL)
    {
        return XST_INVALID_PARAM;
    }

    switch(Mode)
    {
        case VIDEOMODE_640X480:
        {
            VGA_Mode = XVTC_VMODE_VGA;

            Config->Wizard.DIVCLK_DIVIDE = 7;
            Config->Wizard.CLKFBOUT_MULT = 64;
            Config->Wizard.CLKFBOUT_FRAC_Multiply = 5;
            Config->VideoClock.DIVIDE = 43;
            Config->VideoClock.FRAC_Divide = 625;

            break;
        }
        case VIDEOMODE_800X600:
        {
            VGA_Mode = XVTC_VMODE_SVGA;

            Config->Wizard.DIVCLK_DIVIDE = 1;
            Config->Wizard.CLKFBOUT_MULT = 8;
            Config->Wizard.CLKFBOUT_FRAC_Multiply = 0;
            Config->VideoClock.DIVIDE = 25;
            Config->VideoClock.FRAC_Divide = 0;

            break;
        }
        case VIDEOMODE_1024X768:
        {
            VGA_Mode = XVTC_VMODE_XGA;

            Config->Wizard.DIVCLK_DIVIDE = 1;
            Config->Wizard.CLKFBOUT_MULT = 8;
            Config->Wizard.CLKFBOUT_FRAC_Multiply = 125;
            Config->VideoClock.DIVIDE = 15;
            Config->VideoClock.FRAC_Divide = 625;

            break;
        }
        default:
        {
            VGA_Mode = XVTC_VMODE_VGA;

            Config->Wizard.DIVCLK_DIVIDE = 7;
            Config->Wizard.CLKFBOUT_MULT = 64;
            Config->Wizard.CLKFBOUT_FRAC_Multiply = 5;
            Config->VideoClock.DIVIDE = 43;
            Config->VideoClock.FRAC_Divide = 625;

            break;
        }
    }

    ClockingWizard_SetClockBuffer(&Config->Wizard);
    ClockingWizard_SetOutput(&Config->Wizard, &Config->VideoClock);

    XVtc_SetGeneratorVideoMode(&Config->VTC, VGA_Mode);
    XVtc_RegUpdate(&Config->VTC);
    XVtc_Enable(&Config->VTC);

    return XST_SUCCESS;
}

Damit ist der Treiber für das Video-Timing einsatzbereit. Im nächsten Teil zeige ich wie der DMA konfiguriert wird.

Zurück

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.