Forum: Mikrocontroller und Digitale Elektronik STM32 Programming Reference


von Bert S. (kautschuck)


Lesenswert?

Hi,

Ich bin gerade am erlernen von ARM auf einem STM32F3Discovery Board.
Die GPIO Manipulation habe ich nun verstanden und möchte mich nun dem 
USART widmen. Ich nutze folgende programming reference:

http://www.st.com/content/ccc/resource/technical/document/reference_manual/59/b9/ba/7f/11/af/43/d5/CD00171190.pdf/files/CD00171190.pdf/jcr:content/translations/en.CD00171190.pdf

Nun sind hier aber die Register nicht so beschrieben, wie ich mir das 
von AVR gewohnt bin, man sieht also nirgends, wo man die Flags setzen 
sollte.
Wenn ich z.B das Register USART_CR1 für die Wortlänge der Transmission 
beschrieben möchte, finde ich nirgends etwas, welche Bits ich 
manipulieren soll? Gibt es irgendwie noch eine detailliertere 
programming reference?

Grüsse Hans

von ... (Gast)


Lesenswert?

Was genau an Kapitel 27.6  reicht nicht aus, dachdem du den 
dazugehörigen Text [Kapitel 27] wenigstens 1x gelesen hast?

von Bert S. (kautschuck)


Lesenswert?

Ok, das hatte ich nicht gelesen, danke. Der Einstieg ist schon ziemlich 
schwieriger als in AVR.

von Bert S. (kautschuck)


Lesenswert?

Wenn ich nun z.B die Wortlänge auf 8bit setzen möchte, muss ich ja M1 
und M0 in  USART_CR1 zu 0 setzen.

In AVR konnte ich ja direkt USART_CR1 &= ...
In ARM aber muss ich nun USART_CR1_M abändern, doch wie setze ich diese 
beiden bits? Die grösse sollte doch 2bit sein?

Ich habe gesehen, es werden oft structs verwendet, um die GPIO-Pins oder 
auch USART zu initialisieren:

USART_InitTypeDef USART_InitStructure;

Welche Bibliotheken müssen da eingebunden werden? Gibt es da eine 
programming reference für all diese Funktionen?

Grüsse Hans

: Bearbeitet durch User
von ... (Gast)


Lesenswert?

Die Peripherien sind in Strukturen beschrieben und nicht so 
hingeklatscht wie im AVR.

das sieht dann so aus:

RCC->AHB1RSTR oder wie auch immer so ein Register heißen mag. Und da 
kannst du dann auch deine gewohnten Bitoperationen drauf ausführen.

RCC ist dann ein Pointer auf die Struktur.. schreib das einfach mal hin 
und lass von der IDE nach der Definition suchen. Dann wirst du sehen, 
dass es etwas ähnliches auch für die USART gibt.. musst nur mal ein 
bischen schauen.

von ... (Gast)


Lesenswert?

Ich hab grade mal geguckt.
Ich habe nur einen Header für einen STM32L hier.. da sind die USART so 
definiert:
1
#define USART2              ((USART_TypeDef *) USART2_BASE)
2
#define USART3              ((USART_TypeDef *) USART3_BASE)
3
#define UART4               ((USART_TypeDef *) UART4_BASE)
4
#define UART5               ((USART_TypeDef *) UART5_BASE)



Du schreibst im Code also
1
USART2->CR1 |= ....   ;
usw...

von PittyJ (Gast)


Lesenswert?

Ich habe die letzten Wochen mit den ARMs von NXP herumgespielt.
Dort ist das viel einfacher. Die haben eine API mit dabei, teilweise 
sogar im ROM. Die serielle Schnittstelle war mit 10 Zeilen erledigt. 
Keine Bitfriemelei dabei, ich habe dafür kein Register direkt gesetzt.
Nur so als Hinweis, wie es auch besser gehen kann. Weil der STM doch oft 
so hoch gelobt wird...

von Horst (Gast)


Lesenswert?

PittyJ schrieb:
> Keine Bitfriemelei dabei, ich habe dafür kein Register direkt gesetzt.

Dafür gibt es bei ST die SPL und die HAL. Aber man sollte es zumindest 
einmal richtig gemacht haben um zu wissen wie es geht, das erleichtert 
die Fehlersuche ungemein.

von W.S. (Gast)


Lesenswert?

Bert S. schrieb:
> Nun sind hier aber die Register nicht so beschrieben, wie ich mir das
> von AVR gewohnt bin, man sieht also nirgends, wo man die Flags setzen
> sollte.

Es gibt mehrere Arten, die Hardware-Register für die Verwendung in C zu 
definieren. Eine Art ist, ein struct zu definieren und dann einen 
Pointer drauf zu definieren. Eine andere Art ist, jedes einzelne 
Register zu definieren. Mir liegt die zweite Version mehr, weil es in 
der ersten wegen diverser Leerstellen immer nötig ist, Fülleinträge in 
structs einzuführen und die gerade gültigen Alignment-Konventionen 
einzuhalten, sonst geht das schief.

Die zweite Version sieht etwa so aus:
1
#define USART1  0x40013800 
2
3
// Universal synchronous asynchronous receiver transmitter (USART)
4
#define USART1_CR1   (*((volatile dword *) (USART1 + 0x0)))
5
#define USART1_CR2   (*((volatile dword *) (USART1 + 0x4)))
6
#define USART1_CR3   (*((volatile dword *) (USART1 + 0x8)))
7
#define USART1_BRR   (*((volatile dword *) (USART1 + 0xC)))
8
#define USART1_GTPR  (*((volatile dword *) (USART1 + 0x10)))
9
#define USART1_RTOR  (*((volatile dword *) (USART1 + 0x14)))
10
#define USART1_RQR   (*((volatile dword *) (USART1 + 0x18)))
11
#define USART1_ISR   (*((volatile dword *) (USART1 + 0x1C)))
12
#define USART1_ICR   (*((volatile dword *) (USART1 + 0x20)))
13
#define USART1_RDR   (*((volatile dword *) (USART1 + 0x24)))
14
#define USART1_TDR   (*((volatile dword *) (USART1 + 0x28)))

Damit kannst du dann deinen USART so einrichten, wie du es haben willst. 
Etwa so in der Art:
1
dword InitSerial1 (long baudrate)    /* liefert tatsächliche Baudrate zurück */
2
{ long Baudteiler;
3
4
  Baudteiler = F_Platform / baudrate; /* SysClk Frequenz */
5
  U1Buf.InWP =                      /* alle Puffer rücksetzen */
6
  U1Buf.InRP =
7
  U1Buf.OutWP =
8
  U1Buf.OutRP = 0;
9
  /* Int 37 */
10
  NVIC_ICPR1 = (1<<(U1Int-32));     /* pending löschen */
11
  NVIC_ISER1 = (1<<(U1Int-32));     /* Int erlauben */
12
  USART1_CR1 = 0;                   /* erstmal aus */
13
  USART1_CR2 = (3<<12);             /* 1.5 Stopbits */
14
  USART1_CR3 = 0;
15
  USART1_GTPR = 0;
16
  USART1_BRR = Baudteiler & 0xFFFF; /* Baudratenteiler */
17
  USART1_CR1 = (1<<7)  |            /* TX Int enable */
18
               (1<<5)  |            /* RX Int enable */
19
         (1<<3)  |            /* TX enable     */
20
               (1<<2)  |            /* RX enable     */
21
               (1<<0);              /* UART enable   */
22
  return F_Platform / Baudteiler;
23
}

