Forum: Mikrocontroller und Digitale Elektronik STM32 DMA1CH5 soll TIM1 Updaten


von SImon (Gast)


Lesenswert?

Hallo miteineander,

ich habe eine Frage bezüglich des STM32F103.
Ich versuche Daten von der SPI an den TIM 1 zu senden. Dazu werden 
Dummybytes über den DMA1CH3 Kanal gesendet und über DMA1CH2 empfangen 
bzw. in den Speicher des STM kopiert. Dort werden sie verarbeitet und 
über DMA1CH5 an den TIM1 gesendet (in das CCR1 Register) Hier soll eine 
PWM erzeugt werden deren Dutycicle sich eben durch die im Speicher 
stehenden Daten ändern lässt (Ausioausgabe).
Wenn die Daten gleich im internen Speicher stehen (DMA1 CH2&3 aus) geht 
alles wunderbar (Testsinus im Speicher). Werden DMA1 CH2&3 aktiviert 
bekomme ich immer nur einen Teil meiner Daten durchsetzt von langen 
Nullvollgen am Ausgang des TIM1CH1. Schalte ich, nachdem DMA1Ch3 meinen 
internen Puffer gefüllt habe DMA1CH2&3 ab habe ich das selbe 
unbrauchbare Ergebnis. Als liegt es auch nicht an der Busauslastung. 
Weiß jemand wie das mit dem Updaten des TIM1 per DMA geht? Das 
Datenblatt und die Appnotes brauchten bisher keine Erleuchtung. Gerne 
sende ich hilfsbereiten Usern auch Teile des Codes. Bitte heltm mir ...

Erwähnenswert.

USART und USB sind auch aktiv wurde aber auch schon deaktiviert - ohne 
Erfolg.


Vielen Dank

Simon

Hier mal Teilausschnitte des Codes:

DMA1CH5
1
void StartDMATransferToSpeaker (uint16_t u16Stepwide)
2
{
3
  DMA_InitTypeDef DMA_InitStructure; 
4
5
  /* DMA1 Channel5 Config */
6
  DMA_DeInit(DMA1_Channel5);
7
8
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM1->CCR1);
9
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&(u16MasterOutBuffer[0]);
10
  DMA_InitStructure.DMA_BufferSize = u16Stepwide*2;
11
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
12
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
13
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
14
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
15
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
16
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
17
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
18
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
19
20
  DMA_Init(DMA1_Channel5, &DMA_InitStructure);
21
22
  //Erste starten wen der Erste Puffer voll ist sonst gibt es noch nichts zum übertragen
23
  while(DOUBLE_BUFFER_1_EMPTY() == FALSE){;}
24
25
  DMA_ITConfig(DMA1_Channel5, DMA_IT_TC, ENABLE);
26
  DMA_ITConfig(DMA1_Channel5, DMA_IT_HT, ENABLE);
27
28
  /* DMA1 Channel5 enable */
29
  //Hier wieder anschalten nur zum debuggen aus
30
  DMA_Cmd(DMA1_Channel5, ENABLE);    
31
}

TIM1:
1
void InitPWM(uint16_t u16Periode, uint16_t u16Prescaler, uint16_t u16_ClockDivision)
2
{
3
#ifdef DEBUG
4
  debug();
5
#endif
6
7
  /* System Clocks Configuration */
8
  RCC_Configuration_PWM();
9
10
  /* NVIC Configuration */
11
  NVIC_Configuration_PWM();
12
13
  /* GPIO Configuration */
14
  GPIO_Configuration_PWM();
15
16
  /* -----------------------------------------------------------------------
17
    TIM1 Configuration: generate 4 PWM signals with 4 different duty cycles:
18
    TIM1 CLK = 36 MHz, Prescaler = 0x0, TIM1 counter clock = 36 MHz
19
    TIM1 ARR Register = 999 => TIM1 Frequency = TIM1 counter clock/(ARR + 1)
20
    TIM1 Frequency = 36 KHz.
21
    TIM1 Channel1 duty cycle = (TIM1_CCR1/ TIM1_ARR)* 100 = 50%
22
    TIM1 Channel2 duty cycle = (TIM1_CCR2/ TIM1_ARR)* 100 = 37.5%
23
    TIM1 Channel3 duty cycle = (TIM1_CCR3/ TIM1_ARR)* 100 = 25%
24
    TIM1 Channel4 duty cycle = (TIM1_CCR4/ TIM1_ARR)* 100 = 12.5%
25
  ----------------------------------------------------------------------- */
26
27
  /* Time base configuration */
28
  TIM_TimeBaseStructure_PWM.TIM_Period = u16Periode;
29
  TIM_TimeBaseStructure_PWM.TIM_Prescaler = u16Prescaler;
30
  TIM_TimeBaseStructure_PWM.TIM_ClockDivision = u16_ClockDivision;
31
  TIM_TimeBaseStructure_PWM.TIM_CounterMode = TIM_CounterMode_Up;
32
33
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure_PWM);
34
35
  /* PWM1 Mode configuration: Channel1 */
