logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Atmega16][asm]TWI/I2C - zapętlanie podczas wysyłania.

maciej_333 26 Lis 2010 00:41 1506 2
REKLAMA
  • #1 8790395
    maciej_333
    Poziom 38  
    Próbuję wykorzystać sprzętowe I2C zawarte w Atmedze16. Poniżej kod:
    .nolist
    .include "m16def.inc" ;dołączenie listy stałych
    .list
    .cseg
    
    ;konfiguracja I2C
    .EQU TWBR_ = 10 ;TWI Bit Rate Register
    .EQU TWPS_ = 3 ;TWI Prescaler Bits
    
    ;status I2C
    .EQU START       = 0x08 ;sygnał startowy - wysłany
    .EQU MT_SLA_ACK  = 0x18 ;SLSA+W wysłany, ACK odebrany
    .EQU MT_DATA_ACK = 0x28 ;dane wysłane, ACK odebrany
    
    ;adresy urządzeń slave I2C
    .EQU ADR_TSA6057 = 0xC4
    
    ;dane dla TSA6057
    .EQU SUBADRESS = 0x03
    .EQU DB0 = 0x63 ;DB0...DB2 - komórki RAM
    .EQU DB1 = 0x64
    .EQU DB2 = 0x65
    .EQU DB3 = 0x00
    
    ;prowizoryczne stałe
    .EQU FM_AM       = 1
    .EQU FM_AM_OPAMP = 1
    .EQU CP_         = 0
    .EQU REF1        = 0 ;1Khz step
    .EQU REF2        = 0
    .EQU BS          = 0
    .EQU DIVIDER = 0x6AA4 ;27300*1KHz=27,3MHz
    .EQU DB0_ = ((DIVIDER & 0x7F) << 1) + CP_
    .EQU DB1_ = ((DIVIDER & 0x7F80) >> 7)
    .EQU DB2_ = ((DIVIDER & 0x18000) >> 15) + 4*BS + 16*FM_AM_OPAMP + 32*FM_AM + 64*REF2 + 128*REF1
    
    .org 0x0000 rjmp RESET
    	I2C_start:
    		ldi r16, (1<<TWINT) | (1<<TWSTA) | (1<<TWEN)
    		out TWCR, r16
    	ret
    
    	I2C_gotowosc:
    		in R16, TWCR
    		sbrs R16, TWINT
    		rjmp I2C_gotowosc
    	ret
    
    	I2C_status:
    		;R17 sprawdzany status
    		in R16, TWSR
    		andi R16, 0xF8
    		cp R16, R17
    		brne ERROR
    	ret
    
    	ERROR:
    		;błąd I2C
    	ret
    
    	I2C_adres_SLA_W:
    		;R16 adres urządzenia SLAVE I2C
    		out TWDR, R16
    		ldi R16, (1<<TWINT) | (1<<TWEN)
    		out TWCR, R16
    		rcall I2C_gotowosc
    	ret
    
    	I2C_dane:
    		;R16 wysyłany bajt danych do urządzenia SLAVE I2C
    		out TWDR, R16
    		ldi R16, (1<<TWINT) | (1<<TWEN)
    		out TWCR, R16
    		rcall I2C_gotowosc
    	ret
    
    	I2C_stop:
    		ldi R16, (1<<TWINT) | (1<<TWEN) | (1 << TWSTO)
    		out TWCR, R16
    	ret
    
    	wyslij_dane_TSA6057:
    		rcall I2C_start
    		ldi R17,START
    		rcall I2C_status
    
    		ldi R16,ADR_TSA6057
    		rcall I2C_adres_SLA_W
    		ldi R17,MT_SLA_ACK
    		rcall I2C_status
    
    		ldi R16,SUBADRESS
    		rcall I2C_dane
    		ldi R17,MT_DATA_ACK
    		rcall I2C_status
    
    		lds R16,DB0
    		rcall I2C_dane
    		ldi R17,MT_DATA_ACK
    		rcall I2C_status
    
    		lds R16,DB1
    		rcall I2C_dane
    		ldi R17,MT_DATA_ACK
    		rcall I2C_status
    
    		lds R16,DB2
    		rcall I2C_dane
    		ldi R17,MT_DATA_ACK
    		rcall I2C_status
    
    		ldi R16,DB3
    		rcall I2C_dane
    		ldi R17,MT_DATA_ACK
    		rcall I2C_status
    
    		rcall I2C_stop
    	ret
    
    RESET:
    ldi R18,low(RAMEND)
    out SPL,R18
    ldi R18,high(RAMEND)
    out SPH,R18
    
    ;ustawienie f dla SCL
    ldi R16,TWBR_
    out TWBR,R16
    
    in R16,TWSR
    ori R16,TWPS_
    out TWSR,R16
    
    
    ldi R16,DB0_
    sts DB0,R16
    
    ldi R16,DB1_
    sts DB1,R16
    
    ldi R16,DB2_
    sts DB2,R16
    rcall wyslij_dane_TSA6057
    
    stop:
    rjmp stop
    

    Adres jest wysyłany poprawnie. Po jego wysłaniu pojawia się ACK. Wysłanie pierwszego bajtu danych też kończy się powodzeniem i odebraniem ACK. Przy drugim wysyłanym bajcie dochodzi do zapętlenia w podprogramie "I2C_gotowosc". Rezystory podciągające dla SDA i SCL wstawiłem 5,6KΩ.
  • REKLAMA
  • #2 8792229
    Andrzej__S
    Poziom 28  
    #1 Po wysłaniu warunku startu na magistralę należy poczekać (podobnie jak po wysłaniu bajtu danych) na ustawienie flagi TWINT i ewentualnie sprawdzić status przed kontynuowaniem transmisji.
    #2 Sprawdzanie statusu nie jest obowiązkowe, niemniej pozwala zaobserwować ewentualne błędy transmisji i odpowiednio na nie zareagować. Wynik działania Twojej procedury I2C_status jest niezależny od wyniku porównania zawartości rejestru TWSR z wartością oczekiwaną. W związku z tym, w przypadku błędów transmisji, program w żaden sposób na nie nie zareaguje. Poza tym znajomość statusu (błędnego) być może pozwoliłaby łatwiej zorientować się, co jest nie tak.
  • #3 8792670
    maciej_333
    Poziom 38  
    Odłączyłem od magistrali I2C układ TSA6057 i dołączyłem zamiast niego głowicę HTP210. Scalak PLL tej głowicy poprawnie odbiera wszystkie dane i poprawnie reaguje na swoje adresy (powinien reagować na dwa adresy zapisu i tak jest).

    W takiej sytuacji raczej TSA6057 jest uszkodzony. Dziwne jest jednak to, że na adres odpowiada poprawnie i przyjmuje pierwszy bajt danych. Przy drugim się zapętla i flaga TWINT nigdy się nie ustawia. Rozumie coś kolega z tego ?

    [edit]
    PLL w dołączonej głowicy nawet chwyciła. W związku z tym po dodaniu oczekiwania na TWINT po warunkach początkowych wszystko działa.
REKLAMA