PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : I2C für Tiny26 - Assembler.



s.o.
13.12.2006, 16:00
Hi @all.

Ich habe eine Frage wegen einer I2C-Routine in Assembler für USIP. Leider wenn ich die SPA und SCl im Avr-Studio Teste springt der Interrupt nicht an.

Was habe ich falsch gemacht? oder liegt das am Avr-Studio?

Nochetwas: Irgendwie springt der (nachdem man das Interrupt manuell eingesetzt hat, und Daten gesendet hat, nie zurück. Was ist dort falsch?

Hier mal der Source:

; This program emulates an I2C bus expander PCF8574 on address 0x40.
; Fuses:
; RSTDISBL programmed (0) - External Reset disabled
; BODEN unprogrammed (1) - Brown out detector disabled
; PLLCK unprogrammed (1) - PLL disabled
; CKOPT unprogrammed (1) - internal capacitors for an Xtal oscillator disabled
; SUT=10 - long start-op time 65ms
; CKSEL=0100 - Internal RC Oscillator 8MHz

.include "tn26def.inc"

; port A - parallel data

; port B
.equ SDA =0
.equ PAR_STROBE =1 ;control
.equ SCL =2
.equ PAR_ERROR =3 ;status
.equ PAR_INIT =4 ;control
.equ PAR_BUSY =5 ;status
.equ PAR_ACK =6 ;status

.def Flags =r16
; meaning of individual bits
.equ START_DETECTED =7 ;set by the USI Start handler when the start
;condition detected

.def Temp1 =r17 ;local temporary variable
.def DeviceAddress =r18

.org 0x0000

rjmp reset ;Reset handler
reti ;IRQ0 handler
reti ;Pin change handler
reti ;Timer1 compare match 1A
reti ;Timer1 compare match 1B
reti ;Timer1 overflow handler
reti ;Timer0 overflow handler
rjmp usi_strt ;USI Start handler
reti ;USI Overflow handler
reti ;EEPROM Ready handler
reti ;Analog Comparator handler
reti ;ADC Conversion Handler

reset: ldi Temp1,RAMEND
out SP,Temp1

ldi Temp1,0x00
out PORTA,Temp1
out DDRA,Temp1
out PORTB,Temp1
out DDRB,Temp1

; USI settings:
; Start Condition Interrupt Enable
; Counter Overflow Interrupt Enable
; Two-wire mode
; Shift Register Clock Source - External, positive edge
; 4-bit Counter Clock Source - External, both edges
ldi Temp1,(1<<USISIE)+(0<<USIOIE)+(1<<USIWM1)+(0<<USIWM0)+(1<<USICS1)+(0<<USICS0)+(0<<USICLK)
out USICR,Temp1
sei

main_loop: cbi DDRB,SDA
cbr Flags,(1<<START_DETECTED)
ldi Temp1,(1<<USIPF)
out USISR,Temp1
; wait for the start condition
main_1: sbrs Flags,START_DETECTED
rjmp main_1
; start condition detected
start_cond: cbr Flags,(1<<START_DETECTED)
ldi Temp1,(1<<USIOIF)+0x0F ;1 SCL edge
out USISR,Temp1
; skip the first falling SCL edge after the start condition
main_2: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp main_2
ldi Temp1,(1<<USIOIF)+0x00 ;10 SCL edges
out USISR,Temp1
; wait until the master sends the Device Address
main_3: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp main_3
in DeviceAddress,USIDR
mov Temp1,DeviceAddress
andi Temp1,0xFE ;ignore the R/W bit
cpi Temp1,0x40 ;PCF8574 device address
brne main_loop
; valid Device Address received from the master,
; read or write?
sbrc DeviceAddress,0 ;R/W bit
rjmp read

; prepare the ATtiny26 to send the ACK bit to the master
write_loop: ldi Temp1,(1<<USIOIF)+0x0E ;2 SCL edges
out USISR,Temp1
cbi PORTB,SDA
sbi DDRB,SDA
; wait until the master reads the ACK bit
write_1: sbis USISR,USIOIF
rjmp write_1
cbi DDRB,SDA
; the master sends data to the ATtiny26
ldi Temp1,(1<<USIOIF)+0x00 ;16 SCL edges
out USISR,Temp1
ldi Temp1,0 ;ACK=0
out USIDR,Temp1 ;bit 0 will be send as ACK
; wait until the master sends the Data Byte
write_2: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp write_2
in Temp1,USIDR
com Temp1
out DDRA,Temp1
rjmp write_loop

; prepare the ATtiny26 to receive the ACK bit from the master
read: ldi Temp1,(1<<USIOIF)+0x0E ;2 SCL edges
out USISR,Temp1
cbi PORTB,SDA
sbi DDRB,SDA
; wait until the master reads the ACK bit
read_1: sbis USISR,USIOIF
rjmp read_1
;
; the master reads data from the ATtiny26
read_loop: in Temp1,PINA
out USIDR,Temp1
ldi Temp1,(1<<USIOIF)+0x00 ;16 SCL edges
out USISR,Temp1
sbi PORTB,SDA
sbi DDRB,SDA
; wait until the master reads the Data Byte
read_2: sbis USISR,USIOIF
rjmp read_2
cbi DDRB,SDA
; prepare the ATtiny26 to receive the ACK bit from the master
ldi Temp1,(1<<USIOIF)+0x0E ;2 SCL edges
out USISR,Temp1
; wait until the master sends the ACK bit
read_3: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp read_3
in Temp1,USIDR
sbrs Temp1,0 ;test the ACK bit
rjmp read_loop
; no acknowledge, wait for a stop or start condition
read_4: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
rjmp read_4


; USI Start handler - called when the start condition detected
usi_strt: push Temp1
in Temp1,SREG
push Temp1
ldi Temp1,(1<<USISIF)
out USISR,Temp1
sbr Flags,(1<<START_DETECTED)
pop Temp1
out SREG,Temp1
pop Temp1
reti


Grüße

s.o.

uffi
16.08.2007, 14:38
hast Du den Code selbst geschrieben?
bin auch an dem Thema interessiert.
Hast Du das Problem schon gelöst?
Die Start-Condition geht ja davon aus, dass die SDA Leitung auf low geht, während SCL low ist. Kann man diese Dynamik im AVR Simulator überhaupt nachbilden?

izaseba
16.08.2007, 14:51
Hallo,
der AVR Simulator unterstützt USI nicht, das kann man nur mit Onboard Debugger testen z.B. einem Dragon

Gruß Sebastian

Hanni
16.08.2007, 19:53
hast Du den Code selbst geschrieben?
bin auch an dem Thema interessiert.

Als kleinen Tip: Atmel bietet auch hierzu ne Appnote an.

Grüße,
Hanni

uffi
26.11.2007, 13:30
Hab jetzt den Assembler Code oben auf einem ATtiny26 als Slave impementiert und lasse ihn von einem ATMEGA16 als Master addressieren (mit der Software-Bibliothek von Peter Fleury -> das Assembler File, welches mit jedem AVR-Pin läuft auch ohne TWI support). In der Assembler Routine des Slaves (siehe oben) wird beim Warten auf den USI overflow ja in der Warteschleife immer auch überprüft, ob eine neue Start- oder eine Stop-Condition vorliegt. Im Code oben ist die Abfrage der Stop-Condition auskommentiert.

So, nun das überraschende: Der Assembler Code des Slave (siehe oben) läuft und empfängt die Adresse und das Command-Byte richtig, so lange ich nicht die Stop-Condition abfrage. Sobald ich dies aber tue, wird die I2C Kommunikation sofort abgebrochen, weil offenbar eine Stop-Condition vorliegt. Ich hab die Signale am Oszi angeschaut und da ist aber definitiv keine Stop-Condition vorhanden, erst am Ende der Übertragung.

Also hatte das wohl schon seinen Grund, dass der Autor des Codes oben die Abfrage der Stop-Condition auskommentiert hatte.

Hat jemand eine Erklärung für dieses unerwartete Verhalten? Kann das eine Störung sein, die man am Oszi nicht sieht? Oder ist das ein bekannter Fehler mit dem Stop-Condition Bit (USIPF) im USISR (USI Status Register?

Danke und Gruß, uffi.

izaseba
26.11.2007, 16:22
Hat jemand eine Erklärung für dieses unerwartete Verhalten? Kann das eine Störung sein, die man am Oszi nicht sieht? Oder ist das ein bekannter Fehler mit dem Stop-Condition Bit (USIPF) im USISR (USI Status Register?


Ich habe hier einen USI slave seit paar Monaten auf einem Tiny24 laufen, ich prüfe auch den USIPF, kann aber keine Probleme feststellen.
Der Slave rennt um sein Leben ;-)

Hier mal mein USI_STRaddr Interrupt:


usi_start:
in sregret,SREG
in tmpi1,USISR
ldi USI_TWI_OVERFLOW_STATUS,USI_SLAVE_CHECK_ADDRESS
cbi USI_DDR,USI_SDA
usi_start1:
sbrc tmpi1,USIPF
rjmp usistart2
sbic USI_PIN,USI_SCL
rjmp usi_start1
usistart2:
ldi tmpi1,(1<<USISIE)|(1<<USIOIE)|(1<<USIWM1)|(1<<USIWM0)|(1<<USICS1)
out USICR,tmpi1
ldi tmpi1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)
out USISR,tmpi1
out SREG,sregret
reti

Gruß Sebastian

P.S. Achso, als Master habe ich bis jetzt Hardware Twi von m8 m16 und m128 gehabt.

uffi
27.11.2007, 14:54
Hallo izaseba,

danke für Deine ausführliche Antwort. Nachdem Dein Code ja gut läuft: kannst Du mir die ganze Assembler-Source für Deinen Slave zur Verfügung stellen? Das wäre super nett.

Ich habe den Autor des Original-Codes, den s.o. oben eingestellt hat, ausfindig gemacht, es ist Piotr Piatek [piotr433@pisi.com.pl], der Code stammt orginal von dieser Internet Seite:

http://www.pisi.com.pl/piotr433/pcf_12.asm

Ich habe folgendes Statement von Piotr erhalten:



Hello Dirk,

On Mon, 26 Nov 2007 15:18:24 +0100, you wrote:

>Now the surprise: your code works properly and the address and command
>byte are well received by the slave, as long as the check for a stop
>condition is left as comment as in your original file. However, when
>removing the comment signs and thereby activating the check of a stop
>condition in the wait loops for USI overflow, the I2C communication is
>always stopped. I watched the signals on osci. I could not find a stop
>condition except at the end of transmission.
>
>Do you have an explanation?

I experienced the same behaviour, but couldn't explain it. The USIPF bit seemed to be permanently set regardless of the bus state. An attempt to clear it by software failed as well. I don't know whether this was a bug in the silicon, or did I misunderstand the datasheet.

>Obviously, you had a reason to comment the check for stop condition and
>not use it in the real code?

It was only a quick fix to make the code work. Eventually I decided to abandon the USI at all, and to do everything in software.

Later I found a similar I2C slave implementation written by someone else (in the attachment, not tested). Please note that it doesn't check for stop condition, either.

Best regards

Piotr


Ich vermute nun, dass die Stop-Condition-Flag USIPF in dem Code versehentlich jeweils in folgender Anweisung gesetzt wird, da das Bit USIPF (in USISR) laut Datenbuch nur durch Beschreiben mit einer 1 gelöscht wird (also möglicherweise durch Schreiben einer 0 dann auch gesetzt wird?):


ldi Temp1,(1<<USIOIF)+0x00 ;10 SCL edges
out USISR,Temp1


Was meint ihr? Ich werd es heute abend ausprobieren.

Gruß, uffi.[/b]

izaseba
27.11.2007, 17:06
Hallo uffi,
Ich habe Dir eine Mail geschickt.

Gruß Sebastian

oberallgeier
03.12.2007, 18:46
Hallo uffi und izaseba,

MEIN GLÜCK dass ich über diesen Thread gestolpert bin. Vielleicht könnt Ihr mir helfen, bitte?

Ich will auf einem 2313 zwei Motoren ansteuern (L293) und zwei Encoder auslesen. Die Motorvorgaben und Encoderwerte sollen mit einem anderen Controller ausgetauscht werden. Nun habe ich allererste Ergebnisse mit ner RS232 in C (mit viel Hilfe von anderen) - aber der Maschinencode ist da relativ lang. Ich will nur jeweils vier, max acht Werte (etwa vier Bytes und zwei words) hin- und vier, max acht andere Werte zurückschaufeln. Jetz sehe ich, dass Ihr I2C auf den Tiny´s in Assembler macht. Bascom kann und will ich nicht, C ist bei mir noch völlig ungenügend - aber ich lerne, Assembler mit AVR geht relativ gut.

Kann ich(man) den Code von s.o. dafür nehmen? Den Code für Tiny26 könnte ich ja schnell umändern für den 2313. Und I2C kann ja wohl bequem ohne externen Quarz laufen, ich könnte den max232 sparen und ein Interrupt-Timer für PWM wär wohl kein Problem! Wie habt Ihr die Fallstricke gelöst? Was muss ich am Code oben ändern?

Danke im Voraus,

Besserwessi
03.12.2007, 19:27
Zum Verbinden von 2 Controllern ist I2C nicht allzu gut geeignet. Einen I2C Master, wie ober zu programmieren ist relativ einfach gegen den slave (gegenseite). Vermutlich wäre SPI einfacher, denn es wird von der Hardware unterstützt (USI Modul). Auch die UART wäre möglich, besonders wenn beide Prozessoren vom gleichen Takt gespeißt werden. Wenn die Verbindung über kurze Distanzen ist, kann man die MAX232 natürlich weglassen und die Daten direkt auf CMOS Pegel übertragen.
Das der Maschinen code den der C Compliler für die UART communication ausgibt lang ist, hat nicht viel zu sagen, das ist auch bei einem "Hallo World" schon so. Der Code für I2C wird ziehmlich sicher deutlich länger.

izaseba
03.12.2007, 19:33
Hallo Joe,

Ob das Programm von oben funktioniert, kann ich nicht so sagen, ich habe mir meine eigene Routine programmiert, die zufälligerweise auch einen Slave macht, der ... 2 Motoren per L293 ansteuert und 2 Radencoder , die ich aus einer alten Kugelmaus gebaut habe per Pinchange Interrupt ausliest.
Leider bin ich noch nicht ganz fertig damit, sonst hätte ich das ganze veröffentlicht.
Die eigentliche I2C Slave Routine klappt aber schon sehr gut auf einem Tiny24.
Welchen µC man nimmt ist es eigentlich Wurst, hauptsache, der hat eine USI.
Wenn Du mir Deine E-Mail Adresse per PN schickst kann ich Dir mein Programm als Alpha Tester zukommen lassen ;-)

