Forum: Mikrocontroller und Digitale Elektronik TxD buffer beim ATXMega32E5 mehr als ein Byte?


von Thomas L. (delfinis)


Angehängte Dateien:

Lesenswert?

Hallo,
will mit dem uC ATXMega32E5 ein paar byte senden und dann wieder den uC 
schlafen legen bis zum nächsten mal.
Nun wurden die Daten nicht richtig übermittelt. Eine Untersuchung hat 
dann ergeben, dass die Daten noch nicht gesendet wurden, wenn ich den uC 
schlafen gelegt habe.
Zum Test hab ich dann halt mal ein delay eingelegt und dann giengs.
Hab dann einen Ausgang zur Kontrolle eingeschaltet vom senden des ersten 
Bytes bis das Flag TXCIF gelöscht wird.
Erstaunlicherweise wird dieses Flag schon gelöscht, drei Byte bevor die 
Daten ganz übertragen worden sind!?
Dabei ist es egal, wieviele Bytes übertragen werden, immer drei Byte 
bevor die letzten bit gesendet wurden, wird das TXCIF-Bit gelöscht.
Siehe Bilder (erstes Signal: PD5, zweites Signal TxD)
Dabei heisst es doch beim TXCIF im Datenblatt (XMEGA-E Series):

"Bit 6 – TXCIF: Transmit Complete Interrupt Flag
This flag is set when the entire frame in the Transmit Shift Register 
has been shifted out and there are no new data
in the transmit buffer (DATA). The TXCIF is automatically cleared when 
the transmit complete interrupt vector is
executed. The flag can also be cleared by writing a one to its bit 
location."

Und USART_TXCIF_bm ist wirklich eine Bitmaske mit dem 6.bit.
Ist da noch ein versteckter Buffer???

Oder darf ich diese flags nicht verwenden, wenn ich nicht die Interrupts 
nicht eingeschalten hab?
1
int main(void) {
2
  
3
#define USART_TXCIF_bm  0x40 /* Transmit Complete Interrupt Flag bit mask. */
4
5
  ...
6
7
  while (1) {
8
    PORTD.OUTSET = 0x20;
9
    putByte('T');
10
    putByte('U');
11
    putByte('V');
12
    putByte('W');
13
    putByte('X');
14
    while( !(USARTC0_STATUS & USART_TXCIF_bm) );//Wait until DATA is sendt
15
    PORTD.OUTCLR = 0x20;
16
    my_delay250kHz((uint16_t)10, 0, 0); // wait 10ms
17
    set_sleep_mode(SLEEP_MODE_PWR_SAVE);
18
    sleep_mode();
19
  }
20
21
  void putByte(uint8_t data) {
22
    // Wait until data buffer is empty before putting character to send buffer
23
    while( !(USARTC0_STATUS & USART_DREIF_bm) ); //Wait until DATA is empty
24
    USARTC0_DATA = data;
25
  }
26
27
}

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

> The flag can also be cleared by writing a one to its bit location.

Ebendies würde ich versuchen/machen unmittelbar vor
> while( !(USARTC0_STATUS & USART_TXCIF_bm) );//Wait until DATA is sent

von Thomas L. (delfinis)


Lesenswert?

Vielen Dank für die schnelle Antwort.
Ja, mit dem Löschen dieses Bits funktioniert es.
Logisch, muss man natürlich machen, wenn man es jeweils neu abfragen 
will. Komisch ist nur dass das Flag 3 Byte vor Ende schon gesetzt ist, 
respektive wenn es schon gesetzt war, dann bin ich ja schon drei Byte 
vor dem Ende fertig mit warten auf das Senden des letzten Bytes..
Na egal, es funktionert jedenfalls.
Danke

: Bearbeitet durch User
von Georg G. (df2au)


Lesenswert?

Thomas L. schrieb:
> Komisch ist nur dass das Flag 3 Byte vor Ende schon gesetzt ist

Das Bit wird nach jedem gesendeten Byte gesetzt.

von S. Landolt (Gast)


Lesenswert?

> Komisch ist nur ...
Wenn es bereits gesetzt war, gibt es ja nichts, wodurch es zurückgesetzt 
wird. Also wird dann nur noch auf die Freigabe im putByte gewartet.

von Bastian W. (jackfrost)


Lesenswert?

Du kannst auch den DMA nutzen und wenn der Fertig ist den Controller 
schlafenlegen.

Wenn du willst kann ich dir Ende der Woche ein paar Zeilen Posten wie 
ich das mit dem dem DMA auf dem AtxMega32e5 für meinen Wassersensor 
gemacht habe.

Gruß JackFrost

von Gerhard G. (xmega)


Lesenswert?

Hallo,

würde mich interessieren wie du das mit dem DMA in den Griff bekommst.

Gruß GG

