Forum: Mikrocontroller und Digitale Elektronik STM32: mit DMA Daten empfangen


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von har (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich versuche derzeit mittels der DMA Daten (16x Bytes) über die UART3 zu 
empfangen.
Ohne DMA funktioniert es, aber jetzt sitze ich schon eine Zeit lang dies 
mit der DMA zu erledigen.
Ich stelle mir die Vorgehensweise so vor: Es werden an UART3-RX 16 Bytes 
gesendet. Sobald alle 16 Bytes empfangen und in ein Array gespeichert 
wurden, wird ein Interrupt ausgelöst und in diese Funktion gesprungen: 
DMA1_Channel3_IRQHandler

Leider wird aber nie in die ISR gesprungen. Daten werden aber an RX 
übertragen (mit Oszi gemessen bzw. wie bereits erwähnt: ohne DMA 
funktioniert das Empfangen)

Hier mein Code für die DMA:
1
uint8_t receive [16]={};          // array in which received 8bit values are stored
2
3
void DMA_UART3_receive_values()
4
{
5
6
    // DMA1 Channel 3 - UART3 RX
7
    DMA_Cmd(DMA1_Channel3, DISABLE);                                    // USART3_TX on Channel 2
8
9
    DMA_InitTypeDef DMA_InitStruct;
10
    //DMA_StructInit(&DMA_InitStruct);
11
    //DMA_InitStruct.DMA_Channel = DMA1_Channel3;
12
    DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&(USART3->RDR);   
13
    DMA_InitStruct.DMA_MemoryBaseAddr = receive[0]; //(uint8_t)&receive[0];          
14
    DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;                     
15
    DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;                           
16
    DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;        
17
    DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;                
18
    DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;                          
19
    DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;       
20
    DMA_InitStruct.DMA_Priority = DMA_Priority_Low;
21
    DMA_InitStruct.DMA_BufferSize = 16;                       
22
    DMA_Init(DMA1_Channel3, &DMA_InitStruct);
23
    DMA_ClearFlag(DMA1_FLAG_TE3);
24
    DMA_ClearFlag(DMA1_FLAG_TC3);
25
    DMA_ClearFlag(DMA1_FLAG_HT3);
26
    DMA_ITConfig(DMA1_Channel3, DMA_IT_TC, ENABLE);
27
    NVIC_EnableIRQ(DMA1_Channel3_IRQn);                                 // Enable DMA1 Chan3 global interrupt
28
29
30
    USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);                      // Enable USARTy DMA RX request
31
32
33
   DMA_SetCurrDataCounter(DMA1_Channel3, 16);          
34
   receive[0] = DMA1_Channel3->CMAR;
35
36
    DMA_Cmd(DMA1_Channel3, ENABLE);
37
}
38
39
40
void DMA1_Channel3_IRQHandler(void)
41
{
42
    //DMA1 Chan3 Interrupt handler implementation for UART3-Receive
43
44
    if(USART_GetFlagStatus(USART3, USART_FLAG_TC) == SET)
45
    {
46
        // Interrupt when Receiving Complete
47
        USART_ClearFlag(USART3, USART_FLAG_TC);
48
        DMA_Cmd(DMA1_Channel3, DISABLE);
49
50
    } // if USART_GetFlagStatus(USART3, USART_FLAG_TC) == SET
51
} //void DMA1_Channel3_IRQHandler
52
53
54
int main ()
55
{
56
    
57
    RCC_Configuration();     //alle entsprechenden Clocks aktivieren
58
    USART3_Configuration();
59
    USART1_Configuration();
60
    DMA_UART1_Configuration();
61
    DMA_UART3_receive_values();
62
63
64
    send_with_DMA_UART1();      
65
66
67
    while(1)
68
        {
69
70
        } //while(1)
71
} //main

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> if(USART_GetFlagStatus(USART3, USART_FLAG_TC) == SET)
>     {

Musst Du hier nicht eher ein DMA_Flag abfragen?

Sowas in der Art:
1
void DMA1_Channel3_IRQHandler(void)
2
{
3
  if (DMA_GetITStatus(DMA1_IT_TC3))
4
  {
5
    /* Clear DMA Stream Transfer Complete interrupt pending bit */
6
    DMA_ClearITPendingBit(DMA1_IT_TC3);
7
    ....
8
  }
9
}

: Bearbeitet durch Moderator
von har (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Frank M. schrieb:
> Musst Du hier nicht eher ein DMA_Flag abfragen?

Danke für den Hinweis. Werde es überarbeiten.

Aber mein Problem ist, dass nicht einmal in die Funktion void 
DMA1_Channel3_IRQHandler(void) gesprungen wird...

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> Aber mein Problem ist, dass nicht einmal in die Funktion void
> DMA1_Channel3_IRQHandler(void) gesprungen wird...

Das hier:

  NVIC_EnableIRQ(DMA1_Channel3_IRQn);

kommt mir arg wenig vor. Ich kenne da eher so etwas in der Form:
1
void NVIC_Configuration(void)
2
{
3
  NVIC_InitTypeDef NVIC_InitStructure;
4
 
5
  /* Configure the Priority Group to 2 bits */
6
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
7
 
8
  /* Enable UART RX DMA Interrupt */
9
  NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel3_IRQn;
10
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
11
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
12
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
13
  NVIC_Init(&NVIC_InitStructure);
14
}

Im Internet findest Du auch jede Menge Beispielcode, wenn Du nach

    stm32 dma usart receive

googelst.

EDIT:

Den Aufruf von NVIC_PriorityGroupConfig() brauchst Du wohl nicht 
unbedingt.

: Bearbeitet durch Moderator
von Ruediger A. (Firma: keine) (rac)


Bewertung
1 lesenswert
nicht lesenswert
Hallo har,

ein Wort der "Warnung:" Ich mache Serial Comms täglich auf etlichen 
Plattformen und mit vielen vielen Protokollen, aber die Kombination RX 
und DMA ist eines der Dinge, von denen ich die Finger lasse. Zunächst 
mal klappt das nur bei Protokollen mit deterministischer (statischer) 
Paketgrösse (bei variabel grossen Paketen musst Du eh den Header 
Zeichen- oder chunkweise lesen, bis die Paketgrösse decodiert ist und Du 
einen DMA aufsetzen kannst; bei Framingprotokollen ohne Kenntnis der 
Paketgrösse geht eh nichts mit DMA), und dann hast Du ein Problem, wenn 
mal ein Zeichen im Paket verloren geht und dein DMA nicht mehr 
zurückkommt... bei den "gängigen" Baudraten (9600-57600) langweilt sich 
ein normal schneller Prozessor eh zu Tode, selbst wenn für jedes Zeichen 
ein Interrupt ausgelöst wird UND eine Dauerlast auf der Schnittstelle 
ist.

Ausserdem setzt so eine Architektur in jedem Fall Protokollkenntnisse im 
ISR voraus; das kann in manchen Anwendungen ok sein, ist aber oft nicht 
wünschenswert.

Auf der Tx Seite kann DMA aber je nach Protokoll durchaus Vorteile 
bringen.

Just my EUR 0,02, als Übung hat es aber sicherlich seinen Wert...

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
du hast vermutlich den falschen irq-handler. Die dma muss vom 
uart-rx-irq gestartet werden.

von Frank M. (ukw) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Ruediger A. schrieb:
> ein Wort der "Warnung:

Das kann ich mich nur anschließen. DMA auf Rx ist in den meisten Fällen 
ziemlich unsinnig.

von Christoph S. (gizmo)


Bewertung
0 lesenswert
nicht lesenswert
1
DMA_InitStruct.DMA_MemoryBaseAddr = receive[0]; //(uint8_t)&receive[0];

Das stimmt nicht, auch das auskommentierte nicht.

Du musst die Adresse des ersten Byte im Array angeben.
"receive[0]" ist nur der Wert im ersten Array element.
Du brauchst den Pointer, also entweder "&receive[0]" oder einfach 
"receive".

Speicheradressen sind beim Cortex-M 32bit breit, um die Compiler-Warnung 
wegzubekommen musst du also zu uint32_t casten.
Wenn du zu uint8_t castest (wie im Kommentar) schneidest du die oberen 
24bit der Adresse weg.

Also entweder
1
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)receive;
oder
1
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&receive[0];

: Bearbeitet durch User
von har (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Ruediger Asche,

ich gebe dir grundsätzlich Recht und bin auch deiner Meinung. 
Ursprünglich habe ich das Empfangen ohne DMA durchgeführt.
Nun habe ich aber die Anforderung, dass die Kommunikation mit 9MBaud 
erfolgen soll.
Wenn ich das ohne DMA, aber mir Interrupts mache, gibt es folgenden 
Nachteil:
ein Datenpaket benötigt für die Übertragung nur 1,11us. Die Abarbeitung 
der zugehörigen ISR benötigt jedoch 3us (mit Oszi gemessen).
Das heißt, ich empfange das erste Byte, aber alle weiteren werden 
"versäumt".

Das Gute ist, dass das Protokoll immer gleich aussieht (natürlich nur so 
lange, bis kein Fehler auftritt).

Deswegen möchte ich das Empfangen mittels DMA probieren, um zu sehen, ob 
dies mit der hohen Baudrate möglich wäre.


grundschüler schrieb:
> du hast vermutlich den falschen irq-handler. Die dma muss vom
> uart-rx-irq gestartet werden.

Ich denke, der irq-handler sollte passen... (wenn ich mich nicht irre!)

von Ruediger A. (Firma: keine) (rac)


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> Hallo Ruediger Asche,
>
> ich gebe dir grundsätzlich Recht und bin auch deiner Meinung.
> Ursprünglich habe ich das Empfangen ohne DMA durchgeführt.
> Nun habe ich aber die Anforderung, dass die Kommunikation mit 9MBaud
> erfolgen soll.
> Wenn ich das ohne DMA, aber mir Interrupts mache, gibt es folgenden
> Nachteil:
> ein Datenpaket benötigt für die Übertragung nur 1,11us. Die Abarbeitung
> der zugehörigen ISR benötigt jedoch 3us (mit Oszi gemessen).
> Das heißt, ich empfange das erste Byte, aber alle weiteren werden
> "versäumt".
>

ok, 9M ist natürlich eine Andere Hausnummer, deswegen hatte ich meine 
erste Antwort auch auf "normale" Baudraten beschränkt.


> Deswegen möchte ich das Empfangen mittels DMA probieren, um zu sehen, ob
> dies mit der hohen Baudrate möglich wäre.
>

was ist das physikalische Medium/Leitungslänge hinter dem UART? Bei so 
hohen Baudraten ist natürlich auch die Stöfungsanfälligkeit höher und 
damit die Wahrscheinlichkeit, Zeichen zu verlieren, und m.W. nach ist 
das mit DMA nicht gut in den Griff zu kriegen.

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> ein Datenpaket benötigt für die Übertragung nur 1,11us. Die Abarbeitung
> der zugehörigen ISR benötigt jedoch 3us (mit Oszi gemessen).

 Du meinst ein Byte (START-8bits-STOP) oder ?

 Auf jeden Fall steht das:
Ruediger A. schrieb:
> Paketgrösse geht eh nichts mit DMA), und dann hast Du ein Problem, wenn
> mal ein Zeichen im Paket verloren geht und dein DMA nicht mehr
> zurückkommt...

 Das musst du dann mit einem Timer abfangen...

 Bei 16Byt und ISR auf RxD, bleibst du in der zugehörigen ISR etwa
 20us (mit Hin- und Rücksprung), das ist erträglich, oder ?

von Felix F. (wiesel8)


Bewertung
0 lesenswert
nicht lesenswert
- Welchen Controller mit wie viel MHz verwendest du?

- Der Cortex M3 (und vmtl auch seine Nachfolger) haben so eine Art Tail 
Chaining. Wenn der nächste INT bereits ansteht, kann der PC fast direkt 
damit weitermachen (Register push/pop etc. wird übersprungen).

- Wieso bleibst du nach dem Empfang des 1. Bytes nicht in der ISR und 
liest alle Bytes von der Nachricht ein. Zur Sicherheit noch ein Timeout 
(Kein Byte innerhalb der letzten 4µs?) einbauen, damit die ISR auch 
garantiert wieder verlassen wird.

mfg

: Bearbeitet durch User
von har (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ruediger A. schrieb:
> was ist das physikalische Medium/Leitungslänge hinter dem UART? Bei so
> hohen Baudraten ist natürlich auch die Stöfungsanfälligkeit höher und
> damit die Wahrscheinlichkeit, Zeichen zu verlieren, und m.W. nach ist
> das mit DMA nicht gut in den Griff zu kriegen.

jetzt zum Probieren mit einem kurzen Kabel einfach TX von UART1 mit RX 
von UART3 verbunden!

Marc Vesely schrieb:
> Du meinst ein Byte (START-8bits-STOP) oder ?
genau!


Felix F. schrieb:
> Welchen Controller mit wie viel MHz verwendest du?
STM32F303 mit 72MHz

> Der Cortex M3 (und vmtl auch seine Nachfolger) haben so eine Art Tail
> Chaining. Wenn der nächste INT bereits ansteht, kann der PC fast direkt
> damit weitermachen (Register push/pop etc. wird übersprungen)

OK, leider habe ich davon keine Ahnung!


> Wieso bleibst du nach dem Empfang des 1. Bytes nicht in der ISR und
> liest alle Bytes von der Nachricht ein. Zur Sicherheit noch ein Timeout
> (Kein Byte innerhalb der letzten 4µs?) einbauen, damit die ISR auch
> garantiert wieder verlassen wird.

gute Idee, habe ich auch versucht. Nach dem Auslösen des 1. Interrupts 
wollte ich mittels einer for-Schleife alle Bytes in ein Array speichern. 
Leider hat das nicht geklappt. Es wurde das 1. Byte 16x in das Array 
gespeichert!

von Felix F. (wiesel8)


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> OK, leider habe ich davon keine Ahnung!

Musst du auch nicht. Das macht der Controller selber. Wollte es bloß 
erwähnt haben.

har schrieb:
> gute Idee, habe ich auch versucht. Nach dem Auslösen des 1. Interrupts
> wollte ich mittels einer for-Schleife alle Bytes in ein Array speichern.
> Leider hat das nicht geklappt. Es wurde das 1. Byte 16x in das Array
> gespeichert!

Du musst mit dem Auslesen auch warten, bis das nächste Byte kommt (alle 
1,1µs).
Der Controller arbeitet seine Befehle im ns-Bereich ab, dementsprechend 
ist die Schleife durch bis das 2 Byte da ist.

mfg

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
Felix F. schrieb:
> Du musst mit dem Auslesen auch warten, bis das nächste Byte kommt (alle
> 1,1µs).

 Oder entsprechende bits abfragen...

 Sobald DR-Register gelesen wird, wird RXNE Flag automatisch
 zurückgesetzt.
 Danach warten, bis es wieder gesetzt wird oder (falls Zeit abgelaufen
 ist), der Timer-INT feuert.
 16 Mal wiederholen.

: Bearbeitet durch User
von Ruediger A. (Firma: keine) (rac)


Bewertung
0 lesenswert
nicht lesenswert
Marc V. schrieb:
> Felix F. schrieb:
>> Du musst mit dem Auslesen auch warten, bis das nächste Byte kommt (alle
>> 1,1µs).
>
>  Oder entsprechende bits abfragen...
>
>  Sobald DR-Register gelesen wird, wird RXNE Flag automatisch
>  zurückgesetzt.
>  Danach warten, bis es wieder gesetzt wird oder (falls Zeit abgelaufen
>  ist), der Timer-INT feuert.
>  16 Mal wiederholen.

Eher suboptimal, da Pollen im ISR wirklich keinerlei Zeit für 
irgendetwas Anders lässt... bei 72MHz ist ein Taktzyklus 1,38 ns, d.h. 
erst wenn 1000 Zyklen im ISR verbraten werden, steht bei 1,1us das 
nächste Zeichen  wieder an. Ich würde vermutlich eher nach Lesen des 
Zeichens sofort gucken, ob wieder ein Zeichen bereit steht (aber nicht 
durch Lesen des DR, sondern durch Abfragen des Interrupt Status) und 
wenn nicht den ISR verlassen.

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
Ruediger A. schrieb:
> irgendetwas Anders lässt... bei 72MHz ist ein Taktzyklus 1,38 ns, d.h.
> erst wenn 1000 Zyklen im ISR verbraten werden, steht bei 1,1us das
> nächste Zeichen  wieder an.

 Bei mir sind es 13,8ns und 80 Zyklen, aber egal, tut nichts zur Sache.


> Zeichens sofort gucken, ob wieder ein Zeichen bereit steht (aber nicht
> durch Lesen des DR, sondern durch Abfragen des Interrupt Status) und
> wenn nicht den ISR verlassen.

 Nicht DR lesen, sondern RXNE abfragen, etwa so:
1
  while ((USART1->SR & USART_SR_RXNE) == 0);

 Und ISR wird verlassen wenn 16 Zeichen empfangen sind oder wenn
 Timer INT (eingestellt auf 100us z.B.) gefeuert hat.

von Felix F. (wiesel8)


Bewertung
0 lesenswert
nicht lesenswert
Ruediger A. schrieb:
> Marc V. schrieb:
>> Felix F. schrieb:
>>> Du musst mit dem Auslesen auch warten, bis das nächste Byte kommt (alle
>>> 1,1µs).
>>
>>  Oder entsprechende bits abfragen...
>>
>>  Sobald DR-Register gelesen wird, wird RXNE Flag automatisch
>>  zurückgesetzt.
>>  Danach warten, bis es wieder gesetzt wird oder (falls Zeit abgelaufen
>>  ist), der Timer-INT feuert.
>>  16 Mal wiederholen.
>
> Eher suboptimal, da Pollen im ISR wirklich keinerlei Zeit für
> irgendetwas Anders lässt... bei 72MHz ist ein Taktzyklus 1,38 ns, d.h.
> erst wenn 1000 Zyklen im ISR verbraten werden, steht bei 1,1us das
> nächste Zeichen  wieder an. Ich würde vermutlich eher nach Lesen des
> Zeichens sofort gucken, ob wieder ein Zeichen bereit steht (aber nicht
> durch Lesen des DR, sondern durch Abfragen des Interrupt Status) und
> wenn nicht den ISR verlassen.

Das war nur eine mögliche Lösung für sein aktuelles Problem. Ich 
persönlich würde das aber völlig angehen.

Das Problem ist seine ISR, die benötigt angeblich ~3µs. Das sind normal 
knapp 300 Befehle. Für was?? Eine RX-ISR für UART liest bei mir nur das 
empfangen Byte aus und legt es in einen Puffer. Das sollte unter 100 
Zyklen gehen. Dann kann ich auch locker 9MBaud einlesen.

mfg

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
Felix F. schrieb:
> Das Problem ist seine ISR, die benötigt angeblich ~3µs. Das sind normal
> knapp 3000 Befehle. Für was?? Eine RX-ISR für UART liest bei mir nur das

 Nein, 10 Mal weniger. Du rechnest dauernd mit 720MHz, anstatt mit 72.

 P.S.
 Wenn die Zeichen wirklich mit 9Mbit hintereinander ankommen, dann ist
 eher ein verlassen der ISR suboptimal...

von Felix F. (wiesel8)


Bewertung
0 lesenswert
nicht lesenswert
Marc V. schrieb:
> Felix F. schrieb:
>> Das Problem ist seine ISR, die benötigt angeblich ~3µs. Das sind normal
>> knapp 3000 Befehle. Für was?? Eine RX-ISR für UART liest bei mir nur das
>
>  Nein, 10 Mal weniger. Du rechnest dauernd mit 720MHz, anstatt mit 72.
>
>  P.S.
>  Wenn die Zeichen wirklich mit 9Mbit hintereinander ankommen, dann ist
>  eher ein verlassen der ISR suboptimal...

Bin von dem Beitrag vor mir ausgegangen.

Wenn ich aber Daten mit 9MBaud einlese, heißt das, dass ich normal 
ziemlich viel einlese. Von daher würde ich einen schnelleren Controller 
(M4) verwenden. Dann kann ich neben einlesen auch noch was vernünftiges 
mit den Daten anstellen.

mfg

von Jan K. (jan_k)


Bewertung
0 lesenswert
nicht lesenswert
Vielleicht läuft schon eine FSM, um fehlerhafte Pakete wegzuschmeißen?

edit: das war ne Antwort auf Felix Beitrag, geht schnell hier..

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
Felix F. schrieb:
> Wenn ich aber Daten mit 9MBaud einlese, heißt das, dass ich normal
> ziemlich viel einlese.

 Tja, dazu hat sich der TO nicht geäußert.

 Es kann genauso gut sein, dass die Pakete 2 Mal pro Sekunde mit
 9Mbit ankommen...

von Felix F. (wiesel8)


Bewertung
0 lesenswert
nicht lesenswert
Marc V. schrieb:
> Felix F. schrieb:
>> Wenn ich aber Daten mit 9MBaud einlese, heißt das, dass ich normal
>> ziemlich viel einlese.
>
>  Tja, dazu hat sich der TO nicht geäußert.
>
>  Es kann genauso gut sein, dass die Pakete 2 Mal pro Sekunde mit
>  9Mbit ankommen...

Dann bietet es sich umso mehr an, in der ISR die Daten lediglich in 
einen Puffer zu schreiben. Zum bearbeiten hat er dann ja genug Zeit ;)

mfg

von Ruediger A. (Firma: keine) (rac)


Bewertung
0 lesenswert
nicht lesenswert
Marc V. schrieb:
> Ruediger A. schrieb:
>> irgendetwas Anders lässt... bei 72MHz ist ein Taktzyklus 1,38 ns, d.h.
>> erst wenn 1000 Zyklen im ISR verbraten werden, steht bei 1,1us das
>> nächste Zeichen  wieder an.
>
>  Bei mir sind es 13,8ns und 80 Zyklen, aber egal, tut nichts zur Sache.
>

Sorry, hast Recht, Rechenfehler meinerseits. 80 Zyklen sind schnell 
verbraten, vor Allem wenn man mit HALs o.ä. arbeitet. 160 aber auch, und 
damit ist in der Tat die Gefahr, Zeichen durch zu langsames Wegschaffen 
zu verlieren, nicht unbeträchtlich (selbst im ISR). Man braucht nur "zu 
spät" nach Eintreffen des ISR dazu zu kommen, das erste Zeichen 
auszulesen, und dann kann das Zweite schon überschrieben sein.

Ironischerweise ist aber vermutlich der kritische Pfad, der hier einen 
schnelleren Prozessor nahelegen würde, gar nicht so kritisch, denn hier 
sind "nur" 16 byte sehr eng aufeinander. Was der Rest macht, müsste man 
wissen. Wenn es ein konstanter Datenstrom ist, dann ja, schnellerer 
Prozessor indiziert, aber wenn das Ganze ein Master-Slave Protokoll ist, 
bei dem die schnellen 16 byte nur auf (mglw. recht weit 
auseinanderliegende) Pollinganfragen kommen, muss man vielleicht gar 
nicht so schnell laufen, ohne den Gesamtdurchsatz zu gefährden. Das sind 
Systemdesignfragen.

BTW, ein Cortex M4 ist nicht notwendigerweise schneller als ein M3. der 
Kern schreibt keine Taktfrequenz vor. Mglw. hilft aber auch schon ein 
Prozessor mit UART FIFO Support.

Edit: Oops, geht echt schnell hier, Marc und Felix haben auch schon 
teilweise gleichlautend geantwortet...

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
Ruediger A. schrieb:
> bei dem die schnellen 16 byte nur auf (mglw. recht weit
> auseinanderliegende) Pollinganfragen kommen, muss man vielleicht gar
> nicht so schnell laufen, ohne den Gesamtdurchsatz zu gefährden.

 Ja, stimme ich voll zu.
 Aber vielleicht ist es auf der anderen Seite Zeitkritisch, deswegen
 die 9Mb.


> Das sind Systemdesignfragen.

 Genau, da sollte man vielleicht ansetzen und die ganze Sache nochmal
 durchdenken.

von har (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Danke euch allen für die zahlreichen Tipps!


Zu meinem Problem (warum nie in den DMA Interrupt Handler gesprungen 
wird) hat mir folgender Hinweis geholfen:

Christoph S. schrieb:
> DMA_InitStruct.DMA_MemoryBaseAddr = receive[0]; //(uint8_t)&receive[0];
> Das stimmt nicht, auch das auskommentierte nicht.
>
> Du musst die Adresse des ersten Byte im Array angeben.
> "receive[0]" ist nur der Wert im ersten Array element.
> Du brauchst den Pointer, also entweder "&receive[0]" oder einfach
> "receive".
>
> Speicheradressen sind beim Cortex-M 32bit breit, um die Compiler-Warnung
> wegzubekommen musst du also zu uint32_t casten.
> Wenn du zu uint8_t castest (wie im Kommentar) schneidest du die oberen
> 24bit der Adresse weg.
>
> Also entwederDMA_InitStruct.DMA_MemoryBaseAddr =
> (uint32_t)receive;oderDMA_InitStruct.DMA_MemoryBaseAddr =
> (uint32_t)&receive[0];

Als ich das ausgebessert habe, funktioniert jetzt das Empfangen mittels 
DMA! Danke!!

Aber leider noch nicht perfekt, denn:
In das erste Array (receive[0]) wird nichts geschriebren (es bleibt 0). 
Das erste empfangene Byte wird in receive[1] geschrieben. Dadurch geht 
mein letztes Byte verloren (da das Array zu Ende ist).
Welche Kleinigkeit in meiner Konfiguration müsste ich ändern, damit das 
erste Byte in das erste Element (receive[0]) geschrieben wird?

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> Welche Kleinigkeit in meiner Konfiguration müsste ich ändern, damit das
> erste Byte in das erste Element (receive[0]) geschrieben wird?
1
   receive[0] = DMA1_Channel3->CMAR;

 Ich kenne das anders rum...

 P.S.
 Abgesehen davon, wieder der Inhalt und nicht die Adresse...

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> Ursprünglich habe ich das Empfangen ohne DMA durchgeführt.
> Nun habe ich aber die Anforderung, dass die Kommunikation mit 9MBaud
> erfolgen soll.

Da fragt man sich eher, wer oder was da nicht richtig tickt.
Erstens: über einen UART mit 9 MBaud übertragen zu wollen.
Zweitens: wer da auf solche Idee gekommen ist
Drittens: wann denn die nötige Auswertung dieser Daten erfolgen soll, 
wenn schon die ISR zum schieren Empfangen zu langsam ist

Mir sieht das eher nach einer Sportübung aus als nach einem durchdachten 
soliden Systementwurf. Also, was soll das ganze überhaupt werden? Nur zu 
sagen "Ich habe die Anforderung.." ist ein bissel arg wenig.

W.S.

von Felix F. (wiesel8)


Bewertung
0 lesenswert
nicht lesenswert
Das ganze erinnert mich eher an Flexray (10MBit), wo (fast) alles durch 
einen extra Baustein erledigt wird.

mfg

von har (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Liebes Forum,

wie bereits erwähnt, funktioniert nun das Empfangen mittels DMA. Nur das 
folgende Problem ist noch vorhanden:
In das erste Array (receive[0]) wird nichts geschriebren (es bleibt 0).
Das erste empfangene Byte wird erst in receive[1] geschrieben.

Wenn ich statt:
1
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&receive[0];

folgendes schreibe:
1
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&receive[-1];

dann wird wiederum das erste Byte in receive[0] geschrieben.
Es wird mittels UART1 gesendet und mit UART3 empfangen.


ABER: Wenn ich mit UART3 sende UND empfange, dann passt die Einstellung:
1
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&receive[0];

Die Konfiguration ist aber die selbe.

Warum fängt das speichern der Bytes im ersten Fall verzögert an? Zum 
Verbinden des TX und RX Pin verwende ich in beiden Fällen ein kurzes 
Kabel...

von aSma>> (Gast)


Bewertung
0 lesenswert
nicht lesenswert
har schrieb:
> Warum fängt das speichern der Bytes im ersten Fall verzögert an? Zum
> Verbinden des TX und RX Pin verwende ich in beiden Fällen ein kurzes
> Kabel...

Hat man dir schon mal gesagt: Dein Konzept ist Kacke.

Oftmals wird ein byte z.B. bei der Initialisierung losgeschickt. Schon 
bricht deine Welt zusammen und du versuchst dieses Missgeschickt mit 
einer "-1" zu retten.

W.S. schrieb:
> Da fragt man sich eher, wer oder was da nicht richtig tickt.
> Erstens: über einen UART mit 9 MBaud übertragen zu wollen.
> Zweitens: wer da auf solche Idee gekommen ist
> Drittens: wann denn die nötige Auswertung dieser Daten erfolgen soll,
> wenn schon die ISR zum schieren Empfangen zu langsam ist

Wenn du schon Hilfe erwartest, dann wäre es respektvollerweise nicht 
schlecht mal auf die gestellten Fragen zu antworten.


Übrigens du brauchst ein Ringbuffer mit Protokoll. ST hat eine Appnote 
zu DMA und uart.

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]
  • [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.