www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik STM32 USART will nicht


Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

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

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: A. K. (prx)
Datum:

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

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

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

Autor: Benni Nori (benninori)
Datum:

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

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: STM32 Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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..

Autor: Benni Nori (benninori)
Datum:

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

Autor: STM32 Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Irgendwie komm ich nicht auf den Fehler... Hab mal meinen Sourcecode 
angehängt:
void usartSetup (void) {
GPIO_InitTypeDef GPIO_InitStructure;

  RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;              // enable clock for GPIOA
   
  GPIOA->CRH   |= (0x0BUL  << 4);                  // Tx (PA9) alt. out push-pull
  GPIOA->CRH   |= (0x04UL  << 8);                  // Rx (PA10) in floating
  RCC->APB2ENR |= RCC_APB2ENR_USART1EN;            // enable clock for USART1
  USART1->BRR  = 8000000L/9600L;                // set baudrate
  USART1->CR1 |= (USART_CR1_RE | USART_CR1_TE);  // RX, TX enable
  USART1->CR1 |= USART_CR1_UE;                    // USART enable

  /* GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);     */
  }  

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..

Autor: Philipp (Gast)
Datum:

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

Autor: Benni Nori (benninori)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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
GPIOA->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

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

Autor: thorstendb (Gast)
Datum:

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

... und AFIO nicht vergessen !

VG,
/th.

Autor: STM32 Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: STM32 Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: STM32 Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Arne (Gast)
Datum:

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

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nachtrag:

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

Autor: STM32 Neuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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-s...
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.

Autor: A. K. (prx)
Datum:

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

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
GPIOA->CRH   &= ~(0x0F << 4)
GPIOA->CRH   |= 0x04 << 8
GPIOA->CRH   &= ~(0x0F << 4)
GPIOA->CRH   |= 0x04 << 8

habe hoffentlich keinen neuen Fehler eingebaut.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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 & ~(...) | ...;

Autor: Arne (Gast)
Datum:

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

Hast natürlich recht ;)
GPIOA->CRH   = GPIOA->CRH & ~(0x0F << 4) | (0x0B << 4)
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.