' USI-I2C SPI Wandler für Stereo-RX ' Slave @ $68 ' ' mit Interrupt und ohne Timer $regfile = "attiny45.dat" $crystal = 8000000 '$baud = 19200 $hwstack = 40 $framesize = 40 $swstack = 15 ' Unterprogramme für die USI-Kommunikation Declare Sub Usi_twi_slave_initialise() On Usi_start Usi_start_condition_isr , Nosave On Usi_ovf Usi_counter_overflow_isr , Nosave ' einige Aliases anlegen Pout_usi_scl Alias Portb.2 Pin_usi_scl Alias Pinb.2 Ddr_usi_scl Alias Ddrb.2 Pout_usi_sda Alias Portb.0 Pin_usi_sda Alias Pinb.0 Ddr_usi_sda Alias Ddrb.0 ' Leitungen für ADF4001 Config Pinb.1 = Output Config Pinb.3 = Output Config Pinb.4 = Output Config Pinb.5 = Output Tt_le2 Alias Portb.5 ' TT-Enable B Tt_dat Alias Portb.4 ' TT-Daten Tt_clk Alias Portb.1 ' TT-Clock Tt_le1 Alias Portb.3 ' TT-Enable A Pin2 Dim Rx1 As Word Dim Rx2 As Word Dim Lo_rx_1 As Byte At Rx1 Overlay Dim Hi_rx_1 As Byte At Rx1 + 1 Overlay Dim Lo_rx_2 As Byte At Rx2 Overlay Dim Hi_rx_2 As Byte At Rx2 + 1 Overlay Dim Tt_prog As Word ' 11 Bit Prog-Counter '************************************************************************* ' Werte für ADF 4001 '************************************************************************* ' Init-byte ' 76543210 76543210 76543210 ' Inhalt : 00000000 00000000 10010111 ' I_Byte3 I_Byte2 I_Byte1 Dim I_byte3 As Byte Dim I_byte2 As Byte Dim I_byte1 As Byte I_byte3 = &B0000_0000 I_byte2 = &B0000_0000 I_byte1 = &B1001_0111 ' Func-byte ' gleicher Inhalt wie Initbyte , bis auf Control-Bits, werden hier nicht verwendet ' 76543210 76543210 76543210 ' Inhalt : 00000000 00000000 10010110 (neu) ' F_Byte3 F_Byte2 F_Byte1 'Const F_byte3 = 0 'Const F_byte2 = 0 'Const F_byte1 = 150 ' N-Count-byte ' 76543210 76543210 76543210 ' Inhalt: 000NNNNN NNNNNNNN 00000001 ' N_Byte3 N_Byte2 N_Byte1 Dim N_byte1 As Byte N_byte1 = &B0000_0001 ' Audio Teiler bei 10 MHz = 8000 5MHz = 4000 ' Ref-count_byte ' 76543210 76543210 76543210 ' Inhalt: 00000000 RRRRRRRR RRRRRR00 ' 10010110 000000 ' R_Byte3 R_Byte2 R_Byte1 ' R= Ref-Quarz(12MHz)/1,25kHz = 9600 Dim R_byte3 As Byte Dim R_byte2 As Byte Dim R_byte1 As Byte R_byte3 = &B0000_0000 R_byte2 = &B1001_0110 R_byte1 = &B0000_0000 'Dim Usi_twi_errorstate As Byte ' eigener Fehlerstatus ' Array der Daten die übertragen werden Dim Twi_txbuf(16) As Byte Dim Twi_rxbuf(16) As Byte ' Zeiger auf Buffer Dim Twi_rxhead As Byte Dim Twi_rxtail As Byte Dim Twi_txhead As Byte Dim Twi_txtail As Byte Dim Temp_usi_isr As Byte ' Byte das in den ISRs verwendet wird Dim Usi_twi_data_in_receive_buffer As Bit ' Flag ob Buffer Daten enthält Dim Usi_twi_overflow_state As Byte Const Twi_slaveaddress = &H68 ' Möglichkeiten für Usi_twi_overflow_state Const Usi_sl_check_address = 0 Const Usi_sl_send_data = 1 Const Usi_sl_req_reply_from_send_data = 2 Const Usi_sl_chk_reply_from_send_data = 3 Const Usi_sl_req_data = 4 Const Usi_sl_get_data_and_send_ack = 5 '************************************************************************* ' Init * '************************************************************************* Readeeprom Rx1 , 0 Readeeprom Rx2 , 2 Gosub Auf_leitung Enable Interrupts ' IRQs global erlauben Call Usi_twi_slave_initialise Waitms 500 ' Sicherheitspause nach Reset '************************************************************************* ' Hauptschleife * '************************************************************************* Do If Twi_rxhead > 0 Then 'While Usisr.usipf = 0 'wait for USIPF (Stop Condition Flag) then the last byte arrived Main_01: SBIS Usisr,usipf 'Wend 'USIPF cleared in next call of _isr_USI_START (SBI Usisr, usipf) rjmp Main_01 Hi_rx_1 = Twi_rxbuf(2) Lo_rx_1 = Twi_rxbuf(3) If Twi_rxhead > 2 Then Hi_rx_2 = Twi_rxbuf(4) Lo_rx_2 = Twi_rxbuf(5) End If Call Usi_twi_slave_initialise Gosub Auf_leitung End If Loop End ' Unterprogramme '**************************************************************** ' Daten auf die Leitung zur Tonträger-PLL ADF4001 schicken * '**************************************************************** Auf_leitung: Writeeeprom Rx1 , 0 Writeeeprom Rx2 , 2 Gosub Leitung1 Gosub Leitung2 Return Leitung1: Reset Tt_le1 Shiftout Tt_dat , Tt_clk , I_byte3 , 1 Shiftout Tt_dat , Tt_clk , I_byte2 , 1 Shiftout Tt_dat , Tt_clk , I_byte1 , 1 Gosub Sr_lesen Shiftout Tt_dat , Tt_clk , R_byte3 , 1 Shiftout Tt_dat , Tt_clk , R_byte2 , 1 Shiftout Tt_dat , Tt_clk , R_byte1 , 1 Gosub Sr_lesen Tt_prog = Rx1 * 8 Tt_prog = Tt_prog + 61 '=76,125kHz ZF Shiftout Tt_dat , Tt_clk , Tt_prog , 1 Shiftout Tt_dat , Tt_clk , N_byte1 , 1 Sr_lesen: Waitus 12 Set Tt_le1 Waitus 12 Reset Tt_le1 Return Leitung2: Reset Tt_le2 Shiftout Tt_dat , Tt_clk , I_byte3 , 1 Shiftout Tt_dat , Tt_clk , I_byte2 , 1 Shiftout Tt_dat , Tt_clk , I_byte1 , 1 Gosub Sr_lesen2 Shiftout Tt_dat , Tt_clk , R_byte3 , 1 Shiftout Tt_dat , Tt_clk , R_byte2 , 1 Shiftout Tt_dat , Tt_clk , R_byte1 , 1 Gosub Sr_lesen2 Tt_prog = Rx2 * 8 Tt_prog = Tt_prog + 61 '=76,125kHz ZF Shiftout Tt_dat , Tt_clk , Tt_prog , 1 Shiftout Tt_dat , Tt_clk , N_byte1 , 1 Sr_lesen2: Waitus 12 Set Tt_le2 Waitus 12 Reset Tt_le2 Return '**************************************************************** ' Initialise USI for TWI Slave mode. * '**************************************************************** Sub Usi_twi_slave_initialise() Gosub Flush_twi_buffers ' Flushes the TWI buffers ' Direction Out Ddr_usi_scl = 1 Ddr_usi_sda = 0 ' SDA Input ' Release SCL & SDA Pout_usi_scl = 1 Pout_usi_sda = 1 ' Preload dataregister with "released level" data. Usidr = &HFF ' Enable Start Condition Interrupt. Disable Overflow Interrupt. ' Set USI in Two-wire mode. No USI Counter overflow prior ' To First Start Condition(potentail Failure) ' Shift Register Clock Source = External , Positive Edge Usicr = &B10101000 ' Clear flags, and reset counter. Usisr = &B11110000 End Sub ' ISR für Startsequenz erkannt Usi_start_condition_isr: $asm PUSH R16 PUSH R20 PUSH R24 PUSH R25 PUSH R26 IN R24,&H3F PUSH R24 $end Asm ' Code Usi_twi_overflow_state = Usi_sl_check_address Ddr_usi_sda = 0 ' Enable SDA as input. ' Wait for SCL to go low. ' If a Stop condition arises then leave the interrupt to prevent waiting forever. While Pin_usi_scl = 1 And Usisr.5 = 0 ' USIPF Wend ' Enable Overflow and Start Condition Interrupt. (Keep StartCondInt to detect RESTART) ' Set USI in Two-wire mode. ' Shift Register Clock Source = External, positive edge Usicr = &B11111000 ' Clear flags, and reset counter. Usisr = &B11110000 $asm POP R24 Out &H3F , R24 POP R26 POP R25 POP R24 POP R20 POP R16 $end Asm Return ' ISR für Counteroverflow Usi_counter_overflow_isr: $asm PUSH R10 PUSH R16 PUSH R20 PUSH R24 PUSH R26 IN R24,&H3F PUSH R24 $end Asm ' Code 'Print Usi_twi_overflow_state Select Case Usi_twi_overflow_state ' -- Address mode -- ' Check address and send ACK (and next USI_SL_SEND_DATA) if OK, else reset USI. Case Usi_sl_check_address : Temp_usi_isr = Usidr And &HFE ' 0. Bit ausblenden falls RW gleich 1 If Temp_usi_isr = Twi_slaveaddress Then ' Read oder Write ? 1 - Master will was von uns haben If Usidr.0 = 1 Then Usi_twi_overflow_state = Usi_sl_send_data Else Usi_twi_overflow_state = Usi_sl_req_data End If Gosub Set_usi_to_send_ack 'Print #1 , "Addr ok" Else Gosub Set_usi_to_twi_start_cond_mode 'Print "nicht ich" End If ' -- Master write data mode -- ' Check reply and goto USI_SL_SEND_DATA if OK, else reset USI. Case Usi_sl_chk_reply_from_send_data : ' If NACK, the master does not want more data. If Usidr = 0 Then Gosub Set_usi_to_twi_start_cond_mode Goto Fertig_usi_counter_overflow_isr Else ' From here we just drop straight into USI_SL_SEND_DATA if the master sent an ACK If Twi_txhead <> Twi_txtail Then ' Twi_txtail = (twi_txtail + 1 ) And Twi_tx_buffer_mask Temp_usi_isr = Twi_txtail + 1 Temp_usi_isr = Temp_usi_isr And &H0F Twi_txtail = Temp_usi_isr Usidr = Twi_txbuf(temp_usi_isr + 1) Else ' If the buffer is empty then: Gosub Set_usi_to_twi_start_cond_mode Goto Fertig_usi_counter_overflow_isr End If Usi_twi_overflow_state = Usi_sl_req_reply_from_send_data Gosub Set_usi_to_send_data End If ' Copy data from buffer to USIDR and set USI to shift byte. Next USI_SL_REQ_REPLY_FROM_SEND_DATA Case Usi_sl_send_data : If Twi_txhead <> Twi_txtail Then ' Twi_txtail = (twi_txtail + 1 ) And Twi_tx_buffer_mask Temp_usi_isr = Twi_txtail + 1 Temp_usi_isr = Temp_usi_isr And &H0F Twi_txtail = Temp_usi_isr Usidr = Twi_txbuf(temp_usi_isr + 1) Else ' If the buffer is empty then: Gosub Set_usi_to_twi_start_cond_mode Goto Fertig_usi_counter_overflow_isr End If Usi_twi_overflow_state = Usi_sl_req_reply_from_send_data Gosub Set_usi_to_send_data ' Set USI to sample reply from master. Next USI_SL_CHK_REPLY_FROM_SEND_DATA Case Usi_sl_req_reply_from_send_data : Usi_twi_overflow_state = Usi_sl_chk_reply_from_send_data Gosub Set_usi_to_read_ack ' -- Master read data mode -- ' Set USI to sample data from master. Next USI_SL_GET_DATA_AND_SEND_ACK. Case Usi_sl_req_data : Usi_twi_overflow_state = Usi_sl_get_data_and_send_ack Gosub Set_usi_to_read_data ' Copy data from USIDR and send ACK. Next USI_SL_REQ_DATA Case Usi_sl_get_data_and_send_ack : ' Put data into Buffer ' Twi_rxhead = (twi_rxhead + 1 ) & Twi_rx_buffer_mask Temp_usi_isr = Twi_rxhead + 1 Temp_usi_isr = Temp_usi_isr And &H0F Twi_rxhead = Temp_usi_isr Twi_rxbuf(temp_usi_isr + 1) = Usidr Usi_twi_overflow_state = Usi_sl_req_data Gosub Set_usi_to_send_ack 'Print #1 , Usidr End Select Fertig_usi_counter_overflow_isr: $asm POP R24 Out &H3F , R24 POP R26 POP R24 POP R20 POP R16 POP R10 $end Asm Return ' Einstellungen für Read und Write ' Set_usi_to_twi_start_cond_mode: ' Enable Start Condition Interrupt. Disable Overflow Interrupt ' Set USI in Two-wire mode. No USI Counter overflow hold. ' Shift Register Clock Source = External, positive edge Usicr = &B10101000 'Clear all flags, except Start Cond Usisr = &B01110000 Return ' Set_usi_to_send_ack: Usidr = 0 ' Prepare ACK Ddr_usi_sda = 1 ' Set Sda As Output ' Clear all flags, except Start Cond ' Set Usi Counter To Shift 1 Bit Usisr = &B01111110 Return ' Set_usi_to_read_ack: Ddr_usi_sda = 0 ' Set Sda As Intput Usidr = 0 ' Prepare ACK ' Clear all flags, except Start Cond ' set USI counter to shift 1 bit Usisr = &B01111110 Return ' Set_usi_to_send_data: Ddr_usi_sda = 1 ' Set Sda As Output ' Clear all flags, except Start Cond ' set USI to shift out 8 bits Usisr = &B01110000 Return ' Set_usi_to_read_data: Ddr_usi_sda = 0 ' Set Sda As Intput ' Clear all flags, except Start Cond ' set USI to shift out 8 bits Usisr = &B01110000 Return ' Check_if_data_in_receive_buf: If Twi_rxtail <> Twi_rxhead Then Usi_twi_data_in_receive_buffer = 1 Else Usi_twi_data_in_receive_buffer = 0 End If Return ' hauwech Flush_twi_buffers: Twi_rxtail = 0 Twi_rxhead = 0 Twi_txtail = 0 Twi_txhead = 0 Return '************************************************************************* ' EEPromwerte beim Brennen speichern * '************************************************************************* $eeprom Data 650% , 600%