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

MSP430 I2C w C: Dlaczego program w C nie działa, a w asemblerze działa?

MarcinBarowski 02 Lut 2008 09:53 3282 14
REKLAMA
  • #1 4761193
    MarcinBarowski
    Poziom 15  
    Posty: 184
    Pomógł: 1
    Ocena: 3
    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]
  • REKLAMA
  • Pomocny post
    #2 4761926
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    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 4763245
    MarcinBarowski
    Poziom 15  
    Posty: 184
    Pomógł: 1
    Ocena: 3
    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 4763938
    Dr_DEAD
    Poziom 28  
    Posty: 829
    Pomógł: 126
    Ocena: 3
    MarcinBarowski napisał:

    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ąć?
  • REKLAMA
  • #5 4766392
    MarcinBarowski
    Poziom 15  
    Posty: 184
    Pomógł: 1
    Ocena: 3
    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 4766962
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    MarcinBarowski napisał:
    ...Może ktoś ma jakieś wytłumaczenie dla tego zjawiska ?

    pozdrawiam

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

    Piotrek
  • REKLAMA
  • #8 4768990
    MarcinBarowski
    Poziom 15  
    Posty: 184
    Pomógł: 1
    Ocena: 3
    Witam!
    W załączniku umieszczam swój kod w C. Ma to być kod do obsługi RTC DS1338.
    Dzięki za pomoc..
    Załączniki:
    • main.c (1.22 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • #9 4769084
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    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!!
  • REKLAMA
  • #10 4769097
    MarcinBarowski
    Poziom 15  
    Posty: 184
    Pomógł: 1
    Ocena: 3
    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 :)
  • Pomocny post
    #11 4769235
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    MarcinBarowski napisał:
    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 4769790
    MarcinBarowski
    Poziom 15  
    Posty: 184
    Pomógł: 1
    Ocena: 3
    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
    Załączniki:
    • main.c (1.42 KB) Musisz być zalogowany, aby pobrać ten załącznik.
  • Pomocny post
    #13 4770114
    zumek
    Poziom 39  
    Posty: 3352
    Pomógł: 695
    Ocena: 52
    MarcinBarowski napisał:
    ... 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 4770960
    MarcinBarowski
    Poziom 15  
    Posty: 184
    Pomógł: 1
    Ocena: 3
    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 4777059
    MarcinBarowski
    Poziom 15  
    Posty: 184
    Pomógł: 1
    Ocena: 3
    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

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy problemów z implementacją komunikacji I2C w języku C na mikrokontrolerze MSP430, gdzie program w asemblerze działa poprawnie, a w C nie. Autor próbował odwzorować ustawienia portów i rejestrów z przykładowego kodu TI w asemblerze, ale napotkał trudności, m.in. z ustawieniem wskaźnika stosu (Stack Pointer) oraz wektora resetu, które w asemblerze są jawnie konfigurowane, a w C sprawiają problemy. Wskazano, że w C nie ma potrzeby ręcznego ustawiania SP, a zmiana wektora resetu może powodować błędy. Problemy wynikały m.in. z niepoprawnego sterowania bitami portów (przypisywanie całych rejestrów zamiast operacji bitowych), błędnej sekwencji sygnałów startu I2C oraz wysyłania tylko 7 bitów zamiast 8. Zaproponowano stosowanie funkcji inline do manipulacji liniami SCL i SDA oraz konieczność sprawdzania bitu ACK. Po poprawkach i dokładnym debugowaniu autor potwierdził, że program w C zaczął działać poprawnie, a komunikacja z RTC DS1338 przebiega bez problemów. W dyskusji pojawiła się także wzmianka o próbach implementacji na procesorze AVR, gdzie również występowały podobne trudności.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA