2012-11-14 27 views
8

Używam kontrolera STM32F2 i współpracuję z wyświetlaczem LCD ST7036 przez 8-bitowy interfejs równoległy.Generowanie nanosekundowego opóźnienia w C na STM32

Arkusz danych mówi, że powinno być 20 nano sekundowe opóźnienie między zatrzymaniem adresu i czasem konfiguracji.

Jak wygenerować opóźnienie o 20 nanosekund w C?

+0

Czy próbowałeś funkcji 'nanosleep()'? Uwaga: musisz użyć '', aby go użyć. –

+0

Nie musisz wprowadzać opóźnień ns. Są to min. Opóźnienia w arkuszu danych, ale możesz zrobić więcej. Dlaczego nie chcesz używać SPI lub I2C? To znacznie prostsze i możesz wysyłać dane w jednym pakiecie. Uwolnisz kontroler do innych zadań. – Bulkin

Odpowiedz

8

Pierwsza specyfikacja, którą znalazłem w Stm32f2, zakłada częstotliwość taktowania 120 MHz. To około 8ns na cykl zegara. Będziesz potrzebował około trzech instrukcji jednego cyklu pomiędzy kolejnymi operacjami zapisu lub odczytu/zapisu. W C, prawdopodobnie będzie to robił a++; (jeśli a znajduje się w stosie).

+0

Tak - dokładnie - wszystkie odpowiedzi, ale ta daje rozwiązania, które wymagałyby 100x więcej czasu niż jest to wymagane ... 20ns to tylko kilka cykli, kilka NOP-ów w montażu będzie więcej niż wystarczające ... –

+0

Czy nie byłoby dobrze zweryfikować opóźnienie przy użyciu rejestru liczby cykli specjalnie zaprojektowanego do tego celu, niezależnie od tego, jaka metoda opóźnienia jest używana? W przeciwnym razie, mógłbym to zweryfikować za pomocą oscyloskopu i cyfrowych pinów. – bunkerdive

+0

Funkcja 'stopwatch_delay()' działa doskonale dla mnie i może być zweryfikowana lub używana dla różnych długości opóźnień. – bunkerdive

11

Użyj stopwatch_delay(ticks) poniżej, aby wykonać opóźnienia. Wykorzystuje rejestr DWT_CYCCNT STM32, który jest specjalnie zaprojektowany do liczenia rzeczywistych tyknięć zegara, zlokalizowanych pod adresem 0xE0001004.

Aby zweryfikować dokładność opóźnienia (patrz main), można wywołać STOPWATCH_START uruchom stopwatch_delay(ticks), a następnie zadzwonić STOPWATCH_STOP i zweryfikować z CalcNanosecondsFromStopwatch(m_nStart, m_nStop). Dostosuj ticks w razie potrzeby.

uint32_t m_nStart;    //DEBUG Stopwatch start cycle counter value 
uint32_t m_nStop;    //DEBUG Stopwatch stop cycle counter value 

#define DEMCR_TRCENA 0x01000000 

/* Core Debug registers */ 
#define DEMCR   (*((volatile uint32_t *)0xE000EDFC)) 
#define DWT_CTRL  (*(volatile uint32_t *)0xe0001000) 
#define CYCCNTENA  (1<<0) 
#define DWT_CYCCNT  ((volatile uint32_t *)0xE0001004) 
#define CPU_CYCLES  *DWT_CYCCNT 

#define STOPWATCH_START { m_nStart = *((volatile unsigned int *)0xE0001004);} 
#define STOPWATCH_STOP { m_nStop = *((volatile unsigned int *)0xE0001004);} 


static inline void stopwatch_reset(void) 
{ 
    /* Enable DWT */ 
    DEMCR |= DEMCR_TRCENA; 
    *DWT_CYCCNT = 0;    
    /* Enable CPU cycle counter */ 
    DWT_CTRL |= CYCCNTENA; 
} 

static inline uint32_t stopwatch_getticks() 
{ 
    return CPU_CYCLES; 
} 

static inline void stopwatch_delay(uint32_t ticks) 
{ 
    uint32_t end_ticks = ticks + stopwatch_getticks(); 
    while(1) 
    { 
      if (stopwatch_getticks() >= end_ticks) 
        break; 
    } 
} 

uint32_t CalcNanosecondsFromStopwatch(uint32_t nStart, uint32_t nStop) 
{ 
    uint32_t nDiffTicks; 
    uint32_t nClkTicksPerMicrosec; 

    nDiffTicks = nStop - nStart; 
    nDiffTicks *= 1000;        // Scale diff by 1000. 
    nClkTicksPerMicrosec = SystemCoreClock/1000000; // Convert (clkTicks/sec) to (clkTicks/microsec), SystemCoreClock = 168000000 

    return nDiffTicks/nClkTicksPerMicrosec;   // nanosec = (ticks * 1000)/(clkTicks/microsec) 
} 

void main(void) 
{ 
    int timeDiff = 0; 
    stopwatch_reset(); 

    STOPWATCH_START; 
    run_my_function(); 
    STOPWATCH_STOP; 

    timeDiff = CalcNanosecondsFromStopwatch(m_nStart, m_nStop); 
    printf("My function took %d nanoseconds\n", timeDiff); 
} 
+0

Czy na pewno to zadziała? Cykl instrukcji będzie około 5ns ... Oczywiście kod używa więcej niż 5 instrukcji. Zatem minimalny czas to 25ns ... Opóźnienie użyte w sprzęcie może jednak być znacznie mniejsze niż 25ns. – richieqianle

+0

Tak. Kod należy zmodyfikować w razie potrzeby. Z pewnością wystarczy użyć minimum potrzebnych elementów, lub najlepiej, aby użytkownik tego kodu uruchamiał '__no_operation()' tysiąc razy w pętli wewnątrz 'main()' (np. Gdzie 'run_my_function()' jest), aby uzyskać nano-drugi stoper na 1000 przebiegów, a następnie po prostu podziel tę liczbę przez 1000, aby zobaczyć, jak długo jedno pojedyncze potokowe wywołanie '_nooperacja()' bierze na system, o którym mowa ... a następnie użyj zgodnie z potrzebami. – bunkerdive

+1

Tylko komentarz, 1000 NOP/1000 może nie być równe 1 NOP. Świetne wyjaśnienie w każdym razie! – richieqianle

0

Powinieneś zajrzeć do urządzenia peryferyjnego FSMC dostępnego w twoim chipie. Chociaż konfiguracja może być skomplikowana, szczególnie jeśli nie upuszczasz części pamięci, dla której został zaprojektowany, może się okazać, że Twoje urządzenie z interfejsem równoległym jest dość dobrze odwzorowane w jednym z trybów interfejsu pamięci.

Te zewnętrzne kontrolery pamięci muszą mieć kilka konfigurowalnych opcji synchronizacji, aby obsłużyć zakres różnych układów pamięci, dzięki czemu będziesz w stanie zagwarantować czas wymagany przez arkusz danych.

Przyjemną zaletą tego jest to, że wyświetlacz LCD będzie wyglądał jak każda stara pamięć zamapowana na urządzenia peryferyjne, oddzielając szczegóły interfejsu niższego poziomu.

Powiązane problemy