Forum: Mikrocontroller und Digitale Elektronik STM32 USART will nicht


von Benni N. (benninori)


Lesenswert?

Hi,

ich sitze hier vor meinem kleinen Board mit einem STM32F105 drauf. Ich 
will jetzt mal meine Peripherie testen und hänge an der USART2. Ich 
initialisiere die Schnittstelle wie in reference manual beschrieben. Das 
klappt auch alles soweit - nur bekommen ich irgendwie nichts ins 
Datenregister. Ich habs händig probiert und mit der DMA, aber keines von 
beiden funktioniert. Das Register steht dauerhaft auf 0x00000000 und 
dadurch kommt natürlich nichts raus.

Hier mein Code zur USART2:

void Usart2()
{
  pUSART2->CR1 =  0x00002000;      //Enable USART2: 1 Start bit, 8 bits
  pUSART2->CR2 =  0x00002000;      //2 stop bits
  pUSART2->CR3 =  0x00000180;      //RTS + DMA enabled
  pUSART2->SR  =  0x00000000;
  Dma1Init();
  pUSART2->BRR =  0x0000001A;      //Clock/4=Baud rate
  pUSART2->CR1 |= 0x00000009;      //Transmission enable

  //pUSART2->DR  = 0x55;

  while (!(pUSART2->SR & 0x00000040))
  {
  }

}

Und die DMA1 initialisier ich folgendermaßen:

void Dma1Init()
{
  pDMA1->CPAR1  = 0x4004404;              //Zieladresse Peripherie
  pDMA1->CMAR1  = (uint32_t) &pSpeicher;  //Zieladresse Speicher
  pDMA1->CNDTR1 = 0x000000FF;             //8 Daten-Bits
  pDMA1->CCR1   = 0x00001010;             //Priorität = mittel; vom 
Speicher lesen
  pDMA1->CCR1  |= 0x00000001;             //enable
}



Hat da jemand eine idee was ich hier falsch mache?
Wäre super wenn mir jemand weiterhelfen könnte. Ich häng grad echt total 
in der Luft.

von (prx) A. K. (prx)


Lesenswert?

Vorneweg die Takte der verwendeten Peripheriemodule einschalten, also 
USART, DMA, GPIO (=> RCC).

von Benni N. (benninori)


Lesenswert?

mache ich:

void ClockInit()
{
  //Clock control register
  pRCC->CR |= 0x00010000;       //HSE on

  // Wait for HSE
  while (!(pRCC->CR & 0x00020000))
  {
  }

  //Clock configuration register
  //HSE clock, PLLx4
  pRCC->CFGR |= 0x00090000;    //PLL on
  pRCC->CR   |= 0x01000000;

  //Wait for PLL
  while (!(pRCC->CR & 0x02000000))
  {
  }

  pRCC->CFGR  |= 0x06000002;

  //Access to RTC and Backup registers enabled
  //pPWR->CR      |= 0x01010100;

  //Peripheral colcks enable registers
  pRCC->AHBENR  |= 0x00000054;   //SRAM-,CRC-, FLITF-clock enable
  pRCC->APB2ENR |= 0x0000281C;   //Timer-, I/O-ports-, AFIO-clock enable
  pRCC->APB1ENR |= 0x1A82003F;   //Timer-, Power interface-,backup 
interface-,USART2-,USB-,CAN-clock enable
}

Zumindest der GPIOA funktioniert auch einwandfrei. das habe ich 
getestet.

von (prx) A. K. (prx)


Lesenswert?

Geht du davon aus, dass du (oder ein Debugger) aus dem Datenregister der 
USART das wieder auslesen kannst, was du vorher reingeschrieben hast? 
Dann hast du die Arbeitsweise einer U(S)ART und von dessen Datenregister 
egal welchen Controllers nicht verstanden.

von Benni N. (benninori)


Lesenswert?

Das mag sein, aber wenn ich das Programm Schritt für Schritt debugge und 
etwas in das Datenregister schreibe, dann muss ich das doch bevor ich 
den den nächsten Schritt ausführe dort sehen können. Oder bin ich da 
jetzt falsch gewickelt? Ich schreibe das doch parallel rein und es wird 
dann seriell an die Schnittstelle weitergegeben. Aslo muss ich es doch 
kurzfristig dort sehen können, oder nicht?

von (prx) A. K. (prx)


Lesenswert?

Benjamin Norenburg schrieb:

> Oder bin ich da jetzt falsch gewickelt?

Ja.