36
  TIM_OCInitStructure_PWM.TIM_OCMode = TIM_OCMode_PWM1;
37
  TIM_OCInitStructure_PWM.TIM_OutputState = TIM_OutputState_Enable;
38
  TIM_OCInitStructure_PWM.TIM_OutputNState = TIM_OutputNState_Enable;
39
  //TIM_OCInitStructure_PWM.TIM_Pulse = 0x12;//CCR1_Val;
40
  TIM_OCInitStructure_PWM.TIM_OCPolarity = TIM_OCPolarity_High;
41
42
  TIM_OC1Init(TIM1, &TIM_OCInitStructure_PWM);
43
44
  TIM_CtrlPWMOutputs(TIM1, ENABLE);
45
  /* TIM1 Update DMA Request enable */
46
  TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);
47
48
  /* TIM1 counter enable */
49
  TIM_Cmd(TIM1, ENABLE);
50
}

Die Clocks sind an die Bridges Configuriert.

von (prx) A. K. (prx)


Lesenswert?

Irgendwie liest sich dein Posting so, als ob du erklärtermassen ein 
Problem mit DMA 2/3 hast und zwecks besserem Verständnis nur den Code 
zum DMA 5 postest.

Alerdings habe ich deine Beschreibung auch nicht wirklich verstanden. 
Also beispielsweise, ob die Daten falsch vom SPI im Speicher ankommen 
oder falsch im Timer ankommen oder zwischendrin mysteriös 
verschwinden...

von SImon (Gast)


Angehängte Dateien:

Lesenswert?

Ehrlich gesagt hab ich keine Ahnung wo das Problem liegt.
Im Bild ist folgendes zu sehen:

DMA1CH5 holt sich Daten aus dem Flash des STM32. Dort liegt wie zu sehen 
ein Sinus.

Diese werden an den Timer gesendet der daraus ein PWM generiert.
Hole ich nun die Daten über einen weiteren DMA Kanal (DMA1CH2) von der 
SPI1 ab (dazu muss ich über DMA1CH3 aber erst ein Dummybyte 
rausschreiben zwecks Clocksignal) kommen an meinem PWM Pin nur noch 40 
bis 80 PWM Zyklen gefolgt von einem langen Pause an. Dies wirdeholt sich 
bis das File (Die Daten im externen Flash) zu Ende sind.

Folgendes habe ich versucht:

DMA Kanal und Timer gewechselt zwecks Laust auf der Bridge. - Erfolglos 
-

Füllen meines internen Puffers mit DMA1 CH2/3 dann abschalten der Kanäle 
2/3
also quasi immer den selben Datensatz auslesen - Erfolglos -
   -> also dürfte es ja nicht an CH 2/3 liegen oder
