.include "m328def.inc" .def ECHO = r23 ; Local Echo on/off .def ASCII = r22 ; ASCII output on/off .def sec_counter = r21 ; 2- Allg. Zaehler .def counter = r20 ; Allg. Zaehler .def HEXDECBIN = r19 .def rcd = r18 ; returncode .def sparetmp = r17 .def tmp = r16 ; allgemeines Register .def null = r15 ; immer 0 .def FIFO_IN = r14 ; Zeiger auf nächste freie Stelle im FIFO .def FIFO_OUT = r13 ; Zeiger auf nächstes Zeichen im FIFO .def NEW_CR = r12 ; Zeiger auf 1. Zeichen nach neuestem .def LAST_CR = r11 ; Zeiger auf 1. Zeichen nach letztem , an dem man vorbei gekommen ist ; ************************************************************************** ; IRQ-Vector-Table ; ************************************************************************** .org 0x0000 ; Reset Handler rjmp init .org URXCaddr ; USART Receive Complete Interrupt Vector Address rjmp USART_receive ;######################################## #### ## ## ################################################ ;######################################## ## ## ################################################ ;######################################## ## ##### ## ##### ################################################ ;######################################## ## ## ## ## ## ################################################ ;######################################## ## ## ## ## ## ################################################ ;######################################## #### ## ## ## ## ################################################ txversion: .db 13,10,"RS232 <-> I2C - V1.1 std - 2020 jobstens.de",13,10,0 init: ; 1. Stackpointer initialisieren ldi tmp, HIGH(RAMEND) out SPH, tmp ldi tmp, LOW(RAMEND) out SPL, tmp ; 2. Initialisierung der seriellen Schnittstelle 8n1 19200 ldi tmp, 0 ; = ((XTAL-Hz/DIV8) / (8 * Bd))-1 sts UBRR0H, tmp ldi tmp, 119 ; 7 @ 7,3MHz / 19 @ 18,4MHz = 115200 ; 119 @ 18,4MHz = 19200 sts UBRR0L, tmp ldi tmp, 0x06 ; Select Async USART, no Parity, 1 Stop, 8-Data bits sts UCSR0C, tmp ldi tmp, 0x98 ; Set Rx Complete IRQ Enable, Rx Enable, Tx enable sts UCSR0B, tmp ldi tmp, 0x42 ; Set Transmit-Flag & Double-Speed sts UCSR0A, tmp ; 3. TWI Init CALL TWI_init_100k ; 4. I2C Ports cbi DDRC, 4 ; I2C als Eingang (sollte eigentlich schon ...) cbi DDRC, 5 sbi PortC, 4 sbi PortC, 5 ; Pullup I2C aktivieren ; 5. Init Variablen CLR HEXDECBIN ; 0 = Hex, 1 = Dec, 2 = Bin, 3 = 0 CLR null ; ... sagt der Name schon CLR counter CLR NEW_CR CLR LAST_CR CLR FIFO_IN CLR FIFO_OUT CLR ECHO ; 6. das war's sei ; Alle Interupts mal an machen - 'ey, Interupt!' ; ######################## ## ## ; ######################## ### ### ## ; ######################## #### #### ; ######################## ## ### ## #### ### ## ### ; ######################## ## # ## ## ## ## ### ## ; ######################## ## ## ## ## ## ## ## ; ######################## ## ## ### ## #### ## ## ; Print Version on RS232 CALL show_help mainloop: CALL ready waitloop: ; was geht? CP LAST_CR, NEW_CR BREQ waitloop ; nothing LDI tmp, 13 CALL USART_transmit CALL GET_FIFO ; Byte holen CPI tmp, 13 ; Iss nüscht BREQ this_last_CR CPI tmp, 'e' BREQ e_pressed CPI tmp, 'E' BREQ e_pressed CPI tmp, 's' BREQ s_pressed CPI tmp, 'S' BREQ s_pressed CPI tmp, 'w' BREQ w_pressed CPI tmp, 'W' BREQ w_pressed CPI tmp, 'r' BREQ r_pressed CPI tmp, 'R' BREQ r_pressed CPI tmp, 'a' BREQ a_pressed CPI tmp, 'A' BREQ a_pressed CPI tmp, 'h' BREQ h_pressed CPI tmp, 'H' BREQ h_pressed ; nichts von alledem CALL FLUSH_DATA_LINE JMP mainloop this_last_CR: MOV LAST_CR, FIFO_OUT JMP mainloop e_pressed: INC ECHO ANDI ECHO, 1 CALL show_echo CALL FLUSH_DATA_LINE JMP mainloop s_pressed: CALL SCAN_BUS JMP mainloop w_pressed: CALL WRITE_2_BUS JMP mainloop r_pressed: LDI ASCII, 0 CALL READ_from_BUS JMP mainloop a_pressed: LDI ASCII, 1 CALL READ_from_BUS JMP mainloop h_pressed: CALL show_help JMP mainloop ; ########################################################################## ; ########################################################################## ; ; MAIN ENDE ; ; ########################################################################## ; ########################################################################## show_help: LDI ZH, HIGH(txversion*2) LDI ZL, LOW (txversion*2) CALL write_ROM LDI ZH, HIGH(txmenu*2) LDI ZL, LOW (txmenu*2) CALL write_ROM RET show_echo: LDI ZH, HIGH(txecho*2) LDI ZL, LOW (txecho*2) CALL write_ROM CPI ECHO, 1 BREQ se_on LDI tmp, 'F' CALL USART_transmit LDI tmp, 'F' CALL USART_transmit CALL SER_CRLF RET se_on: LDI tmp, 'N' CALL USART_transmit CALL SER_CRLF RET txecho: .db "ECHO O",0,0 ; ########################################################################## ; ########################################################################## SCAN_BUS: CLR counter SCAN_loop: CALL TWI_reset CALL TWI_send_STA MOV tmp, counter ; Adresse CALL TWI_write_Address CP rcd, null BRNE SCAN_skip ; Hysterisch: Ich habe etwas gefunden! MOV tmp, counter CALL VALUE_2_OUT CALL SER_CRLF SCAN_skip: CALL TWI_send_STO INC counter INC counter CP counter, null BRNE SCAN_loop CALL done CALL FLUSH_DATA_LINE RET done: LDI ZH, HIGH(txDONE*2) LDI ZL, LOW(txDONE*2) CALL write_ROM RET txDONE: .db "DONE",13,10,0,0 ready: LDI ZH, HIGH(txREADY*2) LDI ZL, LOW(txREADY*2) CALL write_ROM RET txREADY: .db "READY",13,10,0 ; ########################################################################## ; ########################################################################## WRITE_2_BUS: CALL TWI_reset ; Mit der I2C-Verbindung beginnen CALL TWI_send_STA CPI rcd, 0 BRNE WfB_I2C_Err CALL FIFO_2_VALUE ; Adresse holen CPI rcd, 0 BRNE WfB_NumberError CALL TWI_write_Address CPI rcd, 0 BRNE WfB_I2C_Err W2B_loop: CALL FIFO_2_VALUE ; Wert holen CPI rcd, 0 BRNE W2B_fertig ; tmp = data to write CALL TWI_write_Byte CPI rcd, 0 BRNE WfB_I2C_Err JMP W2B_loop W2B_fertig: CALL TWI_send_STO CALL done RET WfB_I2C_Err: JMP RfB_I2C_Err WfB_NumberError: JMP RfB_NumberError ; ########################################################################## ; ########################################################################## RfB_NumberError: LDI ZH, HIGH(txSYNTAX*2) LDI ZL, LOW(txSYNTAX*2) CALL write_ROM CALL SER_CRLF CALL FLUSH_DATA_LINE RET RfB_NumberError2: LDI ZH, HIGH(txSYNTAX2*2) LDI ZL, LOW(txSYNTAX2*2) CALL write_ROM CALL SER_CRLF CALL FLUSH_DATA_LINE RET RfB_last: CALL TWI_read_last_Byte CPI rcd, 0 BRNE RfB_I2C_Err ; tmp = read Byte CALL VALUE_2_OUT CALL SER_CRLF CALL TWI_send_STO RfB_schluss: CALL FLUSH_DATA_LINE RET READ_from_BUS: CALL FIFO_2_VALUE ; Adresse holen CPI rcd, 0 BRNE RfB_NumberError MOV counter, tmp CALL FIFO_2_VALUE ; Anzahl holen CPI rcd, 0 BRNE RfB_NumberError2 MOV sparetmp, counter MOV counter, tmp CPI counter, 0 BREQ RfB_schluss ; 0!? Nix zu tun! CALL TWI_reset ; Mit der I2C-Verbindung beginnen CALL TWI_send_STA CPI rcd, 0 BRNE RfB_I2C_Err MOV tmp, sparetmp ; Nu ist's richtig *wirbel* ; Adresse in tmp ; Anzahl in counter CALL TWI_read_Address CPI rcd, 0 BRNE RfB_I2C_Err CLR sec_counter RfB_loop: DEC counter BREQ RfB_last ; nur noch einer zu lesen CALL TWI_read_Byte CPI rcd, 0 BRNE RfB_I2C_Err ; tmp = read Byte CALL VALUE_2_OUT CPI sec_counter, 15 BREQ RfB_newline LDI tmp, ' ' CALL USART_transmit INC sec_counter LDI tmp, 1 AND tmp, sec_counter BRNE RfB_loop LDI tmp, ' ' ; Alle 2 Byte 2 Leerzeichen ausgeben CALL USART_transmit JMP RfB_loop RfB_newline: CALL SER_CRLF CLR sec_counter JMP RfB_loop RfB_I2C_Err: CALL VALUE_2_OUT LDI tmp, ' ' CALL USART_transmit MOV tmp, rcd CALL VALUE_2_OUT LDI tmp, ' ' CALL USART_transmit LDI ZH, HIGH(txRfBi2cerr*2) LDI ZL, LOW(txRfBi2cerr*2) CALL write_ROM CALL SER_CRLF CALL TWI_send_STO CALL FLUSH_DATA_LINE CALL done RET txRfBi2cerr: .db "I2C Error",0 txSYNTAX: .db "ERROR in Address",0,0 txSYNTAX2: .db "ERROR in count",0,0 ; ########################################################################## ; ########################################################################## ; ## ### ### # # ; # # ## # # # ; #### ## # # # ; # # ### ### # # VALUE_2_OUT: MOV sparetmp, tmp LDI tmp, '0' CALL USART_transmit LDI tmp, 'x' CALL USART_transmit MOV tmp, sparetmp V20O: ANDI tmp, 0xF0 SWAP tmp ORI tmp, 0x30 CPI tmp, 0x3A BRLO V2O_no_add1 SUBI tmp, -7 V2O_no_add1: CALL USART_transmit MOV tmp, sparetmp ANDI tmp, 0x0F ORI tmp, 0x30 CPI tmp, 0x3A BRLO V2O_no_add2 SUBI tmp, -7 V2O_no_add2: CALL USART_transmit CPI ASCII, 1 BRNE V2O_return ; wenn ASCII nicht gesetzt, dann ist hier schluss CPI sparetmp, 0x20 BRSH V2O_skip1 LDI sparetmp, ' ' V2O_skip1: CPI sparetmp, 0x80 BRLO V2O_skip2 LDI sparetmp, ' ' V2O_skip2: LDI tmp, ' ' CALL USART_transmit ; LDI tmp, '(' ; CALL USART_transmit MOV tmp, sparetmp CALL USART_transmit ; LDI tmp, ')' ; CALL USART_transmit V2O_return: RET VALUE_0_OUT: MOV sparetmp, tmp JMP V20O FIFO_2_VALUE: CALL GET_FIFO CPI tmp, 13 BREQ F2V_nothing ; Bin am Ende der Zeile angelangt CPI tmp, 32 BREQ FIFO_2_VALUE ; Vor der Zahl stehen noch Leerzeichen - ignore CPI tmp, '0' BRNE F2V_number_error CALL GET_FIFO CPI tmp, 'x' BRNE F2V_number_error ; hier steht nun also 0x - und weiter? CALL OneASCII_2_Nibble CPI rcd, 0 BRNE F2V_number_error MOV sparetmp, tmp CALL OneASCII_2_Nibble CPI rcd, 0 BRNE F2V_number_error SWAP sparetmp ADD tmp, sparetmp RET F2V_number_error: CALL FLUSH_DATA_LINE LDI rcd, 1 RET F2V_nothing: MOV LAST_CR, FIFO_OUT LDI rcd, 13 RET OneASCII_2_Nibble: CLR rcd CALL GET_FIFO CPI tmp, '0' BRLO F2V_number_error_pop CPI tmp, 0x3A BRLO OA2N_number ANDI tmp, 0xDF ; großbuchstaben CPI tmp, 'A' BRLO F2V_number_error_pop CPI tmp, 'G' BRLO OA2N_AbisF F2V_number_error_pop: LDI rcd, 0xff RET OA2N_number: ANDI tmp, 0x0F RET OA2N_AbisF: SUBI tmp, 55 RET ; #### # #### ## ; # # # # # ; ### # ### # # ; # # # ## FLUSH_DATA_LINE: ; Holt alles aus der FIFO bis zu CALL GET_FIFO CPI tmp, 13 BRNE FLUSH_DATA_LINE MOV LAST_CR, FIFO_OUT RET GET_FIFO: CP FIFO_IN, FIFO_OUT BREQ GET_FIFO ; Wenn beide Zeiger an einer Position, hier hängen bleiben LDI XH, 1 MOV XL, FIFO_OUT LD tmp, X INC FIFO_OUT RET ; # # ## ### ### ; # # # # # # # ; # # #### ### # ; ### # # # # # USART_receive: PUSH tmp IN tmp, SREG PUSH tmp PUSH XL LDS tmp, UDR0 ; Empfangenes Byte CPI ECHO, 0 BREQ IRQ_kein_ECHO ; Wenn ECHO = 1: PUSH tmp CPI tmp, 13 BRNE URE_10 LDI tmp, 10 URE_10: CALL USART_transmit POP tmp IRQ_kein_ECHO: CPI tmp, 10 ; wenn BRNE IRQ_kein_LF LDI tmp, 13 ; dann IRQ_kein_LF: ; Speicherbereich für RingFIFO ist 0x0100 - 0x01FF ; High-Byte immer 01, Lowbyte ist FIFO_IN / OUT ; Konventionen: ; - Empfangenes Byte wird auf die alte Stelle geschrieben ; - Zeiger wird erst dann inkrementiert ; - Beim lesen wird zuerst übereinstimmung getestet ; - Wenn nicht, kann gelesen werden. LDI XH, 1 MOV XL, FIFO_IN ST X, tmp INC FIFO_IN ; the only way is up CPI tmp, 13 ; Wenn BRNE IRQ_kein_CR ; Wenn CR oder LF dann MOV NEW_CR, FIFO_IN ; damit kann dann auf einem CR festgestellt werden, ; ob ein weiterer folgt IRQ_kein_CR: POP XL POP tmp OUT SREG, tmp POP tmp RETI USART_transmit: STS UDR0, tmp PUSH sparetmp CLR sparetmp CALL SER_wait POP sparetmp RET SER_wait: DEC sparetmp BREQ SER_break CALL WAIT_10us LDS tmp, UCSR0A ; Statusreg der UART einlesen. SBRS tmp, TXC0 JMP SER_wait ; Solange das Bit nicht gesetzt ist, hier verbleiben STS UCSR0A, tmp ; wieder zuruecksetzen (Durch Schreiben einer 1 - also einfach zurückschreiben) CALL WAIT_1us SER_break: RET ; weitere Verarbeitung wenn Byte gesendet wurde SER_CRLF: LDI tmp, 13 CALL USART_transmit LDI tmp, 10 CALL USART_transmit RET write_ROM_next: CALL USART_transmit write_ROM: ; Z (ZL, ZH) sollte schon gesetzt sein LPM tmp, Z+ CPI tmp, 0 BRNE write_ROM_next RET ; ### # # # # # 2 ## ; # # # # # # # # ; # # # # # # # # ; # # # # # # ## ; ************************************************************************** ; TWI init ; ************************************************************************** TWI_init_1k: LDI tmp, 0 ; TWI abschalten (Reset) STS TWCR, tmp LDI tmp, 154 STS TWBR, tmp LDI tmp, 3 STS TWSR, tmp ; I2C auf 1kHz bei 9,8MHz Takt LDI tmp, 0 STS TWAR, tmp LDI tmp, 0 STS TWAMR, tmp LDI tmp, 0 ; TWI abschalten (Reset) STS TWCR, tmp RET TWI_init_10k: LDI tmp, 0 ; TWI abschalten (Reset) STS TWCR, tmp LDI tmp, 115 STS TWBR, tmp LDI tmp, 2 STS TWSR, tmp ; I2C auf 10kHz bei 9,8MHz Takt LDI tmp, 0 STS TWAR, tmp LDI tmp, 0 STS TWAMR, tmp LDI tmp, 0 ; TWI abschalten (Reset) STS TWCR, tmp RET TWI_init_100k: LDI tmp, 0 ; TWI abschalten (Reset) STS TWCR, tmp LDI tmp, 184 STS TWBR, tmp LDI tmp, 0 STS TWSR, tmp ; I2C auf 100kHz bei 9,8MHz Takt LDI tmp, 0 STS TWAR, tmp LDI tmp, 0 STS TWAMR, tmp LDI tmp, 0 ; TWI abschalten (Reset) STS TWCR, tmp RET ; ************************************************************************** ; TWI ; ************************************************************************** TWI_write: CALL TWI_reset CALL TWI_send_STA ; tmp = Adresse CALL TWI_write_Address ; tmp = data to write CALL TWI_write_Byte CALL TWI_send_STO RET TWI_read: CALL TWI_reset CALL TWI_send_STA ; tmp = Adresse CALL TWI_read_Address CALL TWI_read_Byte ; tmp = read Byte CALL TWI_read_last_Byte ; tmp = read Byte CALL TWI_send_STO RET TWI_reset: LDI tmp, 0 ; TWI abschalten (Reset) STS TWCR, tmp RET TWI_send_STA: LDI tmp, 164 ; STA senden ; TWCR = 128 + 32 + 4 (INT + STA + TWI EN) STS TWCR, tmp CALL warte_auf_TWINT LDS rcd, TWSR ; TWSR AND 0xF8 = 0x08 ? - STA gesendet? ANDI rcd, 0xF8 SUBI rcd, 0x08 ; Wenn rcd = 0, dann ist alles gut RET TWI_send_STO: LDI tmp, 148 ; STO senden ; TWCR = 128 + 16 + 4 (INT + STO + TWI EN) STS TWCR, tmp CALL wait_10us RET TWI_write_Address: ANDI tmp, 0xFE ; TWDR = I2Caddress mit 0 als RW STS TWDR, tmp LDI tmp, 132 ; TWCR = 128 + 4 (INT + TWI EN) STS TWCR, tmp CALL warte_auf_TWINT LDS rcd, TWSR ; TWSR AND 0xF8 = 0x18 ? - Adresse+W gesendet? ACK erhalten? ANDI rcd, 0xF8 SUBI rcd, 0x18 RET TWI_read_Address: ORI tmp, 0x01 ; TWDR = I2Caddress mit 1 als RW STS TWDR, tmp LDI tmp, 132 ; TWCR = 128 + 4 (INT + TWI EN) STS TWCR, tmp CALL warte_auf_TWINT LDS rcd, TWSR ; TWSR AND 0xF8 = 0x40 ? - Adresse+R gesendet? ACK erhalten? ANDI rcd, 0xF8 SUBI rcd, 0x40 RET TWI_write_Byte: STS TWDR, tmp LDI tmp, 132 ; TWCR = 128 + 4 (INT + TWI EN) STS TWCR, tmp CALL warte_auf_TWINT LDS rcd, TWSR ; TWSR AND 0xF8 = 0x28 ? - Data gesendet? ACK erhalten? ANDI rcd, 0xF8 SUBI rcd, 0x28 RET TWI_read_Byte: ; Datenbyte MIT ACK abholen LDI tmp, 196 ; TWCR = 128 + 64 + 4 (INT + ACK + TWI EN) STS TWCR, tmp CALL warte_auf_TWINT LDS rcd, TWSR ; TWSR AND 0xF8 = 0x50 ? - Daten empfangen, ACK gesendet? ANDI rcd, 0xF8 SUBI rcd, 0x50 LDS tmp, TWDR RET TWI_read_last_Byte: ; Datenbyte OHNE ACK abholen LDI tmp, 132 ; TWCR = 128 + 4 (INT + TWI EN) STS TWCR, tmp CALL warte_auf_TWINT LDS rcd, TWSR ; TWSR AND 0xF8 = 0x58 ? - Daten empfangen, kein ACK gesendet? ANDI rcd, 0xF8 SUBI rcd, 0x58 LDS tmp, TWDR RET warte_auf_TWINT: LDS tmp, TWCR SBRS tmp, 7 JMP warte_auf_TWINT RET ; # # ## # ##### ; # # # # # # # ; # # # #### # # ; # # # # # # ; ************************************************************************** ; Warten, Zeit verbraten ; ************************************************************************** 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 RET txmenu: .db 13,10,"Kommandos:",13,10 .db "Echo - Toggelt lokales Echo",13,10," Use: E",13,10 .db "Scan - Listet alle gefundenen Devices",13,10," Use: S",13,10 .db "Read - Liest Bytes von einem Device",13,10," Use: R [Adr] [count]",13,10 .db "Read ASCII - Liest ASCII Bytes von einem Device",13,10," Use: A [Adr] [count]",13,10 .db "Write - Schreibt Bytes in ein Device",13,10," Use: W [Adr] [Val] [Val] ..",13,10 .db "Help - Diese Hilfe",13,10," Use: H ",13,10,13,10 .db "Alle Werte sind Bytes (0x00-0xFF) und in HEX anzugeben. ",13,10 .db "Die Adresse ist MSB-buendig. Das LSB ist also das R/W-Bit. Das R/W-Bit wird von der Software automatisch selbst richtig gesetzt.",13,10 .db "Alle Kommandos werden mit CR und/oder LF (also Enter Taste) abgeschlossen.",13,10,13,10,0,0