.include "m88def.inc" ; PB2 = MC / Clock ; PB1 = MD / Data ; PD6 = MS / Select PCM1738 ; PC4, PC5 = Drehgeber zum einstellen der Lautstärke - sofern gewünscht. ; ###### ###### ##### ## ###### ###### ###### ###### ###### ; ## ## ## ## ## ## ## ## ## ## ## ; ###### ##### ## ## ## ##### ## ##### ###### ##### ; ## ## ## ## ## ## ## ## ## ## ## ## ; ## ## ###### ###### ## ###### ## ###### ## ## ###### .def Dreg = r20 .def Dout = r19 .def chnl = r18 .def tmp2 = r17 .def tmp = r16 .def zero = r15 .def one = r14 ; ##### ##### ### ## ###### ###### ##### ### ## ###### ###### ; ## ## ## ## #### ## ## ## ## ## #### ## ## ## ; ## ## ## ## ## ## ##### ## ####### ## ## ## ## ##### ; ## ## ## ## ## #### ## ## ## ## ## #### ## ## ; ##### ##### ## ### ###### ## ## ## ## ### ## ###### ; Memory ; PCM1738 ; Reg 16 .equ DAC_ATTN_L = 0x180 ; Reg 17 .equ DAC_ATTN_R = 0x181 ; Reg 18 .equ DAC_ATTN_EN = 0x182 ; ATLD .equ DAC_InputWordFormat = 0x183 ; FMT .equ DAC_Deemphasis = 0x184 ; DMF .equ DAC_Deemphasis_freq = 0x185 ; DME .equ DAC_Mute = 0x186 ; Mute ; Reg 19 .equ DAC_Phase_Reversal = 0x187 ; REV .equ DAC_Attn_Rate = 0x188 ; ATS .equ DAC_Operation_EN = 0x189 ; OPE ; CLKD ; CLKE .equ DAC_DF_Roll_off = 0x18A ; FLT .equ DAC_Zero_Detect = 0x18B ; INZD ; Reg 20 .equ DAC_Reset = 0x18C ; SRST ; MRST .equ DAC_DF_Bypass_EN = 0x18D ; DFTH .equ DAC_Mono = 0x18E ; MONO .equ DAC_Mono_Channel_sel = 0x18F ; CHSL .equ DAC_Oversampling = 0x190 ; OS ; ## ## ##### ##### ###### ##### ###### ; ### ### ## ## ## ## ## ## ## ## ## ; #### #### ####### ## ###### ## ## ##### ; ## ### ## ## ## ## ## ## ## ## ## ## ; ## # ## ## ## ##### ## ## ##### ###### ; Reg 18 .macro Set_DAC_ATTN_DISABLE LDI tmp, 0 STS DAC_ATTN_EN, tmp .endmacro .macro Set_DAC_ATTN_ENABLE LDI tmp, 0x80 STS DAC_ATTN_EN, tmp .endmacro .macro Set_DAC_In_16_MSB_right LDI tmp, 0 STS DAC_InputWordFormat, tmp .endmacro .macro Set_DAC_In_20_MSB_right LDI tmp, 0x10 STS DAC_InputWordFormat, tmp .endmacro .macro Set_DAC_In_24_MSB_right LDI tmp, 0x20 STS DAC_InputWordFormat, tmp .endmacro .macro Set_DAC_In_24_MSB_left LDI tmp, 0x30 STS DAC_InputWordFormat, tmp .endmacro .macro Set_DAC_In_16_I2S LDI tmp, 0x40 STS DAC_InputWordFormat, tmp .endmacro .macro Set_DAC_In_24_I2S LDI tmp, 0x50 STS DAC_InputWordFormat, tmp .endmacro .macro Set_DAC_Deemphasis_Freq_44100 LDI tmp, 0x08 STS DAC_Deemphasis_freq, tmp .endmacro .macro Set_DAC_Deemphasis_Freq_48000 LDI tmp, 0x04 STS DAC_Deemphasis_freq, tmp .endmacro .macro Set_DAC_Deemphasis_Freq_32000 LDI tmp, 0x0C STS DAC_Deemphasis_freq, tmp .endmacro .macro Set_DAC_Deemphasis_OFF LDI tmp, 0 STS DAC_Deemphasis, tmp .endmacro .macro Set_DAC_Deemphasis_ON LDI tmp, 2 STS DAC_Deemphasis, tmp .endmacro .macro Set_DAC_MUTE_ON LDI tmp, 1 STS DAC_Mute, tmp .endmacro .macro Set_DAC_MUTE_OFF LDI tmp, 0 STS DAC_Mute, tmp .endmacro ; Reg 19 .macro Set_DAC_Phase_Reversal_ON LDI tmp, 0x80 STS DAC_Phase_Reversal, tmp .endmacro .macro Set_DAC_Phase_Reversal_OFF LDI tmp, 0 STS DAC_Phase_Reversal, tmp .endmacro .macro Set_DAC_Attn_Rate_LRCK1 LDI tmp, 0 STS DAC_Attn_Rate, tmp .endmacro .macro Set_DAC_Attn_Rate_LRCK2 LDI tmp, 0x20 STS DAC_Attn_Rate, tmp .endmacro .macro Set_DAC_Attn_Rate_LRCK4 LDI tmp, 0x40 STS DAC_Attn_Rate, tmp .endmacro .macro Set_DAC_Attn_Rate_LRCK8 LDI tmp, 0x60 STS DAC_Attn_Rate, tmp .endmacro .macro Set_DAC_Operation_ENABLED LDI tmp, 0 STS DAC_Operation_EN, tmp .endmacro .macro Set_DAC_Operation_DISABLED LDI tmp, 0x10 STS DAC_Operation_EN, tmp .endmacro ; CLKD ; CLKE .macro Set_DAC_Filter_SHARP_roll_off LDI tmp, 0 STS DAC_DF_Roll_off, tmp .endmacro .macro Set_DAC_Filter_SOFT_roll_off LDI tmp, 2 STS DAC_DF_Roll_off, tmp .endmacro .macro Set_DAC_Zero_Detect_mute_EN LDI tmp, 1 STS DAC_Zero_Detect, tmp .endmacro .macro Set_DAC_Zero_Detect_mute_DIS LDI tmp, 0 STS DAC_Zero_Detect, tmp .endmacro ; Reg 20 .macro Set_DAC_RESET LDI tmp, 0x40 STS DAC_Reset, tmp .endmacro .macro ReSet_DAC_RESET LDI tmp, 0 STS DAC_Reset, tmp .endmacro ; MRST .macro Set_DAC_DF_INTERNAL LDI tmp, 0 STS DAC_DF_Bypass_EN, tmp .endmacro .macro Set_DAC_DF_EXTERNAL LDI tmp, 0x10 STS DAC_DF_Bypass_EN, tmp .endmacro .macro Set_DAC_STEREO LDI tmp, 0 STS DAC_Mono, tmp .endmacro .macro Set_DAC_MONO_L LDI tmp, 8 STS DAC_Mono, tmp LDI tmp, 0 STS DAC_Mono_Channel_sel, tmp .endmacro .macro Set_DAC_MONO_R LDI tmp, 8 STS DAC_Mono, tmp LDI tmp, 4 STS DAC_Mono_Channel_sel, tmp .endmacro .macro Set_DAC_OVSAMPLING_64x_8x LDI tmp, 0 STS DAC_Oversampling, tmp .endmacro .macro Set_DAC_OVSAMPLING_128x_16x LDI tmp, 2 STS DAC_Oversampling, tmp .endmacro .macro Set_DAC_OVSAMPLING_32x_4x LDI tmp, 3 STS DAC_Oversampling, tmp .endmacro ; ## ##### ## #### ## ## ; ##### ## ## ## ## ## ## ## ; ######## ##### ## ###### ##### ; ##### ## ## ## ## ## ; ## ## ###### ## ## #### .org 0x0000 ; Reset Handler rjmp init .org OC0Aaddr ; Clear timer on compare match irq rjmp TI0IRQ_entry DrehgeberTBL: .db 0,-1,0,0, 1,0,0,0, 0,0,0,0, 0,0,0,0 TI0IRQ_entry: push tmp in tmp, sreg ;Register sichern push tmp push ZH push ZL ; Drehgeber sbis PinC, 4 ori Dreg, 8 ;Drehgeber abgfragt (erstes bit) sbis PinC, 5 ;Drehgeber abgfragt (zweites bit) ori Dreg, 4 ;Dout = Dout + Inhalt von ROM Adresse (DrehgeberTBL+Dreg) CLR tmp LDI ZL, LOW(2*DrehgeberTBL) LDI ZH, HIGH(2*DrehgeberTBL) ; Startadresse der Tabelle ADD ZL, Dreg ADC ZH, tmp ; Alten und neuen Wert des Drehgebers zur Startadresse dazu zählen LPM tmp, Z ; Ein byte aus der Adresse des Z-Registers in tmp geladen ADD Dout, tmp ; Addiere tmp zu Dout dazu CPI Dout, 0 ; wenn 0 erreicht wurde, dann wieder zurück auf 255 BRNE TI0IRQ_br1 LDI Dout, 255 TI0IRQ_br1: CPI Dout, 13 ; wenn 13 erreicht wurde, dann wieder zurück auf 14 BRNE TI0IRQ_br2 LDI Dout, 14 TI0IRQ_br2: LSR Dreg ; LSR Dreg ; Die 2 alten bits werden nach rechts raus geschoben und die 2 neuen bits werden zu den alten POP ZL POP ZH POP tmp OUT sreg, tmp ; Register + SR zurück schieben POP tmp RETI ; Timer 0 IRQ fertig. version: .db 13,10,"PCM1738 Control V1 Single w/o DF",13,10,"2025 jobstens.de",13,10,"Build %YEAR%-%MONTH%-%DAY% %HOUR%:%MINUTE% UTC",13,10,"File %SOURCE%" ,13,10,13,10,0,0 ; ## ### ## ## ###### ; ## #### ## ## ## ; ## ## ## ## ## ## ; ## ## #### ## ## ; ## ## ### ## ## init: ; Stackpointer init (Auf die letzte Speicherstelle setzen) ldi tmp, HIGH(RAMEND) out SPH, tmp ldi tmp, LOW(RAMEND) out SPL, tmp RCALL wait_200ms ;Warten ; constreg clr zero clr one inc one ; PortD LDI tmp, 0xFB ; Alle ausser /SRC_INT Ausgang OUT DDRD, tmp LDI tmp, 0xF7 ; PullUp /SRC_INT ; /RST Low ; Rest H - WO IST EIGENTLICH LE_PCM4222 ABGEBLIEBEN? n.c. - what a pitty! Naja ... OUT PortD, tmp ; PortC LDI tmp, 0x0F ; I2C Eingang, 4 Ausgang OUT DDRC, tmp LDI tmp, 0xF4 ; Pullup I2C aktivieren ; ADC 24M und Masterclock 24M OUT PortC, tmp ; PortB LDI tmp, 0xEF ; Alle Ausgang ; MISO Input ; PB2 MUSS Output sein, da sonst SPI auf die Klappe fällt. OUT DDRB, tmp LDI tmp, 0xFB ; Defaults ; MC(PB2) L OUT PortB, tmp ; Timer0init (IRQ) ldi tmp, 10 out OCR0A, tmp ldi tmp, 0x02 ; WGM00/01 - CTC out TCCR0A, tmp ldi tmp, 0x03 ; Teiler 32 ; WGM02 - CTC out TCCR0B, tmp ldi tmp, 0x02 ; Irq an sts TIMSK0, tmp SEI ; Drehgeber zyklisch abfragen RCALL WAIT_100ms LDI Dout, -1 ; Startlautstaerke - volle Pulle ; Hardware default config ; Speichertyp RCALL CONFIG_Load_Defaults ; Defaultwerte laden ; ## ## ##### ## ### ## ; ### ### ## ## ## #### ## ; #### #### ####### ## ## ## ## ; ## ### ## ## ## ## ## #### ; ## # ## ## ## ## ## ### main: STS DAC_ATTN_L, Dout ; Lautstärke vom Drehgeber übernehmen. STS DAC_ATTN_R, Dout RCALL InitHardware RCALL WAIT_200us RJMP main ; ##### ### ### ## ## ##### ## ##### ; ##### ## ## ## ## ### ## ## ## ## ; ##### ## ## ## ###### ### ## ## ### ; ##### ## ## ## ## ## ### ## ## ## ## ; ##### ### ### ## ## ## ## ##### CONFIG_Load_Defaults: ; Hier Einstellungen vornehmen! ; Reg 18 ;Set_DAC_ATTN_DISABLE Set_DAC_ATTN_ENABLE ;Set_DAC_In_16_MSB_right ; <--- Hier das gewünschte Format auswählen ;Set_DAC_In_20_MSB_right ;Set_DAC_In_24_MSB_right ;Set_DAC_In_24_MSB_left ;Set_DAC_In_16_I2S Set_DAC_In_24_I2S Set_DAC_Deemphasis_Freq_44100 ;Set_DAC_Deemphasis_Freq_48000 ;Set_DAC_Deemphasis_Freq_32000 Set_DAC_Deemphasis_OFF ;Set_DAC_Deemphasis_ON ;Set_DAC_MUTE_ON Set_DAC_MUTE_OFF ; Reg 19 ;Set_DAC_Phase_Reversal_ON Set_DAC_Phase_Reversal_OFF Set_DAC_Attn_Rate_LRCK1 ;Set_DAC_Attn_Rate_LRCK2 ;Set_DAC_Attn_Rate_LRCK4 ;Set_DAC_Attn_Rate_LRCK8 Set_DAC_Operation_ENABLED ;Set_DAC_Operation_DISABLED Set_DAC_Filter_SHARP_roll_off ;Set_DAC_Filter_SOFT_roll_off ;Set_DAC_Zero_Detect_mute_EN Set_DAC_Zero_Detect_mute_DIS ; Reg 20 ;Set_DAC_RESET ReSet_DAC_RESET ; MRST Set_DAC_DF_INTERNAL ;Set_DAC_DF_EXTERNAL Set_DAC_STEREO ;Set_DAC_MONO_L ;Set_DAC_MONO_R ;Set_DAC_OVSAMPLING_64x_8x ; default Set_DAC_OVSAMPLING_128x_16x ;Set_DAC_OVSAMPLING_32x_4x RET InitHardware: RCALL WAIT_10ms SBI PortD, 3 ; Release Reset RCALL WAIT_10ms RCALL InitHardware_PCM1738 RET InitHardware_PCM1738: ; DAC vollquatschen CBI PortD, 6 ; /MS_PCM1738A auf L setzen LDI tmp, 16 ; Lautstärke L setzen RCALL DAC_SendByte LDS tmp, DAC_ATTN_L RCALL DAC_SendByte ; Daten übernehmen SBI PortD, 6 ; /MS_PCM1738A auf H setzen NOP CBI PortD, 6 ; /MS_PCM1738A auf L setzen LDI tmp, 17 ; Lautstärke R setzen RCALL DAC_SendByte LDS tmp, DAC_ATTN_R RCALL DAC_SendByte ; Daten übernehmen SBI PortD, 6 ; /MS_PCM1738A auf H setzen NOP CBI PortD, 6 ; /MS_PCM1738A auf L setzen LDI tmp, 18 ; Register 18 RCALL DAC_SendByte LDS tmp, DAC_ATTN_EN LDS tmp2, DAC_InputWordFormat OR tmp, tmp2 LDS tmp2, DAC_Deemphasis_freq OR tmp, tmp2 LDS tmp2, DAC_Deemphasis OR tmp, tmp2 LDS tmp2, DAC_Mute OR tmp, tmp2 RCALL DAC_SendByte ; Daten übernehmen SBI PortD, 6 ; /MS_PCM1738A auf H setzen NOP CBI PortD, 6 ; /MS_PCM1738A auf L setzen LDI tmp, 19 RCALL DAC_SendByte LDS tmp, DAC_Phase_Reversal LDS tmp2, DAC_Attn_Rate OR tmp, tmp2 LDS tmp2, DAC_Operation_EN OR tmp, tmp2 LDS tmp2, DAC_DF_Roll_off OR tmp, tmp2 LDS tmp2, DAC_Zero_Detect OR tmp, tmp2 RCALL DAC_SendByte ; Daten übernehmen SBI PortD, 6 ; /MS_PCM1738A auf H setzen NOP CBI PortD, 6 ; /MS_PCM1738A auf L setzen LDI tmp, 20 RCALL DAC_SendByte LDS tmp, DAC_Reset LDS tmp2, DAC_DF_Bypass_EN OR tmp, tmp2 LDS tmp2, DAC_Mono OR tmp, tmp2 LDS tmp2, DAC_Mono_Channel_sel OR tmp, tmp2 LDS tmp2, DAC_Oversampling OR tmp, tmp2 RCALL DAC_SendByte ; Daten übernehmen SBI PortD, 6 ; /MS_PCM1738A auf H setzen NOP ReSet_DAC_RESET RET DAC_SendByte: ; versendet Byte in tmp per Bitbanging ; MD = Data = PB1 ; MC = Clock = PB2 ; Bit wird mit steigender Flanke vom PCM1738 übernommen ; nach fallender Flanke setzen wir also ein neues Bit ; MSB first ; Spaghetti! CBI PortB, 2 ; MC / Clock 0 SBRS tmp, 7 CBI PortB, 1 ; MD / Data 0 SBRC tmp, 7 SBI PortB, 1 ; MD / Data 1 NOP NOP SBI PortB, 2 ; MC / Clock 1 NOP NOP CBI PortB, 2 ; MC / Clock 0 SBRS tmp, 6 CBI PortB, 1 ; MD / Data 0 SBRC tmp, 6 SBI PortB, 1 ; MD / Data 1 NOP NOP SBI PortB, 2 ; MC / Clock 1 NOP NOP CBI PortB, 2 ; MC / Clock 0 SBRS tmp, 5 CBI PortB, 1 ; MD / Data 0 SBRC tmp, 5 SBI PortB, 1 ; MD / Data 1 NOP NOP SBI PortB, 2 ; MC / Clock 1 NOP NOP CBI PortB, 2 ; MC / Clock 0 SBRS tmp, 4 CBI PortB, 1 ; MD / Data 0 SBRC tmp, 4 SBI PortB, 1 ; MD / Data 1 NOP NOP SBI PortB, 2 ; MC / Clock 1 NOP NOP CBI PortB, 2 ; MC / Clock 0 SBRS tmp, 3 CBI PortB, 1 ; MD / Data 0 SBRC tmp, 3 SBI PortB, 1 ; MD / Data 1 NOP NOP SBI PortB, 2 ; MC / Clock 1 NOP NOP CBI PortB, 2 ; MC / Clock 0 SBRS tmp, 2 CBI PortB, 1 ; MD / Data 0 SBRC tmp, 2 SBI PortB, 1 ; MD / Data 1 NOP NOP SBI PortB, 2 ; MC / Clock 1 NOP NOP CBI PortB, 2 ; MC / Clock 0 SBRS tmp, 1 CBI PortB, 1 ; MD / Data 0 SBRC tmp, 1 SBI PortB, 1 ; MD / Data 1 NOP NOP SBI PortB, 2 ; MC / Clock 1 NOP NOP CBI PortB, 2 ; MC / Clock 0 SBRS tmp, 0 CBI PortB, 1 ; MD / Data 0 SBRC tmp, 0 SBI PortB, 1 ; MD / Data 1 NOP NOP SBI PortB, 2 ; MC / Clock 1 NOP NOP RET ; ##### Warten, Zeit verbraten WAIT_1s: RCALL WAIT_100ms WAIT_900ms: RCALL WAIT_100ms WAIT_800ms: RCALL WAIT_100ms WAIT_700ms: RCALL WAIT_100ms WAIT_600ms: RCALL WAIT_100ms WAIT_500ms: RCALL WAIT_100ms WAIT_400ms: RCALL WAIT_100ms WAIT_300ms: RCALL WAIT_100ms WAIT_200ms: RCALL WAIT_100ms WAIT_100ms: RCALL WAIT_10ms WAIT_90ms: RCALL WAIT_15ms WAIT_75ms: RCALL WAIT_15ms WAIT_60ms: RCALL WAIT_15ms WAIT_45ms: RCALL WAIT_15ms WAIT_30ms: RCALL WAIT_15ms WAIT_15ms: RCALL WAIT_1ms WAIT_14ms: RCALL WAIT_1ms WAIT_13ms: RCALL WAIT_1ms WAIT_12ms: RCALL WAIT_1ms WAIT_11ms: RCALL WAIT_1ms WAIT_10ms: RCALL WAIT_1ms WAIT_9ms: RCALL WAIT_1ms WAIT_8ms: RCALL WAIT_1ms WAIT_7ms: RCALL WAIT_1ms WAIT_6ms: RCALL WAIT_1ms WAIT_5ms: RCALL WAIT_1ms WAIT_4ms: RCALL WAIT_1ms WAIT_3ms: RCALL WAIT_1ms WAIT_2ms: RCALL WAIT_1ms WAIT_1ms: RCALL WAIT_100us WAIT_900us: RCALL WAIT_100us WAIT_800us: RCALL WAIT_100us WAIT_700us: RCALL WAIT_100us WAIT_600us: RCALL WAIT_100us WAIT_500us: RCALL WAIT_100us WAIT_400us: RCALL WAIT_100us WAIT_300us: RCALL WAIT_100us WAIT_200us: RCALL WAIT_100us WAIT_100us: RCALL WAIT_10us WAIT_90us: RCALL WAIT_10us WAIT_80us: RCALL WAIT_10us WAIT_70us: RCALL WAIT_10us WAIT_60us: RCALL WAIT_10us WAIT_50us: RCALL WAIT_10us WAIT_40us: RCALL WAIT_10us WAIT_30us: RCALL WAIT_10us WAIT_20us: RCALL WAIT_10us WAIT_10us: RCALL WAIT_1us WAIT_9us: RCALL WAIT_1us WAIT_8us: RCALL WAIT_1us WAIT_7us: RCALL WAIT_1us WAIT_6us: RCALL WAIT_1us WAIT_5us: RCALL WAIT_1us WAIT_4us: RCALL WAIT_1us WAIT_3us: RCALL WAIT_1us WAIT_2us: RCALL WAIT_1us WAIT_1us: NOP NOP NOP NOP ; Anzahl der NOPs je nach CPU-Frequenz anpassen (Anzahl der NOPs = ca. MHz -1) RET ; 8... MHz