Ich habe alle peripheren Gerätschaften bis auf DMA1CH5 deaktiviert 
(Clock aus EN raus usw. - das Signal bleibt zerhackt -

Noch mal zum Verständnis.



     DMA1CH3 Dummy raus                     DMA1CH5
SPI   <------------->      interner Puffer    ---->   TIM1UPDATE
     DMA1CH2 Daten rein


Daten von der SPI werden in zwei 256k langen Puffern gespeichert -je 
nachdem welcher gerade Frei ist -  diese werden verarbeitet (ich muss 
die wave Daten erst mal PWM tauglich machen da die wav Daten pos und neg 
sind. Außerdem muss ich die Quantisierung reduzieren, da der TIM1 für 
44,1Khz und 16Bit zu langsam ist. Die verarbeiteten Daten werden in eine 
512k breiten Puffer geschrieben der im Cicle mode von DMA1CH5 an den 
TIM1 gesendet wird. Getriggert wird hierbei auf das Update-Event des 
Timers.
Im 512k breiten Puffer kommen die Daten richtig an.
An die Außenwelt gelangt aber nur ein Teil.
Wie gesagt nachdem mein Ausgangspuffer ein mal richtig beschrieben wurde 
habe ich auch schon DMA1CH2/3 abgeschalten und diese Daten endlos 
ausgeben lassen - diese sind auch von Unterbrechungen durchsetzt.
Ich habe auch schon eine Methode mit nur einem Puffer versucht.
Da es sich hierbei um meine Bachelorarbeit handelt und ich noch 
lediglich 3 Wochen Zeit habe freue ich mich über jede Art von Hilfe.


Einen Dank schon mal an A.K. für die Hilfe.

Grüße

Simon

von (prx) A. K. (prx)


Lesenswert?

Bei externem Speicher gibt es ein klitzekleines Problem in Verbindung 
mit DMA. Siehe Errata Sheet unter 2.13: "Multimaster access on the FSMC 
memory map".

Kurz gesagt: DMA ist über FSMC effektiv nicht nutzbar.

von (prx) A. K. (prx)


Lesenswert?

PS: ... nur bedingt nutzbar. Darf eben immer nur einer drauf zugreifen. 
Ich fürche aber, das ist nicht genau das, was du dir unter double 
buffering mit DMA vorgestellt hattest.

Ich hoffe du findest einen Weg, mit dem internen Speicher auszukommen.

von SImon (Gast)


Lesenswert?

So wie ich das in den ERRATA Sheets verstanden habe kann ich per DMA 
nichts von einer Peripherieadresse an eine andere Peripherieadresse 
senden, da der Cortex Kern dann nicht Prüft ob diese zwei Geräte gerade 
die Bridge nutzen wenn er selbst darauf schreiben will.
Bekomme ich in solch einem Fall nicht immer einen BUS ERROR?
Der Tritt nämlich nicht auf?
Bedeutet das jetzt im Umkehrschluss, dass der Controller dem gleichen 
Bug unterworfen ist wenn man von der Peripherie ins interne Memory 
schreibt.
(Beitrag "STM32 DMA und externes RAM")
Gibt es da irgend eine Lösung?
Ich werde mal damit beginnen die Daten der SPI auf normelem Wege 
abzurufen.
Ich verstehe nicht warum die Sinustestfunktion dann korrekt ausgegeben 
wird.

Wie beschrieben kann ich den Puffer ein mal mit Hilfe der Kanäle 2/3 
Füllen lassen. Nach abschalten der Kanäle bleibt der Fehler jedoch 
erhalten?
Warum, es greift dann doch nichts mehr auf den Bus zu was sich da 
verheddern könnte oder?

Gibt es irgend welche Lösungsansätze bzw wie kann ich den per sw checken 
ob etwas andes auf den Bus zugreift?

Ich habe noch keine geschickte Möglichkeit gefunden die DMA bzw. den 
Verkehr auf den Bridges zu debuggen. Ist das irgendwie möglich. Oder 
anders herum, wie soll ich den Bridge-Zugriff überwachen wenn ich ihn 
nicht sehe?

Grüße und vielen Dank

Simon

von (prx) A. K. (prx)


Lesenswert?

SImon schrieb:

> So wie ich das in den ERRATA Sheets verstanden habe kann ich per DMA
> nichts von einer Peripherieadresse an eine andere Peripherieadresse
> senden, da der Cortex Kern dann nicht Prüft ob diese zwei Geräte gerade
> die Bridge nutzen wenn er selbst darauf schreiben will.

Peripherie zu Peripherie kann der DMA überhaupt nicht. Nur P<=>M und 
M<=>M. Der externe Speicher zählt hierbei als Speicher, nicht als 
Periphierie.

Ich lese das allerdings anders. Wenn mehrere Bus-Master (CPU/DMA1/DMA2) 
um den vom FSMC verwalteten Speicher konkurrieren, dann kann es es Mist 
geben. Bus Error oder Schrott. Wie oft, ob selten oder häufig, steht 
nicht da.

Der dargestellte Workaround heisst, dass die CPU nicht in dem externen 
Speicher rumfroschen sollte, wenn zwischendurch DMA stattfinden kann. 
Allerdings tritt der DMA-Controller vermutlich nicht mit sich selbst in 
Konkurrenz, jedenfalls nicht auf der kritischen Ebene, so dass mehrere 
aktive Kanäle auf dem gleichen DMA-Controller zulässig sein dürften. Nur 
darf eben nicht parallel dazu die CPU auf den externen Speicher 
zugreifen wollen.

> Ich verstehe nicht warum die Sinustestfunktion dann korrekt ausgegeben
> wird.

Es muss auch nicht bedeuten, dass dieser Bug wirklich dein Problem ist. 
Ausserdem sind uns die exakten internen Randbedingungen dieses Bugs 
nicht bekannt.

> Gibt es irgend welche Lösungsansätze bzw wie kann ich den per sw checken
> ob etwas andes auf den Bus zugreift?

DMA abschalten bevor die CPU auf den Speicher zugreift und danach wieder 
einschalten. Wenn das nicht geht (klingt auch recht schaurig), dann hast 
du ein ernstes Problem.

von (prx) A. K. (prx)


Lesenswert?

PS: Ist dir das offizielle STM32 Forum bekannt? Dort sitzt auch ST mit 
drin, und wohl auch Leute, die schon drüber gestolpert sind. Aber bitte 
erst suchen, dann fragen.
https://my.st.com/public/STe2ecommunities/mcu/Lists/ARM%20CortexM3%20STM32/AllItems.aspx

von Andre R. (ryan87)


Lesenswert?

Zu deinem Problem:
Guck mal im Reference Manual unter 10.3.7.
Ich glaube du verwendest Peripherie die auf dem gleichen Channels liegt 
(TIM1_CH1, SPI1_RX auf Ch2).

von (prx) A. K. (prx)


Lesenswert?

Er schreibt zwar per DMA in TIM1.CH1, nutzt aber als DMA-Trigger das 
Update Event, und das liegt auf DMA1.CH5.

Allerdings vemisse ich TIM_SelectCCDMA, denn laut Referenz ist CR2 per 
Default auf CC-DMA statt Update-DMA konfiguriert.

Wobei ich freilich den Eindruck habe, dass diese Funktion in V3.3.0 
genau das Gegenteil dessen tut was sie suggeriert. Name/Beschriebung 
suggeriert, dass mit ENABLE auf CC-DMA und mit DISABLE auf Update-DMA 
konfiguriert wird. Wenn die Register-Referenz korrekt ist, dann passiert 
aber genau das Gegenteil.

Generell: Die FwLib ist eine zusätzliche potentielle Fehlerquelle. Bei 
Problemen immer kontrollieren, ob in den Peripherieregistern wirklich 
das drinsteht, was man dort entsprechen der der Referenz vorzufinden 
hofft.

von Simon (Gast)


Angehängte Dateien:

Lesenswert?

Zwischenfrage:

Ich nutze die SPI mit der von ST bereitgestellten Lib.
Dazu befindet sich auf meinem Board ein M25P64 (8MBit Flash)
Greife ich hierbei auf den FSMC Controller zu?

Ich habe mir das mit den Channels angesehen.
Ich habe drei unterschiedlich Kanäle der DMA1

CH2   SPI1_RX  leitet SPI Daten an einen internen Puffer
CH3   SPI1_TX  Clockt ein Dummybyte raus um den SPI Takt zu generieren
CH5   TIM1_UP leitet die Daten aus dem internen Puffer an den Timer1

Events:

CH2 TIM1_RX
CH3 ?? gute Frage
CH5 TIM1_UP


TIM_SelectCCDMA(TIM1, ENABLE); wurde in die TIM1 init implementiert - 
ohne Änderung der Funktion - was macht diese Abschnitt?
Ich hab schon den Kommentar in der Lib nicht ganz verstanden.

Zu den Bildern:

tek0002: Unterbrochenes PWM Signal nach aktivieren der DMA1CH2/3 um neue 
Daten von der SPI in den Puffer zu laden.
tek0004: Ausgabe zweier Sinusfunktionen, je eine Periode aus den 
internen Puffer. Dies Funktioniert.

Hat jemand eine Idee was diese aussetzer verursachen könnte?
Ich habe die gesammte Peripherie nach auftreten diese Fehlers 
deaktiviert - der Fehler bleibt -

Code für CH2/3:
1
void StartDMATransferToBuffer (uint16_t u16Titel)
2
{
3
  /**
4
  Test wie man Daten über die DMA Schnittstelle vom Mem an die SPI sendet
5
  DMA SPI1 TX -> DMA1 CH3
6
  kann nur 16 Bit sein wenn SPI auch 16 bit empfangen kann !!!
7
  hoffentlich!
8
  **/
9
  DMA_InitTypeDef DMA_InitStructure;
10
  uint8_t rw_workbyte[] = { 0x55 };
11
  uint32_t u32Laufvar;
12
13
  float tCPU     = 1.0/TIMFREQUENZ;
14
  float tSampling   = 1.0/get_SampleRate( u16Titel );
15
  
16
  fQuantisationTime = (uint16_t)(tSampling/tCPU);
17
18
  fSkalierungsfaktorXAchse = fQuantisationTime/(pow(2,get_BitsPerSample(u16Titel)));
19
20
  for(u32Laufvar = 0 ; u32Laufvar < (BUFFER_WIDE*2) ; u32Laufvar++) 
21
  {
22
    u16MasterOutBuffer[u32Laufvar] = fQuantisationTime/2;
23
  }
24
25
  //Alle Puffer gelten als leer
26
  u8DoubleBufferCommunicationControl = 0;
27
28
    DMA_DeInit(DMA1_Channel3);
29
30
    RCC_Configuration_DMA();
31
    RCC_Configuration_PWM();
32
    NVIC_Configuration_DMA();
33
    
34
  u16BytesToTransferPerDMACycle = BUFFER_WIDE * get_BlockAlign(u16Titel);
35
36
  //Neue Adresse im Flash da immer ein Byte übersprungen wurde
37
  u32JumpAdressDuringBufferChanging = get_AudioStartAdress(u16Titel);
38
    PrepareFlashToRead(u32JumpAdressDuringBufferChanging);
39
40
  DMA_DeInit(DMA1_Channel3);
41
42
  DMA_Cmd(DMA1_Channel2, DISABLE);
43
  DMA_Cmd(DMA1_Channel3, DISABLE);
44
45
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR);
46
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&rw_workbyte[0];
47
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
48
49
  DMA_InitStructure.DMA_BufferSize = u16BytesToTransferPerDMACycle;//(uint32_t)(get_AudioEndAdress(u16Titel)-get_AudioStartAdress(u16Titel)); //<-wie viel
50
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
51
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
52
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA_Mode_Circular;
53
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
54
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
55
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
56
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;  
57
58
  
59
  //TX Chanel um Clock zu erzwingen  
60
  DMA_Init(DMA1_Channel3, &DMA_InitStructure);
61
  //---------------------------------9---------------------
62
63
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
64
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR);
65
  
66
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&(u16DoubleBuffer1[0]);
67
  
68
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//DMA_MemoryInc_Enable;
69
   
70
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
71
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//DMA_MemoryDataSize_HalfWord;  
72
  //DMA_InitStructure.DMA_BufferSize = (uint32_t)0x4; //<-wie viel
73
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
74
  //RX Chanel um zu empfangen
75
  DMA_Init(DMA1_Channel2, &DMA_InitStructure);
76
  //PufferWahl();
77
78
  DMA_ITConfig(DMA1_Channel2, DMA_IT_TC, ENABLE);
79
  //------------------------------------------------------
80
  SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, ENABLE);
