5941


Laboratorium Podstaw Informatyki

Kierunek Elektrotechnika

Ćwiczenie HW1

Elementy programowania sprzętu.

Własne procedury obsługi przerwań.

Obsługa karty z przetwornikami

analogowo-cyfrowymi.

Zakład Metrologii AGH

Kraków 2001

1. Przykładowa obsługa przerwania zegarowego 0x1C.

W tym punkcie zajmiemy się przerwaniem generowanym przez układ zegara czasu rzeczywistego komputera PC, a więc przerwaniem generowanym w sposób sprzętowy.

W procesorze rodziny x86 dolne 1 KB pamięci jest zajmowane przez 256 elementową tablicę wektorów przerwań. Elementami tej tablicy są wektory przerwań, czyli adresy procedur obsługi przerwań. Ponieważ w procesorze x86 adres komórki pamięci składa się z dwóch 16 bitowych wartości (segment oraz offset), to jak łatwo policzyć na jeden adres potrzebne są 4 bajty, co dla 256 adresów (wektorów) daje owe 1 KB.

Ponieważ tablica ta jest w pamięci typu RAM, czyli o swobodnym dostępie, to jej zawartość może być zmieniona. Dzięki temu możemy zainstalować swoją własną procedurę obsługi wybranego przerwania. Oczywiście należy przy tym zachować ostrożność. Do podmiany wektora procedury obsługi przerwania służą dwie funkcje języka C getvect oraz setvect. Funkcje te są równoważne dwóm funkcjom przerwania DOS 21h, odpowiednio 25h i 35h. Tak więc chcąc zainstalować swoją własną obsługę przerwania korzystamy najpierw z funkcji getvect, aby otrzymać adres starej funkcji, adres ten zapamiętujemy. Następnie używamy funkcji setvect, aby zainstalować swoją procedurę, gdy nie jest ona już nam potrzebna, to przywracamy z powrotem strarą obsługę korzystając ponownie z funkcji setvect. Pisanie własnej procedury obsługi przerwania jest zadaniem dość prostym i sprowadza się do poprzedzenia nazwy naszej funkcji słowem kluczowym interrupt. Poniżej przedstawiony jest kompletny program demonstrujący użycie omawianych funkcji.

#include <stdio.h>

#include <dos.h>

#include <conio.h>

#define INTR 0X1C /* numer przerwania od zegara */

void interrupt ( *oldhandler)(void); /* oldhandler jest wskaznikiem, czyli adresem do funkcji, ktora nie zwraca zadnej wartosci i nie posiada żadnego parametru */

int count=0; /* zmienna globalna */

void interrupt handler( )

{

// zwieksz wartosc zmiennej globalnej

count++;

// wywolaj stara procedure obslugi przerwania

oldhandler( );

}

int main(void)

{

// pobierz i zapamietaj stary wektor przerwania

oldhandler = getvect(INTR);

//ustaw nowy wektor przerwania

setvect(INTR, handler);

// poczekaj az count bedzie wieksze od 20

while (count < 20)

printf("count is %d\n",count);

// przywroc stary wektor przerwania

setvect(INTR, oldhandler);

return 0;

}

1. Zadanie

Zapoznać sie z przedstawionym powyżej przykładem.

2. Inicjalizacja karty z przetwornikami analog-cyfra.

Tematem dalszej części tego ćwiczenia, jak i następnych, będzie programowanie karty dźwiękowej typu SoundBlaster. Karta SoundBlaster widziana jest przez programistę jako zbiór rejestrów umieszczony od pewnego adresu w przestrzeni wejścia/wyjścia procesora x86.

Aby moć rozpocząć programowanie należy znać adresy rejestrów do których będziemy coś pisać lub coś z nich czytać. Zazwyczaj adresy rejestrów definiujemy poprzez podanie adresu bazowego (początkowego) oraz przemieszczenia względem tego adresu. Jest to o tyle wygodne, że często adres bazowy może być zmieniany np. za pomocą przełączników na karcie. Tak właśnie jest w przypadku karty SoundBlaster. Jej adresem bazowy może być 220h, 230h, 240h, w zależności od konfiguracji karty.

Przesunięcia adresów interesujących nas rejestrów względem adresu bazowego są znane i wynoszą.

#define BaseAddr0 0x220 /* pierwszy możliwy adres bazowy */

#define Reset 0x06 /* zerowanie karty */

#define RdData 0x0A /* odczyt danych z karty */

#define WrData 0x0C /* zapis danych do karty SB*/

#define WrCmd 0x0C /* zapis rozkazów do karty SB*/

#define StatWrBuf 0x0C /* stan bufora wyjściowego (Write-Buffer Status) */

#define StatRdBuf 0x0E /* stan bufora wejściowego (Read-Buffer Status) */

Poniższy fragment kodu służy do resetowania karty SoundBlaster, pod warunkiem że 220h jest poprawnym adresem bazowym.

int base_adres = BaseAddr0;

outportb(base_adres+Reset, 1); //wpisz liczbę 1 pod adres 0x226

delay(1); //poczekaj 1 ms

outportb(base_adres+Reset, 0); //wpisz liczbę 1 pod adres 0x226

Jak się przekonać czy wybrany adres bazowy jest właściwym adresem bazowym dla aktualnie zainstalowanej karty? Pytanie to jest równoważne pytaniu: Jak sprawdzić czy w danym komputerze jest zainstalowana karta SoundBlaster, oczywiście bez rozkręcania go.

Zadanie 2

Odpowiedzią na te pytania jest poniższy algorytm postępowania, który należy przećwiczyć ręcznie przy użyciu programu debug.exe. Jest to program DOSowy, który po uruchomieniu przyjmuje i wykonuje proste komendy użytkownika. Program posiada pomoc (help) dostępny po wciśnięciu klawisza? Przy pomocy tego programu (przy użyciu komend I i O) wykonać owe ćwiczenie.

Algorytm postępowania:

Dla adresów: b_adr = 0x220, 0x230, 0x240

wykonaj:

do rejestru: b_adr+Reset wpisz 1

czekaj 1ms

do rejestru: b_adr+Reset wpisz 0

czekaj 1ms

przeczytaj zawartość rejestru: b_adr+StatRdBuf

jeśli najstarszy bit tego rejestru jest ustawiony (równy 1) to odczytaj zawartość

rejestru: b_adr+RdData, jesli jest ona równa 0xAA to karta znaleziona,

jeśli nie to weź kolejny adres i ponów całą procedurę od początku

Zadanie 3

Po ręcznym przećwiczeniu algorytmu z poprzedniego zadania zaprogramować go w języku C z użyciem funkcji outportb.

3. Obsługa karty z przetwornikami analog-cyfra.

Karta dźwiękowa (tzw. SoundBlaster) wyposażona jest między innymi w przetworniki analog-cyfra i cyfra-analog, a więc w przetworniki pozwalające na współpracę komputera ze "światem analogowym". Obsługa karty polega na dostarczeniu danych do przetworników C/A i odebraniu danych z przetworników A/C. Proces ten można rozwiązać na dwa sposoby. Sposób pierwszy to obsługa czysto programowa, sposób drugi to wykorzystanie kanału DMA (bezpośredni dostęp do pamięci). Sposób pierwszy jest prymitywny i posiada szereg wad, ale za to jest bardzo prosty. Sposób drugi jest elegancki, ale wymaga programowania dość złożonego układu DMA oraz układu kontrolera przerwań. Zajmiemy się teraz sposobem pierwszym.

Karta SoundBlaster rozpoznaje pewne niżej podane komendy służące do jej sterowania.

/* komendy dla karty SoundBlaster */

#define KONVERT_AC 0x20 /* komenda konwersji analog-cyfra bez DMA*/

#define KONVERT_CA 0x10 /* komenda konwersji cyfra-analog bez DMA*/

#define SpeakerOn 0xD1 /* komenda włącz głośnik */

#define SpeakerOff 0xD3 /* komenda wyłącz głośnik */

Oprócz tych komend istnieją pewne procedury, które określają sposób wydawania tych komend.

Zapisywanie danych lub komend do bufora karty SB

Zanim wpiszesz coś do bufora karty musisz się upewnić, że jest on pusty (tzn. że karta wykonała poprzednią komendę i jest gotowa na następną). Aby to sprawdzić należy przeczytać rejestr stanu: StatWrBuf. Jeśli 7bit tego rejestru (najstarszy) jest zero (zgaszony) to bufor jest pusty i możesz spokojnie wpisać do niego nową daną lub komendę.

Czytanie danych z bufora karty SB

Zanim przeczytasz daną z bufora karty SB, musisz się upewnić, że bedzie to nowa dana, a nie stara (poprzednia) lub wręcz jakiś śmieć. W tym celu musisz przeczytać rejestr stanu: StatRdBuf. Jeśli 7bit tego rejestru (najstarszy) jest 1 (zapalony) to w buforze jest nowa (ważna) dana, którą możesz przeczytać.

Zadanie 4

Napisać program dla karty SoundBlaster, który odtworzy wybrany, krótki sygnał z pliku dyskowego. Odtwarzanie będzie realizowane sposobem czysto programowo, czyli bez użycia kanału DMA. Poniżej przedstawiony jest algorytm postępowania:

1. Inicjalizacja karty.

2. Otworz zbiór z sygnałem, który chcesz odtworzyć.

3. Zaalokuj pamięć (funkcja malloc) i wczytaj zbiór do pamięci.

4. Włącz głośnik.

5. Poczekaj, na gotowość SoundBlaster'a:

czekaj tak długo jak długo w rejestrze: StatWrBuf najstarszy bit jest 1.

6. Do rejestru: WrCmd wyślij komendę: KONVERT_CA.

7. Poczekaj, na gotowość SoundBlaster'a:

czekaj tak długo jak długo w rejestrze: StatWrBuf najstarszy bit jest 1.

8. Do rejestru: WrData wyślij kolejną próbkę sygnału.

9. Niestety w tym trybie karta SoundBlaster przetwarza próbki dźwiękowe z maksymalną szybkością (zależną od szybkości procesora komputera). Chcąc uzyskać poprawne brzmienie należy samemu dobrać odpowiedni czas oczekiwana, np. poprzez odpowiednią pętlę opoźniającą wstawioną właśnie w tym miejscu.

10. Jeśli nie przetworzyłeś wszystkich próbek, to wróć do punktu 5

Zadanie 5

Napisać program dla karty SoundBlaster, który najpierw przy użyciu komendy konwersji analog-cyfra: KONVERT_AC nagra sygnał do buforu, a następnie odtworzy nagrany fragment. Zarówno nagrywanie jak i odtwarzanie będzie realizowane sposobem pierwszym, czyli czysto programowo bez użycia kanału DMA. Algorytm postępowania jest analogiczny jak w zadaniu 1.1. Uwaga: przypominam, że warunki gotowości karty na operację czytania i pisania są różne (przy czytaniu czekamy na zapalenie flagi, a przy pisaniu na jej zgaśnięcie). Dodatkowo karta posiada osobny rejestr stanu dla operacji pisania i czytania.

Laboratorium Podstaw Informatyki Strona 1

Zakład Metrologii AGH



Wyszukiwarka

Podobne podstrony:
5941
5941
5941

więcej podobnych podstron