.include "m168def.inc" ; Rev History ; 27.12.24 Init ; 28.12.24 V1 ; 28.12.24 V1.1: Samples per include ; 28.12.24 V1.2: SampleLength aktiviert, Samplerate variabel, C-Bits besser konfigurierbar. ; 44100 * 256 = 11289600 = 16 Takte / Byte bzw. 2 Takte / Bit ; ; ; [BYTE 1][BYTE 2][BYTE 3][BYTE 4][BYTE 5][BYTE 6][BYTE 7][BYTE 8] auf der als MSPI arbeitenden USART. ; ; ___---_-__--__--__--__--__--__--__--__--__--__--__--__--__--__-- ; ; PPPPPPPPEEEEEEEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASSSSSSSS ; P = Preamble ; E = Extended Audio (17-24 Bit) ; A = 16 Bit PCM Audio ; S = Subcode (VVUUCCPP) ; ; ; Preable - 8 Slots ; ; B Block 11101000 (E8/17) = Links (Kanal A) ; M Frame 11100010 (E2/47) = Links (Kanal A) ; W 11100100 (E4/27) = Rechts (Kanal B) und weitere Kanäle ; ; BWMWMW...BWMW ; ; Audio ; LSB First 24 Bit (48 Slots) ; ; Subcode - 8 Slots ; ## ## ##### ##### ###### ##### ###### ; ### ### ## ## ## ## ## ## ## ## ## ; #### #### ####### ## ###### ## ## ##### ; ## ### ## ## ## ## ## ## ## ## ## ## ; ## # ## ## ## ##### ## ## ##### ###### .macro CheckUDRE LDS tmp2, UCSR0A ; 2 Word 2 Cycles SBRS tmp2, 5 ; 1 Word 1 Cycles (f) / 3 Cycles (t) Skip if Bit 5 is set RJMP -3 ; 1 Word 2 Cycles Execute if Bit 5 is NOT set .endmacro ; Channelstatusmacro ; Jedes Byte: 0bPPCCUUVV (Parity, Channestatus, Userdata, Validity) - wobei 0b00110011 = 0000 ist ; Da Validity und Userbit immer 0 sind und Parity immer automatisch gebildet wird, Gibt es nur 2 Bitmuster: ; C = 0: 0b00110011 ; C = 1: 0b11010011 ; Mit C = 0 wird der gesamte Bereich formatiert, daher müssen nur 1 gesetzt werden .macro SetChannelBit LDI BlkCnt, @0 LDI tmp, 0b11010011 ST X, tmp .endmacro ; ##### ##### ### ## ###### ###### ##### ### ## ###### ###### ; ## ## ## ## #### ## ## ## ## ## #### ## ## ## ; ## ## ## ## ## ## ##### ## ####### ## ## ## ## ##### ; ## ## ## ## ## #### ## ## ## ## ## #### ## ## ; ##### ##### ## ### ###### ## ## ## ## ### ## ###### ;.equ COPYPROTECT = 1 ; Muss nur definiert werden, wenn Copyprotection gewünscht. ;.equ EMPHASIS = 1 ; Muss nur definiert werden, wenn Emphasis (50/15µs) gewünscht. .equ SampleRate = 44100 ; Hz ; Setzt auch gleich die Bits im Subcode richtig. Zumindest für 32, 44.1 und 48kHz .equ Clock = SampleRate*256 ; 8.192MHz f. 32kHz; 11.2896MHz f. 44.1kHz; 12.288MHz f. 48kHz; 16.384MHz f. 64kHz; 22.5792MHz f. 88.2kHz .equ Baudrate = SampleRate*128 .equ BaudValue = (Clock / (2*Baudrate))-1 ; Formel gilt nur bei MSPI .equ PreambleB = 0x17 ;0xE8 ; Blockstart (L) ; LSB first! .equ PreambleM = 0x47 ;0xE2 ; Framestart (L) .equ PreambleW = 0x27 ;0xE4 ; Subframestart (R) .equ BlockLength = 192 .equ SampleLength = 2205 ; So viele Samples werden nämlich für 20Hz benötigt. ; Memory .equ SubcodeData = 0x100 ; 192 Bytes Subcode ab hier - muss x00 sein! ; ###### ###### ##### ## ###### ###### ###### ###### ###### ; ## ## ## ## ## ## ## ## ## ## ## ; ###### ##### ## ## ## ##### ## ##### ###### ##### ; ## ## ## ## ## ## ## ## ## ## ## ## ; ## ## ###### ###### ## ###### ## ###### ## ## ###### ; Register - 16Bit Zugriff ; LDD LD ADIW MOVW Außerdem: ; STD ST SBIW ;r31:r30 - Z : X X X X LPM, IJMP, ICALL, XCH, SPM, LAC, LAS, LAT ;r29:r28 - Y : X X X X ;r27:r26 - X : X X X ;r25:r24 X X ;rn+1:rn X ;r1:r0 X MUL.., SPM ; Z wird für Samplezeiger genutzt (LPM!) ; X wird für Subcodezeiger genutzt .def BlkCnt = r26 ; == XL .def SmplCntH = r25 .def SmplCnt = r24 .def SmpLENhelpH = r20 .def SmpLENhelpL = r19 .def VUCP = r18 ; 4 Bit Subcode .def tmp2 = r17 .def tmp = r16 ; r7 - MSN (Nibble - aber BMC in 8 Bit) ; 24 Bit Audiodaten für beide Kanäle ; r2 - LSN ; ###### ## ## ### ## ; ## ## ## ## #### ## ; ###### ## ## ## ## ## ; ## ## ## ## ## #### ; ## ## ###### ## ### .org 0x0000 rjmp init ; Da wir ohne jeglichen IRQ arbeiten müssen, geht es hier sogleich ohne IRQ Table los! version: .db 13,10,"SPDIF Testgenerator V1.0",13,10,"2024 jobstens.de",13,10,"Build %YEAR%-%MONTH%-%DAY% %HOUR%:%MINUTE%",13,10,"File %SOURCE%" ,13,10 ; ## ### ## ## ###### ; ## #### ## ## ## ; ## ## ## ## ## ## ; ## ## #### ## ## ; ## ## ### ## ## init: ; Stackpointer init (Auf die letzte Speicherstelle setzen) ldi tmp, HIGH(RAMEND) out SPH, tmp ldi tmp, LOW(RAMEND) out SPL, tmp ; Ports SBI DDRC, 2 ; Test SBI DDRD, 1 ; SPDIF Output (TxD, SPI USART) ; Initialisierung der SPI USART ; UDR0 = Datenregister - Put Data into it ; UCSR0A = Nur lesen. Bit 5 ist gesetzt, wenn ein Byte in UDR0 abgelegt werden kann. ; UCSR0B = 0b00001000 = 0x08 = nur TxD einschalten ; UCSR0C = 0b11000100 = 0xC0 = MSPI, LSB first ; UBRR0H:UBRR0L = 0:1 LDI tmp, HIGH(BaudValue) STS UBRR0H, tmp LDI tmp, LOW(BaudValue) STS UBRR0L, tmp LDI tmp, 0x08 ; Tx enable STS UCSR0B, tmp LDI tmp, 0xC4 ; MSPI, LSB first STS UCSR0C, tmp ; ## ## ##### ## ### ## ; ### ### ## ## ## #### ## ; #### #### ####### ## ## ## ## ; ## ### ## ## ## ## ## #### ; ## # ## ## ## ## ## ### ; ####################################################################################################################### ; Channelstatus bauen ; ####################################################################################################################### ; Channelstatus (Subcode) blank ziehen LDI XH, HIGH(SubcodeData) ; Zeiger auf Anfang LDI XL, LOW(SubcodeData) LDI tmp, 0b00110011 ; V = 0 ; U = 0 ; C = 0 ; P = 0 formatC: ST X+, tmp CPI XL, 192 BRNE formatC LDI XH, HIGH(SubcodeData) ; Zeiger auf Anfang LDI XL, LOW(SubcodeData) ; Jedes Byte: 0bPPCCUUVV - wobei 0b00110011 = 0000 ist ; Da Validity und Userbit immer 0 sind und Parity immer automatisch gebildet wird, Gibt es nur 2 Bitmuster: ; C = 0: 0b00110011 ; C = 1: 0b11010011 ; s.a. https://www.mikrocontroller.net/articles/S/PDIF#Channel-Status_/_Subcode ; Channelstatus bauen ; evtl. noch durch Jumpersettings von außen einstellbar machen!? ; 2: C-Bit (CopyBit) ; 0 = Kopierschutz aktiv ; 1 = Kopierschutz inaktiv .ifndef COPYPROTECT SetChannelBit 2 .endif ; 3: Emphasis (50/15µs) ; 0 = Emphasis inaktiv ; 1 = Emphasis aktiv .ifdef EMPHASIS SetChannelBit 3 .endif ; 8-14: Category code. 0000001 = Experimental SetChannelBit 14 ; 15: L-Bit - mal auf 1 gesetzt SetChannelBit 15 ; 24-27: Fs. 0000 = 44.1kHz, 0100 = 48kHz, 1100 = 32kHz .if SampleRate==48000 SetChannelBit 25 .endif .if SampleRate==32000 SetChannelBit 24 SetChannelBit 25 .endif ; 28-29: Taktabweichung. 01 = ...? SetChannelBit 29 ; ####################################################################################################################### ; /Channelstatus bauen ; ####################################################################################################################### ; Startbedingungen (funktioniert zwar auch ohne - aber so ist's schöner) LDI tmp, PreambleB LDI SmplCnt, 0 LDI SmplCntH, 0 LDI XH, HIGH(SubcodeData) ; Zeiger auf Anfang ; BlkCnt LDI XL, LOW(SubcodeData) LDI ZH, HIGH(SampleBase*2) ; Zeiger auf Anfang ; SMPLCNT LDI ZL, LOW(SampleBase*2) ; SMPLCNT LDI SmpLENhelpH, HIGH(SampleLength) LDI SmpLENhelpL, LOW(SampleLength) ; ## ##### ##### ###### ; ## ## ## ## ## ## ## ; ## ## ## ## ## ###### ; ## ## ## ## ## ## ; ###### ##### ##### ## ; Einrückung: ; A = Verwaltungscode ; B = Zeitkritischer Code f. Ausgabe ; C = Abteilung bei Verwaltung ; A B C loop: ; ####################################################################################################################### ; links ; ####################################################################################################################### CheckUDRE ; 5*x Cycles STS UDR0, tmp ; Preamble verschickt CheckUDRE ; 5*x Cycles STS UDR0, r2 ; 4 LSB 24-Bit Audio L verschickt LPM r4, Z+ ; GET_SAMPLE LPM r5, Z+ ; GET_SAMPLE CheckUDRE ; 5*x Cycles STS UDR0, r3 ; 4 LSB 20-Bit Audio L verschickt LPM r6, Z+ ; GET_SAMPLE LPM r7, Z+ ; GET_SAMPLE CheckUDRE ; 5*x Cycles STS UDR0, r4 ; 4 LSB 16-Bit Audio L verschickt LD VUCP, X+ ; Hole Subcode und inc. gleichzeitig Zeiger UND BlkCnt ; SUBCODE , BLKCNT CheckUDRE ; 5*x Cycles STS UDR0, r5 ; 4 Bit Audio L verschickt CheckUDRE ; 5*x Cycles STS UDR0, r6 ; 4 Bit Audio L verschickt tst r7 ; r7 (auf MSB) testen ; SUBCODE BRPL sb0end ; Branch wenn MSB von r7 == 0 ; SUBCODE COM VUCP ; wenn r7.MSB gesetzt ist, muss VUCP invertiert werden ; SUBCODE sb0end: ; SUBCODE CheckUDRE ; 5*x Cycles STS UDR0, r7 ; 4 MSB Audio L verschickt ANDI VUCP, 0x7F ; Parity immer richtig ; SUBCODE ADIW SmplCnt, 1 ; ++ ; SMPLCNT CheckUDRE ; 5*x Cycles STS UDR0, VUCP ; 4 Bit VUCP verschickt ; ####################################################################################################################### ; rechts ; ####################################################################################################################### LDI tmp, PreambleW ; Rechts ist IMMER W CheckUDRE ; 5*x Cycles STS UDR0, tmp ; Preamble verschickt CheckUDRE ; 5*x Cycles STS UDR0, r2 ; 4 LSB 24-Bit Audio R verschickt CP SmplCnt, SmpLENhelpL ; SMPLCNT CPC SmplCntH, SmpLENhelpH ; SMPLCNT BRLO scend ; SampleLength < SmplCnt ; SMPLCNT LDI SmplCntH, 0 ; SampleLength erreicht, Reset ; SMPLCNT LDI SmplCnt, 0 ; SMPLCNT scend: ; SMPLCNT CheckUDRE ; 5*x Cycles STS UDR0, r3 ; 4 LSB 20-Bit Audio R verschickt CheckUDRE ; 5*x Cycles STS UDR0, r4 ; 4 LSB 16-Bit Audio R verschickt MOV tmp, SmplCnt ; SMPLCNT OR tmp, SmplCntH ; SMPLCNT BRNE sc2end ; Branch if tmp != 0 ; SMPLCNT LDI ZH, HIGH(SampleBase*2) ; Wenn tmp == 0 Zeiger auf Anfang ; SMPLCNT LDI ZL, LOW(SampleBase*2) ; SMPLCNT sc2end: ; SMPLCNT CheckUDRE ; 5*x Cycles STS UDR0, r5 ; 4 Bit Audio R verschickt CheckUDRE ; 5*x Cycles STS UDR0, r6 ; 4 Bit Audio R verschickt LPM r2, Z+ ; GET_SAMPLE LPM r3, Z+ ; GET_SAMPLE CheckUDRE ; 5*x Cycles STS UDR0, r7 ; 4 MSB Audio R verschickt CheckUDRE ; 5*x Cycles STS UDR0, VUCP ; 4 Bit VUCP verschickt ; ####################################################################################################################### LDI tmp, PreambleM ; normalerweise kommt als nächstes M ; BLKCNT ; 1 CPI BlkCnt, BlockLength ; BLKCNT ; 1 BRLO loop2 ; BLKCNT ; 1 (false) / 2 (true) CLR BlkCnt ; Blockstart = 0 ; BLKCNT ; 1 LDI tmp, PreambleB ; Bei Blockstart jedoch B ; BLKCNT ; 1 loop2: RJMP loop ; 2 ; ###### ## ## ###### ## ## ###### ; ## ## ## ## ## ## ## ; ## ####### ##### ##### #### ; ## ## ## ## ## ## ## ; ## ## ## ###### ## ## ###### ; Bitte bedienen Sie sich! ; Eine Zeile = ein 24 Bit Sample - bereits als biphase mark code SampleBase: .include "asmwaves/SinTable_multitone_20_50_-_10k_20k_je_-20dB.asm"