81
    
82
  DMA_Cmd(DMA1_Channel2, ENABLE);
83
  DMA_Cmd(DMA1_Channel3, ENABLE);
84
85
  InitPWM((uint16_t)fQuantisationTime,0,0);
86
87
  StartDMATransferToSpeaker(BUFFER_WIDE);
88
  
89
   //Stimmt das? nachprüfen
90
//  while (DMA_GetFlagStatus(DMA1_FLAG_TC2) == RESET) { ; }
91
92
//  SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Rx | SPI_I2S_DMAReq_Tx, DISABLE);
93
//  DMA_Cmd(DMA1_Channel2, DISABLE);
94
//  DMA_Cmd(DMA1_Channel3, DISABLE);
95
}

In den Anhang habe ich mein gesammtes Projekt gepackt.

Die betreffenden Passagen befinden sich in:
  DMA_user.c
  Timer_PWM.c

Da ich z.Z. sehr viel im Code versucht habe gibt es einige
#ifdef´s und auskommentierte Passagen.

Die Ausgabe des Testsinus funktioniert, die Ausgabe eines wav Files 
nicht.

Vielen Dank im Voraus
Denkt daran ich bin kein pro.
Den Cortex programiere ich das erste mal

Simon

von (prx) A. K. (prx)


Lesenswert?

Simon schrieb:

> TIM_SelectCCDMA(TIM1, ENABLE); wurde in die TIM1 init implementiert -
> ohne Änderung der Funktion - was macht diese Abschnitt?
> Ich hab schon den Kommentar in der Lib nicht ganz verstanden.

Wirst nicht darum herum kommen, dir die Steuerregister des Timers direkt 
anzusehen, sowohl die Referenz als auch den tatsächlichen Zustand nach 
der Initialisierung, insbesondere das DMA-Steuerbit im CR2. Und den 
Quellcode der Funktion(en). Die Doku der Fwlib allein ist nicht 
ausreichend. Nochmal: Nicht auf Fehlerfreiheit der FWlib vertrauen!

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.