Ich habe auch mehr oder weniger eine Appnote von Atmel verwendet und etwas auf meine Bedürfnisse abgeändert.

Gruß Sebastian

uffi
04.12.2007, 10:18
@Besserwessi: der Code oben ist ein Slave und kein Master (wie Du vermutet hast).

@oberallgeier: der Code oben läuft, so wie er oben zitiert ist. Allerdings fehlt dann die Funktionalität, mitten in der Übertragung oder nach irgendeinem Byte mit einer Stop-Condition oder Start-Condition vom Master zu operieren. Wenn man diese auskommentierten Zeilen aktiviert, werden die meisten Übertragungen allerdings durch fehlerhaft erkannte (aber nicht vorhandene) Stop-Condition abgebrochen. Das kann man so umschiffen:
Man fragt die Stop-Condition nur während der ersten SCL clock des nächsten Bytes ab, dann gibt es weniger Fehler aber die Funktionalität ist da.

man muß dazu folgende Code Sequenz im Code oben:

; the master sends data to the ATtiny26
ldi Temp1,(1<<USIOIF)+0x00 ;16 SCL edges
out USISR,Temp1
ldi Temp1,0 ;ACK=0
out USIDR,Temp1 ;bit 0 will be send as ACK
; wait until the master sends the Data Byte
write_2: ; sbic USISR,USIPF ;stop condition detected?
; rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp write_2




