- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Seite 2 von 2 ErsteErste 12
Ergebnis 11 bis 15 von 15

Thema: Frage zu USI Schnittstelle

  1. #11
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    52
    Beiträge
    2.236
    Anzeige

    Praxistest und DIY Projekte
    Hallo Stefan,
    ich weiß zwar nicht, ob Du hier noch mitliest, aber egal.

    Ich habe mich heute mit USI Master auseinandergesetzt und, es ist doch nicht ganz so wild, ich glaube die nackte Routine ergibt etwa 160 Bytes.

    Testumgebung :

    Tiny 25 als Master.
    Mein I2C Display als Slave Nr.1 zur Ausgabe
    DS1621 I2C Temperatursensor als Slave Nr.2
    Eine Real Time Clock als Slave Nr.3

    Der Aufbau läuft seit einer Stunde und zeigt mir schön in Sekundentakt die Temeratur und Uhrzeit abweschseln an \/

    Der Master läuft mit 1MHz und 100 kHz Bustakt

    ich poste einfach mal das Program:
    Code:
    ;			USI_TWI_master Routinen
    ;**************************************************
    
    
    .macro TRANSFER_8_BIT
    	ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)
    	rcall USI_TWI_master_transfer
    .endmacro
    
    .macro TRANSFER_1_BIT
    	ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0xE<<USICNT0)
    	rcall USI_TWI_master_transfer
    .endmacro
    
    .equ WRITE = 0
    .equ READ = 1
    .equ ACK = 1
    .equ NACK = 0
    
    
    ; I2C Master init 
    ;keine Parameter, keine Rueckgabewerte
    ;************************************************************************
    USI_TWI_master_init:
    	ldi tmp1,(1<<PORT_USI_SDA)|(1<<PORT_USI_SCL);Pullups an SDA u. SCL an
    	out PORT_USI,tmp1
    	out DDR_USI,tmp1;SDA u. SCL als Ausgaenge
    	ser tmp1 ;Lade Dataregister mit High Bytes
    	out USIDR,tmp1
    	;USI Interrupts inaktiv, USI im 2 Wire Modus Software Clock
    	ldi tmp1,(1<<USIWM1)|(1<<USICS1)|(1<<USICLK)
    	out USICR,tmp1
    	ldi tmp1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC);Lösche USI Flags
    	out USISR,tmp1	;und resete den Counter
    	ret
    ;************************************************************************
    
    
    ;			USI_TWI_master_start
    ;   Sendet Startbedingung und die Slaveadresse
    ;	Parameter, Slaveadresse im Register param1
    ;	Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
    ;************************************************************************
    USI_TWI_master_start:
    	sbi PORT_USI,PIN_USI_SCL;zieht SCL High
    USI_TWI_master_start_1:
    	sbis PIN_USI,PIN_USI_SCL;warte bis SCL High ist
    	rjmp USI_TWI_master_start_1
    	rcall delay
    	cbi PORT_USI,PIN_USI_SDA ; zieht SDA LOW
    	rcall delay
    	cbi PORT_USI,PIN_USI_SCL ;SCL wieder LOW 
    	sbi PORT_USI,PIN_USI_SDA ;SDA High
    	out USIDR,param1; Slaveadresse/Data in den USI Dataregister schreiben
    	;mastertransfer aufrufen 
    	TRANSFER_8_BIT
    	cbi DDR_USI,PIN_USI_SDA	;SDA auf Eingang
    	TRANSFER_1_BIT 
    	ret
    ;***********************************************************************
    
    
    ;	USI_TWI_master_write
    ;	Sendet ein Byte am den Master
    ;	Parameter: Data im Register param1
    ;	Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
    ;***********************************************************************
    USI_TWI_master_write:
    	out USIDR,param1; Data in den USI Dataregister schreiben
    	;mastertransfer aufrufen für die
    	TRANSFER_8_BIT ;Byte Uebergabe
    	cbi DDR_USI,PIN_USI_SDA	;SDA auf Eingang
    	TRANSFER_1_BIT;um ACK/Nack Abzuholen 
    	ret
    ;***********************************************************************
    
    ;	USI_TWI_master_read
    ;	Liest ein Byte vom Slave aus
    ;	Parameter: Sende ACK/Nack im param1 1 == ACK senden; 0 == kein ACK senden(Nack)
    ;	Rueckgabe gelesene Daten in param1
    USI_TWI_master_read:
    	tst param1 ;Schaue ob zum Schluss NACK oder ACK soll
    	breq USI_TWI_master_read_prepare_NACK
    	set ;T Flag setzen
    	rjmp USI_TWI_master_read_1
    USI_TWI_master_read_prepare_NACK:
    	clt ;T Flag loeschen
    USI_TWI_master_read_1:
    	cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang setzen
    	TRANSFER_8_BIT
    	push param1 ;gelesene Daten sichern
    	brtc USI_TWI_master_read_send_NACK ;wenn T Flag geloescht ist erfolgt ein NACK
    	;sonst muss ein ACK erfolgen
    	clr param1
    	rjmp USI_TWI_master_read_end
    USI_TWI_master_read_send_NACK:
    	ser param1
    USI_TWI_master_read_end:
    	out USIDR,param1
    	TRANSFER_1_BIT
    	pop param1
    	ret
    ;***********************************************************************
    	
    
    ;			USI_TWI_master_transfer
    ; sorgt für die Komunikation mit dem slave
    ;mit param1 wird übergeben ob ein Byte empfange/gesendet wird, oder nur 1 Bit für ACK/NACK
     
    USI_TWI_master_transfer:
    	out USISR,param1;der Counter wird vorgeladen
    USI_TWI_master_transfer_1:
    	rcall delay
    	sbi USICR,USITC ;Positive Flanke an SCL erzeugen 
    USI_TWI_master_transfer_2:	
    	sbis PIN_USI,PIN_USI_SCL	; warten bis SCL High ist
    	rjmp USI_TWI_master_transfer_2
    	rcall delay
    	sbi USICR,USITC;negative Flanke an SCL erzeugen
    	sbis USISR,USIOIF;testen ob Counter ubergelaufen ist
    	rjmp USI_TWI_master_transfer_1	;wenn nicht mit dem nächstem Bit 
    	rcall delay		;wenn gelesen wird
    	in param1,USIDR;Daten holen 
    	ldi tmp1,0xFF
    	out USIDR,tmp1
    	sbi DDR_USI,PIN_USI_SDA; SDA auf Ausgang stellen
    	ret
    ;***********************************************************************
    
    
    ;			USI_TWI_master_stop:
    ;Sendet die Stop Bedingung
    ;***********************************************************************
    USI_TWI_master_stop:
    	cbi PORT_USI,PIN_USI_SDA
    	sbi PORT_USI,PIN_USI_SCL
    USI_TWI_master_stop_1:
    	sbis PIN_USI,PIN_USI_SCL
    	rjmp USI_TWI_master_stop_1
    	rcall delay
    	sbi PORT_USI,PIN_USI_SDA
    	rcall delay
    	ret
    ;***********************************************************************
    
    ; 			delay
    ;Eine kurze Pause von insgesammt 10 Takten
    ;Bei 1 MHz ergibt das 100 kHz Mastertakt
    ;;keine Parameter, keine Rueckgabewerte
    ;***********************************************************************
    delay:
    	;Rcall hat 3 Takte gedauert
    	nop	;1 Takt
    	nop ;1 Takt
    	nop ;1 Takt
    	ret ; 4 Takte
    ;***********************************************************************
    Du mußt Dir 2 Register definieren tmp1, und param1, die nicht gesichert werden.

    Ich habe es anhand der o.g. appnote geschrieben, aber so ziemlich umgekrämpelt, weil es mir nicht so gefallen hat.
    Die ist etwa genauso zu benutzen, wie die Routine von Peter Fleury, da komm ich besser mit klar, als diese komische Pufferlösung von Atmel.
    Ein Miniprogramm um den DS1621 Wandeln zu lassen und auszulesen könnte damit etwa so aussehen:
    Code:
    .include "tn25def.inc"
    
    .equ PORT_USI = PORTB
    .equ DDR_USI = DDRB
    .equ PIN_USI = PINB
    .equ PORT_USI_SDA = PORTB0
    .equ PORT_USI_SCL = PORTB2
    .equ PIN_USI_SDA = PINB0
    .equ PIN_USI_SCL = PINB2
    
    .equ I2C_DISPLAY = 0x14
    .equ THERMO = 0x90
    .def nachkomma = r1
    .def tmp1 = r16
    .def tmp2 = r17
    .def param1 = r18
    .def param2 = r19
    .def temperatur = r21
     
    .cseg
    
    .org 0x0000 
    	rjmp reset
    
    reset:
    	clr ausgabe
    	ldi tmp1,RAMEND
    	out SPL,tmp1
    	rcall USI_TWI_master_init
    	;Thermometer einschalten
    	ldi param1,THERMO+WRITE
    	rcall USI_TWI_master_start
    	ldi param1,0xEE
    	rcall USI_TWI_master_write
    	rcall USI_TWI_master_stop
    	;Thermometer eingeschaltet
    
    loop:
            ;Temperatur auslesen
    	ldi param1,THERMO+WRITE
    	rcall USI_TWI_master_start
    	ldi param1,0xAA
    	rcall USI_TWI_master_write
    	ldi param1,THERMO+READ
    	rcall USI_TWI_master_start
    	ldi param1,ACK
    	rcall USI_TWI_master_read
    	mov temperatur,param1
    	ldi param1,NACK
    	rcall USI_TWI_master_read
    	mov nachkomma,param1
    	rcall USI_TWI_master_stop
    	;Temperatur ausgelesen
    loop1:
            loop1
    Noch etwas unaufgeräumt, ich denke bis zum Wochenende werde ich Zeit finden und alles besser dokumentieren.

    Ich hoffe, das Du was mit tun kannst

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  2. #12
    Hallo Sebastian,

    vielen Dank für deine Mühe.

    Ich glaube, mir ist das zu kompliziert. Ich dachte an eine primitive Debug-Funktion. In meiner Anwendung ist der Speicher bereits recht voll. Da kann ich mir solchen Luxus nicht leisten. Außerdem kam ich bisher ohne bestens zurecht. Ich lege das Thema auf Eis und denke beim nächsten Projekt noch einmal darüber nach. Oder ich steige auf einen Controller mit UART um.

    Gruß
    Stefan

  3. #13
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    52
    Beiträge
    2.236
    Hallo Stefan,

    vielen Dank für deine Mühe.
    Naja, sagen wir mal so, es hat mir Spaß gemacht.
    Ich wollte zwar I2C in Software nehmen, aber wenn man dabei was neues lernt ist kein Weg zu weit.

    Ich habe mittlerweile die Routine etwas abgeändert, es werden keine Register verändert und ein paar Makros ersetzen die lästige rcalls.

    Ich habe sie schon mehrere Tage im Einsatz und keine Probleme festgestellt

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  4. #14
    Neuer Benutzer Öfters hier
    Registriert seit
    04.09.2008
    Beiträge
    5

    Optimierter I2C Code

    Hi izaseba,

    auch von mir erst mal ein Danke für deine Arbeit.
    Ich bin noch recht neu in der MC Welt und mich interessiert, wie du deine Optimierungen gemacht hast.

    Auch wenn der Post schon eine Weile her ist... Hast du deinen Code noch in Reichweite?

    Wäre super, wenn du den noch mal posten könntest.

    Danke!
    Totti

  5. #15
    Neuer Benutzer Öfters hier
    Registriert seit
    04.09.2008
    Beiträge
    5

    Optimierten Code gefunden

    Habe den optimierten Code gefunden und poste ihn an dieser Stelle nochmal. Nochmal ein Danke an izaseba für die Arbeit!

    Der Code stand hier:
    https://www.roboternetz.de/phpBB2/pr...=39337&start=0
    Code:
    ;         USI_TWI_master Routinen
    ;**************************************************
    
    
    .macro TRANSFER_8_BIT
       ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)
       rcall USI_TWI_master_transfer
    .endmacro
    
    .macro TRANSFER_1_BIT
       ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0xE<<USICNT0)
       rcall USI_TWI_master_transfer
    .endmacro
    
    .macro READ_ACK
       set
       rcall USI_TWI_master_read
    .endmacro
    
    .macro READ_NACK
       clt
       rcall USI_TWI_master_read
    .endmacro
    
    .macro START_I2C
       ldi param1,(@0)
       rcall USI_TWI_master_start
    .endmacro
    
    
    ;USI Pin Konfiguration fuer tiny 24
    
    .equ PORT_USI = PORTA
    .equ DDR_USI  = PORT_USI- 1
    .equ PIN_USI  = DDR_USI - 1
    .equ PORT_USI_SDA = PORTA6
    .equ PORT_USI_SCL = PORTA4
    .equ PIN_USI_SDA = PINA6
    .equ PIN_USI_SCL = PINA4
     
    
    .equ WRITE = 0
    .equ READ = 1
    
    
    ; I2C Master init
    ;keine Parameter, keine Rueckgabewerte
    ;************************************************************************
    USI_TWI_master_init:
       ldi tmp1,(1<<PORT_USI_SDA)|(1<<PORT_USI_SCL);Pullups an SDA u. SCL an
       out PORT_USI,tmp1
       out DDR_USI,tmp1;SDA u. SCL als Ausgaenge
       ser tmp1 ;Lade Dataregister mit High Bytes
       out USIDR,tmp1
       ;USI Interrupts inaktiv, USI im 2 Wire Modus Software Clock
       ldi tmp1,(1<<USIWM1)|(1<<USICS1)|(1<<USICLK)
       out USICR,tmp1
       ldi tmp1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC);Lösche USI Flags
       out USISR,tmp1   ;und resete den Counter
       ret
    ;************************************************************************
    
    
    ;         USI_TWI_master_start
    ;   Sendet Startbedingung und die Slaveadresse
    ;   Parameter, Slaveadresse im Register param1
    ;   Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
    ;************************************************************************
    USI_TWI_master_start:
       sbi PORT_USI,PIN_USI_SCL;zieht SCL High
    USI_TWI_master_start_1:
       sbis PIN_USI,PIN_USI_SCL;warte bis SCL High ist
       rjmp USI_TWI_master_start_1
       rcall delay
       cbi PORT_USI,PIN_USI_SDA ; zieht SDA LOW
       rcall delay
       cbi PORT_USI,PIN_USI_SCL ;SCL wieder LOW
       sbi PORT_USI,PIN_USI_SDA ;SDA High
       out USIDR,param1; Slaveadresse/Data in den USI Dataregister schreiben
       ;mastertransfer aufrufen
       TRANSFER_8_BIT
       cbi DDR_USI,PIN_USI_SDA   ;SDA auf Eingang
       TRANSFER_1_BIT
       ret
    ;***********************************************************************
    
    
    ;   USI_TWI_master_write
    ;   Sendet ein Byte am den Master
    ;   Parameter: Data im Register param1
    ;   Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
    ;***********************************************************************
    USI_TWI_master_write:
       out USIDR,param1; Data in den USI Dataregister schreiben
       ;mastertransfer aufrufen für die
       TRANSFER_8_BIT ;Byte Uebergabe
       cbi DDR_USI,PIN_USI_SDA   ;SDA auf Eingang
       TRANSFER_1_BIT;um ACK/Nack Abzuholen
       ret
    ;***********************************************************************
    
    ;   USI_TWI_master_read
    ;   Liest ein Byte vom Slave aus
    ;   Parameter: Sende ACK/Nack im param1 1 == ACK senden; 0 == kein ACK senden(Nack)
    ;   Rueckgabe gelesene Daten in param1
    USI_TWI_master_read:
       cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang setzen
       TRANSFER_8_BIT
       push param1
       brtc USI_TWI_master_read_send_NACK ;wenn T Flag geloescht ist erfolgt ein NACK
       ;sonst muss ein ACK erfolgen
       out USIDR,null
       rjmp USI_TWI_master_read_end
    USI_TWI_master_read_send_NACK:
       out USIDR,full
    USI_TWI_master_read_end:
       TRANSFER_1_BIT
       pop param1
       ret
    ;***********************************************************************
       
    
    ;         USI_TWI_master_transfer
    ; sorgt für die Komunikation mit dem slave
    ;mit param1 wird übergeben ob ein Byte empfange/gesendet wird, oder nur 1 Bit für ACK/NACK
     
    USI_TWI_master_transfer:
       out USISR,param1;der Counter wird vorgeladen
    USI_TWI_master_transfer_1:
       rcall delay
       sbi USICR,USITC ;Positive Flanke an SCL erzeugen
    USI_TWI_master_transfer_2:   
       sbis PIN_USI,PIN_USI_SCL   ; warten bis SCL High ist
       rjmp USI_TWI_master_transfer_2
       rcall delay
       sbi USICR,USITC;negative Flanke an SCL erzeugen
       sbis USISR,USIOIF;testen ob Counter ubergelaufen ist
       rjmp USI_TWI_master_transfer_1   ;wenn nicht mit dem nächstem Bit
       rcall delay      ;wenn gelesen wird
       in param1,USIDR;Daten holen
       out USIDR,full
       sbi DDR_USI,PIN_USI_SDA; SDA auf Ausgang stellen
       ret
    ;***********************************************************************
    
    
    ;         USI_TWI_master_stop:
    ;Sendet die Stop Bedingung
    ;***********************************************************************
    USI_TWI_master_stop:
       cbi PORT_USI,PIN_USI_SDA
       sbi PORT_USI,PIN_USI_SCL
    USI_TWI_master_stop_1:
       sbis PIN_USI,PIN_USI_SCL
       rjmp USI_TWI_master_stop_1
       rcall delay
       sbi PORT_USI,PIN_USI_SDA
       rcall delay
       ret
    ;***********************************************************************
    
    ;          delay
    ;Eine kurze Pause von insgesammt 10 Takten
    ;***********************************************************************
    delay:
       ;Rcall hat 3 Takte gedauert
       nop   ;1 Takt
       nop ;1 Takt
       nop ;1 Takt
       ret ; 4 Takte
    ;***********************************************************************
    
    
    das Ganze ist als usi_master.asm gespeichert und im Hauptprogramm eingebunden.
    
    Mögliche Verwendung sieht dann so aus:
    
    Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]
    
    
    ;EEPROM Slave Adresse von HP03
    .equ HP03_sEEPROM = 0xA0
    
    .org 0x0000
       rjmp reset
    .org OVF1addr
       rjmp timer1
    .include "usi_master.asm"
    
    reset:
       ldi tmp1,RAMEND
       out SPL,tmp1
                    rcall USI_TWI_master_init
    loop:   
                    rcall HP03_EEPROM_read
                    rjmp loop
    
    
    HP03_EEPROM_read:
       ;es sind insgesamt 18 Bytes zu empfangen und schoen der Reihe nach bei C1
       ;angefangen abzulegen
       ldi tmp1,0x12 ;Readzaehler belegen
       ldi XH,HIGH(C1)
       ldi XL,LOW(C1)
       START_I2C HP03_sEEPROM+WRITE ;Start an HP03 EEPROM senden
       ldi param1,HP03_dEEPROM ;EEPROM Adresse einstallen
       rcall USI_TWI_master_write    
       START_I2C HP03_sEEPROM+READ ;RepStart an HP03 EEPROM senden
    HP03_EEPROM_read1:
       cpi tmp1,2
       brlo HP03_EEPROM_read2
       READ_ACK
       st X+,param1
       dec tmp1
       rjmp HP03_EEPROM_read1
    HP03_EEPROM_read2:
       READ_NACK
       st X,param1
       rcall USI_TWI_master_stop
       ret                   
    
    
    Was man anpassen muß ist das hier:
    Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]
    
    ;USI Pin Konfiguration fuer tiny 24
    
    .equ PORT_USI = PORTA
    .equ DDR_USI  = PORT_USI- 1
    .equ PIN_USI  = DDR_USI - 1
    .equ PORT_USI_SDA = PORTA6
    .equ PORT_USI_SCL = PORTA4
    .equ PIN_USI_SDA = PINA6
    .equ PIN_USI_SCL = PINA4
    [/code]

Seite 2 von 2 ErsteErste 12

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

12V Akku bauen