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

STM32F030C8T6 - Konfiguracja SPI1 i zrozumienie ustawień GPIO

Jagi_prg 03 Maj 2014 12:40 2475 4
  • #1 13564928
    Jagi_prg
    Poziom 10  
    Posty: 44
    Ocena: 4
    Witam,

    Mam pewnien problem ze zrozumieniem SPI w STM32F0 (dokładnie STM32F030C8T6).
    Mianowicie, przy takiej konfiguracji:
    void SPI_Set(void)
    {
        RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // wlaczenie zegara dla SPI1
        RCC->AHBENR |= RCC_AHBENR_GPIOAEN;  //wlaczenie zegara dla portu A (ponowne)
    
        GPIOA->MODER |= (GPIO_MODER_MODER4_1 | GPIO_MODER_MODER5_1 | GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1); //GPIO jako funkcje alternatywne
        GPIOA->OSPEEDR |= (GPIO_OSPEEDR_OSPEEDR4_0 |GPIO_OSPEEDR_OSPEEDR5_0 | GPIO_OSPEEDR_OSPEEDR6_0 | GPIO_OSPEEDR_OSPEEDR7_0); // GPIO œrednia predkosc
        GPIOA->AFR[0] &= ~(GPIO_AFRL_AFR4 | GPIO_AFRL_AFR5 | GPIO_AFRL_AFR6 | GPIO_AFRL_AFR7); // funkcja alternatywna jako SPI1
    
    
        //Ustawienia SPI1
        SPI1->CR2 |= (SPI_CR2_DS_0 | SPI_CR2_DS_1 | SPI_CR2_DS_2 | SPI_CR2_TXEIE | SPI_CR2_RXNEIE | SPI_CR2_NSSP | SPI_CR2_FRXTH | SPI_CR2_SSOE); // DS[0:4]= 8 bitów wysyla; wywolanie przerwania kiedy odbierzemy/zapelnimy rejestr DR; ustawienie flagi na SPI1->SR gdy FRLCL bedzie zajmowac conajmniej 1/4 buffora
        SPI1->CR1 |= (SPI_CR1_BR_1 | SPI_CR1_MSTR );// | SPI_CR1_SSM | SPI_CR1_SSI  //BR = F_PCLK/8 ; STM jako Master; nSS jako programowy a stan na wyjsciu ustawiany jest bitem SSI;
        SPI1->CR1 &= ~(SPI_CR1_CPOL | SPI_CR1_CPHA | SPI_CR1_LSBFIRST);//CPOL = 0 i CPHA = 0; wysylanie od MSB
    
        SPI1->CR1 &= ~(SPI_CR1_SPE);//wlaczenie SPI
    
        //NVIC_EnableIRQ(SPI1_IRQn);//wlaczenie przerwania SPI
    }
    


    oraz chcąc wysłać 1 bajt dancych za pomocą tego kodu:
    
    uint8_t SPI_Receive_Data (uint8_t data)
    {
        uint8_t tmp;
        tmp = data;
        SPI1->DR = tmp;//wprowadza do rejestru przesownego 'data'
        SPI1->CR1 |= (SPI_CR1_SPE);//wlaczenie spi
        //while(!(SPI1->SR & SPI_SR_TXE));//sprawdza czy buffor TXFIFO jest pelen
    	while((SPI1->SR & SPI_SR_FTLVL_0));
    	while((SPI1->SR & SPI_SR_BSY));
        SPI1->CR1 &= ~(SPI_CR1_SPE);//wylaczenie spi
        tmp = (SPI1->DR);
        return tmp;
    }

    mam połowiczny sukces.
    Moje pytania są następujące:
    1) Dlaczego gdy wysyłam do slave np 0x82 to w rejestrze FTLVL mam 0x02 (czyli tak jak bym miał 2 bajty w TxFIFO a nie jeden) kiedy wysylam jeden bajt?( widzę to od razu po wykonaniu załadowania danych do rejestru przesuwnego DR). Przez to w RxFIFO pierwszy bajt (LSB) są jakieś śmieci (np. 0x00 lub 0x01) a w kolejnym bajcie mam już prawidłową wartość jaką powinienem dostać z układu (np. 0x20)?
    W inicjalizacji mam, że bufor "dzieli się na 4x8 bitów",
    2) Jak puszczam by bajty odebrane przesyłał mi na terminal to widzę, że na przemian odbiera prawidłową wartość a następnie śmieci (tak z 5 razy) po czym wysyła już same śmieci. (Gdy zatrzymuje debugowanie to widzę, że rejestr przesuwny jest pusty DR = 0x0 ale podejrzewam, że po prostu nie odczytuje wszystkich rzeczy z RxFIFO przez co on się przepełnia i wywala błędy),
    3) Jak to jest z tym nSS bo go kompletnie nie rozumiem?! :D można sprzętowo/programowo uruchamiać slave za pomocą nSS czy trzeba wykorzystywać GPIO? Czyli zamiast zaprzęgać f. alternatywną dać zwykłe GPIO typu push-pull?! Z tego co zrozumiałem to on się przydaje gdy STM32F0 staje się slavem, no ale mogłem źle zrozumieć. :) Gdzieś tutaj na forum podpatrzyłem kombinację z włączaniem/wyłączaniem SPI ale to nie jest moim zdaniem dobry pomysł bo w nocie jest napisane że po wył SPI odłącza się od logiki GPIO i (moim zdaniem) mamy stan Hi-Z. Może wtedy warto dać pull-up wewnętrzny? (jeżeli chodzi o połączenie maste <-> slave to full duplex, bez zewnętrznych rezystorów (pull-up/down) na magistrali. (w ksążce Marka Galewskiego zobaczyłem że na linii SCK ma podłączony pull-up)

    Byłbym bardzo wdzięczny za pomoc, ponieważ sam od niedawna zaczynam ogarniać STM...:)
  • #2 13565234
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Do rejestru DR trzeba się odwoływać przez 8-bitowy wskaźnik, bo on jest zadeklarowany jako 16-bitowy. Twoja zmienna tmp zupełnie nic nie zmienia.

    *(volatile uint8_t *)&SPI1->DR = ...

    4\/3!!
  • #3 13566378
    Jagi_prg
    Poziom 10  
    Posty: 44
    Ocena: 4
    Dzięki, pomogło ale znowu mam jakieś ale... :)
    Mianowicie, zaczynam debugowanie i wysyłam żądanie po SPI do układu by odczytał parametry z układu (MFRC522) wartości rejestru. W tym celu ustawiam 0x84 do poniższej funkcji:
    uint8_t SPI_Receive_Data (uint8_t data)
    {
        uint8_t tmp;
        SPI1->CR1 |= (SPI_CR1_SPE);//wlaczenie spi
        *(volatile uint8_t *)&SPI1->DR = data;//wprowadza do rejestru przesownego 'data'
    	while(!(SPI1->SR & SPI_SR_RXNE));
        SPI1->CR1 &= ~(SPI_CR1_SPE);//wylaczenie spi
        tmp = SPI1->DR;
        while(SPI1->SR & SPI_SR_RXNE);
        return tmp;
    }

    Odpalam debugowanie i dane które wypluje ta funkcja idą do bufora cyklicznego i przesyłane są do terminala. I tutaj już dwie rzeczy mnie nie pokoją.
    1) Po odpaleniu i zrobieniu np 30 cykli odczytu to w pierwszym cyklu od razu po inicjalizacji wypluwa mi 0x1 (nie wiadomo skąd ta wartość?!) z układu a następnie prawidłową wartoś ( w tym przypadku 0x80) w pozostałych 29 cyklach.
    2) W rejestrze DR po wykonaniu funkcji odczytu z SPI mam wartość DR = 0x8080 (wygląda to jak by były zdublowane...) Ale dane oprócz tej pierwszej (patrz pkt. 1) są prawidłowe.
    Nie wiem czy to nie jest wina samego układu?! (Nie inicjalizuje go jeszcze tylko wprost żądam odczytu danych z rejestru jakie producent narzucił).

    jest gdzieś na stronie ST opis działania SPI?! Bo manual naprawde nic mi nie mówi o tym jak się steruje programowo/sprzetowo pinem nSS (Jak w ogóle postawić stan wysoki?! wiem że stan niski jest gdy uruchomie SPI w obsłudze sprzętowej a jak jest w programowej?!)
    Z góry jeszcze raz dzięki za pomoc :)
  • Pomocny post
    #4 13566410
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Przy odczycie z DR jest dokładnie ten sam problem co przy zapisie - jak chcesz 8-bitów, to musisz się odwołać przez wskaźnik 8-bitowy (identyczny jak ten powyżej do zapisu). Twoja zmienna tmp i w tym przypadku nie ma żadnego znaczenia, bo "szerokość" odczytu/zapisu jest zdeterminowana tylko i wyłącznie przez źródło odczytu lub cel zapisu, a nie rozmiar jakiejś zmiennej.

    Sterowanie pinem CS sprzętowo dla trybu master jest nieprzydatne (na CS byłby impuls po każdym bajcie), więc należy go sterować programowo jako zwykły pin GPIO (stan niski -> układ "wybrany"), a rejestrze CR1 ustawić bity SSI oraz SSM. Sprzętowa kontrola ma sens w trybie slave lub multi-master.

    No i to włączanie/wyłączanie SPI przed każdym bajtem jest naprawdę bezsensowne - włącz po prostu raz (podczas inicjalizacji) i już.

    Tak samo druga (ostatnia) pętla oczekiwania na RXNE jest błędna i niepotrzebna.

    4\/3!!
  • #5 13568624
    Jagi_prg
    Poziom 10  
    Posty: 44
    Ocena: 4
    Dzięki za pomoc!! Serio moją 3 dniową rozkminę załatwiłeś w ciągu niecałej godziny! :D
    Nota coś wspominała o ustawieniu jako wej lub wyj nSS ale nie wpadłem na to że to ma być GPIO. Myślałem bardziej że to alternatywna funkcja nSS można ustawić jako wej lub wyj w SPI.
    Wszystko śmiga bez zastrzeżeń! Jeszcze raz dziękuje! :D
    temat do wywalenia lub zostawienia dla potomnych... :)
REKLAMA