Forum: Mikrocontroller und Digitale Elektronik ARM LPC1313 delay


von Christoph (Gast)


Lesenswert?

Hallo Leute,

ich habe mir eine Delayfunktion mit dem CT32B0 Timer des ARM LPC1313 
geschrieben. Nun habe ich den fall dass es mit 1s, 0.500s, 0.100s 
funktioniert, aber z.B. mit 0.0001, 0.00000001 nicht geht, d.h. er 
bleibt in meiner while schleife hängen, weil anscheinend kein 
interruptflag gesetzt wird. Jetzt habe ich bestimmt einen Fehler drin, 
den ich nicht erkenne, evtl. sieht es von euch jemand :-)
Der Timer läuft  mit einer 72 MHz Clock und der Prescaler gibt jeden 
Takt zum Timer Counter durch.

hier der die init Funktion:
1
void delay_init()
2
{
3
  /* set timer */
4
  SYSAHBCLKCTRL_bit.CT32B0 = ONE_C;     // PCLK enabled for CT32B0
5
  TMR32B0TCR_bit.CE = ZERO_C;           // disable counting
6
  TMR32B0TCR_bit.CR = ONE_C;            // reset timer
7
  TMR32B0TCR_bit.CR = ZERO_C;                   
8
  TMR32B0CTCR_bit.CTM = ZERO_C;         // set rising PCLK edge timer mode
9
  
10
  /* set prescale counter */
11
  TMR32B0PC = 0;                        // reset prescale counter
12
  TMR32B0PR = 0x00000000;               // every PCLK
13
  
14
  /* set MR0 */
15
  TMR32B0MCR_bit.MR0I = ONE_C;          // interrupt when MR0 matches TC
16
  TMR32B0MCR_bit.MR0R = ONE_C;          // TC will be reset if MR0 matches
17
  TMR32B0MCR_bit.MR0S = ONE_C;          // TC and PC will be stopped 
18
}
hier die delay funktion:
1
void delay_CT32B0(float time_delay)
2
{
3
  //14ns tick
4
  uint32_t count = (uint32_t)((72000000 * time_delay) - 1); // countervalue
5
  
6
  TMR32B0MR0 = count;                     // write countervalue to MR0
7
  TMR32B0TCR_bit.CE = ONE_C;              // enable TC and PC for counting
8
  
9
  while(TMR32B0IR_bit.MR0INT != ONE_C);   // waiting for interrupt
10
    
11
  TMR32B0IR_bit.MR0INT = ONE_C;           // MR0 Interruptflag zurücksetzen
12
}

Dann noch eine Frage: Wie kann das Programm ohne Interrupt geschrieben 
werden?

Danke im voraus

Gruß Christoph

von Tobi (Gast)


Lesenswert?

Hallo,

ich habe mir für die STM32 (auch M3, also übertragbar) folgendes 
zusammengesucht:
1
// variables
2
uint32_t clocks_per_microsecond;
3
4
// functions
5
void delay_init (void)
6
  {
7
    clocks_per_microsecond = SystemCoreClock / 1000000;
8
  }
9
10
void delay_us (uint32_t us)   // max. delay at 72 MHz is 910 µs and 8 ms at 8 MHz
11
  {
12
    uint32_t delaycount = DWT->CYCCNT + (clocks_per_microsecond * us);
13
    while ((DWT->CYCCNT - delaycount) & 0x8000000)
14
      ;
15
  }
16
17
void delay_ms (uint32_t ms)   // 2 * ms to be save at 72 MHz (2 * 500 µs = 1 ms)
18
  {
19
    uint32_t i;
20
    uint32_t j = 2 * ms;
21
    for (i = 0; i < j; i++)
22
      {
23
        delay_us(500);
24
      }
25
  }

Am Anfang einmalig delay_init() aufrufen.
DWT und CYCCNT ist von ARM. Hat also jeder M3.
Der Witz hier ist, daß man zur Laufzeit nicht viel rechnen muß, was 
gerade für kurze delays wichtig ist. Es wird einfach nur das MSB 
geprüft. Auch ist es überlaufsicher. Habe auch länger gebraucht, bis ich 
das richtig verstanden hatte.
Und delay_ms benötigt es, wenn es längere Verzögerungen braucht.