von Falk B. (falk)


Lesenswert?

@Georg G. (df2au)

>> Komisch ist nur dass das Flag 3 Byte vor Ende schon gesetzt ist

>Das Bit wird nach jedem gesendeten Byte gesetzt.

Falsch! Nur dann, wenn in dem Moment der Sendepuffer leer ist und damit 
kein neues Byte gesendet werden kann. Steht auch so in der Doku und im 
Originalbeitrag!

von Bastian W. (jackfrost)


Lesenswert?

Hi,

für den xMega32E5 in meinem Wasserzähler( 
https://github.com/JackFrost80/Wasserzaehler-CAN-Modul ) habe ich die 
Daten per DMA an den USART D0 gesendet , damit die CPU hier nicht so 
viel zu tun hat.
1
#define DMA_TX_ESP_CHANNEL  EDMA.CH2
2
#define USART_Netzwerk  USARTD0
3
4
char send_buffer[96] = {0};
5
const void * tx_buffer_Pointer = &send_buffer[0];
6
volatile bool send = true;
7
8
ISR(EDMA_CH2_vect, ISR_BLOCK)  //die ISR ist sehr wichtig !!!
9
{
10
  //PORTE.OUTTGL = PIN2_bm;
11
  DMA_TX_ESP_CHANNEL.TRFCNT = 0;
12
  DMA_TX_ESP_CHANNEL.CTRLA &= ~EDMA_CH_ENABLE_bm;  // this shouldn't be necessary
13
  DMA_TX_ESP_CHANNEL.CTRLB |= (EDMA_CH_TRNIF_bm | EDMA_CH_ERRIF_bm);
14
  memset(send_buffer, '\0', sizeof(send_buffer));
15
        send = true;
16
}
17
18
void DMA_TX_ESP_init()  // DMA vorbereiten der Trigger ist hier auf D0 gelegt.
19
{
20
  // reset source address
21
  DMA_TX_ESP_CHANNEL.ADDRL = 0;
22
  DMA_TX_ESP_CHANNEL.ADDRH = 0;
23
24
  // set up destination address nicht nötig im Peripheral mode
25
  //DMA_TX_ESP_CHANNEL.DESTADDRL = (((uint16_t) &USART_Netzwerk.DATA) >> 0) & 0xff;
26
  //DMA_TX_ESP_CHANNEL.DESTADDRH = (((uint16_t) &USART_Netzwerk.DATA) >> 8) & 0xff;
27
  
28
  DMA_TX_ESP_CHANNEL.ADDRCTRL |= EDMA_CH_DIR_INC_gc;        // increment source address during transfer
29
  DMA_TX_ESP_CHANNEL.ADDRCTRL |= EDMA_CH_DESTRELOAD_NONE_gc;      // destination address does not need to be reloaded
30
  DMA_TX_ESP_CHANNEL.ADDRCTRL |= EDMA_CH_DESTDIR_INC_gc;        // Memory address incremented
31
32
  DMA_TX_ESP_CHANNEL.TRIGSRC = EDMA_CH_TRIGSRC_USARTD0_DRE_gc;      // automatically trigger a new burst when UARTD0 is ready
33
  DMA_TX_ESP_CHANNEL.TRFCNT = 0;                    // reset block size
34
  DMA_TX_ESP_CHANNEL.CTRLA = EDMA_CH_SINGLE_bm;            // single shot mode (i.e. one burst transfer per trigger event)
35
  DMA_TX_ESP_CHANNEL.CTRLB |= EDMA_CH_TRNINTLVL_HI_gc;
36
}
37
38
void main(void)
39
{ 
40
      EDMA.CTRL |= EDMA_ENABLE_bm;  
41
      PMIC.CTRL |= PMIC_HILVLEN_bm |      PMIC_MEDLVLEN_bm | PMIC_LOLVLEN_bm;
42
      sei();
43
      while(1)
44
      {
45
         if(send)
46
         {
47
           DMA_TX_ESP_CHANNEL.ADDRL = ((uint16_t)tx_buffer_Pointer >> 0) & 0xff;
48
           DMA_TX_ESP_CHANNEL.ADDRH = ((uint16_t)tx_buffer_Pointer >> 8) & 0xff;
49
           DMA_TX_ESP_CHANNEL.TRFCNT = strlen (send_buffer);
50
           DMA_TX_ESP_CHANNEL.CTRLA |= EDMA_CH_ENABLE_bm;
51
           send = false;
52
         }
53
     }
54
}

Damit kannst du den Inhalt vom send_buffer an die USART sende. Wenn der 
dann leer ist wird die DMA ISR ausgelöst. In der könntest du dann das 
Flag für den sleep setzen und dann in der Main in den sleep gehen.

Gruß JackFrost

: Bearbeitet durch User
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.