Das Datenregister gibt es zweimal, eins für Empfang (lesender Zugriff) 
und eins für Senden (schreibender Zugriff), aber beide an der gleichen 
Adresse. Und zu allem Überfluss verschwindet der Inhalt des ohnehin 
nicht auslesbaren Datenregisters fürs Senden sofort im Schieberegister 
(wenn frei).

In der Referenz findet man ein Prinzipschaltbild der USART (USART block 
diagram), in dem das illustriert wird.

von Benni N. (benninori)


Lesenswert?

Aso, dass die Daten weitergegeben werden war mir klar. Ich habe nur 
gedacht, dass ich sie im ersten Moment noch sehen müsste bevor der 
nächste schritt ausgeführt wird. Ok, dann ist das nicht mein Problem, 
danke schonmal. Da bleibt die Frage: Was mach ich dann falsch?

von (prx) A. K. (prx)


Lesenswert?

Deine einzige bisher gelieferte Fehlerbeschreibung war, dass im DR 
hinterher nichts steht. Dieser Fall wäre geklärt.

von Benni N. (benninori)


Lesenswert?

Ja, das war meine vermutung, dass es daran hängt. Du hast mir ja klar 
gemacht, dass dem nicht so ist. Das Problem aller Probleme ist, dass 
nicht rauskommt. Kein einziges Bit. Ich Schau nochmal nach ob ich den 
Takt richtig initialisiert habe, aber ich denke schon.

von Benni N. (benninori)


Lesenswert?

Sieht gut aus, der Takt müsste da sein. Und ich gehe bei der 
Initialisierung Schritt für Schritt wie im reference manual beschrieben 
vor. Keine Ahnung warum das nicht geht. Ich steh grad voll auf dem 
Schlauch.

von (prx) A. K. (prx)


Lesenswert?

Und wie werden die Pins initialisiert? Tip dazu: Hexsalat wie oben werde 
ich nicht zur Kenntnis nehmen, dafür gibt es Namen.

von Benni N. (benninori)


Lesenswert?

Die pins werden als alternate funktion output Push-pull mit maximal 50 
MHz initialisiert. Habe ich gerade auch nochmal überprüft.

von Benni N. (benninori)


Lesenswert?

Moment, Komando zurück. jetzt sind Sie alle so konfiguriert. Habe gerade 
beim TX was falsch gemacht. jetzt klappts.

Danke für deine Hilfe. War ein dämlicher Fehler an dem ich ohne deinen 
Schupser in die richtige Richtung warscheinlich noch einen Tag 
rumgemacht hätte.

von STM32 Neuling (Gast)


Lesenswert?

Hi,

weißt du was du da damals beim TX falsch gemacht hast? Ich fürchte, ich 
steh grad vor dem selben Problem - komm aber irgendwie nicht drauf was 
mir fehlt..

von Benni N. (benninori)


Lesenswert?

ich glaube ich habe den pin falsch konfiguriert gehabt. überprüf nochmal 
genau jedes einzele bit im entsprechenden register.

von STM32 Neuling (Gast)


Lesenswert?

Irgendwie komm ich nicht auf den Fehler... Hab mal meinen Sourcecode 
angehängt:
1
void usartSetup (void) {
2
GPIO_InitTypeDef GPIO_InitStructure;
3
4
  RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;              // enable clock for GPIOA
5
   
6
  GPIOA->CRH   |= (0x0BUL  << 4);                  // Tx (PA9) alt. out push-pull
7
  GPIOA->CRH   |= (0x04UL  << 8);                  // Rx (PA10) in floating
8
  RCC->APB2ENR |= RCC_APB2ENR_USART1EN;            // enable clock for USART1
9
  USART1->BRR  = 8000000L/9600L;                // set baudrate
10
  USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE);  // RX, TX enable
11
  USART1->CR1 |= USART_CR1_UE;                    // USART enable
12
13
  /* GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
14
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
15
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
16
  GPIO_Init(GPIOA, &GPIO_InitStructure);     */
17
  }

Das komische ist, dass es funktioniert, wenn ich den Kommentar am Ende 
des Unterprogramms entferne...
Die Frage ist nur, warum funktionierts dann? Eigentlich konfiguriere ich 
PA.9 ja oben schon als AF-Push-Pull..

von Philipp (Gast)


Lesenswert?

Der Sende-Interrupt wird angestoßen? Wie erfolgt die Datenübergabe - als 
ISR?

von Benni N. (benninori)


Lesenswert?

aso, so weit mit ich garnicht gegangen. ich habe garnicht mit interupts 
gearbeitet. mein entstand war, dass ich was über die serielle 
schnittstelle empfange kurz zwischenspeicher und gleich wieder zurück 
schick. es ging nur ums testen der hardware.