durch die folgende ersetzen:


; the master sends data to the ATtiny26
ldi Temp1,(1<<USISIF)+(1<<USIOIF)+(1<<USIPF)+0x0E ;2 SCL edges
out USISR,Temp1

;wait for 1 SCL clock to detect stop condition or new start condition
first_SCL:
sbic USISR,USIPF ;stop condition detected?
rjmp main_loop
sbrc Flags,START_DETECTED ;start condition detected?
rjmp start_cond
sbis USISR,USIOIF
rjmp first_SCL

ldi Temp1,(1<<USISIF)+(1<<USIOIF)+(1<<USIPF)+0x02 ;14 SCL edges
out USISR,Temp1

; wait until the master sends the Data Byte
write_2:
sbis USISR,USIOIF
rjmp write_2



Als I2C Master benutze ich die Bibliothek von Peter Fleury, die man auf seiner Homepage herunterladen kann, und zwar den Part, der in rein in Software (ohne Nutzung des TWI-Moduls) für eine C-Compilierung in GNU-Assembler codiert ist.

oberallgeier
04.12.2007, 15:58
Hallo uffi, hallo izaseba, erst mal danke :)
Na ja, es kommt Arbeit auf mich zu :) - aber JETZT hab ich ein bisschen mehr Plan :)

