PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : TWI mit ATtiny25/26



maximat
27.03.2008, 10:09
Guten Tag an alle Assembler-Programmierer
ich möchte den (eingeschränkten) TWI (i2C) Bus am tiny 25/26 nutzen und werde nicht ganz schlau aus dem Datenblatt. Man muss sich wohl einige Befehle selber stricken.
hat jemand Erfahrung damit? ich habe nichts gefunden bisher.
Vielen Dank im Voraus
Herzlich Klaus

izaseba
27.03.2008, 17:46
Hallo Klaus,

Hier Master (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=34326&highlight=usi) ziemlich zum Schluß.
Hier Slave (http://www.izaseba.roboterbastler.de/index.php?popup=Projekte&section=i2cdisplay)

Vielleicht hilft es Dir weiter.

Gruß Sebastian

maximat
27.03.2008, 22:39
Hallo Sebastian, das ist interessant und ich werde es ausprobieren und das Ergebnis melden.

Du schreibst in og. thread:
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
hast du diese veränderte Version auch noch?
herzlich Klaus

izaseba
27.03.2008, 23:27
Hallo Klaus,


hast du diese veränderte Version auch noch?

Natürlich, die ist seit etwa 2 Monaten auf einem T24 im Einsatz und tut ihren Dienst.



; 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:




;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:


;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


Und ein paar Register benennen, welche, findest Du raus, wenn es Fehler wegen unbekannte Register hagelt ;-)

Am sonsten ist es ziemlich einfach:
rcall USI_TWI_master_init beim Reset durchführen

START_I2C HP03_sEEPROM+WRITE
Start senden an I2C Adresse HP03_sEEPROM mit WRITE Bit

rcall USI_TWI_master_write
sendet ein Byte an den Slave,davor mußt Du in param1 laden, was Du senden möchtest...

START_I2C HP03_sEEPROM+READ
start/repstart mit READ Bit

READ_ACK
empfängt ein Byte und sendet ACK an den Slave, in param1 befndet sich das, was empfangen wurde

READ_NACK
sehe READ_ACK nur mit NACK

rcall USI_TWI_master_stop
ohne Komentar(Anmerkung, ich weiß im Moment selber nicht, warum ich das nicht auch in ein Makro verpackt habe :-k )

Am sonsten hab ich das einigermassen gut komentiert...

Ja dann schau mal ;-)

Gruß Sebastian

P.S.

Nochwas , solltest Du Dich über Fehler wegen Register null und full wundern, ehm ich lege mir am Anfang 2 untere Register null mit 0 und full mit 255 an, das erleichtet einiges beim programmieren...

maximat
28.03.2008, 11:15
Hallo Sebastian, extra noch ne Nachtschicht für mich, Vielen Dank!
Es brennt nicht so weil ich viel arbeite und nur zwischendurch zeit habe, außerdem ist die Festplatte meine laptops abgeschmiert und ich muss einiges an Wiederherstellung machen, ich melde mich wieder wenn was neues gibt.
Dieses Thema hier wird ja relativ viel gelesen, da hast du eine wichtige Vorarbeit geleitest.

izaseba
28.03.2008, 19:13
Hallo Sebastian, extra noch ne Nachtschicht für mich, Vielen Dank!

Ach was, manchmal kann ich nicht einschlafen, liegt wahrscheinlich am Alter ;-)


Dieses Thema hier wird ja relativ viel gelesen, da hast du eine wichtige Vorarbeit geleitest.

Naja, ich habe die Erfahrung gemacht, daß die Leute USI nicht sehr mögen, man muß halt etwas selber Programmieren, und das ist zu umständlich...

Mir hat es trotzdem Spaß gemacht, diese Routinen zu entwickeln und mit 100 und paar Bytes ist sie sicherlich nicht zu groß.

Ich würde mich auf jedem Fall freuen, wenn sie bei Dir auch funktionieren würde.

Gruß Sebastian

maximat
23.12.2008, 22:43
Hallo Sebastian, vielleicht liest du das hier eines tages.
Ich wollte dir gern rückmelden, dass da mit dem USI_TWI jetzt funktioniert mit einen I2C-LCD. Hatte im Frühjahr keinen Erfolg und den Sommer über keine Zeit. Habs jetzt noch einmal versucht mit einer MInimalkonfiguration und jetzt geht es. Werde es mit weitren I2C Bausteinen versuchen.

Noch mal vielen Dank für deine Unterstützung

Frohes Fest
herzlich
Klaus-Dieter