Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

I2C w C MSP430

MarcinBarowski 02 Feb 2008 09:53 3066 14
  • #1
    MarcinBarowski
    Level 15  
    Witam!
    Mam takie problem, starałem się napisać program w C dla szyny I2C.
    Wszystkie ustawienia portu napisałem tak jak było pokazane w przykładowym programie (assembler) z TI. Czy może mi ktoś powiedzieć czemy procek nie dogaduje się z układem?
    Jak uruchomię program w asemblerze to wszystko działa, a jak mój w C to nic...
    Jedynie z czym jeszcze mam problem to ustawienie stosu na wartość 0x300. Nie wiem jak sie odwołać do stosu w C, gdyż wyskakuje mi błąd że dana zmienna nie jest zdeklarowana :(

    Dla dokładniejszego zapoznania sie z problemem przesyłam wam kod z TI:

    #define RXTXI2C R7 ; I2C Receive/Transmit Register
    #define ADDRI2C R8 ; I2C Address Register
    #define DATAI2C R9 ; I2C Data Register
    #define BITI2C R10 ; I2C Bit Counter Register
    ;
    ; Definitions for I2C bus
    DACADDR equ 098h ; DAC8574 HW Address (A0=A1=0+WR)
    DACCTRL equ 034h ; DAC Control Word (Broadcast to all DAC Channels)
    SCL equ 001h ; P2.0 controls SCL line (pull-up)
    SDA equ 002h ; P2.1 controls SDA line (pull-up)
    TRIG equ 001h ; Trigger point
    ;******************************************************************************
    #include   ”msp430x44x.h”
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    ; 16−bit Sine Lookup table with 256 steps
    .
    .
    .
    .
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    ORG 0F000h
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    RESET mov.w #300h,SP ; Initialize stack−pointer
    call #Init_Sys  ; Initialize system
    clr.w R6
    One_Shot
    ; bis.b #TRIG,&P4OUT ; Toggle Trigger
    ; bic.b #TRIG,&P4OUT
    mov.b #DACADDR,RXTXI2C ; Load DAC8574 Address
    call #I2C_Start ; Generate Start Condition
    call #I2C_TX
    call #I2C_Stop  ; Generate Stop Condition
    mov.b #DACADDR,RXTXI2C ; Reload DAC8574 Address
    call #I2C_Start ; Repeat Start
    call #I2C_TX
    mov.b #DACCTRL,RXTXI2C ; Load DAC8574 Control Byte
    call #I2C_TX
    Write_Data
    mov.w #0FFh,R6
    mov.w #0,R5
    Again mov.w Sin_tab(R5),DATAI2C
    swpb DATAI2C ; MSB first
    call #Write_I2C
    swpb DATAI2C ; LSB next
    call #Write_I2C
    incd.w R5
    sub.w #1,R6
    and.w #0FFh,R6
    jnz Again
    jmp Write_Data
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    Init_Sys;   Subroutine sets up Modules and Control Registers
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    mov.w #WDTPW+WDTHOLD,&WDTCTL ; Stop WDT
    SetupFLL2 bis.b #FN_4,&SCFI0 ; x2 DCO, 8MHz nominal DCO
    bis.b #DCOPLUS+XCAP14PF,&FLL_CTL0 ; DCO+, configure load caps
    mov.b #121,&SCFQCTL ;(121+1) x 2 x 32768 = 7.99 MHz
    SetupPorts mov.b #0FFh,&P1DIR ; Set port to outputs
    clr.b &P1OUT ; P1OUTs = 0
    mov.b #0FFh,&P2DIR ; Set port to outputs
    clr.b &P2OUT ; P2OUTs = 0
    mov.b #0FFh,&P3DIR ; Set port to outputs
    clr.b &P3OUT ; P3OUTs = 0
    mov.b #0FFh,&P4DIR ; Set port to outputs
    clr.b &P4OUT ; P4OUTs = 0
    mov.b #0FFh,&P5DIR ; Set port to outputs
    clr.b &P5OUT ; P5OUTs = 0
    mov.b #0FFh,&P6DIR ; Set port to outputs
    clr.b &P6OUT ; P6OUTs = 0
    ret ; 
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    Write_I2C
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    mov.b DATAI2C,RXTXI2C ; Load Out−Going Data
    call #I2C_TX ; Send Data and Acknowledge
    ret ; Return from subroutine
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    I2C_Start; enter SDA=1, SCL=x
    ; exit  SDA=1, SCL=0
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    bic.b #SCL+SDA,&P2DIR ; SCL and SDA to input direction
    bic.b #SCL+SDA,&P2OUT ; SCL=1, SDA=1
    bis.b #SDA,&P2DIR ; SDA=0
    bis.b #SCL,&P2DIR ; SCL=0
    ret
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    I2C_TX; enter SDA=x, SCL=0
    ; exit  SDA=1, SCL=0
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    mov #08,BITI2C   ; number of bits to transfer
    I2C_TX_Bit rla.b RXTXI2C ; data bit −> carry
    jc I2C_TX1 ; test carry for 1 or 0
    I2C_TX0 bis.b #SDA,&P2DIR ; SDA=0
    jmp I2C_TXx ; Toggle SCL
    I2C_TX1 bic.b #SDA,&P2DIR ; SDA=1
    jmp I2C_TXx
    I2C_TXx bic.b #SCL,&P2DIR ; SCL=1
    nop ; delay to meet I2C spec
    nop ;
    bis.b #SCL,&P2DIR ; SCL=0
    dec BITI2C ; all bits read?
    jnz I2C_TX_Bit ; continue until 8 bits are sent
      bic.b #SDA,&P2DIR ; SDA=1, release SDA line for acknowledge
    ;
    TX_Ackn bic.b #SCL,&P2DIR ; SCL=1
    nop ; delay to meet I2C spec
    nop ;
    bis.b #SCL,&P2DIR ; SCL=0
    ret ; Return from subroutine
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    I2C_Stop; enter SDA=x, SCL=0
    ; exit  SDA=1, SCL=1
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    bis.b #SDA,&P2DIR ; SDA = 0
    bic.b #SCL,&P2DIR ; SCL = 1
    bic.b #SDA,&P2DIR ; SDA = 1
    I2C_End ret ; Return from subroutine
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    ; Interrupt Vectors Used MSP430F449
    ;−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    ORG 0FFFEh ; MSP430 RESET Vector
    DW RESET ;
    END
    

    Jak ktoś by mi mógł wytłumaczyć, dlaczego nie dokonuje sie ustawienia portu OUT tylko DIR to też byłbym wdzięczny!

    Dzięki za pomoc
    pozdrawiam


    Proszę umieszczać listingi programów w znacznikach "Code". [c_p]
  • Helpful post
    #2
    Freddie Chopin
    MCUs specialist
    bo nie ma takiej potrzeby. wystarczy uzywac kierunku portu - oszczedza sie tym kilka instrukcji.

    po ustawieniu kierunku porty na wejscie, przelaczany jest on na stan wysokiej impedancji, tym samym podciagany jest on do logicznej 1 przez pull-up'y wymagane przez I2C. Przy ustawieniu portu na wyjscie, przepisywany jest na niego ustalony wczesniej stan z rejestru PxOUT - czyli logiczne 0.

    jesli wolisz, to mozesz sterowac portami w klasyczny sposob, niczego to nie zmienia, jest jedynie troszke mniej zoptymalizowane. wydaje mi sie, ze w zaleznosci od procesora moze byc tez troche szybsze, zwlaszcza jesli zastosuje sie wieksze rezystory podciagajace, aby oszczedzac prad.

    EDIT: jesli chcesz, to moge wrzucic swoj kod w asm dla msp430, w ktorym I2C jest obsluzone klasycznie.

    0x41 0x56 0x45!!
  • #3
    MarcinBarowski
    Level 15  
    Tak też myślałem że port PDIR będzie do tego służył. Co do kodu to stokrotne dzięki ale mam u siebie też kilka kodów. Wszystkie jednak są w asemblerze a chciałbym przerobić je na C.
    Cały dzień szukałem sprawdzałem i doszedłem do tego jak można zmienić Stack Pointer w C:

    __set_SP_register(dana wartość);

    Pobawiłem sie również tymi programami w asemblerze i zmieniłem wartość wektora resetu co uniemożliwiło komunikację z układem.
    To teraz czy ktoś napisał może podobny programik w C??
    W necie sprawdzałem i znalazłem jedynie programy dla sprzętowych wersji I2C. Czy muszę ustawiać dany wektor? I w jaki sposób wartość tego wektora obliczyć?? Nie sądzę bowiem iż programista mając układ przed sobą za pierwszym razem wpisze dobrą wartość.

    Będę wdzięczny za pomoc!!
    dzięki
  • #4
    Dr_DEAD
    Level 28  
    MarcinBarowski wrote:

    Pobawiłem sie również tymi programami w asemblerze i zmieniłem wartość wektora resetu co uniemożliwiło komunikację z układem.
    .......
    Czy muszę ustawiać dany wektor? I w jaki sposób wartość tego wektora obliczyć?? Nie sądzę bowiem iż programista mając układ przed sobą za pierwszym razem wpisze dobrą wartość.

    Piszesz tak jakbyś wiedział co robisz, a mnie sie wydaje że albo Cie nie rozumiem albo to co robisz jest bez sensu. Po pierwsze to wartość Stock Pointera to nie powinna Cie wogóle obchodzić gdy piszesz w C i jakoś nie widzę sensu ustawiania tej wartości w programie. Po drugie nie widzę też sensu zmiany wartości Wektora Resetu, może wytłumacz nam co chciałeś tym osiągnąć?
  • #5
    MarcinBarowski
    Level 15  
    Pytam o to wszystko ponieważ nic nie działa jak napiszę program w C. Ustawienia procka dokonałem tak jak w tym przykładzie było.
    I jedynie czego nie ustawiałem to ten dziwny stos i ten wektor.
    Dlatego też to chciałem ustawić i sprawdzić czy tu nie leży błąd.
    Tak wogóle to kolega też stara sie urichomić i2c w jezyku C i też nic.
    Jedynie w asemblerze wszystko jest ok..Acha nalezy dodać że kolega pracuje na procesorze AVR.

    Może ktoś ma jakieś wytłumaczenie dla tego zjawiska ?

    pozdrawiam
  • #6
    zumek
    Level 39  
    MarcinBarowski wrote:
    ...Może ktoś ma jakieś wytłumaczenie dla tego zjawiska ?

    pozdrawiam

    Jak byś pokazał co tam spłodziłeś , to kto wie :?: :)

    Piotrek
  • #8
    MarcinBarowski
    Level 15  
    Witam!
    W załączniku umieszczam swój kod w C. Ma to być kod do obsługi RTC DS1338.
    Dzięki za pomoc..
  • #9
    Freddie Chopin
    MCUs specialist
    wszystko spoko, tylko z tymi jedynkami, dwojkami i trojkami to troche przegiales... skad my mamy wiedziec ktory pin jest od czego? pozatym jakies komentarze bylyby mile widziane... tego sie po prostu tak nie pisze, bo w ogole nie wiadomo o co chodzi...

    0x41 0x56 0x45!!
  • #10
    MarcinBarowski
    Level 15  
    heh :) sorry!:)
    Wiem że mało opisu ale sie spieszyłem troche, teraz zabardzo też nie mam czasu żeby to poprawić. 1 oznacza linie SCL, 2 oznacza linie SDA a 3 odnosi sie zarówno do linii SCL jak i SDA. W kodzie tym nie ma sprawdzania bitu ACK, ale w tamtym z asemblera tez nie było. Jak będzie przynajmniej coś działało to pózniej to dopisze...

    pozdrawiam :)
  • Helpful post
    #11
    zumek
    Level 39  
    MarcinBarowski wrote:
    heh :) sorry!:)

    Tu nie ma co "sorry" , tylko trzeba sie wziąć do roboty.
    Programowania w C , to chyba sie dopiero zaczynasz uczyć , bo zamiast operacji logicznycz na poszczególnych bitach rejestru , ty uznajesz wyłącznie przypisywanie wartości do całego rejestru - makabra :|
    Ano , popatrz na to:
    
    I2C_start()
    {
      P2DIR =~ 3; //SDA=SCL=1
      P2OUT =~ 3;
      P2DIR = 2;  //P2.1=OUT P2.0=IN -> SDA=0:SCL=1
      P2DIR = 1;  //P2.1=IN P2.0=OUT -> SDA=1:SCL=0
    }
    
    

    Czy to jest prawidłowa sekwencja START :?:

    Piotrek
  • #12
    MarcinBarowski
    Level 15  
    witam!
    Tak zgadza się, jestem początkującym w tym języku. Wogóle myślałem że asembler ustawia bity podobnie jak C, dlatego też przypisałem komendy tak jak widziałeś. Teraz to poprawiłem ... jednak dalej coś jest nie tak bo RTC nie reaguje...

    W załączniku ponownie umieszczam program.
    Dzieki
  • Helpful post
    #13
    zumek
    Level 39  
    MarcinBarowski wrote:
    ... jednak dalej coś jest nie tak bo RTC nie reaguje...

    Myślałem , że zauważysz , ale nie zauważyłeś :|
    Twoja funkcja I2C_Tx() , wysyła na magistrale tylko 7 bitów :(
    Poza tym , nie odkładaj na później sprawdzania ACK , bo możesz nigdy nie dojść do tego momentu ;)
    I na koniec propozycja . Wstaw sobie taki fragment i używaj funkcji do operacji na SCL i SDA , a wtedy łatwiej napisać pozostałe funkcje i kod staje sie czytelniejszy .
    
    #define	SDA	0
    #define	SCL	1
    #define	PI2C	P2DIR
    
    inline	void	ALL_LO()
    {
    	PI2C|=(1<<SDA)|(1<<SCL);
    }
    inline	void	ALL_HI()
    {
    	PI2C&=~( (1<<SDA)|(1<<SCL) );
    }
    inline	void	SDA_LO()
    {
    	PI2C|=(1<<SDA);
    }
    inline	void	SCL_LO()
    {
    	PI2C|=(1<<SCL);
    }
    inline	void	SDA_HI()
    {
    	PI2C&=~(1<<SDA);
    }
    inline	void	SCL_HI()
    {
    	PI2C&=~(1<<SCL);
    }
    
    

    Acha , jeszcze w init_sys() proponuję poprawić kofigurację portu.
    
    //zwolnij magistralę i2c
     P2SEL&=~(1<<SDA) | (1<<SCL); //   I/O
     P2REN&=~(1<<SDA) | (1<<SCL); //  wyłącz pull-up/down
     P2DIR&=~(1<<SDA) | (1<<SCL); //  wejscie
     P2OUT&=~(1<<SDA) | (1<<SCL);
    


    Piotrek
  • #14
    MarcinBarowski
    Level 15  
    hmm... Dalej nic! Zmieniłem Piotrek kod tak jak pisałeś, poprawiłem wysyłanie danych na 8 bitów i dalej nic.
    Sprawdziłem ustawienia jeszcze raz i wszystko sie zgadza....

    Sprawdziłem też ACK i rtc zwraca coś po trzykrotnym wysłaniu adresu.
    Ale nawet po tym jest "cisza".... <załamka>
  • #15
    MarcinBarowski
    Level 15  
    A jednak zadziałało... Po dlugich intensywnych badaniach, znalazłem kilka błedów w programie. Teraz jednak wszystko ładnie działa...
    Dziekuje wam wszystkim za pomoc!
    Pozdrawiam