Ich versuche mich an der Ansteuerung eines FU-ICs mittels Stm32f103C8. Anbei die main.c der ersten lauffähigen Version. Frage zur Deadtime: Diese braucht es beim Umschalten von positiver auf negative Halbwelle, damit es keinen Kurzschluss gibt. Bei meiner Sinustabelle ist der erste Wert der positiven Halbphase Null. Also von 48 Werten sind nur 23 größer alws null. Dadurch kann es zwichen den um 24 Steps versetzten Halbphasen niemals zu einem Kurzschluss kommen. Kann man die Totzeitberechnung dann einfach weglassen?
grundschüler schrieb: > Kann man die Totzeitberechnung dann einfach weglassen? Warum macht du es dir so schwer? Timer 1 und Timer 8 im STM32F103 sind Advanced Timer und haben jeweils 3 PWM Kanäle mit komplementären Ausgängen und einem Deadband Unit pro PWM. Ein einziger Timer erzeugt ohne Klimmzüge alle 3 Phasen mit einstellbarer Totzeit. Je nach Gehäuse hat evtl. nur ein Timer der beiden alle Anschlüsse herasugeführt, aber das findest du anhand des Datenblattes schnell raus.
Matthias S. schrieb: > Warum macht du es dir so schwer? Gerade einfach hast du es dir mit dem AVR ja auch nicht gemacht. Am einfachsten wäre es, deinen code zu nehmen und keine Fragen mehr zu stellen. Ich habe da ein Verständnisproblem von dem ich nicht weiß, ob es an mir (wahrscheinlich) oder ob es an deinem code (unwahrscheinlich) liegt. Ich will halt wissen, wie es funktioniert. Der Stm-Tim1 ist sehr komplex. Es gibt fertigen code - https://arm-stm.blogspot.de/2015/01/3-phase-sinusoidal-pulse-width.html - den ich noch nicht ausprobiert habe. Mit tim2, tim3, + tim4 geht es halt sehr einfach weil genug Rechenleistung da ist und weil dise tims einfach zu handeln sind. Also mache ich es mir eher so einfach wie möglich.
grundschüler schrieb: > Gerade einfach hast du es dir mit dem AVR ja auch nicht gemacht. So einfach wie möglich. Der kleine AVR8 hat nun mal keinen Timer mit 3 PWM Kanälen, sondern nur 3 Timer mit je 1 PWM Kanal. Deswegen die Klimmzüge beim 3 Phasen Generator. Die STM32 und XMega hingegen haben fertige Blöcke für den Betrieb von Motoren, die man nur benutzen muss. grundschüler schrieb: > Also > mache ich es mir eher so einfach wie möglich. Nö. Mit einem Advanced Timer brauchst du nur eine ISR, um alles zu laden. Mein BLDC Antrieb mit Sinusmodulation auf dem STM32 ist deutlich unkomplizierter als der gleiche Antrieb lt. AVR447. Vllt. portiere ich den 3-Phasen Generator mal aufs VL Discovery - die liegen hier im Moment sowieso nur rum.
@grundschüler Hier ein Ansatz von St, den ich nur mal vorsichtshalber gezogen habe. http://www.st.com/en/embedded-software/stsw-stm32100.html Die beschriebene Software habe ich in einen chinesischen Forum gefunden, aber noch nicht evaluiert. Sind zwei *.exe. Die würden nach genauer Untersuchung verlangen. Deswegen kein Link.
Nachtrag. Man bekommt auch Software von ST. Da muß man erst Java-Script zulassen und diverse Lizenzen unterschreiben und Namen angeben.
Hier mal der Versuch, alles in den advanced timer zu packen /Ukmschaltung nur eine Phase. Ich brauche ja 6 um jeweils 60° versetzte Halbphasen. Tim1 hat aber nur 3*2+1 channel. Ganz zufrieden bin ich mit dem Ergebnis noch nicht. Nach dem Umschalten scheint der abgeschaltete Channel nachzuschwingen.
1 | void TIM1_CC_IRQHandler(void) |
2 | {
|
3 | period= speedmult*255/speeddiv; |
4 | pulse_vh= speedmult*sinetable[step]/speeddiv; |
5 | pulse_uh= speedmult*sinetable[step+8]/speeddiv; |
6 | pulse_wh= speedmult*sinetable[step+16]/speeddiv; |
7 | TIM1->ARR = period; |
8 | TIM1->CCR1 = pulse_uh; |
9 | TIM1->CCR2 = pulse_vh; |
10 | TIM1->CCR3 = pulse_wh; |
11 | |
12 | switch (step) |
13 | {
|
14 | case (0)://change ch1n to ch1 |
15 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; |
16 | TIM_OCInitStructure.TIM_OutputNState= TIM_OutputNState_Disable; |
17 | TIM_OC1Init(TIM1, &TIM_OCInitStructure); |
18 | ;
|
19 | break; |
20 | |
21 | case (48)://change ch1 to ch1n |
22 | TIM1->CCER&=~(1<<0);//CC1E löschen |
23 | TIM1->CCER|=(1<<2);//CC1NE setzen |
24 | /**/
|
25 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputNState_Disable; |
26 | TIM_OCInitStructure.TIM_OutputNState= TIM_OutputState_Enable; |
27 | TIM_OC1Init(TIM1, &TIM_OCInitStructure); |
28 | ;
|
29 | break; |
30 | |
31 | default:
|
32 | ;
|
33 | break; |
34 | }
|
35 | |
36 | |
37 | zl_tim1++; |
38 | |
39 | step++; |
40 | if(step>(47)){ |
41 | step=0; |
42 | led1_tog; |
43 | speed_ctrl++; |
44 | }
|
45 | |
46 | TIM_ClearFlag(TIM1,TIM_FLAG_CC1); |
47 | }
|
noreply@noreply.com schrieb: > http://www.st.com/en/embedded-software/stsw-stm32100.html Hab ich installiert, c-code wär mir aber lieber.
Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut. Code für den Timer ist hier: https://gitlab.com/higaski/stm32f405_vfd/blob/master/Src/Periph/pwm.c Deadtime hab ich damals keine gebraucht, da die in Hardware realisiert war. Jeder brauchbare Treiber bietet aber mittlerweile solche Optionen an.
Vincent H. schrieb: > Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut. Sieht allerdings mehr nach einem BLDC Antrieb für Motoren mit Hallsensoren aus. Der STM32F1xx hat eine Deadtime Unit:
1 | void UpdateDTI(u8 deadTime){ |
2 | TIM_BDTRInitTypeDef TIM_BDTRInitStructure; |
3 | |
4 | TIM_BDTRStructInit(&TIM_BDTRInitStructure); |
5 | /* Automatic Output enable, Break, dead time and lock configuration*/
|
6 | TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; |
7 | TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; |
8 | TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; |
9 | TIM_BDTRInitStructure.TIM_DeadTime = deadTime; |
10 | TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; |
11 | TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; |
12 | TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; |
13 | TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); |
14 | }
|
:
Bearbeitet durch User
Als Hilfe poste ich dir mal die Init von Timer 1 für 3 PWM Kanäle:
1 | /* init the main PWM Timer 1 with 3 channels and dead time insertion
|
2 | *
|
3 | */
|
4 | void TimerInit(u8 deadTime) { |
5 | |
6 | RCC_APB2PeriphClockCmd(TIM1_CLK, ENABLE); |
7 | /* Initialize basic structures to default */
|
8 | TIM_TimeBaseStructInit(&TIM_TimeBaseStructure); |
9 | TIM_OCStructInit(&TIM_OCInitStructure); |
10 | /* Time base configuration */
|
11 | |
12 | TIM_TimeBaseStructure.TIM_Prescaler = 256; |
13 | TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; |
14 | TIM_TimeBaseStructure.TIM_Period = 0x00FF; |
15 | TIM_TimeBaseStructure.TIM_ClockDivision = 0; |
16 | TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; |
17 | |
18 | TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); |
19 | TIM_UpdateRequestConfig(TIM1, TIM_UpdateSource_Global); |
20 | TIM_UpdateDisableConfig(TIM1,DISABLE); |
21 | |
22 | /* Channel 1, 2 and 3 Configuration in PWM mode */
|
23 | TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; |
24 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; |
25 | TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; |
26 | TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; |
27 | TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; |
28 | TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; |
29 | TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set; |
30 | |
31 | TIM_OCInitStructure.TIM_Pulse = 0x0000; |
32 | TIM_OC1Init(TIM1, &TIM_OCInitStructure); |
33 | TIM_OC2Init(TIM1, &TIM_OCInitStructure); |
34 | TIM_OC3Init(TIM1, &TIM_OCInitStructure); |
35 | |
36 | UpdateDTI(deadTime); |
37 | }
|
Und so initialisiere ich die 6 PWM Ausgänge:
1 | // from setup.h
|
2 | #define TIM1_CLK RCC_APB2Periph_TIM1
|
3 | // Channel 1
|
4 | #define PHASE_UL_GPIO_PORT GPIOA
|
5 | #define PHASE_UL_GPIO_PIN GPIO_Pin_8
|
6 | // Channel 2
|
7 | #define PHASE_VL_GPIO_PORT GPIOA
|
8 | #define PHASE_VL_GPIO_PIN GPIO_Pin_9
|
9 | // Channel 3
|
10 | #define PHASE_WL_GPIO_PORT GPIOA
|
11 | #define PHASE_WL_GPIO_PIN GPIO_Pin_10
|
12 | // Group configuration
|
13 | #define LOWSIDE_PINS PHASE_UL_GPIO_PIN | PHASE_VL_GPIO_PIN | PHASE_WL_GPIO_PIN
|
14 | // Complementary N Outputs
|
15 | #define PHASE_UH_GPIO_PORT GPIOB
|
16 | #define PHASE_UH_GPIO_PIN GPIO_Pin_13
|
17 | //
|
18 | #define PHASE_VH_GPIO_PORT GPIOB
|
19 | #define PHASE_VH_GPIO_PIN GPIO_Pin_14
|
20 | //
|
21 | #define PHASE_WH_GPIO_PORT GPIOB
|
22 | #define PHASE_WH_GPIO_PIN GPIO_Pin_15
|
23 | // Group configuration
|
24 | #define HIGHSIDE_PINS PHASE_UH_GPIO_PIN | PHASE_VH_GPIO_PIN | PHASE_WH_GPIO_PIN
|
25 | // define Motor Port properties for the two needed ports
|
26 | #define PHASE_UH_GPIO_CLK RCC_APB2Periph_GPIOA
|
27 | #define PHASE_UL_GPIO_CLK RCC_APB2Periph_GPIOB
|
28 | // end from setup.h
|
29 | //*****************************************************
|
30 | // in main.c
|
31 | void PortInit(void) |
32 | {
|
33 | GPIO_InitTypeDef GPIO_InitStructure; |
34 | /* Motor Port setup for all six phases */
|
35 | // Port A
|
36 | RCC_APB2PeriphClockCmd(PHASE_UH_GPIO_CLK, ENABLE); |
37 | // Port B
|
38 | RCC_APB2PeriphClockCmd(PHASE_UL_GPIO_CLK, ENABLE); |
39 | // Highsides are on Port A
|
40 | GPIO_InitStructure.GPIO_Pin = HIGHSIDE_PINS ; |
41 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; |
42 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; |
43 | GPIO_Init(PHASE_UH_GPIO_PORT, &GPIO_InitStructure); |
44 | // Preset to Off
|
45 | GPIO_ResetBits(PHASE_UH_GPIO_PORT, HIGHSIDE_PINS); |
46 | // LowSides are on Port B
|
47 | GPIO_InitStructure.GPIO_Pin = LOWSIDE_PINS ; |
48 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; |
49 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; |
50 | GPIO_Init(PHASE_UL_GPIO_PORT, &GPIO_InitStructure); |
51 | // Preset to Off
|
52 | GPIO_ResetBits(PHASE_UL_GPIO_PORT,LOWSIDE_PINS) ; |
53 | }
|
Und hier Timer 1 Interrupt Config:
1 | void EnableInterrupts(void){ |
2 | NVIC_InitTypeDef NVIC_InitStructure; |
3 | // Timer interrupt
|
4 | /* TIM Interrupts enable */
|
5 | TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE); |
6 | /* TIM1 counter enable */
|
7 | /* Enable and set TIM1 Interrupt to the lowest priority */
|
8 | /* Enable the TIM1 global Interrupt */
|
9 | NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM16_IRQn; |
10 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; |
11 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0; |
12 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; |
13 | NVIC_Init(&NVIC_InitStructure); |
14 | TIM_Cmd(TIM1, ENABLE); |
15 | /* Main Output Enable */
|
16 | //TIM_CtrlPWMOutputs(TIM1, ENABLE);
|
17 | TIM_ClearITPendingBit(TIM1,TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3); |
18 | }
|
Der Timer 1 Interrupt ist bei mir motorspezifisch, aber das Prinzip ist das gleiche wie beim AVR Frequenzumrichter. Also inco addieren, Zeiger in die Tabelle berechnen, Werte aus der Tabelle skalieren und dann auf alle 3 OC Register schicken.
:
Bearbeitet durch User
Matthias S. schrieb: > Vincent H. schrieb: >> Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut. > > Sieht allerdings mehr nach einem BLDC Antrieb für Motoren mit > Hallsensoren aus. > Der STM32F1xx hat eine Deadtime Unit: >
1 | >
|
2 | > void UpdateDTI(u8 deadTime){ |
3 | > TIM_BDTRInitTypeDef TIM_BDTRInitStructure; |
4 | >
|
5 | > TIM_BDTRStructInit(&TIM_BDTRInitStructure); |
6 | > /* Automatic Output enable, Break, dead time and lock configuration*/ |
7 | > TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; |
8 | > TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; |
9 | > TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF; |
10 | > TIM_BDTRInitStructure.TIM_DeadTime = deadTime; |
11 | > TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable; |
12 | > TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; |
13 | > TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; |
14 | > TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure); |
15 | > } |
16 | >
|
Woran soll man das sehen? Ich seh keine Initialisierung für Hallsensoren? Drehgeber hab ich damals glaub ich benutzt, aber die sind woanders initialisiert. Hab mir meinen Code grad nochmal angesehn und die Deadtime ist sogar drin... auch wenn meine Treiber die damals wie gesagt inkludiert hatten.
Vincent H. schrieb: > Woran soll man das sehen? Du erwähnst die Messung des Motorstroms im Programm und durchläufst die für BLDC typischen 6 Sektoren.
Matthias S. schrieb: > Vincent H. schrieb: >> Woran soll man das sehen? > > Du erwähnst die Messung des Motorstroms im Programm und durchläufst die > für BLDC typischen 6 Sektoren. Achso, ja der Eindruck täuscht. Die "6 Sektoren" entstehen durch die Schaltzeiten der Brücke und bilden die möglichen Zustände aller 6 Schalter ab. Je nachdem welche Schalter gerade offen bzw. zu sind, wird ein anderer Phasenstrom gemessen.
Vielen Dank für die Beiträge. Vincent H. schrieb: > Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut. Wenn ichs richtig verstehe, werden die Halbbrücken blockweise - also nicht mit einem trägerfrequenzmodulierten Sinus angesteuert? Matthias S. schrieb: > Als Hilfe poste ich dir mal die Init von Timer 1 für 3 PWM Kanäle: Ich würde ja deinen avr-code komplett auf arm umsetzen, wenn ich ihn verstehen würde. Nach meinem Konzept wird die positive Halbbrücke jeder Phase sinusförmig mit einem Ausgang angesteuert während der korrespondierende Ausgang der negativen Halbbrücke aus ist und keinen Puls generiert. Ich brauche jeweils 6 unterschiedliche Werte aus der Sinetable. Nach deinem code
1 | InsertDeadband(tempU, &compareHigh, &compareLow); |
2 | OCR0A = compareHigh; |
3 | OCR0B = compareLow; |
scheinen beide Halbbrücken gleichzeitig invertiert angesteuert zu werden? Du brauchst nur 3Werte aus der Sinetable. Ist mein Konzept grundsätzlich falsch?
grundschüler schrieb: > Nach deinem code > InsertDeadband(tempU, &compareHigh, &compareLow); > OCR0A = compareHigh; > OCR0B = compareLow; > scheinen beide Halbbrücken gleichzeitig invertiert angesteuert zu > werden? Du brauchst nur 3Werte aus der Sinetable. Richtig 3 Werte, 'InsertDeadband()' berechnet die Werte für compareHigh und compareLow aus tempU. Das gleiche passiert gleich darauf auch für tempV und tempW. Beim STM32 kannst du darauf verzichten, wenn du das DTI benutzt - das Dings fügt von alleine eine Totzeit zwischen den low und High Ausgängen ein. Du musst auch leglich CCR1 schreiben und nicht wie beim AVR OC0A und OC0B. Die Kernroutine im Timer1 Interrupt sieht dann so aus:
1 | uint8_t tempU, tempV, tempW; |
2 | {
|
3 | uint8_t sineTablePtr ; |
4 | AdjustSineTableIndex(sineTableIncrement); |
5 | // Add sine table offset to pointer. Must be multiplied by 3, since one
|
6 | // value for each phase is stored in the table.
|
7 | sineTablePtr =(uint8_t)(sineTableIndex >> 8) * 3; |
8 | tempU = sineTable[sineTablePtr++]; |
9 | if (GetDesiredDirection() == DIRECTION_REVERSE) |
10 | {
|
11 | tempV = sineTable[sineTablePtr++]; |
12 | tempW = sineTable[sineTablePtr]; |
13 | }
|
14 | else
|
15 | {
|
16 | tempW = sineTable[sineTablePtr++]; |
17 | tempV = sineTable[sineTablePtr]; |
18 | }
|
19 | }
|
20 | /* Scale sine modulation values to the current amplitude
|
21 | * and poke them into the Compare registers
|
22 | */
|
23 | TIM_SetCompare1(TIM1,(uint16_t)(amplitude * tempU) >> 8); |
24 | TIM_SetCompare2(TIM1,(uint16_t)(amplitude * tempV) >> 8); |
25 | TIM_SetCompare3(TIM1,(uint16_t)(amplitude * tempW) >> 8); |
:
Bearbeitet durch User
grundschüler schrieb: > Also ist mein 6-werte-Ansatz grundsätzlich falsch? Er ist unnötig redundant. Sowohl die AVR Software als auch der STM32 brauchen nur 3 Werte. Der AVR macht daraus mit InsertDeadband() zwei Werte (für High und Low) und beim STM32 machts das DTI und die gewählte Polarität der PWM Ausgänge aus einem Wert pro Phase.
Matthias S. schrieb:
Dein code läuft ja bei mir auf einem m328. Ich werd mir das mal mit
einem la anschauen, was da an Werten konkret rauskommt. Der
6-werte-Modus hat halt den Vorteil, dass er den Sinus direkt nachbildet
und unkompliziert zu programmieren ist.
grundschüler schrieb: > Vielen Dank für die Beiträge. > > Vincent H. schrieb: >> Ich hab mal einen FU mit einem STM32F405 und dessen TIM1 gebaut. > > Wenn ichs richtig verstehe, werden die Halbbrücken blockweise - also > nicht mit einem trägerfrequenzmodulierten Sinus angesteuert? Nein, der Code verwendet nur keine Sinus-Tabelle, erzeugt aber genauso einen Drehvektor. In Zeile 316 steht der Sinus sogar als Funktionsaufruf drin. Ein STM32F405 hat mehr als genug Saft um die nötigen Sinus-Werte "on demand" zu berechnen. (sogar in double...) Ob das jetzt sinnvoll ist oder nicht, sei mal dahingestellt.
grundschüler schrieb: > Der > 6-werte-Modus hat halt den Vorteil, dass er den Sinus direkt nachbildet > und unkompliziert zu programmieren ist. Ich sehe das nicht so als Vorteil. Denn du bist dann fix auf Totzeit etc. festgelegt. Vincent H. schrieb: > Ein STM32F405 hat mehr als genug Saft um die nötigen Sinus-Werte > "on demand" zu berechnen. Sicher richtig, vor allem, wenn man die Hardware FPU benutzt. Wir spielen hier in der Liga STM32F1nn, wo man das leider nicht so hat und meist auch nur mit 25MHz taktet.
Matthias S. schrieb: > Wir > spielen hier in der Liga STM32F1nn Das stm32f426-disco kostet unter 30€. Angesichts des Aufwands - den wir ohnehin alle betreiben - sollten 30€ für die bestmögliche mcu kein Hindernis sein. Ich hatte mir für das avr-Projekt extra einen 328pb - mit zusätzlichen Timern - zugelegt. Vincent H. schrieb: > In Zeile 316 steht der Sinus sogar als Funktionsaufruf > drin. Ich werde deinen code auch mal ausprobieren.
grundschüler schrieb: > Das stm32f426-disco kostet unter 30€ So etwas gibt es nicht. Es gibt ein F407 Discovery und ein F429 Dicovery Board. http://www.st.com/en/evaluation-tools/stm32-mcu-discovery-kits.html?querycriteria=productId=LN1848 Ausserdem ist es hilfreich, sich vor der Beschaffung mal eine Pinbelegung des Boards anzuschauen, denn die meisten Ports sind auf den Disco Boards belegt: http://mikrocontroller.bplaced.net/wordpress/?page_id=46 http://mikrocontroller.bplaced.net/wordpress/?page_id=2848 Ich habe mit beiden Boards und dem VL-Discovery mit STM32F100 gearbeitet. Für einen Motorantrieb oder FU ist das VL-Disco gut geeignet, weil es billig ist und alle Ports verfügbar sind. http://www.st.com/en/evaluation-tools/stm32vldiscovery.html
:
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.