Elektroda.pl
Elektroda.pl
X
PCBway
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Generacja dźwięku za pomocą AVR

mi_ma 02 Kwi 2008 20:49 23890 29
  • #9
    lechoo
    Poziom 39  
    Dosyć ciekawy jest format MOD znany jeszcze z komputerów Amiga, utworki w tym formacie zawierają zarówno zapis nutowy, jak i 8-bitowe próbki brzmień instrumentów. Przeglądając kiedyś zagraniczne projekty znalazłem coś takiego: Link
    Uprościłem ten układ do niezbędnego minimum, pozostawiłem tylko mikrokontroler ATMEGA32 i przetwornik TDA1543, wyświetlacz LCD jest opcjonalny. Maksymalna wielkość odtwarzanego pliku przez to zmalała do około 27kB ze względu na brak pamięci zewnętrznej. Wyszedł mi z tego taki oto prototyp:

    Link

    W załączeniu zamieszczam dodatkowo nagranie wykonane poprzez wejście line-in w komputerze, bez żadnej ingerencji poza kompresją mp3.
    Jak będzie większe zainteresowanie tym prostym projekcikiem to zamieszczę schemat i kod programu (asm) w dziale DIY.
  • PCBway
  • #10
    olinek2
    Poziom 23  
    Nonono jestem pod wrażeniem Lechoo :)
    Dodać jeszcze obsługę klawiaturki i SD, które ostatnio są tanie jak barszcz i mamy uniwersalny odtwarzacz :)
  • #11
    muzyk_radiowezel
    Poziom 10  
    Jestem zainteresowany czymś takim.
    Mam pytanie: jaki jest orientacyjny koszt całości?
  • #12
    lechoo
    Poziom 39  
    Koszt podzespołów to 11zł za ATMEGA32 i 8zł za TDA1543 - ceny ze znanej łódzkiej firmy. Pozostałych części nie liczę, bo to drobnica którą miałem w szufladzie lub z demontażu. Bez wyświetlacza LCD też będzie działać. Oryginalny program odchudziłem m.in. z obsługi przycisków, gdyż nie są potrzebne - można załadować tylko jednego MOD-a który jest odtwarzany w pętli. Kod programu zajmuje nieco poniżej 4800 bajtów, pozostała pamięć flash jest przeznaczona na załadowanie utworku do odtwarzania. W przyszłym tygodniu postaram się naszkicować schemat i zamieścić tu wraz z kodem programu i przykładowymi utworkami.
  • #13
    Atlantis86
    Poziom 19  
    Mógłbyś zaprezentować jak to odtwarza "Anti Atari Song"? ;P
  • #14
    lechoo
    Poziom 39  
    Atlantis86 napisał:
    Mógłbyś zaprezentować jak to odtwarza "Anti Atari Song"? ;P

    Nie mogę :)
    Jest za mało pamięci w mikrokontrolerze na jego załadowanie. Trzebaby dodać zewnętrzną pamięć, tak jak w oryginalnym czeskim projekcie, do którego link podałem kilka postów wyżej.
  • PCBway
  • #15
    Haden
    Poziom 11  
    Jestem pod wrażeniem! Gratuluję! Swego czasu interesowałem się umieszczoną na stronie Atmela notą aplikacyjną AVR335, ale zabrakło mi determinacji... mam nadzieję, że uda mi się do tego wrócić - dzięki za inspirację. Czy można liczyć na obiecany schemat i program?
  • #16
    lechoo
    Poziom 39  
    Namalowałem wreszcie ten schemat, odręcznie bo nie chciało mi się bawić z Protelem...
    Na schemacie pominąłem stabilizator 5V z układem 7805, bo przecież każdy wie jak on wygląda. Wyświetlacz LCD jest elementem opcjonalnym, bez niego też będzie grała muzyczka.
    W poniższym załączniku znajduje się (oprócz schematu) kod źródłowy programu, a także przykładowe gotowe do wgrania pliki hex. Zamieściłem również zrzut z ustawieniami FuseBit-ów.
    Załączniki:
  • #17
    musznik
    Poziom 10  
    Super robota. ;) Teraz zastanawia mnie jak by wygladalo rozszerzenie pamieci na mod'y o te kilkanascie KB ( jakie I2C ?:P ) - zawsze to kilka min wiecej ;)
  • #19
    musznik
    Poziom 10  
    Jak wygląda upload takiej muzyczki? z tego co widze na schematach wymagany jest dodatkowo uklad COM/USB ,albo ja sie myle. Z reszta autor tego watku nie wspomnial o tym nic, no moze poza "Drobnica" :]
  • #20
    lechoo
    Poziom 39  
    Autor tego wątka nie ma nic wspólnego z czeskim, ani moim projektem.
    U mnie muzyczka MOD jest załadowana bezpośrednio do pamięci flash mikrokontrolera (brak zewnętrznej pamięci), opisałem to w dokumentacji kilka postów wyżej.
    Natomiast w czeskim oryginalnym pierwszym projekcie utworki są załadowane programatorem do pamięci EPROM, można też załadować pojedynczy MOD do pamięci RAM poprzez RS232 i dowolny program terminala umożliwiający wysyłanie plików prze port szeregowy. Drugi czeski projekt wykorzystuje pamięć w karcie CF do przechowywania MOD-ów, zaś komunikacja odbywa się przez USB, a dokładniej poprzez wirtualny port szeregowy COM z szybkością 1,25Mb/s.
  • #21
    maly_elektronik
    Poziom 23  
    Ja bym toie lecho proponował może zaimplementować obsługe kart SD\MMC :) I przy takiej prędkości zdążysz sobie odczytać sektor z karty i wysłać go do tda . Wcale nie muszi nawet zaimplementować obsługi fat bo jak napiszesz swój program to możesz ładować zawartość bezpośrednio do sektorów a potem tak samo odczytywać :idea:
  • #22
    lechoo
    Poziom 39  
    Wszystko można zrobić, tylko trzeba mieć na to czas... Jednak w zaproponowany przez Ciebie sposób można co najwyżej odtwarzać pliki wav/pcm, z mod-ami tak łatwo się nie da - odczyt kart SD przez uC jest zbyt wolny...
  • #23
    maly_elektronik
    Poziom 23  
    Ale czy MOD rózni się czym w swojej strukturze od WAV :?: Czy odtwarza się wszystko tak samo :?:
  • #24
    Samuraj
    Poziom 35  
    WAV i MOD to zupełnie różne pliki. Rożnica jest w samej strukturze pliku jak i w formacie zapisu dźwięku. Pliki te nie są zamienne. Podobnie jak i VOC, PCM itp.
    To nie jest różnica tylko w rozszerzeniu pliku !
  • #25
    lechoo
    Poziom 39  
    -> http://pl.wikipedia.org/wiki/MOD
    Odtwarzanie nieskompresowanych plików WAV jest banalne, gdyż procesor nie robi nic więcej tylko odczytuje kolejne próbki z pamięci i wysyła je do przetwornika C/A. W przypadku odtwarzania MOD-ów procesor musi wykonać dużo więcej operacji - odczytywać nuty z paternów, obliczać częstotliwość odtwarzania poszczególnych próbek, pobierać próbki z tablicy próbek, dokonywać interpolacji oraz miksowania tych próbek i wysyłać je na przetwornik.
  • #26
    Guma1975
    Poziom 14  
    Witam serdecznie.

    Zachciało mi się odtworzyć wav-a z marnym skutkiem i kiepską wiedzą programistyczną.
    Może komuś przyda się przepis na AVR-DOS na atmega32. Aby to zadziałało podłączyłem kartę SD przez kostkę 74LS07. W pliku CONFIG_AVR-DOS.bas zmieniamy tak jak poniżej:
    Const Cfilehandles = 1
    Const Csepfathandle = 0
    W pliku config_MMC.bas zmieniamy definicję pinów dla atmegi32
    Const Cmmc_soft = 0 "zero dla hardware SPI"
    w konfigu SPI clockrate=16 dla kwarcu 20MHz a 4 dla 12MHz. Po zmianie kwarcu z 12MHz na 20MHz komunikacji z kartą nie było. Jako przetwornik C/A zastosowany fast pwm (dla 20MHz 78KHz). Karta musi być w slocie inaczej krzaczki. Jest to tylko namiastka tego rozwiązania nie odtwarzam wava od próbek tylko razem z headerem, chciałem zobaczyć czy avd-dos pociągnie. Blędem moim jest pobieranie próbki jednobajtowo i co jakis czas (widoczne na oscyloskopie) pwm przerywa na kilka ms pracę (czy to się dzieje co sektor 512b ?). Czy byłby ktoś w stanie naprowadzić mnie jak to "zbuforować" aby wyeliminować "czkawkę" ?
    załączam pliki konfiguracyjne avr-dos-a mogą zaoszczędzić nerwów początkującym.

    Code:
    ' Adjust HW Stack, Soft-Stack and Frame size to 128 minimum each!!!
    
    $regfile = "m32def.dat"                                     'informuje kompilator o pliku
          'dyrektyw mikrokontrolera
    $crystal = 20000000                                         'informuje kompilator
          'o czêstotliwoœci oscylatora
          'taktuj¹cego mikrokontroler
    Dim Dane_save As String * 30

    Config Graphlcd = 128 * 128 , Dataport = Portd , Controlport = Portc , Ce = 2 , Cd = 3 , Wr = 0 , Rd = 1 , Reset = 4 , Fs = 5 , Mode = 6
    'Wybralem tryb 6x8 font konieczne zmiany na PCB LCD odpowiednie zworki oraz koniecznosc konwersji tak przygotowanej grafiki
    'mode 8 gives 240 / 8 = 30 columns , mode=6 gives 240 / 6 = 40 columns
    '----------------------------------------------------------------------------
    Dim B As Byte , S As String * 12
    Dim D As Byte
    Dim R As Byte
    Dim Czas As Byte , Czas1 As Byte
    Dim Pobieraj As Byte

    Config Porta = Output
    Set Porta.0
    '============UWAGA poprawilem w config_MMC.bas CLOCKRATE na 16 20MHz/16 1.25MHz bylo na 4
    '============------------------ ale nie dzialalo po zmianie kwarcu z 12 na 20MHz
    $include "Config_MMC.bas"                                   'include mmc

    If Gbdriveerror <> 0 Then End
    $include "Config_AVR-DOS.BAS"                               'include avr-dos

    B = Initfilesystem(1)                                       'init file system
    'If B <> 0 Then Print "Errore MMC" 'se errore
    '=====-----------------------------------------------------
    '=====                 FAST PWM prescale 1 78kHz
    Ddrb.3 = 1
    Tccr0 = &B01101001                                          'timer0 in fast pwm mode, prescale = 1
    Ocr0 = 0                                                    'tu wpisujemu próbkê 8 bit
    '
    '=====-----------------------------------------------------
    'Enable Timer0
    Config Timer2 = Timer , Prescale = 8
    'Capture Edge = Rising , Compare A = Disconnect , Compare B = Disconnect , Clear Timer = 0
    On Timer2 Odmierz
    Enable Interrupts
    Enable Timer2
    Start Timer2

    Cls
    Cursor Off
    ' porty
    ' port Pinb.0 ustawiamy minuty
    ' port Pinb.1 ustawiamy godziny
    ' uwaga wymagane rezystory 10k Ohm na magistrali i2c
    ' podpiete pod +5V
    ' portc.0/1 magistrala i2c
    Do
    Locate 1 , 2

    Lcd "Sprawdzam MMC/SD"
    Locate 2 , 2
    If B <> 0 Then Lcd "ERROR MMC"
    If Gbdriveerror <> 0 Then Lcd "GB blad"
    '=========================================
    'Lcd "Gbdoserror=" ; Gbdoserror
    'Locate 3 , 2
    'Lcd "gbfilesystem=" ; Gbfilesystem
    'Locate 4 , 2
    'lcd "gwRootEntries="; gwRootEntries
    '=========================================
    Locate 3 , 2
    S = Dir( "*.*")
    While Len(s) > 0                                            'jeœli znaleziono jakieœ pliki
      Lcd S ; "  " ; Filelen()

      'wydrukuj nazwê pliku , datê i czas utworzenia/zmiany, czas i d³ugoœæ pliku
      S = Dir()                                                 'odczytaj nastêpny
    Wend
    '===============================================================
    Open "guma.txt" For Binary As #1

    'While Eof(1) = 0
    Pobieraj = 1
    Wait 5
    Pobieraj = 0
    Close #1
    Locate 10 , 2
    Lcd Czas ; " " ; D

    Loop
    End

    Odmierz:
    Porta.0 = Not Porta.0                                       'pomiar oscyloskopem

    Load Timer2 , 60                                            '72
    If Pobieraj = 1 And Eof(1) = 0 Then
    Get #1 , D
    Ocr0 = D
    'Incr Czas
    End If

    Return

    End



    Buforowanie w/g naszego kolegi z forum tez nic nie daje. Przy 32kHz nie daje rady, lecz 22KHz już się wyrabia.
    Code:
    ' Adjust HW Stack, Soft-Stack and Frame size to 128 minimum each!!!
    
    $regfile = "m32def.dat"
    $crystal = 20000000
    Dim Dane_save As String * 30

    Config Graphlcd = 128 * 128 , Dataport = Portd , Controlport = Portc , Ce = 2 , Cd = 3 , Wr = 0 , Rd = 1 , Reset = 4 , Fs = 5 , Mode = 6
    'Wybralem tryb 6x8 font konieczne zmiany na PCB LCD odpowiednie zworki oraz koniecznosc konwersji tak przygotowanej grafiki
    'mode 8 gives 240 / 8 = 30 columns , mode=6 gives 240 / 6 = 40 columns
    '----------------------------------------------------------------------------
    Dim B As Byte , S As String * 12

    '=========================
    Dim Pozycja As Byte
    Dim Buf_dol As Byte
    Dim Buf_gora As Byte
    Dim Bufor(255) As Byte
    Dim Probka_lad As Byte
    Dim Poz_lad As Byte
    Dim Probka As Byte

    Const Zero = 0
    '=========================
    Config Porta = Output
    Set Porta.0
    '============UWAGA poprawilem w config_MMC.bas CLOCKRATE na 16 20MHz/16 1.25MHz bylo na 4
    '============------------------ ale nie dzialalo po zmianie kwarcu z 12 na 20MHz
    $include "Config_MMC.bas"                                   'include mmc

    If Gbdriveerror <> Zero Then End
    $include "Config_AVR-DOS.BAS"                               'include avr-dos

    B = Initfilesystem(1)                                       'init file system
    'If B <> 0 Then Print "Errore MMC" 'se errore
    '=====-----------------------------------------------------
    '=====                 FAST PWM prescale 1 78kHz
    Ddrb.3 = 1
    Tccr0 = &B01101001                                          'timer0 in fast pwm mode, prescale = 1
    Ocr0 = Zero                                                 'tu wpisujemu próbkê 8 bit
    '
    '=====-----------------------------------------------------

    Config Timer2 = Timer , Prescale = 8
    On Timer2 Int_player
    Enable Interrupts
    Enable Timer2
    Start Timer2

    Cls
    Cursor Off

    Locate 5 , 2
    S = Dir( "*.*")
    While Len(s) > Zero                                         'jeœli znaleziono jakieœ pliki
      Lcd S ; "  " ; Filelen()

      'wydrukuj nazwê pliku , datê i czas utworzenia/zmiany, czas i d³ugoœæ pliku
      S = Dir()                                                 'odczytaj nastêpny
    Wend

    'Do
    Locate 1 , 2

    Lcd "Sprawdzam MMC/SD"
    Locate 2 , 2
    If B <> Zero Then Lcd "ERROR MMC"
    If Gbdriveerror <> Zero Then Lcd "GB blad"
    '=========================================
    Lcd "Gbdoserror=" ; Gbdoserror
    Locate 3 , 2
    Lcd "gbfilesystem=" ; Gbfilesystem
    Locate 4 , 2
    Lcd "gwRootEntries=" ; Gwrootentries
    '=========================================

    '===============================================================
    Do
    Open "guma.txt" For Binary As #1
    Start Timer2
    Do
    If Pozycja > 127 And Pozycja < 255 And Buf_dol = Zero Then
    For Poz_lad = Zero To 127
    Get #1 , Probka_lad
    Bufor(poz_lad) = Probka_lad
    Next Poz_lad
    Buf_dol = 1
    End If

    If Pozycja > Zero And Pozycja < 128 And Buf_gora = Zero Then
    For Poz_lad = 128 To 255
    Get #1 , Probka_lad
    Bufor(poz_lad) = Probka_lad
    Next Poz_lad
    Buf_gora = 1
    End If
    Loop Until Eof(1) <> Zero
    Close #1
    Stop Timer2
    Loop
    'Print "KONIEC"
    '-------------------------------------------------------------------------------
    End
    '-------------------------------------------------------------------------------

    Int_player:
    Porta.0 = Not Porta.0
    Timer2 = 160                                                '160 22kHz
    Stop Timer2
    Probka = Bufor(pozycja)
    Ocr0 = Probka
    If Pozycja = 255 Then Pozycja = Zero
    If Pozycja = 127 Then Buf_dol = Zero
    If Pozycja = Zero Then Buf_gora = Zero
    Incr Pozycja
    Start Timer2
    Return
    End
  • #27
    maly661
    Poziom 10  
    Atlantis86 napisał:
    Mógłbyś zaprezentować jak to odtwarza "Anti Atari Song"? ;P

    "Anti Atari Song" RULEZ - projekcik fajny i całkiem nieżle daje czadu. Przetestowane. Dziękuję :)
  • #28
    Ture11
    Poziom 35  
    Witam. Czy ktoś przetestował już ten układ do odtwarzania midi, od którego zaczął się temat? Spróbowałem coś takiego zrobić, ale nie dysponowałem Atmegą16, więc zrobiłem to na Atmedze32.
    Jedyne działanie układu to bardzo cichy pomruk w głośniczku...
    Program wgrałem do procka poprzez programator zintegrowany w Bascomie, a rezonator ustawiłem na 1MHz.
    Dziwi mnie tylko pobór - na zasilaczu pokazuje się 70mA.... To chyba dużo...
  • #29
    elmłot
    Poziom 18  
    lechoo napisał:

    Odtwarzanie nieskompresowanych plików WAV jest banalne, gdyż procesor nie robi nic więcej tylko odczytuje kolejne próbki z pamięci i wysyła je do przetwornika C/A.


    Karta SD 128MB kosztuje w granicach 5zł.
    Chciałbym zapisać kilka plików wav (kilka minut) na karcie SD , ale z częstotliwością próbkowania nie tylko 44,1kHz a więcej np: 96kHz lub 192kHz.
    Około 2-3 pliki będą to pliki o f próbkowania 44,1kHz oraz 2 pliki 96kHz i 2 pliki 192kHz.
    Następnie odtwarzać je w określonych sekwencjach (np sekwencja 1 = odtwórz plik nr1,następnie nr3, nr 5) , powiedzmy że wybór jednej z 4 sekwencji przez określony czas (wybór jednego z 4 czasów).
    Np wybieram sekwencję nr 1 i czas nr 3 (3godziny) i przez 3 godziny sekwencja nr 1 jest odtwarzana w kółko tzn plik nr1 , nr3, nr5, nr1, nr3 , nr5 itd.
  • #30
    IMEX
    Poziom 20  
    Rozumiem że ten cały dźwięk generuje ten scalaczek?

    Jestem w szoku

    stara klawiatura midi -> atmega128 => tda1547 i muzyczka gra :)