Ist dir jetzt klar, wie man Hardware-Register definiert und wie man sie 
dann auch verwendet?

W.S.

von Bert S. (kautschuck)


Lesenswert?

Super, danke euch, jetzt glaube ich ist mir alles klar.

Grüsse Hans

von Bert S. (kautschuck)


Lesenswert?

Wenn ich die Variante mit dem Struct verwende, kommt die Fehlermeldung:

"use of undeclared identifier USART_initTypeDef"

Muss ich noch eine Library einbinden, damit ich das verwenden kann?
Ich verwenden Keil uVision5. "Driver_USART.h" habe ich bereits 
eingebunden.

Ich habe gesehen, das es noch das STM32CubeMX gibt, lässt sich damit 
leichter alle Treiber einbinden?

: Bearbeitet durch User
von Bert S. (kautschuck)


Lesenswert?

Ich begreife nicht ganz, wie ich mit STM32CubeMX ein Keil Projekt öffnen 
kann. Ich müsste ja in uVision 5 folgendes Framework haben:

http://www.keil.com/pack/doc/STM32Cube/General/html/cubemx_proj.html

Dies ist bei mir nicht vorhanden und ich kann es mit dem package 
installer in Keil auch nicht installieren. Ich verwende die Keil MDK521A
und die neuste STM32CubeMX Version.

Grüsse Hans

von Bert S. (kautschuck)


Angehängte Dateien:

Lesenswert?

Ich habe hier nun mal meine Einstellungen im Anhang. Wie komme ich zur
stm32F30x_gpio.h library etc? Irgendwie müsste ich doch im package 
installer noch ARM:CMSIS Driver auswählen können, ich habe aber nur 
validation zur Verfügung?

: Bearbeitet durch User
von Dr. Sommer (Gast)


Lesenswert?

Bert S. schrieb:
> Ich bin gerade am erlernen von ARM auf einem STM32F3Discovery Board.
> Die GPIO Manipulation habe ich nun verstanden und möchte mich nun dem
> USART widmen. Ich nutze folgende programming reference:
Wie man am Titel erkennt, nennt sich dieses Dokument "Reference Manual", 
nicht "programming reference". Außerdem ist das für die STM32F1 
Controller, und daher für dein STM32F3 Discovery doch etwas ungeeignet.

von Bert S. (kautschuck)


Lesenswert?

Ich finde einfach keine Library, damit ich USART_initTypeDef, 
GPIO_initTypeDef etc. nutzen kann. Dies sollte doch standardmäßig 
vorhanden sein in der Keil MDK 5?

von Cyblord -. (cyblord)


Lesenswert?

Bert S. schrieb:
> Ich finde einfach keine Library, damit ich USART_initTypeDef,
> GPIO_initTypeDef etc. nutzen kann.

Die nennt sich "Standard Peripheral Library" und kann von der STM32 
Seite heruntergeladen werden.

> Dies sollte doch standardmäßig
> vorhanden sein in der Keil MDK 5?

Keine Ahnung, aber ich würde mal davon ausgehen.

von Bert S. (kautschuck)


Angehängte Dateien:

Lesenswert?

Von dieser Seite habe ich nun das STSW-STM32118.zip runtergeladen:

http://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-eval-tools/stm32-mcu-eval-tools/stm32-mcu-discovery-kits/stm32f3discovery.html

Darin ist ein Ordner STM32F30x_StdPeriph_Driver wo ich die 
stm32f30x_gpio.c und stm32f30x_gpio.h finde.

Nun könnte man ja denken, dass man die einfach dem Projekt hinzufügen 
kann und gut ist, aber aus irgend einem Grund findet er die files nicht.

von Lothar (Gast)


Lesenswert?

Bert S. schrieb:
> Der Einstieg ist schon ziemlich schwieriger als in AVR

Hättest nur statt STM32 einen LPC ARM zu nehmen brauchen, da ist das 
Manual übersichtlich und mit Beispielen zum Abtippen.

von W.S. (Gast)


Lesenswert?

Bert S. schrieb:
> Ich finde einfach keine Library, damit ich USART_initTypeDef,
> GPIO_initTypeDef etc. nutzen kann. Dies sollte doch standardmäßig
> vorhanden sein in der Keil MDK 5?

Sowas ist standardmäßig NIRGENDWO vorhanden. Allenfalls hat irgendwer 
(z.B. die von ST) sowas mal geschrieben und in deren herunterladbaren 
Krempel verpackt.

Aber WOZU willst du unbedingt darauf herumreiten? Schau in das 
Referenz-Manual, dort findest du die erschöpfende Beschreibung der 
Peripherie und deren Hardware-Register nebst den dort üblichen Namen der 
Register.

Das und nur das ist es eigentlich, was von allen anderen verstanden 
werden kann, denn das Referenzmanual ist eben das, was der Name sagt: 
die Referenz.

Sämtlicher Hoppelpoppel, der woanders und mit anderen Bezeichnern 
beschrieben oder definiert ist, ist eben keinerlei Referenz.

Wie man Hardwareregister in C definieren kann und sie anschließend 
benutzen kann, habe ich dir bereits geschrieben. Also solltest du damit 
keinerlei Probleme haben. Aber den Blick in die Doku des Chips kann dir 
keiner abnehmen, das mußt du schon selber tun.

Es ist nicht auszuschließen, daß ich eine aus dem RefMan der STM32F30x 
generierte Headerdatei hier schon mal jemand anderem gepostet habe. Aber 
ich suche jetzt nicht danach. Lerne du lieber mit den Originalen 
umzugehen. Das ist auf lange Sicht das Beste, was du für dich selbst tun 
kannst.

W.S.

von Nop (Gast)


Lesenswert?

Tja.. das ST-Zeugs erzeugt halt bei Anfängern die Illusion, sie könnten 
sich das Durcharbeiten des Reference Manuals ersparen. Eigentlich sollte 
man mit der Einstellung lieber gleich zum Arduino gehen, der ist genau 
dafür gemacht.

Sobald aber auch nur irgendwas hakt, beispielsweise weil die ST-Libs 
buggy sind, muß man nicht nur das RefMan trotzdem durcharbeiten, sondern 
auch noch die Software von ST verstehen. Diese ist wiederum keine 
Abstraction Layer, sondern eher eine Obfuscation Layer.

Und dann kommen solche Fragen dabei raus.

von Christopher J. (christopher_j23)


Lesenswert?

Bevor du dir den HOL oder die StdPeriphlib von ST antust schau lieber 
mal in den CMSIS-Header. Das ist in deinem Fall stm32f303xc.h . Damit 
geht dann nämlich folgendes:

