Frage zu USI Schnittstelle
Hallo,
Ich programmiere gerade einen I2C Slave auf einem Tiny24, und ich muß sagen, es klappt \:D/
Jetzt kommt aber das Problem/Frage
SCL hängt an PA4
SDA PA6
Pins PA0-PA3 sind als Ausgänge konfiguriert und hängen an Inputs von l293.
Jetzt will ich natürlich was an PA0-PA3 ausgeben um die Drehrichtung der Motoren zu bestimmen.
Eigentlich hatte ich es so vor:
Code:
in r16,PINA
andi r16,0xF0
or r16,r17
out PORTA,r16
Kein Hexenwerk also , in r17 ist der obere Nibble natürlich gelöscht.
Ich frage mich aber, was passiert, wenn in der Zeit zwischen in und out der Zustand an SCL SDA sich geändert hat, der Master komuniziert gerade mit einem anderen Slave, bzw. schickt/holt Daten von mir :-k
Würde ich jetzt Störungen am Bus verursachen, oder läßt es den Tiny kalt, wenn man USI aktiviert hat ?
Vielleicht weißt jemand eine Antwort drauf, sonst muß ich es per Brutal force ausprobieren.
Hab ich vielleicht das Datenblatt nicht gründlich genug studiert, ich meine aber, keine Antwort auf diese Frage gefunden zu haben.
Gruß Sebastian
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]