Elektroda.pl
Elektroda.pl
X
CControls
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ARM][LPC2138] częstotliwość taktowanie procesora oraz SPI

kotlar 06 Paź 2008 11:30 4707 23
  • #1 06 Paź 2008 11:30
    kotlar
    Poziom 13  

    Witam od jakiegoś czasu zmagam się z projektem urządzenia którego zadaniem jest odbieranie danych z prędkością 1Mb/s(ciągły sygnał) i zapis tych danych na karcie MMC.

    Projekt robie na płytce ewolucyjnej EVBlpc213x na której zamontowany jest mikrokontroler LPC2138. Karta MMC podpięta jest pod SSP, komunikacja z nią przebiega prawidłowo. Sygnał który mam rejestrować wrzuciłem na MISO SPI0 jest to sygnał ciągły o prędkości 1Mb/s. Idea odbierania polega na tym że po SPI0(MOSI) wysyłam cokolwiek (np.0xFF) co powoduje uruchomienie zegara SPI, i w tym czasie odbieram mój sygnał na MISO. Przebieg sygnału zegarowego SPI w czasie tej transmisji wygląda następująco:
    [ARM][LPC2138] częstotliwość taktowanie procesora oraz SPI
    Jak wydać nie zdaje to egzaminu ponieważ następuje przerwa w odbieraniu i zgubione zostaje kulka próbek rejestrowanego sygnału. Jeśli dane wrzucał bym jeszcze na MMC to odbieranie całkowicie ustaje na kilka ms. Zainteresowałem się wiec częstotliwością taktowanie procesora i natrafiłem tam na kilka niejasnych dla mnie kwestii o których wyjaśnienie bardzo bym prosił.

    A mianowicie:
    Do dyspozycji mam mikrokontroler ARM LPC2138 o wydajności do 60MIPS. Wraz z nim występuje wbudowany rezonator 32.768kHz dla zegara RTC, oraz wbudowany systemowy rezonator kwarcowy 12MHz.

    Jak powinienem ustawić blok PLL aby układ działał 60Mhz???
    Programuje w C pod Keilem.
    W tej chwili inicjalizacja bloku PLL w pliku startup.s wygląda następująco:

    Code:
    ; Phase Locked Loop (PLL) definitions
    
    PLL_BASE        EQU     0xE01FC080      ; PLL Base Address
    PLLCON_OFS      EQU     0x00            ; PLL Control Offset
    PLLCFG_OFS      EQU     0x04            ; PLL Configuration Offset
    PLLSTAT_OFS     EQU     0x08            ; PLL Status Offset
    PLLFEED_OFS     EQU     0x0C            ; PLL Feed Offset
    PLLCON_PLLE     EQU     (1<<0)          ; PLL Enable
    PLLCON_PLLC     EQU     (1<<1)          ; PLL Connect
    PLLCFG_MSEL     EQU     (0x1F<<0)       ; PLL Multiplier
    PLLCFG_PSEL     EQU     (0x03<<5)       ; PLL Divider
    PLLSTAT_PLOCK   EQU     (1<<10)         ; PLL Lock Status





    PLL_SETUP       EQU     1
    PLLCFG_Val      EQU     0x00000024

    ; Setup PLL
                    IF      PLL_SETUP <> 0
                    LDR     R0, =PLL_BASE
                    MOV     R1, #0xAA
                    MOV     R2, #0x55

    ;  Configure and Enable PLL
                    MOV     R3, #PLLCFG_Val
                    STR     R3, [R0, #PLLCFG_OFS]
                    MOV     R3, #PLLCON_PLLE
                    STR     R3, [R0, #PLLCON_OFS]
                    STR     R1, [R0, #PLLFEED_OFS]
                    STR     R2, [R0, #PLLFEED_OFS]

    ;  Wait until PLL Locked
    PLL_Loop        LDR     R3, [R0, #PLLSTAT_OFS]
                    ANDS    R3, R3, #PLLSTAT_PLOCK
                    BEQ     PLL_Loop

    ;  Switch to PLL Clock
                    MOV     R3, #(PLLCON_PLLE:OR:PLLCON_PLLC)
                    STR     R3, [R0, #PLLCON_OFS]
                    STR     R1, [R0, #PLLFEED_OFS]
                    STR     R2, [R0, #PLLFEED_OFS]
                    ENDIF   ; PLL_SETUP

    Czyli mnożnik ustawiony jest na 0x1F + 1 co daje 32 a dzielnik na 0x03 co daje 8.
    Tak wiec CCLK powinno wynosić 12Mhz*32/8=48Mhz czy dobrze myślę???
    Jeśli jestem w startup.s to mogę przejść do Configuration Wizard i tam MSEL ustawione jest na 5 a PSEL ustawione jest na 2. czyli CCLK powinno wynosić 12Mhz*5/2=30Mhz czyli zupełnie cos innego. Jeśli zmieniam to MSEL i PSEL w Configuration Wizard to zmienia mi się w pliku startup.s wartość zmiennej PLLCFG_Val natomiast PLLCFG_MSEL oraz PLLCFG_PSEL pozostają niezmienione. Jeśli ktoś mógłby mi wytłumaczyć o co w tym chodzi to byłbym bardzo wdzięczny. I jak to ustawić aby procek działał 60Mhz.

    Jeśli chodzi o prędkość pracy interfejsu SSP to po ustawieniu SSPCPSR na 2 a SCR na 0 prędkość zegara SSP odczytana na oscyloskopie wynosi 7,5Mhz. A powinno chyba być 30MHz jeśli zegar procesora pracował by z 60Mhz.

    Pierwszy raz bawię się z mikroprocesorem i to co tu pisze może być totalna brednią. Jeśli ktoś mogłaby mi pomóc w zrozumieniu zagadnienia częstotliwości procesora i SSP to byłbym bardzo wdzięczny.

    0 23
  • CControls
  • Pomocny post
    #2 06 Paź 2008 12:17
    94075
    Użytkownik usunął konto  
  • Pomocny post
    #3 06 Paź 2008 12:20
    Freddie Chopin
    Specjalista - Mikrokontrolery

    // edit: fak, 3 minuty za pozno <:

    no zdecydowanie troche sie mylisz [;

    czestotliwosc procka wynosi FCPU=FOSC*mnoznik, tak wiec dla kwarcu 12MHz mnoznik musi byc rowny 5

    dzielnik sluzy jedynie konfiguracji PLLa i nie przeklada sie w zaden sposob na czestotliwosc procka. musisz jedynie wziasc pod uwage to, ze czestotliwosc FCPU*dzielnik*2 musi byc w jakichs tam granicach - chyba 156MHz - 320MHz, czyli wybierasz sobie dzielnik 2, dzieki czemu masz czestotliwosc wewnetrzna PLLa rowna 240MHz.

    co do czestotliwosci SPI, to zasadniczo musisz tez pamietac o tym, ze SSP jest na magistrali APB, ktorej zegar domyslnie jest 4x wolniejszy niz zegar systemowy (poszukaj rejestru VPBDIV).

    twoj pomysl odbioru jest troche nietrafiony jak juz sam zauwazyles - dosyc ciezko bedzie to zrobic niestety. proponowalbym przerwanie od timera i za jego pomoca probkowac sygnal, ale to bedzie niestety bardzo wolne - przerwanie co 60cykli zajmie ci bardzo duzo mocy procka - moze sie nie wyrobic. dlatego tez osobiscie proponowalbym ci dostawienie do ukladu rejestru przesuwnego, ktory zbieralby np 8bitow, do tego jakiegos zatrzasku, ktorym sobie owe 8bitow zatrzasniesz (sa rejestry z zatrzaskiem, juz nie pamietam oznaczen, szukaj SIPO z latch'em to znajdziesz). tym sposobem w przerwaniu raz na 8*60 cykli lapiesz cale 8bitow na raz.

    mozna tez troche pokombinowac [; przy pomocy jednego PWMa robisz 'zegar' tego sygnalu, dolaczajac go do wejscia zegarowego SPI. teraz konfigurujesz owe SPI na tryb SLAVE i po problemie. musisz tylko pamietac o tym, ze zanim odpalisz zegar musisz sie zsynchronizowac z sygnalem!

    4\/3!!

    0
  • Pomocny post
    #4 06 Paź 2008 12:27
    94075
    Użytkownik usunął konto  
  • Pomocny post
    #5 06 Paź 2008 12:32
    Freddie Chopin
    Specjalista - Mikrokontrolery

    albertb napisał:
    Freddie z tym dzielnikiem to mylisz się PODWÓJNIE.
    Przy x4 to będzie 480MHz.

    zgadza sie! jest jeszcze dodatkowy dzielnik standardowy przez 2, dlatego w istocie dzielnik ktory ustawiamy musi spelniac zaleznosc:

    FCPU*dzielnik*2>156MHz && FCPU*dzielnik*2<320MHz

    juz poprawiam

    nie dosc ze 3 minuty za pozno, to jeszcze wtopa <:

    4\/3!!

    0
  • #6 06 Paź 2008 12:48
    kotlar
    Poziom 13  

    Ok dzięki za pomoc
    Co do VPBDIV to rzeczywiście mam ustawiony tak że VPB Clock = CPU Clock/4
    A jeśli chodzi o rejestry SIPO to jeśli mógłbyś to napisz mi coś o tym szerzej. O co chodzi z tym zatrzaskiem??

    0
  • Pomocny post
    #7 06 Paź 2008 13:04
    Freddie Chopin
    Specjalista - Mikrokontrolery

    to glupi pomysl z tym zatrzaskiem i rejestrem przesuwnym - lepiej wykorzystac to co jest w procku zamiast dostawiac uklady dodatkowe. dorob z PWMa zegar dla SPI i skonfiguruj je jako SLAVE i bedzie 10x lepiej <:

    4\/3!!

    0
  • CControls
  • #8 06 Paź 2008 13:19
    kotlar
    Poziom 13  

    aha to jeszcze raz dziękuję za pomoc:) zabieram się wiec za to PWM

    0
  • #9 07 Paź 2008 13:07
    kotlar
    Poziom 13  

    częstotliwość procka, szyny VPB oraz SPI opanowana.
    napisałem też PWM i jego wyjście puściłem na wejście zegara SPI0(slave)
    teraz chciałbym za pomocą przerwań obsługiwać odbieranie z SPI. jak do tej pory nie pisałem obsługi przerwań pod ARM i nie wiem za bardzo jak się za to zabrać. jeśli ktoś miałby jakiś przykładowy kod albo opis jak to uczynić to byłbym bardzo wdzięczny.
    pozdrawiam kotlar

    0
  • Pomocny post
    #10 07 Paź 2008 14:47
    94075
    Użytkownik usunął konto  
  • #11 07 Paź 2008 15:47
    kotlar
    Poziom 13  

    no wiec naskrobałem takie rzeczy:
    PWM inicjalizuje funkcją:

    Code:
    void PWM5Init(void)
    
    {
       //Preskaler CCLK/PWMPR+1)
       PWMPR = 59;
       //Zgodne zbocze kasuje timer
       PWMMCR |= PWMMCR_Reset_on_PWMMR0;
       //Ustaw PWM5 jako wyjscie
       PWMPCR |= PWMPCR_PWMENA5;
       //Ustaw rejestr zakres 100
       PWMMR0 = 100;
       //PWM= 50%
       PWMMR5 = 50;
       //Wykonaj zapis MR0 i MR5
       PWMLER = (1<<5) | (1<<0);
       //Wlacz alternatywny pin PWM5
       PINSEL1 |= PWM5_P021_SEL;
       //Zeruj licznik i preskaler
       PWMTCR = PWMTCR_Counter_Reset;
       //Wlacz licznik PWM
       PWMTCR = PWMTCR_PWM_Enable | PWMTCR_Counter_Enable;
    }

    PWM wygląda że działa poprawnie a stwierdzam to na podstawie diody podpiętej do P0.21, i jeżeli zmieniam PWMMR5 to jasność świecenia diody tez się zmienia:)
    Sygnał PWM z P0.21 zwarłem z P0.4 gdzie mam SCK SPI0.

    Inicjalizacja SPI0 wygląda następująco:

    Code:

    #define SCK0_P04_SEL   (1<<8)
    #define MISO0_P05_SEL   (1<<10)
    #define MOSI0_P06_SEL   (1<<12)

    void spi0Init(void){
       //Piny jako funkcja alternatywna SPI0
       PINSEL0 |= SCK0_P04_SEL|MISO0_P05_SEL|MOSI0_P06_SEL;
       //SPI Slave 8 bitow CPOL 0
       S0SPCR=1<<7;
       //Podzielnik czestotlwosci
       S0SPCCR=30;
    }


    Nie wiem co zrobić z SSEL w SPI0 który mam na nodze P0.7 narazie wisi on w powietrzu.

    A teraz o napisanej przeze mnie obsłudze przerwania która z pewnością jest bledną.

    Na samym początku programu wsadziłem definicje nagłówku przerwania:

    Code:
    void SPI0Interrupt(void) __attribute__ ((interrupt ("IRQ")));


    Później już w main'nie coś takiego:

    Code:
       VICVectCntl0 = 0x00000030;        
    
       VICVectAddr0 = (unsigned)SPI0Interrupt;
       VICIntEnable = 0x00000400;

    Funkcja przerwania wygląda następująco:
    Code:
    void SPI0Interrupt(void)
    
    {
       bw[wsk]=S0SPDR;
       wsk++;
       S0SPINT=1;
       VICVectAddr = 0x00000000;
    }


    Wykonywanie programu wygląda tak że załączam wszystkie funkcje inicjalizujace SPI0, SPI1, LCD, resetuje kartę MMC załączam niby te przerwania:
    Code:
       VICVectCntl0 = 0x00000030;        
    
       VICVectAddr0 = (unsigned)SPI0Interrupt;
       VICIntEnable = 0x00000400;

    nio i załączam PWM uruchamiając


    Code:
    PWM5Init()


    Program oczywiście nie wchodzi do przerwania i kreci się w bezczynności.
    Bardzo proszę o pomoc w zlokalizowaniu błędów których zapewnie narobiłem mnóstwo.
    Za wszelaka pomoc z góry dziękuję.

    0
  • Pomocny post
    #12 07 Paź 2008 16:24
    Freddie Chopin
    Specjalista - Mikrokontrolery

    w kodzie startowym procesora przerwania musza byc wlaczone. to po pierwsze. po drugie musi byc tam zlokalizowany prawidlowy wektor przerwania IRQ. to dwie rzeczy na poczatek.

    najprosciej bedzie naprawde jak znajdziesz w necie jakis dzialajacy przyklad z SPI i go przeanalizujesz/przerobisz. powodow niedzialania moze byc mnostwo.

    a linie SSEL przypnij do masy.

    edit:

    kilka uwag:

    VICVectCntl0 = 0x00000030;

    patrze w datasheeta i widze ze SPI0 ma IRQ rowne 10, wiec skad u ciebie wyszlo to 0x30? wg mnie powinno byc 0x2A (or sth like that, na pewno koncowka A)

    dalej:

    VICVectAddr0 = (unsigned)SPI0Interrupt;

    nie ma takiego rodzaju zmiennej jak (unsigned) - jest za to (unsigned int)

    dalej:

    VICIntEnable = 0x00000400;

    tu akurat dobrze, wiec skad wytrzasnales to 0x30 wczesniej...

    dobrym zwyczajem jest na poczatku inicjalizacji przerwan dorzucic jeszcze:

    Code:

       VICIntEnClr=0xFFFFFFFF;
       VICVectAddr=0;
       VICIntSelect=0;


    tzw. 'just in case' <:

    4\/3!!

    0
  • #13 07 Paź 2008 21:10
    kotlar
    Poziom 13  

    poprawiłem te błędy i efekt jest taki ze program wchodzi w przerwanie, wychodzi też z niego ale dzieje się to tylko jeden jedyny raz:( dlaczego tak może być???

    mój program wygląda teraz tak:

    na samym początku definicja nagłówku przerwania:

    Code:
    void SPI0Interrupt(void) __irq;

    następnie juz w main'nie
    Code:
       
    
    VICIntEnClr  = 0xFFFFFFFF;
    VICVectAddr  = 0;
    VICIntSelect = 0;
    VICVectCntl0 = 0x2A;        
    VICVectAddr0 = (unsigned long)SPI0Interrupt;
    VICIntEnable = 0x00000400;

    funkcja obsługi przerwania wygląda następująco:
    Code:
    void SPI0Interrupt(void) __irq
    
    {
       bw[wsk]=S0SPSR;
       wsk++;
       S0SPINT=1;
       VICVectAddr = 0x00000000;
    }

    co może być przyczyna tego ze program tylko raz wchodzi do przerwania???
    PWM przecież po załączeniu pracuje cały czas wiec teoretycznie SPI0 cały czas powinno przyjmować dane.

    0
  • Pomocny post
    #14 08 Paź 2008 00:03
    Freddie Chopin
    Specjalista - Mikrokontrolery

    nie uzywalem jeszcze SPI w LPC, ale zainteresuj sie flagami, szczegolnie SPIF. sprawdz tez, czy przypadkiem cos ci sie nie krzaczy - moze ustawiona jest jakas inna flaga, ktora powoduje zatrzymanie procesu.

    4\/3!!

    0
  • Pomocny post
    #15 08 Paź 2008 10:57
    94075
    Użytkownik usunął konto  
  • #16 08 Paź 2008 11:09
    kotlar
    Poziom 13  

    wiec tak SSEL ustawiłem jako funkcje alternatywna pinu i przypiąłem do masy
    poprawiłem też jeden błąd(literówkę)
    odczytywałem dane tak:

    Code:
    bw[wsk]=S0SPSR;
    co oczywiście było blednę bo S0SPSR jest rejestrem statusu a dane do odebrania znajdują się w rejestrze S0SPDR

    w tej chwili funkcja obsługi przerwania wygląda tak:
    Code:
    void SPI0Interrupt(void) __irq
    
    {
       if(S0SPSR & 0x80)
          {
          bw[wsk]=S0SPDR;
          wsk++;
          }
       S0SPINT=1;
       VICVectAddr = 0x00000000;
    }

    po wstępnym teście wygląda na to ze przerwania działają prawidłowo:D
    za wszelaką pomoc bardzo dziękuje
    ps. jeśli spotkał bym się jeszcze z jakimś problem to pozwolę sobie podzielić się nim z Wami
    pozdrawiam kotlar

    0
  • #17 08 Paź 2008 12:10
    Freddie Chopin
    Specjalista - Mikrokontrolery

    albertb napisał:
    Freddie:
    Przerwania muszą być włączone, ale dlaczego w kodzie startowym? ;-)

    nie musza byc wlaczone w kodzie startowym oczywiscie, niemniej jednak prosciej zrobic to tam (przy okazji inicjalizacji stosow), skoro procek po resecie jest w trybie supervisor, niz kombinowac z tym po zakonczeniu boot'a i robic jakies przerwania software'owe [;

    Cytat:

    brzydko wyglada <: jestem perfekcjonista <:

    4\/3!!

    0
  • #18 08 Paź 2008 12:33
    94075
    Użytkownik usunął konto  
  • #19 08 Paź 2008 13:06
    Freddie Chopin
    Specjalista - Mikrokontrolery

    z perfekcjonitycznego punktu widzenia kod ktory przedstawiles zasluguje na bana na tydzien. mysle czy zglosic moderatorom, czy nie [;

    ja wiem ze wszystko to jest poprawne. ostatnio nawet poczytalem sobie o code morphingu, w ktorego efekcie kod jest skrajnie bezsensowny, ale skladniiowo poprawny i dziala jak trzeba [; wszystko sie da, jednak obstaje wciaz przy pelnym definiowaniu zmiennych <:

    4\/3!!

    0
  • #20 16 Paź 2008 16:44
    kotlar
    Poziom 13  

    no i napotkałem kolejny kamień który nie wiem jak przeskoczyć

    po przeprowadzeniu kolejnych testów układu doszedłem do wniosku że dane nie są odbierane ciągle mimo tego że odbieranie po SPI0 zrobione jest na przerwaniach. w momencie kiedy dane wysłane są na kartę odbieranie ustaje.

    przeprowadziłem następujący eksperyment:
    podpiąłem przez Transceiver PCA82C250 sygnał CAN do SPI0(slave), sygnał wpuściłem na nogę MOSI, na SCK dałem sygnał z PWMa o częstotliwości 2MHz, sygnał CAN puszczałem z kompa poprzez kartę CANowską z częstotliwością 500kHz tak aby próbkowanie na uP mieć 4 razy większe niż częstotliwość rejestrowanego sygnału.
    i tak zarejestrowałem 10 sektorów na karcie MMC
    po przerzuceniu danych z karty na kompa programem WINHEX odpowiednim obrobieniu(scaleniu 4 próbek w jedna) i zinterpretowaniu jako ramki CAN otrzymałem wyniki:

    na karcie zarejestrowałem 99 ramek CAN
    91 z nich było poprawne(CRC z ramki zgadzało się z CRC wyliczonym przeze mnie)
    8 ramek było błędne(różne CRC)
    zacząłem wiec sprawdzać jak odebrane przeze mnie ramki maja się do tego co wysłałem i tu niemiła niespodzianka.
    w porównaniu do tego co wysłałem to co odebrałem wygląda następująco:
    18 poprawnie odebranych ramek
    1 błędna ramka(błąd CRC)
    16 zgubionych ramek(to znaczy ze je wysłałem z PC a nie odebrałem ich na uP)
    10 poprawnie odebranych ramek
    1 błędna ramka(błąd CRC)
    16 zgubionych ramek
    10 poprawnie odebranych ramek
    1 błędna ramka(błąd CRC)
    16 zgubionych ramek
    i tak w sumie 9 razy

    no i nasuną mi się wniosek ze w momencie kiedy dane wysyłam na kartę to odbieranie ustaje przez co tracę bardzo dużo danych

    co zrobić z tym fantem
    myślałem ze skoro odbieranie po SPI jest na przerwaniach to będzie to działać niezawodnie
    nie wiem jak jest z sygnałem PWM(nie widziałem go na oscyloskopie) bo jeśli w momencie wysyłania na kartę sygnał ten przestaje być generowany to odbieranie tez automatycznie ustaje.
    bardzo proszę o jakakolwiek rade co z tym zrobić

    0
  • #21 16 Paź 2008 22:35
    Freddie Chopin
    Specjalista - Mikrokontrolery

    zdecydowanie musisz sie w to wglebic.

    sygnal PWM na pewno sam sie nie wylacza, wiec o to sie nie obawiaj - blad na pewno nie lezy tam. skoro calosc jest niesamowicie regularna, ja obstawiam bledy czestotliwosci albo bledy synchronizacji...

    oscyloskop wskazany.

    4\/3!!

    0
  • #22 18 Paź 2008 19:35
    kotlar
    Poziom 13  

    Po obejrzeniu PWMa na oscyloskopie rzeczywiście działa on bez zarzutu przez cały czas i dane odbierane są prawidłowo. A problem tkwi w karcie MMC. Po teście karty MMC na która zapisuje programem "cardtest1.2a" wyszło że karta ta przy zapisie wyciąga max 0.6Mb/s a ja chciałem słać na nią ciąg danych z prędkością 2Mb/s co powodowało ze dane przychodziły pogubione.
    Posiadam jeszcze dwie karty MMC oraz dwie SD w tym jedna z nich przy zapisie wyciąga 3,6Mb/s ale niestety uP mi ich nie wykrywa. Co może być tego przyczyną???
    Czy istnieje jakaś różnica w obsłudze karty SD w porównaniu do MMC???(z tego co wyczytałem to chyba nie)
    Karta SD posiada 9 pinów a MMC tylko 7 i te 7 używam do komunikacji z karta, co w takim razie zrobić z pozostałymi 2 pinami w karcie SD???(podpiąć do GND,VCC????)

    0
  • #23 20 Paź 2008 21:04
    94075
    Użytkownik usunął konto