Forum: Mikrocontroller und Digitale Elektronik AVR32 UC3A1512 USART1 TXEMPTY Interrupt Problem


von Billy _. (slowflyer)


Lesenswert?

Hallo,

ich hab da ein Problem mit dem TXEMPTY Interrupt des UC3A1512 (AVR32).

Ich möchte auf einer Leitung senden und empfangen, dafür schalte ich den 
Transmitter zum Senden an und für den Empfang ab (Master Slave 
Kommunikation). Um einen Datenblock zu senden verwende ich den TXRDY 
Interrupt (was wunderbar funktioniert) zum Abschalten des Transmitters 
hätte ich gerne den TXEMPTY Interrupt verwendet um den Sender 
abzuschalten und auf Empfang zu schalten. In der Theorie sollte das 
gehen (bereits in einem AVR realisiert) doch nun zur Praxis:

TXEMPTY Interrupt ist aktiviert und in der ISR behandelt. Das Problem 
ist: die Stelle in  der ISR , die dafür vorgesehen ist (siehe Pfeil in 
der ISR), wird nicht angesprungen. Warum?

hier ein paar Codeteile:

Initialisierung:
1
init_usart1()
2
{
3
static const gpio_map_t USART1_GPIO_MAP =
4
  {
5
    {USART1_RX_PIN, USART1_RX_FUNCTION},
6
    {USART1_TX_PIN, USART1_TX_FUNCTION}
7
  };
8
  
9
  // Options for debug USART.
10
  usart_options_t USART1_options =
11
  {
12
    .baudrate = USART1_BAUDRATE,
13
    .charlength = 8,
14
    .paritytype = USART_NO_PARITY,
15
    .stopbits = USART_1_STOPBIT,
16
    .channelmode = USART_NORMAL_CHMODE
17
  };
18
19
  // Setup GPIO
20
  gpio_enable_module(USART1_GPIO_MAP, sizeof(USART1_GPIO_MAP) / sizeof(USART1_GPIO_MAP[0]));
21
  
22
  
23
  // Initialize it in RS232 mode.
24
  usart_init_rs232(USART1, &USART1_options, FPBA);
25
  USART1->cr = AVR32_USART_CR_RXEN_MASK|AVR32_USART_CR_TXDIS_MASK;
26
  
27
  // Init interrupt and timeout
28
  INTC_register_interrupt(&USART1_isr, AVR32_USART2_IRQ, AVR32_INTC_INT1);
29
  USART1->ier = AVR32_USART_IER_RXRDY_MASK|AVR32_USART_IER_TXRDY_MASK|AVR32_USART_IER_TIMEOUT_MASK|AVR32_USART_IER_TXEMPTY_MASK;
30
  USART1->rtor = 50;
31
  USART1->ttgr = 1;

ISR:
1
__attribute__((__interrupt__)) void USART1_isr( void )
2
{
3
4
  unsigned char cs = 0;
5
  int rx_char = 0, i;
6
  
7
  if (USART1->csr & AVR32_USART_CSR_TIMEOUT_MASK)
8
  {
9
    USART1->cr |= AVR32_USART_CR_STTTO_MASK;
10
    
11
    //TODO empfang
12
13
    // disable receiver
14
    USART1->idr = AVR32_USART_IDR_RXRDY_MASK;
15
  }
16
  else if (USART1->csr & AVR32_USART_CSR_TXRDY_MASK)
17
  {
18
    if (tx_ptr < length) 
19
    {
20
      USART1->thr = (tx_buffer[tx_ptr++] << AVR32_USART_THR_TXCHR_OFFSET) & AVR32_USART_THR_TXCHR_MASK;
21
    }
22
  }
23
  else if (USART1->csr & AVR32_USART_CSR_TXEMPTY_MASK)
24
  {
25
    // disable transmitter
26
-->    USART1->cr = AVR32_USART_CR_TXDIS_MASK;
27
  }
28
  else if (USART1->csr & AVR32_USART_CSR_RXRDY_MASK)
29
  {
30
    if ( usart_read_char(USART1, &rx_char) == USART_SUCCESS)
31
    {
32
        rx_buffer[rx_ptr++] = (char) rx_char;
33
    }
34
  }
35
}

Hat jemand eine Idee oder Hinweis woran es scheitert?

Gruß Willi

von Gast (Gast)


Lesenswert?

Den Prozessor kenne ich nur vom oberflächlichen Lesen des Datenblattes. 
Was mich zunächst wundert: gibt es nur einen Interruptvector für USART1? 
Keinen für Rx1, Tx1 und TxEmpty1?

Egal.
Stimmt der Wert von AVR32_USART_CSR_TXEMPTY_MASK? Hast Du die Abfrage 
auf TxE mal ganz an den Anfang der Int-Routine gestellt? Wird das 
enable-Bit vielleicht irgendwo gelöscht? Sind Lesezugriffe auf 
USART1->csr vielleicht destruktiv? Könntest Du TxE explizit noch einmal 
aktivieren, wenn der Puffer der zu sendenen Zeichen leer ist (tx_ptr >= 
length)?

von Billy _. (slowflyer)


Lesenswert?

Gast wrote:
> Was mich zunächst wundert: gibt es nur einen Interruptvector für USART1?
> Keinen für Rx1, Tx1 und TxEmpty1?

Genau so ist es (werden durch Abfragen des CSR in der ISR unterschieden)

> Stimmt der Wert von AVR32_USART_CSR_TXEMPTY_MASK?

Stimmt (als 0x00000200 definiert in der Header-Datei), vgl. Datenblatt

> Hast Du die Abfrage
> auf TxE mal ganz an den Anfang der Int-Routine gestellt? Wird das
> enable-Bit vielleicht irgendwo gelöscht? Sind Lesezugriffe auf
> USART1->csr vielleicht destruktiv?

Das glaub ich weniger, denn sonst würde der Empfangs-Interrupt auch nie 
durchkommen (am Ende).

> Könntest Du TxE explizit noch einmal
> aktivieren, wenn der Puffer der zu sendenen Zeichen leer ist (tx_ptr >=
> length)?

Auch schon probiert, leider ohne Erfolg

Ich seh schon, wird eine harte Nuss...

von Gast (Gast)


Lesenswert?

>Das glaub ich weniger, ...

Ich glaube an nichts und mache es daher trotzdem.

Ein weiter Schritt wäre, am Anfang gleich mit:

unsigned long csr_temp = USART1->csr;

den aktuellen Wert zu retten und mit diesem die Vergleiche 
durchzuführen. Da Du offensichtlich keine großen Möglichkeiten zur 
Fehlersuche hast, könntest Du auch an einem Ausgang eine LED aktivieren, 
sobald ein TxEmpty-Zustand erkannt wird (nicht wieder löschen!). Damit 
könnte festgestellt werden, ob jemals das Bit überhaupt gesetzt wurde.

....

von Sab (Gast)


Lesenswert?

"RS485 AVR32* "
Der mode ist z.B für RS458
Google mal mit dem stichwort RS485 AVR32.
Aber im Google "CodeSearch".
Da sind die Code Beispiele für diesen Mode drin.
Die IRQ Vectoren ca 10 Stück.

von Sab (Gast)


Lesenswert?

So solten die Suchergebnisse dan kommen.
Du soltest das z.B auf RS485 einstellen.
Um das z.B Transmit Register Empty zu bekommen.
/*---------------------------------------------------------------------- 
-----+
 | 
|
 |                         TRANSMIT/RECEIVE FUNCTIONS         |
 | 
|
 +----------------------------------------------------------------------- 
----*/

/**
 * Description: While in RS485-mode, receviers only accept data 
addressed to them.
 *              A packet/char with the address tag set has to preceed 
any data.
 *              usart_send_addr() is used to address a receiver. This 
receiver should read
 *              all the following data, until an address packet 
addresses someone else.
 * Arguments:   *usart:  Base address of the usart
 *              addr: the address of the target device
 * Returns:     USART_SUCCESS if the current mode is RS485
 *              USART_MODE_FAULT if called while in wrong mode
 */
int usart_send_addr(volatile struct avr32_usart_t * usart, int addr);


/*!
 * If the transmitter is ready; write the given character to the TX 
buffer
 * 'param *usart  Base address of the usart
 * 'param c       The character (up to 9 bits) to transmit
 * 'return        USART_SUCCESS when the transmitter is ready
 *                USART_TX_BUSY when the transmitter is busy
 */

von Gast (Gast)


Lesenswert?

@Sab

Deinem Vorschlag folgend, habe ich versucht über die Suchmaschine etwas 
in Erfahrung zu bringen: ohne Erfolg.
Hast Du vielleicht eine Quelle beim Hersteller, wo man die erwähnten 
"IRQ Vectoren ca 10 Stück" dokumentiert hat. Im Datenblatt des 
AT32UC3A... scheinen sie nicht aufgeführt zu sein.

von Billy _. (slowflyer)


Lesenswert?

Hab jetzt mal folgendes ausprobiert:

- hab die if else if else Verschachtelungen in der ISR in ganz normale 
if if if aufgebrochen

- CSR habe ich in eine Variable eingelesen und diese auf die Int-Flags 
geprüft (falls das Lesen destruktiv wirkt)

Und siehe da! Es geht juhu!!!

Welche von beiden Maßnahmen nun geholfen hat, weiss ich nicht (evtl. 
sogar beide). Hab jetzt auch kaum Zeit um es herauszufinden. Mal sehen 
vielleicht mal in einer etwas ruhigeren Minute. Im Moment bin ich 
einfach nur froh, dass es tut.

Danke für die Hinweise, ich hätt mir sonst einen Wolf gesucht

Gruß Willi

von Gast (Gast)


Lesenswert?

Habe Deine Erfolgsmeldung erst heute gelesen - nun ist ja gut!
Ich tippe ja auf das destruktive Lesen des Status. Was mich aber nach 
wie vor irritiert, daß es nur einen Interruptvektor für die USART gibt. 
Das erinnert doch sehr an 8051 & Co.

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.