Habe eine kleine (STM32CubeIDE) Anwendung auf einem STM32F103C8T6 und möchte auf pin PA15 ein PWM-Signal ausgeben. Es kommt aber leider nichts raus. Habe das Problem auf ein kleineres Projekt heruntergebrochen, was auch nicht funktioniert. Wo liegt der Fehler?
Zuerst mal die Standardfrage für alle Probleme mit einem STM: Sind alle Clocks aktiviert?... Ja?... Wirklich alle?... Ganz sicher ?...
Werner A. schrieb: > Zuerst mal die Standardfrage für alle Probleme mit einem STM: > Sind alle Clocks aktiviert?... > Ja?... > Wirklich alle?... > Ganz sicher ?... Wenn ich mir im .ioc File die Clockkonfiguration ansehe, so haben die Timer 72MHz Clock. Im Tim2 Setup ist Internal Clock enabled. Des weiteren verlasse ich mich auf die generierte MX_TIM2_Init().
1 | static void MX_TIM2_Init(void) |
2 | { |
3 | |
4 | /* USER CODE BEGIN TIM2_Init 0 */ |
5 | |
6 | /* USER CODE END TIM2_Init 0 */ |
7 | |
8 | TIM_ClockConfigTypeDef sClockSourceConfig = {0}; |
9 | TIM_MasterConfigTypeDef sMasterConfig = {0}; |
10 | TIM_OC_InitTypeDef sConfigOC = {0}; |
11 | |
12 | /* USER CODE BEGIN TIM2_Init 1 */ |
13 | |
14 | /* USER CODE END TIM2_Init 1 */ |
15 | htim2.Instance = TIM2; |
16 | htim2.Init.Prescaler = 0; |
17 | htim2.Init.CounterMode = TIM_COUNTERMODE_UP; |
18 | htim2.Init.Period = 1023; |
19 | htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; |
20 | htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; |
21 | if (HAL_TIM_Base_Init(&htim2) != HAL_OK) |
22 | { |
23 | Error_Handler(); |
24 | } |
25 | sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; |
26 | if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) |
27 | { |
28 | Error_Handler(); |
29 | } |
30 | if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) |
31 | { |
32 | Error_Handler(); |
33 | } |
34 | sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; |
35 | sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; |
36 | if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) |
37 | { |
38 | Error_Handler(); |
39 | } |
40 | sConfigOC.OCMode = TIM_OCMODE_PWM1; |
41 | sConfigOC.Pulse = 0; |
42 | sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; |
43 | sConfigOC.OCFastMode = TIM_OCFAST_ENABLE; |
44 | if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) |
45 | { |
46 | Error_Handler(); |
47 | } |
48 | /* USER CODE BEGIN TIM2_Init 2 */ |
49 | |
50 | /* USER CODE END TIM2_Init 2 */ |
51 | HAL_TIM_MspPostInit(&htim2); |
52 | |
53 | } |
PA15 muss "remapped" werden, weil dieser normalerweise für JTAG reserviert ist. Siehe auch: https://community.st.com/t5/stm32-mcu-products/what-am-i-supposed-to-do-to-use-pa14-pa15-in-stm32f103xx/td-p/400555 https://www.stm32duino.com/viewtopic.php?t=713 P.S. Ich mach das immer so:
1 | #if defined (STM32F103) // disable JTAG to get back PB3, PB4, PA13, PA14, PA15
|
2 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // turn on clock for the alternate function register |
3 | GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE); // disable the JTAG, enable the SWJ interface |
4 | #endif
|
:
Bearbeitet durch Moderator
Ich kann da nichts auffälliges entdecken, allerdings ist der Takt, den du erzeugst ca 70kHz, aber funktionieren sollte das. Du brauchst also schon nen Oszi oder LA um das sinnvoll auswerten zu können.
Frank M. schrieb: > PA15 muss "remapped" werden, weil dieser normalerweise für JTAG > reserviert ist. > Ach ja, jetzt fällt's mir wieder ein. Bin ich schon mal drauf reingefallen. Danke.
Christoph K. schrieb: > Frank M. schrieb: >> PA15 muss "remapped" werden, weil dieser normalerweise für JTAG >> reserviert ist. >> > Ach ja, jetzt fällt's mir wieder ein. Bin ich schon mal drauf > reingefallen. Danke. Musst du nicht! Das hat CubeMX bereits für dich erledigt.
Harry L. schrieb: > Ich kann da nichts auffälliges entdecken, allerdings ist der Takt, den > du erzeugst ca 70kHz, aber funktionieren sollte das. > > Du brauchst also schon nen Oszi oder LA um das sinnvoll auswerten zu > können. Das mit den 70KHz ist schon OK. Habe Pulseview. Oder sagen wir so, mit den 70 KHz ist so eine Geschichte :) Aber da müßte ich weiter ausholen. Vielleicht später (aber das fällt vielleicht unter die Rubrik: mein größter Bock).
Harry L. schrieb: > Und du solltest auch das Debugging einschalten! (siehe Screenshot!) Debugging funktioniert ja im CubeIDE momentan. Harry L.: es lag daran. Es stand "No Debug" drin. Ich habe "Serial Wire" eingetragen. Erster Gedanke war, daß htim2.Instance->CCR1 dem von mir verwendeten TIM2->CCR1 vorzuziehen sei. Mag bei HAL sicher auch intuitiver sein. Aber Ursache war letztlich die Debug Einstellung, die offenbar dann das Remapping besorgt. In dem größeren Projekt, in dem TIM2_CH1 output nicht funktionierte, konnte ich Serial Wire nicht einstellen, da ich einen Konflikt mit PA13 hatte, der als GPIO programmiert war. Wo sind PA13 und PA14 übrigens an der blue pill? Hab den Schaltplan gerade nicht zur Hand, aber vermute, die werden für die SWD Schnittstelle gebraucht. Denn gerade geht's Debuggen nicht mehr. Muß jetzt wohl doch wieder zu PA15 zurück. Das mit dem Remappen habe ich noch nicht hinbekommen. Ich will ja nicht alles remappen wie in der von @Frank M.(ukw) oben beschriebenen Methode. Die einzelnen Calls funktionierten nicht. Da fehlten Symbole/Macros.
:
Bearbeitet durch User
Beitrag #7465050 wurde vom Autor gelöscht.
Christoph K. schrieb: > Wo sind PA13 und PA14 übrigens an der blue pill? An der vierpoligen Stiftleiste http://stefanfrings.de/stm32/stm32f1.html#bluepill > vermute, die werden für die SWD Schnittstelle gebraucht Ja
So. Ruhe ist. Habe jetzt im Hauptprojekt die Timer noch mal umrangiert. Timer 1 jetzt für die PWM genommen. Weniger Konflikte. Um aber noch die Hintergrundgeschichte zu erzählen, falls es jemand interessiert: meine Aufgabenstellung für dieses kleine Bastelprojekt ist, ein 13 töniges Baßpedal (diesmal keine 25 Töne) mit einer Klangerzeugung zu versorgen. Habe mir eine Wavetable mit 256 Stützwerten berechnet, die ins Programm geladen. Die Frequenzen gehen von 32 bis 65 Hz. 256 Stützwerte ergibt eine Samplefrequenz von ca. 8,3 - 17,7 KHz. Die gibst Du dann auf den DAC und fertig - dachte ich. Vielleicht noch einen Tiefpass als Opamp hinter den Ausgang und fertig. DAC? Wo war der denn? Mußte lernen, daß der STM32F103C8T6 gar keinen DAC besitzt. Gut, das war der "Bock". Also was machen, um den Bastelaufbau zu retten? PWM mußte her. Problem ist aber, daß ich jetzt nicht mehr von 12Bit Auflösung ausgehen kann, sondern nur so etwa 10 bit. Daher die 70KHz PWM. Vielleicht hat jemand eine bessere Idee, aber im Moment schreibe ich (im Falle der höchsten Frequenz) alle 59 µs einen Wert ins Timer_CCR Register. Vielleicht doch noch einen kleinen seriellen DAC dranklemmen?
:
Bearbeitet durch User
Brauche noch mal Hilfe zu den Timerinterrupts. Habe jetzt die Lösung reduziert auf nur 2 Timer. Es war Quatsch, einen extra PWM-Timer zu nehmen. TIM3 macht jetzt den Tastatur Scan und TIM1 gibt die 256 Samples in Form von Pulsweiten aus. Ich dachte daran, die als one-shot mit jedem Interrupt aus einer Tabelle zu nehmen, die den Amplituden (Tastverhältnissen) entspricht. Zuvor hatte ich einen global Interrupt, den sich TIM3 und TIM2 teilten. TIM1 hat aber
1 | break |
2 | update |
3 | trigger and commutation |
4 | capture compare |
Interrupts. Ich vermute mal, daß "update" der Interrupt ist, der ausgelöst wird, wenn der Timer die Periode zu Ende gezählt hat. Ich hatte bei dem Global Interrupt eine Routine namens
1 | void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim) |
Ich weiß nicht mehr, ob ich die da selbst hingeschrieben habe ins main() oder ob die da automatisch eingesetzt wurde. Aber das sind ja Routinen, die man überschreibt. Jetzt sehe ich in stm32f1xx_it.c :
1 | void TIM1_UP_IRQHandler(void) |
2 | { |
3 | /* USER CODE BEGIN TIM1_UP_IRQn 0 */ |
4 | |
5 | /* USER CODE END TIM1_UP_IRQn 0 */ |
6 | HAL_TIM_IRQHandler(&htim1); |
7 | /* USER CODE BEGIN TIM1_UP_IRQn 1 */ |
8 | |
9 | /* USER CODE END TIM1_UP_IRQn 1 */ |
10 | } |
Meines Wissens soll man da hinein keinen User Code schreiben. Wie heißt die Routine, mit der ich den IR im main.c dann überschreibe (abfange)? EDIT: ich glaube, es hat sich erledigt. Ich kann offenbar den "PeriodElapsedCallback" nehmen. Da landet der TIM1 IR auch drin. Wollte eigentlich meinen Beitrag löschen, laß ihn aber stehen, falls es noch etwas Hilfreiches dazu zu bemerken gilt.
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.