von Arne (Gast)


Lesenswert?

Philipp schrieb:
> Der Sende-Interrupt wird angestoßen?

Er hat Interruptbetrieb gar nicht konfiguriert, sonst müsste TXEIE in 
USART1_CR1 gesetzt sein. Ergo reicht gepollter Versand.

@STM32 Neuling:
Du müsstest nach
1
GPIOA->CRH   |= (0x0BUL  << 4);                  // Tx (PA9) alt. out push-pull
2
  GPIOA->CRH   |= (0x04UL  << 8);                  // Rx (PA10) in floating
noch IOPAEN in RCC->APB2ENR anknipsen.
Könntest Du evtl. so machen:
1
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;            // enable clock for USART1

Da ich meine eigene Lib benutze, weiß ich nicht, ob RCC_APB2ENR_IOPAEN 
in der ST-Lib die richtige Konstante ist.

von thorstendb (Gast)


Lesenswert?

> Vorneweg die Takte der verwendeten Peripheriemodule einschalten, also
> USART, DMA, GPIO (=> RCC).

... und AFIO nicht vergessen !

VG,
/th.

von STM32 Neuling (Gast)


Lesenswert?

Arne schrieb:
> @STM32 Neuling:
> Du müsstest nachGPIOA->CRH   |= (0x0BUL  << 4);                  // Tx (PA9) 
alt. out push-pull
>   GPIOA->CRH   |= (0x04UL  << 8);                  // Rx (PA10) in floating
> noch IOPAEN in RCC->APB2ENR anknipsen.
> Könntest Du evtl. so machen:RCC->APB2ENR |= RCC_APB2ENR_USART1EN | 
RCC_APB2ENR_IOPAEN;            // enable clock for USART1

IOPAEN hab ich angeknipst - siehe 2.Zeile des Unterprogramms.

@thorstendb: In der STM32 FAQ hab ich zum Thema AFIO-clock folgendes 
gefunden:

"If the application is mapping USART1 on the default port A, then there 
is no need to enable the AFIO clock. If the application is remapping the 
USART1 pins from port A to port B, then the AFIO clock should be 
enabled."

So wie ich das sehe, brauche ich den AFIO-clock nicht, da ich eh den 
Standard USART1 Port A verwende?

von STM32 Neuling (Gast)


Lesenswert?

Hat noch jemand nen Tipp?
Langsam bin ich echt am Verzweifeln...

Ich find das Reference Manual von ST ein bisschen schwach - es werden 
zwar viele Sachen angeschnitten, aber ne ausführliche Erklärung findet 
man dann selten - zumindest ist das mein Eindruck.

von Arne (Gast)


Lesenswert?

Naja, es gibt schlimmere Manuals, als das RM0008 von ST ;) Zum Beispiel 
die zum Coldfire :-O
Ansonsten könnte es sein, dass die Reihenfolge der ganzen Enablebits 
entscheidend ist. Ich kann mich da düster entsinnen, hab meine UART Lib 
vor ca. 1 Jahr geschrieben. Sonst schau mal im Debugger nach, ob durch 
den auskommentierten Code ein Enablebit wieder angeknipst wird.
Denn mit dem auskommentierten bereich am Ende funktioniert es ja?!?

BTW: Du willst erstmal nur senden? Dein terminalprg. am anderen Ende 
hast Du richtig konfiguriert? Die Baudrate im STM hast Du von den Werten 
des USART1_BRR Mantissa/Fraction (wie in kap 24.3.4 beschrieben) 
zurückgerechnet?

von STM32 Neuling (Gast)


Lesenswert?

Genau, im Moment moecht ich nur mal Daten zum PC uebertragen. Wenn ich 
den Kommentar am Ende entferne, dann funktionierts. Die Einstellungen im 
Terminalprogramm passen. Wenn ich daheim bin, werd ich mir mal die 
Enable-Bits anschauen. Danke fuer den Tipp!

von Arne (Gast)


Lesenswert?

Da ich ja nicht die ST-Lib nutze, habe ich meine Initialisierung hier 
mal in 'Pseudocode' abgetippt:
1
RCC_APB2RSTR_USART1RST = 1  // reset des UART Moduls
2
RCC_APB2RSTR_USART1RST = 0
3
RCC_APB2ENR_USART1EN = 1  // enable UART1 im RCC
4
RCC_APB2ENR_IOPAEN = 1    // enable GPIO-A
5
GPIOA->CRH   |= 0x0B << 4        // Portbits für UART definieren
6
GPIOA->CRH   |= 0x04 << 8
7
USART1_BRR = ...      // Baudrate (bei 72MHz steht bei mir das BRR auf 0x0271 für 115200bd)
8
USART1_CR1 = 0 // 8 databits, parity off
9
USART1_CR2 = 0
10
USART1_CR1 |= USART_CR1_UE          // UART ein
11
USART1_CR1 |= USART_CR1_TE | USART_CR1_TE  // Transm. & Receiv. ein

