Forum: Mikrocontroller und Digitale Elektronik STM32 Timer Problem mit internen Quarz (?)


von Massi87 (Gast)


Lesenswert?

Hi zusammen,

ich beschäftige mich aktuell mit der Synchronisation von zwei Timern 
(soll später mal für die Signalerzeugung verwendet werden und daher ist 
mir die Genauigkeit der Timer sehr wichtig).
Der TIM1 ist der Slave-Timer und soll immer wenn er vom Master TIM2 
getriggert wird, einen Puls von aktuell 1 Sekunden (das soll später mal 
im Mikrosekundenberich sein) nach 4 Sekunden auslösen und auf GPIOA-10 
an die angeschlossene LED ausgeben. TIM2 schickt in TIM1 immer den 
Trigger beim Start und läuft aktuell 10 Sekunden (soll später auch mal 
im Mikrosekundenbereich sein.

Das Ganze lasse ich aktuell endlos laufen und messe mit einer Stoppuhr 
die Zeit. Mir ist aber aufgefallen, dass der erste Puls bei 4 Sekunden 
kommt, aber der zweite kommt nicht bei 14 Sekunden, sondern etwas eher 
(der Puls sollte immer bei 4, 14, 24, 34, 44 Sekunden kommen, was er 
aber nicht macht(ungefähr 4, 13.8, 23.65, 33.5, 43.35, 53, 62.9)).

Das Board nutzt aktuell als Versorgungsquelle den PC über USB (wegen 
Programmierung und Debugging).

Hat der interne Quarz so eine schlechte Qualität, dass er so start 
abweicht und ich einen externen Quarz verwenden sollte? Oder mache ich 
irgendetwas falsch?

Ich bin über jede Hilfe sehr dankbar!!



Im Programm STM32CubeMX habe ich zuvor das STM32F446RE-Nucleo 64 Board 
konfiguriert und dann den Quellcode mit TrueStudio weiter angepasst.

Einstellungen STM32CubeMX:
- PLL Source MuX = HSI (HSI RC = 16MHz)
- PLLM = /8
- PLLN = 180
- PLLP = /2
- System Clock Mux = PLLCLK
-> SYSCLK (MHz) = 180
- AHB Prescaler = /1
- HCLK (MHz) = 180

Für TIM2:
- APB1 Prescaler = /4
- APB1 Faktor = x2
- APB1 Clock -> 90 MHz

Für TIM1:
- APB2 Prescaler = /2
- APB2 Faktor = x2
- APB2 Clock = 180


C-Code in True Studio mit HAL-Libraries. Wenn gewünscht, kann ich auch 
den Code mit Registern posten:
1
#include "main.h"
2
/* Private variables ---------------------------------------------------------*/
3
TIM_HandleTypeDef htim1;
4
TIM_HandleTypeDef htim2;
5
TIM_HandleTypeDef htim3;
6
7
/* Private function prototypes -----------------------------------------------*/
8
void SystemClock_Config(void);
9
static void MX_GPIO_Init(void);
10
static void MX_TIM1_Init(void);
11
static void MX_TIM2_Init(void);
12
static void MX_TIM3_Init(void);
13
14
15
int main(void)
16
{
17
  /* MCU Configuration--------------------------------------------------------*/
18
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
19
  HAL_Init();
20
21
  /* Configure the system clock */
22
  SystemClock_Config();
23
24
  /* Initialize all configured peripherals */
25
  MX_GPIO_Init();
26
  MX_TIM1_Init();
27
  MX_TIM2_Init();
28
  MX_TIM3_Init();
29
30
  while (1)
31
  {} // wird akuell noch nicht benötigt
32
}
33
34
35
void SystemClock_Config(void)
36
{
37
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
38
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
39
40
  /** Configure the main internal regulator output voltage 
41
  */
42
  __HAL_RCC_PWR_CLK_ENABLE();
43
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
44
  /** Initializes the CPU, AHB and APB busses clocks 
45
  */
46
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
47
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
48
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
49
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
50
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
51
  RCC_OscInitStruct.PLL.PLLM = 8;
52
  RCC_OscInitStruct.PLL.PLLN = 180;
53
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
54
  RCC_OscInitStruct.PLL.PLLQ = 2;
55
  RCC_OscInitStruct.PLL.PLLR = 2;
56
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
57
  {
58
    Error_Handler();
59
  }
60
  /** Activate the Over-Drive mode 
61
  */
62
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
63
  {
64
    Error_Handler();
65
  }
66
  /** Initializes the CPU, AHB and APB busses clocks 
67
  */
68
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
69
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
70
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
71
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
72
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
73
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
74
75
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
76
  {
77
    Error_Handler();
78
  }
79
}
80
81
82
static void MX_TIM1_Init(void)
83
{
84
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
85
  TIM_SlaveConfigTypeDef sSlaveConfig = {0};
86
  TIM_MasterConfigTypeDef sMasterConfig = {0};
87
  TIM_OC_InitTypeDef sConfigOC = {0};
88
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
89
90
  htim1.Instance = TIM1;
91
  htim1.Init.Prescaler = 17999; // APB2 Clock / (Prescaler + 1) = 10kHz = 0.1ms
92
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
93
  htim1.Init.Period = 49999; // APB2 Clock / ((Prescaler + 1) * (Period +1)) = 0.2Hz = 5s
94
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
95
  htim1.Init.RepetitionCounter = 0;
96
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
97
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
98
  {
99
    Error_Handler();
100
  }
101
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
102
  if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
103
  {
104
    Error_Handler();
105
  }
106
  if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
107
  {
108
    Error_Handler();
109
  }
110
  if (HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) != HAL_OK)
111
  {
112
    Error_Handler();
113
  }
114
  sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
115
  sSlaveConfig.InputTrigger = TIM_TS_ITR1;
116
  if (HAL_TIM_SlaveConfigSynchro(&htim1, &sSlaveConfig) != HAL_OK)
117
  {
118
    Error_Handler();
119
  }
120
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
121
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
122
  if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
123
  {
124
    Error_Handler();
125
  }
126
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
127
  sConfigOC.Pulse = 40000; //CCR1 Wert: (Period + 1) - Pulse = 1s (Pulsdauer)
128
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
129
  sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
130
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
131
  sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
132
  sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
133
  if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
134
  {
135
    Error_Handler();
136
  }
137
  sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
138
  sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
139
  sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
140
  sBreakDeadTimeConfig.DeadTime = 0;
141
  sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
142
  sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
143
  sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
144
  if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
145
  {
146
    Error_Handler();
147
  }
148
  /* USER CODE BEGIN TIM1_Init 2 */
149
  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
150
  /* USER CODE END TIM1_Init 2 */
151
  HAL_TIM_MspPostInit(&htim1);
152
}
153
154
155
static void MX_TIM2_Init(void)
156
{
157
158
  /* USER CODE BEGIN TIM2_Init 0 */
159
160
  /* USER CODE END TIM2_Init 0 */
161
162
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
163
  TIM_MasterConfigTypeDef sMasterConfig = {0};
164
165
  /* USER CODE BEGIN TIM2_Init 1 */
166
167
  /* USER CODE END TIM2_Init 1 */
168
  htim2.Instance = TIM2;
169
  htim2.Init.Prescaler = 44999; // APB1 Clock / (Prescaler + 1) = 2kHz = 0.5ms
170
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
171
  htim2.Init.Period = 19999; // APB2 Clock / ((Prescaler + 1) * (Period +1)) = 0.1Hz = 10s
172
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
173
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
174
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
175
  {
176
    Error_Handler();
177
  }
178
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
179
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
180
  {
181
    Error_Handler();
182
  }
183
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
184
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
185
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
186
  {
187
    Error_Handler();
188
  }
189
  /* USER CODE BEGIN TIM2_Init 2 */
190
  TIM2->CR1 |= TIM_CR1_CEN; //aktiviere den Timer
191
  /* USER CODE END TIM2_Init 2 */
192
}
193
194
195
static void MX_GPIO_Init(void)
196
{
197
198
  /* GPIO Ports Clock Enable */
199
  __HAL_RCC_GPIOA_CLK_ENABLE();
200
201
}

von A. B. (Gast)


Lesenswert?

Einen "internen Quarz" gibt es nicht. Der HSI RC ist (wie der Name schon 
sagt) ein RC-Oszillator. Der ist halt nicht "quarzgenau". Wie genau, 
steht im Datenblatt ...

von Massi87 (Gast)


Lesenswert?

Danke! Hmm da muss ich zugeben, dass ich das mit dem Quarz falsch zuvor 
verstanden habe. Jetzt macht es mehr Sinn mit den internen RC Oszillator 
(HSI) - Danke dafür :)

Habe im Dokument DM00135183.pdf den Abschnitt "6.2.2 HSI Clock" 
gefunden.
Dort steht, dass er von Werk aus bei T_A=25°C mit einer Genauigkeit von 
1% kalibriert ist. Wenn ich das richtig lese, kann man die Frequenz 
selber noch trimmen. Das werde ich mal ausprobieren.

von Schorsch X. (bastelschorsch)


Lesenswert?

Mach doch einen externen Oszillator ran. Ein DSC6011 kostet bei 25ppm 
<0,80€

von Massi87 (Gast)


Lesenswert?

Vielen Dank für die Antwort Schorch! Ich werde mich zu dem DSC6011 mal 
schlau machen.

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.