joerg2712
07.01.2008, 15:56
[quote="izaseba"]
Ich habe hier einen USI slave seit paar Monaten auf einem Tiny24 laufen, ich prüfe auch den USIPF, kann aber keine Probleme feststellen.
Der Slave rennt um sein Leben ;-)
[quote]

Hallo Sebastian,

ich stecke noch ganz am Anfang meiner Assembler-Karriere und möchte auch einen TWI-Slave auf einem ATtiny 2313 realisieren. Scheint aber nicht ganz trivial zu sein.
Es wäre super nett, wenn Du mir bitte Deinen ASM-Code als Beispiel zur Verfügung stellen könntest?

Vielen Dank im Voraus und viele Grüße

Jörg

izaseba
29.01.2008, 23:10
Hallo Jörg,

Sorry, daß ich mich bis jetzt nicht gemeldet habe, die Benachrichtigung bei neuen Posts hat aber nicht funktioniert :-(

Ja, schau mal auf meiner HP (http://www.izaseba.roboterbastler.de/index.php?popup=Projekte&section=i2cdisplay) rein, da ist ein 'halber' Slave :-b
Halb deswegen, weil ich den nur beschreiben wollte.
Für den auszulesen muß nur etwas im usi overflow Interrupt geändert werden.
Das kann ich bei Bedarf auch noch einfügen.

Sonst habe ich heute noch einen usi Master geschrieben, schau (https://www.roboternetz.de/phpBB2/viewtopic.php?p=348046#348046)
Vielleicht ist es auch was.

Gruß Sebastian

uffi
28.06.2008, 21:36
Also mein I2C Slave läuft jetzt. Die Implementierung ist interrupt-basiert. Codierung in Assembler auf einem ATtiny26. Den Source Code kann man sich hier ansehen:

http://freenet-homepage.de/uffmann/Ultrasonic2.html

Bediene sich wer mag.

Gruß, uffi.