нужно обрезать код так чтобы можно было проиграть вавчик указанный в нашей переменной ну допустим "Wav_Out"
работа с директориями нафиг не нужна
для начала схемы:
у них мега162 16МГц
у нас мега32 7.372800 MГц
у них звук выводится в
Ch1 PortE.2 (OC1B)
Ch2 PortB.4 (OC3B)
у нас PordD.7 (OC2)
еще меня смущает их кварц на 23КГц висящий на PortD.4 (TOSC1) и PortD.5 (TOSC2)
почему не часовой, можно обойтись без него?
основной код:
- Код: Выделить всё • Развернуть
'***************************************************************
'Play a Wave file
'***************************************************************
'parses the wav file, sets up PWM on counter 1 and 3, generates 50X sample rate clock on counter 0, and plays wav file
'If playing a single wav, bugs out if not a compatible wav format
'If playing a dir, skips it, and gets the next.
'Flashes a message on the LCD if something is wrong.
Sub Playwav(direntry As Word)
Local Lcdtime As Byte , Attr As Byte
Attr = Dir_attr(direntry) 'get the attribute of the directory entry
Attr = Attr And Attr_directorymsk 'mask off all but the directory bit
Do
If Playbutton = 0 Then
Attr = 0
Goto Playwavend 'don't like the song or dir, bug out
End If
If Attr = Attr_directorymsk Then
'we are playing a whole dir
Do
Call Nextfile(direntry , 1) 'get next valid file
If Direntry = 0 Then 'if next file returns zero then we have wraped
Call Dir2lcd(direntry) 'display dir on lcd, for the last time
Exit Sub 'and bug out
End If
Loop Until Dir_ext(direntry) = "WAV" 'find a WAV file
Call Openfile(direntry) 'open the file
Call Dir2lcd(direntry) 'display dir on lcd
Else
'we are playing one dir entry
If Dir_ext(direntry) <> "WAV" Then 'make sure it is a WAV file
Call Flashlcd(1 , 1 , "not a WAV")
Exit Sub
End If
End If
Fileoffset = 0 'finished playing with directories, set file offset to zero
Gosub Parsewav 'check out the wav file and pull out format info
If Warningcode > 0 Then 'If parsewav cannot find format info,
Print "WAV error" ; Warningcode 'display warning on serial port for fun
Call Flashlcd(1 , 1 , "WAV error")
Goto Playwavend 'then bug out
End If
If Formattag <> 1 Then 'if Formattag is not 1 (uncompressed raw pcm)
Call Flashlcd(1 , 1 , "Unsupported WAV")
Goto Playwavend 'then bug out
End If
Endofdata = Endofdata + Fileoffset 'End of WAV data = current file offset + bytesperlong
Endofdata = Endofdata + Bytesperlong
'Counter 1 & 3 are used as a PWM Digital to Analogue converter
'Set up counter1 Timer Counter Control 1A & 1B
'Compare Output Mode counter 1 B = clear on compare. Page 127
Tccr1a = &B00100011
'Waveform Generation Mode = 15, TOP = OCR1A, update of OCR1B at TOP, TOV1 flag on TOP. Page 129
Tccr1b = &B00011001
Samplespersec = _xtal / Samplespersec
Decr Samplespersec
Compare1a = Samplespersec 'Set TOP Counter1
'Set up counter3 Timer Counter Control 3A & 3B
'Compare Output Mode counter 3 B = clear on compare. Page 127
Tccr3a = &B00100011
'Waveform Generation Mode = 15, TOP = OCR3A, update of OCR3B at TOP, TOV3 flag on TOP. Page 129
Tccr3b = &B00011001
Compare3a = Samplespersec 'Set TOP Counter3
'Fudge factor is a multiply if we are doing 8 bit or divide if 16 bit.
'In 8 bit WAV uses more of the available range of the compare register.
'In 16 bit WAV makes sure the compare register is less than TOP by chopping off the LSBs.
Fudgefactor = Samplespersec / &H00FF 'by default
If Bitspersample = 16 Then Fudgefactor = &HFFFF / Samplespersec 'bad
'If Bitspersample = 16 Then Fudgefactor = &H8FFF / Samplespersec 'better
'If Bitspersample = 16 Then Fudgefactor = &H4FFF / Samplespersec 'best of bad bunch
'If Bitspersample = 16 Then Fudgefactor = &H2FFF / Samplespersec 'clips peaks
'Counter 0 is used to generate a 50 X sample rate square wave (1:1 mark:space ratio) clock for switched cap filter.
'set up counter0 Timer Counter Control 0
'Clear Timer on Compare Match (CTC) Waveform Generation Mode 2. Page 99
'Toggle OC0 on Compare Match. Page 100
'clkI/O/(No prescaling). Page 101
Tccr0 = &B00011001
Incr Samplespersec
Samplespersec = Samplespersec / 100 '50X and another 2X because we are using toggle on match
Decr Samplespersec
Ocr0 = Samplespersec
Putpointer = 0 'Initialise fifo control
Takepointer = 0
Fifostatus = 0
Counter1 = 0 'Sync counters, as they are running in parallel
Counter3 = 0
Gosub Fillfifo 'Give the fifo a head start
'Set up interrupt on counter1
in r16, timsk 'Read Timer Interrupt Mask
ori r16, &B01000000 'Set OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
!out timsk, r16 'Put it back.
'Interrupt is a go
'Lets play
Lcdtime = Ticktock + 1 'time for lcd to display something
Do
Gosub Fillfifo
If Lcdtime = Ticktock Then
Locate 1 , 13 'play position
Lcdtime = Ticktock + 1 'update lcd time
If Ticktock.0 = 1 Then 'On even second
Lcd "Play"
Else 'On odd second
Lcd " "
End If
End If
If Playbutton = 0 Then
Attr = 0
Goto Playwavend 'don't like the song or dir, bug out
End If
Loop Until Fileoffset >= Endofdata 'If we do not have any more data, then bug out
'Finished Playing Wav File, but there are still a few bytes left in the fifo
While Fifostatus <> 0
'hang around
Wend
Playwavend:
in r16, timsk 'Read Timer Interrupt Mask
andi r16, &B10111111 'Clear OCIE1A: Timer/Counter1, Output Compare A Match Interrupt Enable
!out timsk, r16 'Put it back
'Interrupt is a NO go
Tccr1a = 0 'Timer Counter Control 1A = off
Tccr3a = 0 'Timer Counter Control 3A = off
Tccr0 = 0 'Timer Counter Control 0 = off
Locate 1 , 13
Lcd " "
Gosub Flushbuffer
Bitwait Playbutton , Set 'wait for finger to come off the play button
Loop Until Attr <> Attr_directorymsk 'loop if we are playing a dir
End Sub
Parsewav:
Warningcode = 1
Endofdata = Chunksize( "RIFF") 'Borrow End of Data, as it is not need yet
If Warningcode <> 0 Then Return
Warningcode = 2
Endofdata = Chunksize( "WAVE") 'Borrow End of Data, as it is not need yet
If Warningcode <> 0 Then Return
Warningcode = 3
Endofdata = Chunksize( "fmt " ) 'Borrow End of Data, as it is not need yet
If Warningcode <> 0 Then Return
Loadadr Filebuffer(21) , X 'Source address
Loadadr Formattag , Z 'Destination address
ldi r21, bytesperword 'Number of bytes to xfer
!Call Mem2mem 'Transfer memory to memory
Loadadr Filebuffer(23) , X
Loadadr Numchannels , Z 'Destination address
ldi r21, bytesperword 'Number of bytes to xfer
!Call Mem2mem 'Transfer memory to memory
Loadadr Filebuffer(25) , X
Loadadr Samplespersec , Z 'Destination address
ldi r21, bytesperlong 'Number of bytes to xfer
!Call Mem2mem 'Transfer memory to memory
Loadadr Filebuffer(29) , X
Loadadr Avgbytespersec , Z 'Destination address
ldi r21, bytesperlong 'Number of bytes to xfer
!Call Mem2mem 'Transfer memory to memory
'Print "AvgBytesPerSec " ; Avgbytespersec
Loadadr Filebuffer(33) , X
Loadadr Blockalign , Z 'Destination address
ldi r21, bytesperword 'Number of bytes to xfer
!Call Mem2mem 'Transfer memory to memory
'Print "blkalg " ; Blockalign
Loadadr Filebuffer(35) , X
Loadadr Bitspersample , Z 'Destination address
ldi r21, bytesperlong 'Number of bytes to xfer
!Call Mem2mem 'Transfer memory to memory
Warningcode = 4
Endofdata = Chunksize( "data" )
Return
основные лаблы:
- Код: Выделить всё • Развернуть
Fillfifo:
'written in ASM since this must be done as fast as possible.
'with 16000 samples per sec & 8 bits per channel & 2 channels, we have to move 32000 bytes per sec
'22.050ks/s & 16b/ch & 2 ch => 88kB/s which is about the limit.
'why fifo > 255 bytes? (= word pointers)
'It takes about 11ms (measured) to fill the 32k file buffer, so we must buffer at least 11ms worth of sound per channel.
'At 16ks/s = a buffer size of about 176. BUT if a fresh fat has to be loaded, it may take >30ms
'so a fifo > 500 is needed (= word pointers).
lds r16, {fifostatus}
cpi r16, &HFF
brne fillfifofill 'While fifo not full, fill it
ret 'RETURN is here
Fillfifofill:
rcall Getsample 'comes back with fudged ch word in r16-r17
push r16
push r17 'save just in case we have 2 channels
lds r18, {Numchannels}
cpi r18, 2 'if we have 2 channels
brne fillfifomono 'skip getting ch2 byte
rcall Getsample 'comes back with fudged ch word in r16-r17
Fillfifomono:
mov r20, r16
mov r21, r17 'copy Ch2 word, in either case
pop r17
pop r16 'pop Ch1 word in either case
lds r24, {putpointer}
lds r25, {putpointer+1} 'put pointer to r24-r25
adiw r24, 1 'incument put pointer
ldi r18, fifosize_lo
ldi r19, fifosize_hi
cp r18, r24
cpc r19, r25 'compare with fifo size
brne fillfifonowrap
clr r24
clr r25 'If we have reached end, then wrap
Fillfifonowrap:
lsl r24
rol r25 'multiply by bytes per word (2) since the fifo contains words
Loadadr Ch1fifo(1) , X
add r26, r24
adc r27, r25 'add pointer to fifo address
st X+, r16 'Store Ch1 lo
st X, r17 'Store Ch2 hi
Loadadr Ch2fifo(1) , X
add r26, r24
adc r27, r25 'add pointer to fifo address
st X+, r20 'Store Ch2 lo
st X, r21 'store Ch2 hi
'Check For Full
lsr r25
ror r24 'divide pointer by bytes per word (2)
sts {putpointer}, r24
sts {putpointer+1}, r25 'Store pointer
adiw r24, 1 'incument put pointer again
'Fifo size still in r18-r19
cp r18, r24
cpc r19, r25 'compare with fifo size again
brne fillfifonowrap1
clr r24
clr r25
Fillfifonowrap1:
lds r18,{takepointer}
lds r19, {takepointer+1} 'Take pointer to r16-r17
cp r24, r18
cpc r25, r19 'compare take pointer with put pointer
ldi r16, 1 'fifo not full
brne fillfifoend
ldi r16, &HFF 'fifo full indication
Fillfifoend:
sts {fifostatus}, r16
rjmp fillfifo
- Код: Выделить всё • Развернуть
'***************************************************************
'New Sample Interrupt Service Routine
'***************************************************************
'Sticks a new sample into the Pulse Width Modulator compare registers, from fifos
'Updates take pointer and fifo status.
'This is called by interrupt, so all registers must stay un corrupted.
'With NoSave, must save used registers
Newsample:
push r16
in r16, sreg
push r16
push r17
push r18
push r24
push r25
push r26
push r27 'Save used registers
lds r24, {takepointer}
lds r25, {takepointer+1} 'get take pointer
lsl r24
rol r25 'multiply by bytes per word (2) since the fifo contains words
Loadadr Ch1fifo(1) , X
add r26, r24
adc r27, r25 'add takepointer to address
ld r16, X+ 'get the pwm lo byte
ld r17, X 'get the pwm hi
!out ocr1bh, r17 'High register first for this 16 bit register, refer page 108
!out ocr1bl, r16 'Lo register next. The CH1fifo(takepointer) byte
Loadadr Ch2fifo(1) , X
add r26, r24
adc r27, r25 'add takepointer to address
ld r16, X+ 'get the pwm lo byte
ld r17, X 'get the pwm hi
'Warning ocr3b outside "out" address range, use "sts" instead
sts Ocr3bh, r17 'High register first for this 16 bit register, refer page 108
sts Ocr3bl, r16 'Lo register next. The CH1fifo(takepointer) byte
lsr r25
ror r24 'divide pointer by bytes per word (2)
adiw r24, 1 'incrument takepointer
ldi r16, fifosize_lo
ldi r17, fifosize_hi
cp r24, r16
cpc r25, r17 'compare with fifosize
brne newsamplenowrap
clr r24 'if we have reached fifo size, set takepointer back to 0
clr r25
Newsamplenowrap:
lds r16, {putpointer}
lds r17, {putpointer+1} 'put pointer to r16-r17
cp r16 , r24
cpc r17, r25 'compare take pointer and put pointer
ldi r18, 0 'empty status and / or under run
breq newsamplenoupdateptr 'on next sample use the same PWM word if take pointer and put pointer are equal
ldi r18, 1 'not full status. We just took a byte, so it is not full.
sts {takepointer}, r24
sts {takepointer+1}, r25 'Save new takepointer if no under run
Newsamplenoupdateptr:
sts {fifostatus}, r18 'Update fifo status 0 = fifo empty, 1= not full
pop r27 'Restore used registers
pop r26
pop r25
pop r24
pop r18
pop r17
pop r16
!Out Sreg, r16
pop r16
reti
Добавлено спустя 3 часа 10 минут 2 секунды:
походу там ошибка в схеме.
в коде есть вот такая запись
'32.768kHz osc on TOSC1 and TOSC prescaled by 128 = 256Hz (1/256seconds). So Tcnt2 (8bit) will wrap every 1 second
'Config Timer2 = Timer , Async = On , Prescale = 1024 'Mass confusion here ???
Assr = &B00001000 'AS2: Asynchronous Timer/Counter2 ON
Tccr2 = &B00000101 'Mode 0 (normal), clkT2s/128