Zum Senden dann:
Solange auf dem USART_SR_TXE pollen, bis es 1 ist, dann einen Wert in 
das USART1_DR poken.

Hoffe Du kannst was mit den Bitbezeichnungen anfangen.

Welche Entwicklungsumgebung nutzt Du? Keil, IAR, GCC,...?

von Arne (Gast)


Lesenswert?

nachtrag:

Muss natürlich...
1
USART1_CR1 |= USART_CR1_TE | USART_CR1_RE  // Transm. & Receiv. ein
heißen.

von STM32 Neuling (Gast)


Lesenswert?

Hi Arne,

erstmal danke für den Sourcecode Auszug. Ich hab mir den Code von dir 
jetzt mal mit Hilfe des Reference Manuals durchgeschaut und ein paar 
Kleinigkeiten übernommen. Wenn ich das Programm nun debugge (ich nutze 
Keil uVision3 als IDE), dann bekomme ich im "Serial Window" innerhalb 
der IDE die gesendeten Daten angezeigt. Beende ich nun den Debugmodus 
und connecte mit einem Terminalprogramm, dann bekomm ich komischerweise 
keine Daten...(die Baudrate, Start -und Stopbit, sowie Parity sind 
korrekt eingestellt)

Was mach ich falsch?

von Arne (Gast)


Lesenswert?

Die IDE zeigt Dir über JTAG an, was rausgegangen sein sollte?
Für Analyse der RS232 PC-seitig setze ich das hier ein:
http://www.serial-port-monitor.com/Download/free-serial-port-monitor.exe
Der klemmt sich zwischen Anwendung und WindowsTreiber. Ab und an hängt 
er bei mir die komplette Kiste weg, aber ist halt so :(
Ansonsten würde ich mal das Demoboard unter die Lupe nehmen: geht der 
UART 1 auch auf Pegelwandler? Nicht, daß der TTL ausgibt. Müssen da 
Lötbrücken (um-)gesetzt werden? Ich kenn Dein Board halt nicht - ich 
selbst nehme ein IAR-Kit mit IAR IDE.

von (prx) A. K. (prx)


Lesenswert?

CRL und CRH sind mit 0x44444444 vorbelegt, nicht mit 0. Daher wird
   CRH |= ...
nicht zum gewünschten Ergebnis führen.

von Arne (Gast)


Lesenswert?

Da hat A.K. vollkommen recht!

Ich hab das bei mir in einer Funktion gekapselt, in der ich dann die 
betreffenden 4 Bits ausnulle, bevor ich eine neue Bitmaske reinschreibe.
Hab ich im Pseudocode unterschlagen. Mea culpa ;)

Somit muss es heissen:
1
GPIOA->CRH   &= ~(0x0F << 4)
2
GPIOA->CRH   |= 0x04 << 8
3
GPIOA->CRH   &= ~(0x0F << 4)
4
GPIOA->CRH   |= 0x04 << 8

habe hoffentlich keinen neuen Fehler eingebaut.

von (prx) A. K. (prx)


Lesenswert?

Arne schrieb:

> habe hoffentlich keinen neuen Fehler eingebaut.

Doch.

Erstens stimmen die Shiftcounts nicht, 4/4/8/8 statt 4/8/4/8 wäre 
richtig.

Zweitens kriegst du einen Zwischenzustand von 0 (analog input), der bei 
rein digitalen Pins möglicherweise nicht definiert ist. Besser:
  CRH = CRH & ~(...) | ...;

von Arne (Gast)


Lesenswert?

@A.K.:
da ich weiß, daß Du hier Korrektur liest, muß ich nicht alles beachten 
;)

Hast natürlich recht ;)
1
GPIOA->CRH   = GPIOA->CRH & ~(0x0F << 4) | (0x0B << 4)
2
GPIOA->CRH   = GPIOA->CRH & ~(0x0F << 8) | (0x04 << 8)

Das 'Ausnullen' und neu Setzen der vier Bits mache ich in meiner Lib 
über eine lokale Variable und schreibe die dann komplett als uint32_t am 
Ende zurück.

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.