Forum: Mikrocontroller und Digitale Elektronik STM32 Systick Variable zurücksetzen


von Jan K. (jan_k)


Lesenswert?

Hi Leute, ich habe im Prinzip ein simples Problem. Ich möchte eine 
einfache Idle Zeit Berechnung machen. Dafür setze ich im SysTick des 
STM32f103TB alle 10ms eine counter Variable zurück. Diese ist natürlich 
volatile.
Nun passiert aber manchmal, dass die Variable schlicht nicht zu 0 
gesetzt wird, dann steht etwa das doppelte in "last_idle_counts".

Die memory Barriere war lediglich ein Versuch, der nix brachte.

Woran könnte das liegen?

main.c:
1
#include "stm32f10x.h"
2
3
static volatile uint32_t idle_counts = 0;
4
static const uint32_t idle_counts_max = 1; // max counts per systick if no task and interrupt is running. Reference value
5
6
7
int main ( void )
8
{
9
10
  // Init Clock
11
  // Init_STM();
12
  SystemInit();
13
  ClockInit();
14
  SystemCoreClockUpdate();
15
16
  SysTick_Config(SystemCoreClock/100); // each 10 ms
17
  
18
  while( 1 )
19
  {
20
    ++idle_counts;
21
  }
22
23
}
24
25
26
void ClockInit(void)
27
{
28
  /* at this point HSI or HSE is the clock source, but no PLL */
29
  RCC->CR |= RCC_CR_HSION;
30
  while ((RCC->CR & RCC_CR_HSIRDY) != RCC_CR_HSIRDY);   /* Wait until HSI ready */
31
32
  // disable pll, otherwise we cannot set the multiplier 
33
  RCC->CR &= ~RCC_CR_PLLON;   
34
  while ((RCC->CR & RCC_CR_PLLRDY) != 0); // wait until off 
35
  
36
  // 8 MHz RC, 4 MHz * 16 = 64 MHz SYSCL = AHB = APB2, APB1 = HCLK/2 = 32 MHz, ADC = APB2/6 = 10.67 MHz; ADC 14 MHz max!
37
  RCC->CFGR = 0x00000000;
38
  RCC->CFGR |= RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL16 | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_SW_PLL | RCC_CFGR_ADCPRE_DIV6;
39
  while((RCC->CFGR & RCC_CFGR_SWS) == RCC_CFGR_SWS_PLL); // wait
40
  
41
  // enable PLL again
42
  RCC->CR |= RCC_CR_PLLON;
43
  while ((RCC->CR & RCC_CR_PLLRDY) == RCC_CR_PLLRDY); // wait until rdy
44
  
45
  
46
  // prefetch enabled, 2 wait states
47
  FLASH->ACR |= FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_2;
48
 
49
  /* Check flash latency */
50
  while ((FLASH->ACR & FLASH_ACR_LATENCY) != FLASH_ACR_LATENCY_2);
51
}
52
 
53
void SysTick_Handler(void)  
54
{                              
55
  uint32_t last_idle_counts;
56
57
  static uint32_t idle_counts_mean;
58
  
59
  last_idle_counts = idle_counts;
60
  idle_counts = 0;
61
  __DMB();
62
63
  idle_counts_mean = (last_idle_counts + idle_counts_mean) / 2;
64
}

Vielen Dank!

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Jan K. schrieb:
>     ++idle_counts;

Das läuft auf 3 separate und zwischendrin unterbrechbare Befehle raus:
   Rx = idle_counts
   Rx = Rx + 1
   idle_counts = Rx
Jetzt klar?

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Abhilfe, ohne die Interrupts abzuschalten:
1
++idle_counts;
ersetzen durch
1
uint32_t t;
2
do {
3
  t = __LDREXW(&idle_count) + 1;
4
} while (__STREXW(t, &idle_count);

von Jan K. (jan_k)


Lesenswert?

Meine Fresse.

Reicht für heute. Habe gerade noch überlegt, ob ich da ne semaphore bzw 
ldrex und strex oder so benutzen muss und habe für mich klar für nein 
entschieden, weil er ja in der ISR nur "gelesen" wird... Alter Verwalter

Danke ;)

Edit: da warst du schneller :(

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Jan K. schrieb:
> weil er ja in der ISR nur "gelesen" wird

Für was hältst du das?
 idle_counts = 0;

von Jan K. (jan_k)


Lesenswert?

Daher die Anführungszeichen. Sollte meinen Gedankenfehler darstellen. 
Habe das resetten als Schreibzugriff schlicht ignoriert.

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.