... schrieb:
> RCC->AHB1RSTR oder wie auch immer so ein Register heißen mag. Und da
> kannst du dann auch deine gewohnten Bitoperationen drauf ausführen.
>
> RCC ist dann ein Pointer auf die Struktur.. schreib das einfach mal hin
> und lass von der IDE nach der Definition suchen. Dann wirst du sehen,
> dass es etwas ähnliches auch für die USART gibt.. musst nur mal ein
> bischen schauen.

Im Klartext steht dort in Zeile 647
1
typedef struct
2
{
3
  __IO uint32_t CR1;    /*!< USART Control register 1,                 Address offset: 0x00 */
4
  __IO uint32_t CR2;    /*!< USART Control register 2,                 Address offset: 0x04 */
5
  __IO uint32_t CR3;    /*!< USART Control register 3,                 Address offset: 0x08 */
6
  __IO uint32_t BRR;    /*!< USART Baud rate register,                 Address offset: 0x0C */
7
  __IO uint32_t GTPR;   /*!< USART Guard time and prescaler register,  Address offset: 0x10 */
8
  __IO uint32_t RTOR;   /*!< USART Receiver Time Out register,         Address offset: 0x14 */
9
  __IO uint32_t RQR;    /*!< USART Request register,                   Address offset: 0x18 */
10
  __IO uint32_t ISR;    /*!< USART Interrupt and status register,      Address offset: 0x1C */
11
  __IO uint32_t ICR;    /*!< USART Interrupt flag Clear register,      Address offset: 0x20 */
12
  __IO uint16_t RDR;    /*!< USART Receive Data register,              Address offset: 0x24 */
13
  uint16_t  RESERVED1;  /*!< Reserved, 0x26                                                 */
14
  __IO uint16_t TDR;    /*!< USART Transmit Data register,             Address offset: 0x28 */
15
  uint16_t  RESERVED2;  /*!< Reserved, 0x2A                                                 */
16
} USART_TypeDef;

Dann in Zeile 836:
1
#define USART2              ((USART_TypeDef *) USART2_BASE)

Damit kannst du dann konkret etwas wie
1
USART2->CR1 = bliblablub;

machen.

Was du sinnvollerweise statt bliblablub ins Register schreibst findest 
du ab Zeile 12131 (!) in besagtem Header, sprich die ganzen 
Bitdefinitionen für die USART-Register.

Dazu dann noch das richtige RefMan von hier:
http://www.st.com/content/ccc/resource/technical/document/reference_manual/4a/19/6e/18/9d/92/43/32/DM00043574.pdf/files/DM00043574.pdf/jcr:content/translations/en.DM00043574.pdf

und schon kann das was werden.

von Bert S. (kautschuck)


Lesenswert?

So, ich habe versucht das ganze mal ohne Libraries zu lösen, jedoch kann 
ich es nicht genau testen, da ich auf dem STM32F3Discovery die RX und TX 
Pins nicht angeschlossen habe und ich auch keinen Pegelwandler zur 
Verfügung habe. Das Board hat ja einen USB USER Anschluss, kann ich den 
irgendwie verwenden oder wie würdet ihr die USART Kommunikation mit dem 
PC Herstellen? Ich möchte mal nur einen Char senden, um zu sehen, ob es 
klappt.

Grüsse Hans
1
/*----------------------------------------------------------------------------
2
 * CMSIS-RTOS 'main' function template
3
 *---------------------------------------------------------------------------*/
4
5
#define osObjectsPublic                     // define objects in main module
6
#include "osObjects.h"                      // RTOS object definitions
7
#include "stm32f3xx.h"                  // Device header
8
9
10
/*
11
 * Defines
12
 */
13
 #define SYS_FREQUENCY 8000000L  //8Mhz
14
 
15
 /*
16
  * Global Variables
17
  */
18
  
19
 long baudrate=9600;
20
  
21
 //----------------------------------------------------------------------------------------------------
22
 void initGPIO() {     
23
  // initialize peripherals here
24
    //Activate red LED Port
25
    RCC->AHBENR |= RCC_AHBENR_GPIOEEN;        //enable PORTE clock
26
    GPIOE->MODER |= GPIO_MODER_MODER9_0;      //PORTE9 (LED red) is output
27
  
28
 }
29
 
30
 void initUSART(long baudrate) {
31
   long baudratio=SYS_FREQUENCY/baudrate;
32
   RCC->APB1ENR |= (1<<17);                                //ENABLE USART2 Clock
33
   USART2->CR1 &=!((1<<28)|(1<<12));                       //8-bit transmission (bit 12,28)
34
   USART2->CR1 |=(1<<7)|(1<<5)|(1<<3)|(1<<2)|(1<<0);      //Enable RX/TX(2,3), TX/RX Interrupt (5,7), UART Enable(0)
35
   USART2->CR2 &=!((1<<13)|(1<<12));                      //1 stop bit
36
   USART2->BRR |= baudratio;                              //set Baudrate to 9600
37
 }
38
 
39
 void sendChar(void const *argument) {
40
   while(1) {
41
     USART2->TDR = 'x';
42
     osDelay(500);
43
   }
44
45
 }
46
 
47
 void Blinky (void const *argument) {
48
   while(1){
49
     GPIOE->BSRRL = (1<<9);    //LED on -> BSRRL is Bit Set Reset Register -> write 1 -> high
50
     osDelay(250);              //250ms Delay
51
     GPIOE->BSRRH = (1<<9);    //LED off
52
     osDelay(250);
53
   }
54
 }
55
 
56
 
57
 osThreadDef(Blinky,osPriorityNormal,1,0);  //Define Thread on function Blinky
58
 osThreadDef(sendChar,osPriorityNormal,1,0);
59
 
60
 //----------------------------------------------------------------------------------------------------
61
 
62
int main (void) {
63
  osKernelInitialize ();                    // initialize CMSIS-RTOS
64
  
65
  //----------------------------------------------------------------------------------------------------
66
  initGPIO();
67
  initUSART(baudrate);
68
  //----------------------------------------------------------------------------------------------------
69
  
70
  
71
  // create 'thread' functions that start executing,
72
  // example: tid_name = osThreadCreate (osThread(name), NULL);
73
  osThreadCreate(osThread (Blinky),NULL);
74
  osThreadCreate(osThread (sendChar),NULL);
75
  osKernelStart ();                         // start thread execution 
76
}

von Bernd K. (prof7bit)


Lesenswert?

Bert S. schrieb:
> RCC->APB1ENR |= (1<<17);                                //ENABLE
> USART2 Clock
>    USART2->CR1 &=!((1<<28)|(1<<12));                       //8-bit
> transmission (bit 12,28)
>    USART2->CR1 |=(1<<7)|(1<<5)|(1<<3)|(1<<2)|(1<<0);      //Enable
> RX/TX(2,3), TX/RX Interrupt (5,7), UART Enable(0)
>    USART2->CR2 &=!((1<<13)|(1<<12));

Das ist vollkommen grausam.

