Forum: Mikrocontroller und Digitale Elektronik [AT91SAM] IRQ-getriebener DMA-Transfer auf UART führt zu Absturz


von Paule (Gast)


Lesenswert?

Hallo Mikros!

UART 1-Kanal ist per DMA angebunden zum Empfangen (RX) und Senden (TX) 
zum PC-Terminalprogramm (Baudrate 57600).

Beim Empfang eines Bytes wird dieses verarbeitet und sofort 
zurückgesandt (echo). Das Verarbeiten ist sehr fix und wird innerhalb 
der IRQ-Routine erledigt, die vom beendeten DMA-Transfer ausgelöst wird. 
(siehe UART1_irqHandler()).

Versuche ich nun, das eben empfangene Byte zurückzusenden 
(UART1_sendCharacter()), scheint irgendwas im Mikro schief zu laufen 
(sieht so aus, als ob ein Reset folgt ... bin mir unsicher). Auf jeden 
Fall reagiert danach der UART 1 nicht mehr (und einige andere Dinge auch 
nicht).

Vermutung:
Aus einer Interrupt-Routine (RX-Zweig) wird Senden ausgeführt, welches 
so fix fertig ist, dass noch während des Sendens ein weiterer Interrupt 
ausgelöst wird (TX).

Kann mit jmd bei der Deutung ein paar Tipps geben?

Danke fürs Lesen,
Paule

PS: Hier der Code-Schnippsel.
1
/** Connection baud rate. */
2
#define    BAUDRATE    57600
3
4
/** Debug input (RX) buffer. */
5
char    inBuffer[4];
6
/** Debug output (TX) buffer. */
7
char    outBuffer[128];
8
9
/**
10
 * Sends a single character to device connected on UART 1.
11
 *
12
 * Blocks, if sending of previous buffer is in progress.
13
 *
14
 * @param[in]  character    single character to send
15
 */
16
void     UART1_sendCharacter(
17
    const char      character){
18
19
  /* wait until former communication ends */
20
  USART1_waitForEndTx();
21
22
  /* make local copy of value */
23
  outBuffer[0] = character;
24
25
  AT91C_BASE_US1->US_TCR  = 1;
26
  AT91C_BASE_US1->US_PTCR = AT91C_PDC_TXTEN;
27
}
28
29
/**
30
 * IRQ handler for incoming (RX) and outgoing (TX) UART 1 communication.
31
 *
32
 * Incoming signals are sent byte-wise to user command unit.
33
 */
34
void    UART1_irqHandler() {
35
36
  if ((AT91C_BASE_US1->US_CSR & AT91C_US_ENDRX) == AT91C_US_ENDRX) {      /* reception done interrupt (ENDRX) */
37
38
    AT91C_BASE_US1->US_RCR = 1;            /* restore the receive count - clears ENDRX flag */
39
    AT91C_BASE_US1->US_RPR = (AT91_REG)inBuffer;  /* address of DMA input buffer */
40
41
    USERCMD_addCharacterToCommand(inBuffer[0]);    /* try to add character to user command input buffer */
42
    
43
    UART1_sendCharacter(inBuffer[0]);        // <<<<<---- crashes
44
    
45
46
  } else if ((AT91C_BASE_US1->US_CSR & AT91C_US_ENDTX) == AT91C_US_ENDTX) {  /* transmission done interrupt (ENDTX) */
47
48
    AT91C_BASE_US1->US_PTCR = AT91C_PDC_TXTDIS;
49
    AT91C_BASE_US1->US_TCR = 1;            /* restore the transmit count - clears ENDTX flag */
50
    AT91C_BASE_US1->US_TPR = (AT91_REG)outBuffer;  /* address of DMA output buffer */
51
52
  }
53
}
von Gost (Gast)


Lesenswert?

Hallo,

ich denke da fehlt noch was in der UART1_sendCharacter. Vorschlag:

AT91C_BASE_US1->US_TCR  = 1;
AT91C_BASE_US1->US_TPR  = (AT91_REG)outBuffer;
AT91C_BASE_US1->US_PTCR = AT91C_PDC_TXTEN;

Damit wäre die DMA Adresse des Buffers nicht mehr NULL wenn zum ersten 
mal zurück gesendet werden soll und noch kein TX-Ready IRQ kam.

Gruß Micoman
von Paule (Gast)


Lesenswert?

Hallo Micoman,

mein Fehler: Die Initialisierung des Buffers wird in einer anderen 
Methode einmalig vorgenommen. Danach soll das die IRQ-Routine 
übernehmen.
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.