von Christoph (Gast)


Lesenswert?

Ok super, vielen Dank.
Werde es mal ausprobieren-

Gruß

von Hermes (Gast)


Lesenswert?

Tobi schrieb:
> while ((DWT->CYCCNT - delaycount) & 0x8000000)
                                              ^ sicher, daß da nicht 
noch 'ne Null fehlt??

von Lutz (Gast)


Lesenswert?

Richtig; da fehlt eine Null (sind ja schließlich 32 bit).

Wenn man aber schon den cyclecounter der DWT mißbraucht, kann man es 
auch gleich "pur" machen:
1
void delay_us (uint32_t us)  
2
   {
3
      DWT->CYCCNT = 0;    
4
      uint32_t delaycount = clocks_per_microsecond * us;
5
      while (DWT->CYCCNT < delaycount)
6
         ;
7
   }

Das ist deutlich genauer, da zur Laufzeit weniger gerechnet werden muß.
Und man hat auch die vollen 32 bit zum "delayen" und nicht nur 31. 
Bringt ja schon enorm was (doppelte Zeit). Wobei bei Verzögerungen, bei 
denen das zum Tragen kommt, sowieso eine andere Lösung genommen werden 
sollte!!!

Dann darf man die DWT allerdings beim debuggen auch nicht wirklich 
nutzen, da man ja das CYCCNT-Register manipuliert.

Ob man jetzt zwischen DEBUG und RELEASE generell etwas beachten muß (DWT 
aktivieren?), weiß ich jetzt auch nicht spontan. Auf jeden Fall im 
RELEASE-build nochmal testen.

von Nico W. (nico_w)


Lesenswert?

Lutz schrieb:
> Ob man jetzt zwischen DEBUG und RELEASE generell etwas beachten muß (DWT
> aktivieren?)

Jo, muss man.

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/CEGHJDCF.html
1
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
2
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;

von Christoph (Gast)


Lesenswert?

Hallo,
danke für die Antworten.

wenn ich mit dem Delay_us() arbeite kommt bei mir der Fehler " 
identifier DWT is undefined". Müsste da noch etwas includiert werden?
Arbeite mit EWARM und den LPC1313.

Jetzt hab ich noch ein weiteres Anliegen.
Ich habe ein Fixed Time Slice System mit dem Systick (24 Bit Timer) 
realisiert. Funktioniert auch ohne Probleme.
Jetzt würde ich gerne eine Delayfunktion realisieren, die die Takte vom 
Systick (1µs) zählt. Hab bereits eine Delayfunktion geschrieben. 
Allerdings funktioniert das Programm nur mit kleinen Delays. Ich denke 
das liegt am Zählerüberlauf. Beim Debuggen sehe ich wenn die 
if(delaystop < 0) durchlaufen wird, bleibt er bei der while schleife 
hängen.

Hier die initialisierung vom Systick
1
void RTOSTimer_Init(void)
2
{
3
SYSTICKCVR = 0x00;    
4
SYSTICKCSR = 0x00;                      // timer disabled
5
SYSTICKRVR_bit.RELOAD = 0x0001869F;     // set timer value which counts to zero
6
SYSTICKCLKDIV = 12;                     // clock divider (12 MHz / 12 = 1 Mhz clock)
7
SYSTICKCSR = 0x07;                      // Systick Control Register - uses clock from clock divider - counter is enabled
8
}

hier die delay funktion
1
void counter_delay(float delaytime){
2
  //1µs tick
3
  int32_t delaycount = (uint32_t)((1000000 * delaytime)-1); //countervalue
4
  int32_t delaystop = SYSTICKCVR_bit.CURRENT - delaycount;  // SYSTICKCVR_bit.CURRENT is current countervalue
5
  if(delaystop < 0){
6
    delaystop = 16776215 + delaystop;                       // (2^24 - 1)= 16776215 -> 24 bit counter
7
  }
8
  while(SYSTICKCVR_bit.CURRENT < delaystop);
9
}

Danke im voraus

Gruß

von Christoph (Gast)


Lesenswert?

hab das Problem lösen können, anderer ansatz genommen...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.