Du solltest Dir abgewöhnen solche Sachen wie 
(1<<7)|(1<<5)|(1<<3)|(1<<2)|(1<<0) direkt in den Code reinzuschreiben 
sondern stattdessen die Bitdefinitionen aus den Headern zu verwenden, 
dann kann man es sogar lesen und verstehen ohne die Kommentare am Ende 
jeder Zeile.

Ich gebe Dir ein Beispiel:

Betrachte Deine Zeile aus obigem Code wo Du schreibst:
1
USART2->CR1 |=(1<<7)|(1<<5)|(1<<3)|(1<<2)|(1<<0);      //Enable RX/TX(2,3), TX/RX Interrupt (5,7), UART Enable(0)

Du warst gezwungen aufgrund der Tatsache daß kein Mensch beim Lesen 
auswendig wissen kann was bits 7,5,3,2 und 0 bedeuten ohne das Manual 
aufzuschlagen einen erklärenden Kommentar hinzuzufügen. Jedoch kann der 
Compiler nicht überprüfen ob der Kommentar zu den Zahlen passt und der 
geneigte Leser (oder der der den Fehler sucht) muss auf den Verdacht hin 
trotzdem wieder jedes einzelne Bit nachschlagen, allein schon um einen 
Tippfehler auszuschließen.

Aber in den Headern sind auch die Namen für alle Bits definiert!

Jetzt schau mal wie man obige Zeile ordentlich hinschreiben kann:
1
    USART2->CR1 |= USART_CR1_TXEIE
2
                 | USART_CR1_RXNEIE
3
                 | USART_CR1_TE
4
                 | USART_CR1_RE
5
                 | USART_CR1_UE;
Alle Bits haben Namen! Du kannst Dir auch die Auto-Vervollständigung 
zunutze machen: Wenn Du weißt daß du das TXEIE Bit in einem der USART 
config Register setzen willst (aber vergessen hast in welchem und wie 
das genau buchstabiert wird) schreibst Du USART_ drückst Ctrl-Space und 
gehst die Liste durch. Dann steht da irgendwo USART_CR1_TXEIE, das ist 
die Bitmaske für dieses Bit in diesem Register, dann weißt Du daß Du

USART2->CR1 |= USART_CR1_TXEIE

schreiben mußt.

Probiers aus, ist ganz einfach, die haben das konsequent durchgezogen. 
Jedes Bit ist definiert nach dem selben Schema:

PERIPHERIE_REGISTERNAME_BITNAME

und Das Register selbst ist

PERIPHERIE->REGISTERNAME

also um es zu setzen:

PERIPHERIE->REGISTERNAME |= PERIPHERIE_REGISTERNAME_BITNAME

Wobei REGISTERNAME und BITNAME wortwörtlich denen im Manual 
entsprechen. Keine Zahlen mehr merken oder nachschlagen oder noch 
schlimmer: nie mehr versehentlich die falsche Zahl hinschreiben und 
stundenlang nach dem Fehler suchen weil die nackte Zahl keinen Namen hat 
und in dem nichtssagenden Zahlenwust nicht weiter auffällt.

: Bearbeitet durch User
von Bert S. (kautschuck)


Lesenswert?

Ok, dass hatte bei mir nicht geklappt, da ich keinen Unterstrich 
verwendet habe, danke. Ich kenne diese Darstellung von AVR her und 
bevorzuge das natürlich.

von Bert S. (kautschuck)


Lesenswert?

Ich habe das mal umgeschrieben. Jedoch sollte ich doch nach folgender 
Manual ein Signal am Port PA2 sehen, wenn USART2 sendet?

http://www.st.com/content/ccc/resource/technical/document/user_manual/8a/56/97/63/8d/56/41/73/DM00063382.pdf/files/DM00063382.pdf/jcr:content/translations/en.DM00063382.pdf
1
/*----------------------------------------------------------------------------
2
 * CMSIS-RTOS 'main' function template
3
 *---------------------------------------------------------------------------*/
4
5
#define osObjectsPublic                     // define objects in main module
6
#include "osObjects.h"                      // RTOS object definitions
7
#include "stm32f3xx.h"                  // Device header
8
9
10
/*
11
 * Defines
12
 */
13
 #define SYS_FREQUENCY 8000000L  //8Mhz
14
 
15
 /*
16
  * Global Variables
17
  */
18
  
19
 long baudrate=9600;
20
  
21
 //----------------------------------------------------------------------------------------------------
22
 void initGPIO() {     
23
  // initialize peripherals here
24
    //Activate red LED Port
25
    RCC->AHBENR |= RCC_AHBENR_GPIOEEN;        //enable PORTE clock
26
    GPIOE->MODER |= GPIO_MODER_MODER9_0;      //PORTE9 (LED red) is output
27
  
28
 }
29
 
30
 void initUSART(long baudrate) {
31
   long baudratio=SYS_FREQUENCY/baudrate;
32
   RCC->APB1ENR |= RCC_APB1ENR_USART2EN;                    //ENABLE USART2 Clock
33
   USART2->CR1 &=!((USART_CR1_M0)|(1<<28));                 // USART_CR1_M1 does not exist???
34
   USART2->CR1 |= (USART_CR1_TXEIE
35
                 | USART_CR1_RXNEIE
36
                 | USART_CR1_TE
37
                 | USART_CR1_RE
38
                 | USART_CR1_UE);
39
   USART2->CR2 &=!((USART_CR2_STOP_0)|(USART_CR2_STOP_1));  //1 stop bit
40
   USART2->BRR |= baudratio;                                //set Baudrate to 9600
41
 }
42
 
43
 void sendChar(void const *argument) {
44
   while(1) {
45
     USART2->TDR = 'x';
46
     osDelay(500);
47
   }
48
49
 }
50
 
51
 void Blinky (void const *argument) {
52
   while(1){
53
     GPIOE->BSRRL = GPIO_BSRR_BS_9;      //LED on -> BSRRL is Bit Set Reset Register -> write 1 -> high
54
     osDelay(250);                      //250ms Delay
55
     GPIOE->BSRRH =  GPIO_BSRR_BS_9 ;    //LED off
56
     osDelay(250);
57
   }
58
 }
59
 
60
 
61
 osThreadDef(Blinky,osPriorityNormal,1,0);  //Define Thread on function Blinky
62
 osThreadDef(sendChar,osPriorityNormal,1,0);
63
 
64
 //----------------------------------------------------------------------------------------------------
65
 
66
int main (void) {
67
  osKernelInitialize ();                    // initialize CMSIS-RTOS
68
  
69
  //----------------------------------------------------------------------------------------------------
70
  initGPIO();
71
  initUSART(baudrate);
72
  //----------------------------------------------------------------------------------------------------
73
  
74
  
75
  // create 'thread' functions that start executing,
76
  // example: tid_name = osThreadCreate (osThread(name), NULL);
77
  osThreadCreate(osThread (Blinky),NULL);
78
  osThreadCreate(osThread (sendChar),NULL);
79
  osKernelStart ();                         // start thread execution 
80
}

von W.S. (Gast)


Lesenswert?

Bernd K. schrieb:
> Das ist vollkommen grausam.

Naja.. JEIN.
Ganz so grausam ist das nicht, aber dazu gehört eben etwas anderes als 
lediglich irgend eine schlimme Funktion in main.c hineinzuklatschen.

Der TO hat sich offenbar lediglich eine grauselige unsystematische Art 
angewöhnt, seine Firmware zu schreiben. Bei seinem bisherigen AVR 
scheint ihm das nicht weiter auf die Füße gefallen zu sein:

Bert S. schrieb:
> Ich bin gerade am erlernen von ARM auf einem...
>
> Nun sind hier aber die Register nicht so beschrieben, wie ich mir das
> von AVR gewohnt bin,...

Aber wenn man von einem kleinen Achtbitter auf einen ARM umsteigt, dann 
sollte man zu allererst sich wenigstens ETWAS Systematik angewöhnen.

Das heiß im Klartext, sich Hardwaretreiber zu schreiben, die den 
zugrundeliegenden Kruscht abstrahieren und kapseln und in sich die 
gesamte Funktionalität erledigen, die man braucht, um sich in höheren 
Programmschichten nicht mehr um einzelne Bits und andere niedere Dinge 
kümmern zu müssen.

Innerhalb so eines Treibers kann man dann durchaus mit (x<<7) und 
dergleichen arbeiten, denn der Bereich des Ganzen ist eingeschränkt, ist 
also eher überschaubar und normalerweise muß man da nicht wieder ran, 
wenn das Ganze erstmal ausgetestet ist.

Viel eher hätte ich da Sorgen, daß all die von dir vorgeschlagenen 
Bit-Namen-Definitionen, die man in irgend einer obskuren Headerdatei 
findet, auch wirklich so stimmen wie im RefMan gedruckt.

Weitaus grauseliger finde ich sowas:

Bert S. schrieb:
> void sendChar(void const *argument) {
>    while(1) {
>      USART2->TDR = 'x';
>      osDelay(500);
>    }

Mal abgesehen von der Form, was soll das? Sieht SO etwa eine 
ernstzunehmende serielle Schnittstelle aus?

W.S.

von Bert S. (kautschuck)


Lesenswert?

W.S. schrieb:
> Bert S. schrieb:
>> void sendChar(void const *argument) {
>>    while(1) {
>>      USART2->TDR = 'x';
>>      osDelay(500);
>>    }
>
> Mal abgesehen von der Form, was soll das? Sieht SO etwa eine
> ernstzunehmende serielle Schnittstelle aus?

Ich wollte nur mal schauen, ob ich ein Signal am richtigen PIN empfange, 
dass soll keine Schnittstelle darstellen, doch irgendwo scheint noch 
etwas mit dem USART2 nicht zu stimmen, bekomme zumindest kein Signal am 
PIN PA2.

Ich werde natürlich vernünftige Treiber selber schreiben, aber zuerst 
mal muss ich schauen, wie genau was funktioniert, daher ist ein einfach 
gehaltenes Programm sicher sinnvoll. Zumindest die Debug Schnittstelle 
mit Hilfe des USART sollte mal laufen.

Grüse Hans

: Bearbeitet durch User
von Bert S. (kautschuck)


Lesenswert?

Ich habe das Programm mal ein bisschen überarbeitet und noch bei GPIO 
die Clock aktiviert, bekomme aber immer noch nichts am PD2 Ausgang:
1
/*----------------------------------------------------------------------------
2
 * CMSIS-RTOS 'main' function template
3
 *---------------------------------------------------------------------------*/
4
5
#define osObjectsPublic                     // define objects in main module
6
#include "osObjects.h"                      // RTOS object definitions
7
#include "stm32f3xx.h"                  // Device header
8
9
/*
10
 * Defines
11
 */
12
 #define SYS_FREQUENCY 8000000L  //8Mhz
13
 
14
 /*
15
  * Global Variables
16
  */
17
  
18
 long baudrate=9600;
19
20
 //----------------------------------------------------------------------------------------------------
21
 void initGPIO() {     
22
  // initialize peripherals here
23
    //Activate red LED Port
24
    RCC->AHBENR |= RCC_AHBENR_GPIOEEN;        //enable PORTE clock
25
    RCC->AHBENR |= RCC_AHBENR_GPIOAEN;        //enable PORTE clock
26
    GPIOE->MODER |= GPIO_MODER_MODER9_0;      //PORTE9 (LED red) is output
27
 }
28
 
29
 void initUSART(long baudrate) {
30
   long baudratio=SYS_FREQUENCY/baudrate;
31
   //GPIO
32
   GPIOA->MODER |= GPIO_MODER_MODER2_1;      //Alternating function
33
   GPIOA->OTYPER &= !(GPIO_OTYPER_OT_2);
34
   
35
   //USART
36
   RCC->APB1ENR |= RCC_APB1ENR_USART2EN;                    //ENABLE USART2 Clock
37
   USART2->CR1 &=!((USART_CR1_M0)|(1<<28));                 // USART_CR1_M1 does not exist???
38
   USART2->CR1 |= (USART_CR1_TE 
39
                 |USART_CR1_TXEIE 
40
                 | USART_CR1_RXNEIE                            
41
                 | USART_CR1_RE
42
                 | USART_CR1_UE);
43
   USART2->CR2 &=!((USART_CR2_STOP_0)|(USART_CR2_STOP_1));  //1 stop bit
44
   USART2->BRR |= baudratio;                                //set Baudrate to 9600
45
 }
46
 
47
 void sendChar(char c) {
48
     while(!USART_ISR_TXE);
49
     USART2->TDR = (c & 0xFF);
50
     GPIOE->BSRRL = GPIO_BSRR_BS_9;      //LED on -> BSRRL is Bit Set Reset Register -> write 1 -> high
51
     osDelay(250);                      //250ms Delay
52
     GPIOE->BSRRH =  GPIO_BSRR_BS_9 ;    //LED off
53
     osDelay(250);
54
 }
55
 
56
 void sendXThread(void const *argument) {
57
   while(1) {
58
    sendChar('X');
59
   }
60
 }
61
 
62
 osThreadDef(sendXThread,osPriorityNormal,1,0);
63
 
64
 //----------------------------------------------------------------------------------------------------
65
 
66
int main (void) {
67
  osKernelInitialize ();                    // initialize CMSIS-RTOS
68
  
69
  //----------------------------------------------------------------------------------------------------
70
  initGPIO();
71
  initUSART(baudrate);
72
  //----------------------------------------------------------------------------------------------------
73
  
74
  
75
  // create 'thread' functions that start executing,
76
  // example: tid_name = osThreadCreate (osThread(name), NULL);
77
  osThreadCreate(osThread (sendXThread),NULL);
78
  osKernelStart ();                         // start thread execution 
79
}

von Christopher J. (christopher_j23)


Lesenswert?

Bei den neueren Discovery und Nucleo Boards ist normalerweise immer ein 
USART mit dem ST-Link verbunden, d.h. du kannst per virtuellem COM-Port 
damit interagieren, ohne das du einen dedizierten USB-UART-Wandler 
brauchst.

Im Falle des F3 Disco ist das USART1 (Achtung, der hängt an APB2 statt 
APB1!).

Warum kein Signal kommen kann:
Du MUSST jeden einzelnen Pin den du benutzen willst, entsprechend 
konfigurieren, da (fast) alle Pins nach einem Reset als Input mit PullUp 
konfiguriert sind.

Du musst (für den Fall USART1) PA9 und PA10 entsprechend konfigurieren, 
d.h. du setzt jeweils für PA9 und PA10 GPIOA->MODER auf "alternate 
function", GPIOA->PUPDR auf "pull up" und GPIOA->AFRH auf AF7 (siehe 
Tabelle im Datenblatt S.44).

: Bearbeitet durch User
von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Beim F3-Discovery auf die Revision aufpassen! Erst ab Board Revision C 
wird der STLink V2-1 verwendet, der CDC-ACM kann und es sind die SB13/15 
geschlossen, so dass Uart Signale an den STLink kommen.

von Bert S. (kautschuck)


Lesenswert?

Die GPIO Pins habe ich nun so definiert (Ich glaube nach Datenblatt ist 
PC4 der TX Pin für die ST-Link USB Schnittstelle):
1
RCC->AHBENR |= RCC_AHBENR_GPIOCEN;        //enable PORTE clock
2
GPIOC->MODER |= GPIO_MODER_MODER4_1 ;      //Alternating function, for TX (PC4)
3
GPIOC->OTYPER &= !(GPIO_OTYPER_OT_4);
4
GPIOC->PUPDR |= GPIO_PUPDR_PUPDR4_0;

Doch ich bekomme immer noch kein Ausgangssignal, nur konstant 3V vom 
Pull-Up. Keine Ahnung was man noch ergänzen könnte.

Grüsse Hans

Christopher J. schrieb:
> GPIOA->AFRH auf AF7 (siehe
> Tabelle im Datenblatt S.44).

Wie genau kann ich das setzen? Bei mir scheint es GPIOA_AFRH nicht zu 
geben, es kommt die Fehlermeldung undeclared identifier.

Uwe B. schrieb:
> Erst ab Board Revision C
> wird der STLink V2-1 verwendet

Wie erkenne ich welches Board ich habe, bzw. welche Revision? SB13/15 
scheinen nicht geschlossen zu sein.

: Bearbeitet durch User
von Christopher J. (christopher_j23)


Lesenswert?

Sorry, AFRL und AFRH sind gebündelt in AFR[2], also GPIOA->AFR[0] und 
GPIOA->AFR[1].

Dabei ist AFRL für die Pins 0-7 und AFRH für die Pins 8-15 zuständig 
(jeweils vier Bits pro Pin). AF7 bedeutet die Bits für den 
entsprechenden Pin sind 0x0111.

Bert S. schrieb:
> Die GPIO Pins habe ich nun so definiert (Ich glaube nach Datenblatt ist
> PC4 der TX Pin für die ST-Link USB Schnittstelle):

Das stimmt glaube ich so nicht.

Im User Manual des F3-Disco steht unter 6.2.3 "VCP Configuration":
> The ST-LINK/V2-B on STM32F3DISCOVERY supports virtual Com port (VCP) on U2
> pin 12 (ST-LINK_TX) and U2 pin 13 (ST-LINK_RX), which are connected to the
> STM32F303 MCU target STM32 USART1 (PA9, PA10), thanks to SB11 and SB15
> solder bridges.
> The SB11 (PA9) and SB15 (PA10) default configurations for STM32F3DISCOVERY
> are given in Table 5: Solder bridges.

Hier kannst du selber nachschauen:
http://www.st.com/content/ccc/resource/technical/document/user_manual/8a/56/97/63/8d/56/41/73/DM00063382.pdf/files/DM00063382.pdf/jcr:content/translations/en.DM00063382.pdf

Aber Uwe hat Recht, dass das erst ab Rev C der Fall ist.

Bert S. schrieb:
> Wie erkenne ich welches Board ich habe, bzw. welche Revision? SB13/15
> scheinen nicht geschlossen zu sein.

Auf den Boards ist normalerweise ein weißer Aufkleber da steht so etwas 
wie "MB1035 B-00" drauf, wobei MB1035 für das Board steht und B-00 für 
die Revision.

Bert S. schrieb:
1
void initUSART(long baudrate) {
2
   long baudratio=SYS_FREQUENCY/baudrate;
3
   //GPIO
4
   GPIOA->MODER |= GPIO_MODER_MODER2_1;      //Alternating function
5
   GPIOA->OTYPER &= !(GPIO_OTYPER_OT_2);
6
7
   //USART
8
   RCC->APB1ENR |= RCC_APB1ENR_USART2EN;                    //ENABLE USART2 Clock
9
   USART2->CR1 &=!((USART_CR1_M0)|(1<<28));                 // USART_CR1_M1 does not exist???
10
   USART2->CR1 |= (USART_CR1_TE
11
                 |USART_CR1_TXEIE
12
                 | USART_CR1_RXNEIE
13
                 | USART_CR1_RE
14
                 | USART_CR1_UE);
15
   USART2->CR2 &=!((USART_CR2_STOP_0)|(USART_CR2_STOP_1));  //1 stop bit
16
   USART2->BRR |= baudratio;                                //set Baudrate to 9600
17
}

Da sind noch ein paar Fehler drin:
Wenn du einem Register mit einem &= einen Wert zuweisen willst, aber das 
Register als Reset-Wert bereits 0x00000000 ist, dann wird es auch nach 
dem &= immer noch 0 sein, egal was auf der rechten Seite steht.
Außerdem darfst du nicht das logische mit dem unären ("bitwise") "Nicht" 
verwechseln (! ist nicht gleich ~).
!(bliblablub) wird immer zu Null, es sei denn bliblablub ist Null, dann 
wird es Eins.

: Bearbeitet durch User
von Bert S. (kautschuck)


Lesenswert?

Das AF7 habe ich nun im Low Register gesetzt, doch es tut sich leider 
immer noch nichts. Die Invertierung muss natürlich bitwise sein, hatte 
das irgendwie gerade vergessen.

Christopher J. schrieb:
> Wenn du einem Register mit einem &= einen Wert zuweisen willst, aber das
> Register als Reset-Wert bereits 0x00000000 ist, dann wird es auch nach
> dem &= immer noch 0 sein

Ist das nicht das Ziel? Das Bit wird gelöscht und wenn es bereits 0 ist, 
dann bleibt es Null?

Christopher J. schrieb:
> Auf den Boards ist normalerweise ein weißer Aufkleber da steht so etwas
> wie "MB1035 B-00" drauf, wobei MB1035 für das Board steht und B-00 für
> die Revision.

Bei mir ist es also Revision B-00 (MB1035 B-00). Dann kann ich das mit 
dem ST-Link vergessen. Kaufe mir halt ein UART->USB Pegelwandler.

Muss ich vielleicht irgendwelche Register clearen? Ich hatte sowas schon 
einmal in AVR, wo alles richtig Programmiert war, aber einige Register 
mussten zuerst resetet werden.

Grüsse und Danke Hans

1
/*----------------------------------------------------------------------------
2
 * CMSIS-RTOS 'main' function template
3
 *---------------------------------------------------------------------------*/
4
5
#define osObjectsPublic                     // define objects in main module
6
#include "osObjects.h"                      // RTOS object definitions
7
#include "stm32f3xx.h"                  // Device header
8
9
/*
10
 * Defines
11
 */
12
 #define SYS_FREQUENCY 8000000L  //8Mhz
13
 
14
 /*
15
  * Global Variables
16
  */
17
  
18
 long baudrate=9600;
19
20
 //----------------------------------------------------------------------------------------------------
21
 void initGPIO() {     
22
  // initialize peripherals here
23
    //Activate red LED Port
24
    RCC->AHBENR |= RCC_AHBENR_GPIOEEN;        //enable PORTE clock
25
    GPIOE->MODER |= GPIO_MODER_MODER9_0;      //PORTE9 (LED red) is output
26
 }
27
 
28
 void initUSART(long baudrate) {
29
   long baudratio=SYS_FREQUENCY/baudrate;
30
   //GPIO
31
   RCC->AHBENR |= RCC_AHBENR_GPIOAEN;        //enable PORTA clock
32
   GPIOA->MODER |= GPIO_MODER_MODER9_1 ;    //Alternating function, for TX (PC4)
33
   GPIOA->OTYPER &= ~(GPIO_OTYPER_OT_9);    //Push-Pull
34
   GPIOA->PUPDR |= GPIO_PUPDR_PUPDR9_0;      //
35
   GPIOA->AFR[0] |= GPIO_AFRL_AFRL7;        //
36
   
37
   //USART
38
   RCC->APB2ENR |= RCC_APB2ENR_USART1EN;                    //ENABLE USART2 Clock
39
   USART1->CR1 &=~((USART_CR1_M0)|(1<<28));                 // USART_CR1_M1 does not exist???
40
   USART1->CR1 |= (USART_CR1_TE |USART_CR1_TXEIE | USART_CR1_RXNEIE| USART_CR1_RE | USART_CR1_UE);
41
   USART1->CR2 &=~((USART_CR2_STOP_0)|(USART_CR2_STOP_1));  //1 stop bit
42
   USART1->BRR |= baudratio;                                //set Baudrate to 9600
43
 }
44
 
45
 void sendChar(char c) {
46
     while(!USART_ISR_TXE);
47
     USART1->TDR = (c & 0xFF);
48
     GPIOE->BSRRL = GPIO_BSRR_BS_9;      //LED on -> BSRRL is Bit Set Reset Register -> write 1 -> high
49
     osDelay(250);                      //250ms Delay
50
     GPIOE->BSRRH =  GPIO_BSRR_BS_9 ;    //LED off
51
     osDelay(250);
52
 }
53
 
54
 void sendXThread(void const *argument) {
55
   while(1) {
56
    sendChar('X');
57
   }
58
 }
59
 
60
 osThreadDef(sendXThread,osPriorityNormal,1,0);
61
 
62
 //----------------------------------------------------------------------------------------------------
63
 
64
int main (void) {
65
  osKernelInitialize ();                    // initialize CMSIS-RTOS
66
  
67
  //----------------------------------------------------------------------------------------------------
68
  initGPIO();
69
  initUSART(baudrate);
70
  //----------------------------------------------------------------------------------------------------
71
  
72
  
73
  // create 'thread' functions that start executing,
74
  // example: tid_name = osThreadCreate (osThread(name), NULL);
75
  osThreadCreate(osThread (sendXThread),NULL);
76
  osKernelStart ();                         // start thread execution 
77
}

: Bearbeitet durch User
von Nico W. (nico_w)


Lesenswert?

Bert S. schrieb:
> USART1->BRR |= baudratio;

Du brauchst den Teil nicht einlesen. Ein einfaches = reicht.

Bert S. schrieb:
> while(!USART_ISR_TXE);

Was ist das? USART_ISR_TXE? Ist das eine Funktion die sich ändern kann?
Oder suchst du doch etwas wie:
1
while(!(USART1->SR & USART_SR_TXE));
?

Edit: Da stimmt noch einiges mehr nicht. TX ist da. RX nicht?
UE nicht am Ende gesetzt sondern zwischen der Config?
Sicher dass du die richtigen Pin konfiguriert hast?

: Bearbeitet durch User
von Christopher J. (christopher_j23)


Lesenswert?

Bert S. schrieb:
> GPIOA->AFR[0] |= GPIO_AFRL_AFRL7;

Die AF Register haben jeweils 4 Bit pro Pin.
GPIO_AFRL_AFRL7 ist daher die Bitmaske für Pin 7 (0xF0000000).
Wenn du das direkt ins AFRL schreibst konfigurierst du PA7 mit AF15. 
Wenn du PA2 als AF7 willst musst du (GPIO_AFRL_AFRL2 & (7U << 8)) ins 
AFRL schreiben.

Guck am besten ins RefMan Kapitel 11.4.9

von W.S. (Gast)


Angehängte Dateien:

Lesenswert?

Bert S. schrieb:
> Doch ich bekomme immer noch kein Ausgangssignal, nur konstant 3V vom
> Pull-Up. Keine Ahnung was man noch ergänzen könnte.

Es jammert einen!
Ich hätte nicht gedacht, daß jemand der nach eigenen Angaben geübt ist 
mit Atmels AVR's, derartig heftige Schwierigkeiten hat.

Ich hänge dir mal drei Dinge hier dran:
1. ein Beispiel, wie man seinen STM32F3.. passabel und lesbar 
konfigurieren kann
2. ein Komplett-Treiber für die U(S)ART's
3. dito für USB-VCP

Aber die Definitionen der HW-Register und solcher Dinge wie byte, word, 
dword machst du dir selber, ebenfalls den Startupcode und die 
Programmteile, die auf diese unterste Treiberebene aufbauen, also sowas 
wie eine E/A-Weiche, Kommandoprogramm und so.

W.S.

von Stefan F. (Gast)


Lesenswert?

Ich habe das gleiche Problem, allerdings nutze ich die CMSIS und USART2 
auf einem STM32F303RE.

Am TxD Ausgang habe ich ständig High Pegel.
1
#include <stdio.h>
2
#include "stm32f3xx.h"
3
4
uint32_t SystemCoreClock=8000000;
5
6
// delay loop for 8 MHz CPU clock
7
void delay(uint16_t msec)
8
{
9
    for (uint32_t j=0; j<2000*msec; j++)
10
    {
11
        __NOP();
12
    }
13
}
14
15
// Redirect standard output to the serial port
16
int _write(int file, char *ptr, int len)
17
{
18
    for (int i=0; i<len; i++)
19
    {
20
        while(!(USART2->ISR & USART_ISR_TXE));
21
        USART2->TDR = *ptr++;
22
    }
23
    return len;
24
}
25
26
int main(void)
27
{
28
    // Enable clock for Port A
29
    SET_BIT(RCC->AHBENR, RCC_AHBENR_GPIOAEN);
30
31
    // PA5 = Output for the LED
32
    MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODER5,  GPIO_MODER_MODER5_0);
33
34
    // Use system clock for USART2
35
    SET_BIT(RCC->APB1ENR, RCC_APB1ENR_USART2EN);
36
    MODIFY_REG(RCC->CFGR3, RCC_CFGR3_USART2SW, RCC_CFGR3_USART2SW_0);
37
38
    // PA2 (TxD) shall use the alternate function 7
39
    MODIFY_REG(GPIOA->AFR[0], GPIO_AFRL_AFRL2, 7U<<GPIO_AFRL_AFRL2_Pos);
40
    MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODER2, GPIO_MODER_MODER2_1);
41
42
    // Set baudrate
43
    USART2->BRR = (SystemCoreClock / 115200);
44
45
    // Enable transmitter of USART2
46
    USART2->CR1 = USART_CR1_UE + USART_CR1_TE;    
47
48
    while (1)
49
    {
50
        // LED Pin -> High
51
        WRITE_REG(GPIOA->BSRR, GPIO_BSRR_BS_5);
52
        delay(500);
53
54
        puts("Hello");
55
56
        // LED Pin -> Low
57
        WRITE_REG(GPIOA->BSRR, GPIO_BSRR_BR_5);
58
        delay(500);
59
    }
60
}

Ich bin langsam am verzweifeln. Das kann doch nicht so schwer sein, eine 
UART zu programmieren. Nachdem ich das bisher mit jedem AVR geschafft 
habe, komme ich mir nun richtig doof vor.

Ich habe viele Beiträge hier und in anderen Foren gefunden, wo Leute 
genau das gleiche Problem haben. Aber leider enden alle ohne Lösung.

Was mache ich falsch?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

W.S. schrieb:
> Es jammert einen!

Ja bei deinem Magic NUmber Code mal wieder!

Bzw es graust einem bei deiner serial.c und den IRQ Handlern:
1
if (USART2_ISR & ((1<<5)|(1<<3)))      // RX: Zeichen empfangen
würg

von Nico W. (nico_w)


Lesenswert?

Stefanus F. schrieb:
> // Enable transmitter of USART2
>     USART2->CR1 = USART_CR1_UE + USART_CR1_TE;

Ich würde niemals sowas hier addieren. Immer verodern.

Ggf. mag der USART ja nicht, dass er angeschmissen wird und TE im selben 
Takt angeht. Ich würde da ggf. mal zunächst TE anschmeißen und den USART 
danach erst anmachen. Nur als Idee zum suchen.

Die Register vom PA2 hast dir im Debugger auch mal angesehen? Nicht das 
dort noch Überraschungen sind (Pullup oder so?).

von Stefan F. (Gast)


Lesenswert?

Jetzt geht es plötzlich. Vielleicht hatte ich bei vorherigen 
fehlerhaften Versuchen irgendwie die HW blockiert und das Problem 
unbewusst durch Unterbrechen der Stromversorgung gelöst.

von Stefan F. (Gast)


Lesenswert?

Nico W. schrieb:
> Ich würde niemals sowas hier addieren. Immer verodern.

Kommt das gleiche bei heraus.

von Nico W. (nico_w)


Lesenswert?

Stefanus F. schrieb:
> Nico W. schrieb:
>> Ich würde niemals sowas hier addieren. Immer verodern.
>
> Kommt das gleiche bei heraus.

In dem Falle schon. Ich hatte einmal etwas ähnliches und das ist mir auf 
die Füße gefallen. Letzendlich willst du ein Bit ändern. Veroderst du 
das gleiche Bit ein paar Mal ist das OK. Addieren...

von Stefan F. (Gast)


Lesenswert?

Nico W. schrieb:
> Letzendlich willst du ein Bit ändern.

In dieser Zeile will ich wirklich alle Bits des Registers in einem 
Abwasch anfassen.

> Veroderst du das gleiche Bit ein paar Mal ist das OK.

Ok, das ist ein einleuchtendes Argument (Fehler vermeiden).

von Achim W. (walder) Benutzerseite


Lesenswert?

Hallo, jetzt habe ich schon viele Seite durchgesehen und leider keinen 
passenden Vorschlag gefunden.
(Ich bin nicht gut mit C und dem STM32 vertraut!!)

Zur Steuerung meiner Modelleisenbahn möchte ich den STM32F103 einsetzen.
Das Ausgeben eines Textes über TX1 funktioniert,
aber vom Terminalprogramm einen Text einlesen über RX1 nicht.

Wer oder wo kann ich hilfe bekommen ?

Vielen Dank im Voraus !

von Stefan F. (Gast)


Lesenswert?

Achim W. schrieb:
> Wer oder wo kann ich hilfe bekommen ?

https://www.programmieraufgaben.ch/aufgabe/ringpuffer-mit-arrays/yui8z5du

Guck Dir mal die Erklärung und dann die erste Lösung in Java an, die 
erscheint mir am einfachsten. Das kannst du sicher in C umsetzen.

Hier ist es noch ausführlicher erklärt: 
https://medium.com/@charlesdobson/how-to-implement-a-simple-circular-buffer-in-c-34b7e945d30e

Wichtig ist in deinem Fall, dass die beteiligten Variablen (auch das 
Array) mit "volatile" deklariert werden. Wenn du nach "volatile isr" 
suchst, findest du jede Menge Erklärungen dazu.

von Johnny B. (johnnyb)


Lesenswert?

Achim W. schrieb:
> Hallo, jetzt habe ich schon viele Seite durchgesehen und leider keinen
> passenden Vorschlag gefunden.
> (Ich bin nicht gut mit C und dem STM32 vertraut!!)
>
> Zur Steuerung meiner Modelleisenbahn möchte ich den STM32F103 einsetzen.
> Das Ausgeben eines Textes über TX1 funktioniert,
> aber vom Terminalprogramm einen Text einlesen über RX1 nicht.
>
> Wer oder wo kann ich hilfe bekommen ?

Für folgende Aussagen werde ich jetzt vielleicht gesteinigt, aber egal:

Wenn Du neu bei STM32 bist, dann würde ich die Entwicklungsumgebung von 
ST nehmen, also STM32CubeIDE.
Die startest Du, machst ein neues STM32 Projekt (mit HAL), wählst den 
richtigen STM32F103 und konfigurierst alle Peripherie im integrierten 
CubeMX und erzeugst den Code. Dann hast Du schonmal ein funktionierendes 
Grundgerüst.

Hier gibts dazu haufenweise Trainingsmaterial:
https://www.st.com/content/st_com/en/support/learning/stm32-education/stm32-moocs.html

Wenn Du das ganze ohne HAL machen willst, dann würde ich mir das für 
etwas später aufheben, wenn Du Dich ein wenig besser mit STM32 
auskennst.

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.