STM32 USART will nicht

OP #1473089
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.
OP #1473117
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.
OP #1473139
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?
#1473145
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.
Gast #1549071
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..
Gast #1549764
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.
Gast #1550514
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?
Gast #1551824
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.
Gast #1552525
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?
Gast #1553017
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!
Gast #1553039
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,...?
Gast #1556541
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?
Gast #1558933
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.
Gast #1559078
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.
#1559092
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 & ~(...) | ...;
Gast #1559220
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren