2012-11-14 18 views
8

Sto utilizzando il controller STM32F2 e sto interagendo con un display LCD ST7036 tramite interfaccia parallela a 8 bit.Generazione del ritardo di nanosecondo in C su STM32

Il foglio dati dice che dovrebbe esserci un ritardo di 20 nano secondi tra il blocco degli indirizzi e il tempo di configurazione.

Come si genera un ritardo di 20 nanosecondi in C?

+0

Hai provato la funzione 'nanosleep()'? Nota: è necessario includere '' per usarlo. –

+0

Non è necessario effettuare ritardi ns. Questi sono ritardi minimi dalla scheda tecnica, ma puoi fare di più. Inoltre, perché non vuoi usare SPI o I2C? È molto più semplice e puoi inviare i dati in un unico pacchetto. Così libererai il controller per altre attività. – Bulkin

risposta

8

La prima specifica che ho trovato su Stm32f2 presuppone una frequenza di clock di 120 MHz. Questo è circa 8ns per ciclo di clock. Avresti bisogno di circa tre istruzioni a ciclo singolo tra operazioni successive di scrittura o lettura/scrittura. In C, probabilmente lo farà a++; (se a si trova nello stack).

+0

Sì - esattamente - tutte le risposte, ma questo offre soluzioni che richiederebbero 100 volte più tempo del necessario ... 20ns sono solo alcuni cicli, alcuni NOP in assemblaggio saranno più che adeguati ... –

+0

Non sarebbe buono per verificare il ritardo utilizzando il registro del ciclo di ciclo progettato specificamente per tale scopo, indipendentemente dal metodo di ritardo utilizzato? Altrimenti, immagino possa essere verificato con un oscilloscopio e alcuni pin digitali. – bunkerdive

+0

La funzione 'stopwatch_delay()' qui sopra è perfetta per me e può essere verificata o utilizzata per diverse lunghezze di ritardo. – bunkerdive

11

Utilizzare stopwatch_delay(ticks sotto per eseguire i tuoi ritardi. Utilizza il registro DWT_CYCCNT di STM32, che è specificamente progettato per contare i ticks dell'orologio, localizzati all'indirizzo 0xE0001004.

Per verificare l'esattezza di ritardo (vedi main), è possibile chiamare STOPWATCH_START, eseguire stopwatch_delay(ticks), quindi chiamare STOPWATCH_STOP e verificare con CalcNanosecondsFromStopwatch(m_nStart, m_nStop). Regolare ticks secondo necessità.

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

Sei sicuro che funzionerebbe? Un ciclo di istruzioni dovrebbe essere di circa 5ns. Ovviamente il codice utilizza più di 5 istruzioni. Quindi il tempo minimo sarebbe 25ns ... Il ritardo utilizzato nell'hardware, tuttavia, potrebbe essere molto inferiore a 25ns. – richieqianle

+0

Sì. Il codice deve essere modificato secondo necessità. Si potrebbe sicuramente usare solo il minimo di pezzi necessari, o idealmente un utente di questo codice eseguirà '__no_operation()' mille volte in un ciclo all'interno di 'main()' (ad esempio dove 'run_my_function()' è) per ottenere il cronometro di secondo livello per 1000 esecuzioni, quindi dividere quel numero per 1000 per vedere per quanto tempo una sola chiamata in pipe '__no_operation()' assume il sistema in questione ... e quindi usa come desiderato. – bunkerdive

+1

Solo un commento, 1000 NOP/1000 potrebbe non essere uguale a 1 NOP. Ottima spiegazione comunque! – richieqianle

0

Si dovrebbe esaminare la periferica FSMC disponibile nel chip. Mentre la configurazione potrebbe essere complicata, specialmente se non stai cadendo in una parte di memoria per cui è stata progettata, potresti scoprire che il tuo dispositivo con interfaccia parallela si adatta abbastanza bene a una delle modalità di interfaccia di memoria.

Questi tipi di controller di memoria esterni devono disporre di una serie di opzioni di temporizzazione configurabili per supportare la gamma di diversi chip di memoria là fuori in modo da essere in grado di garantire i tempi richiesti dalla scheda tecnica.

Il vantaggio di poterlo fare è che il vostro LCD sembrerà come una qualsiasi vecchia periferica mappata in memoria, distruggendo i dettagli dell'interfaccia di livello inferiore.