TxD buffer beim ATXMega32E5 mehr als ein Byte?

OP #5238635
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
}
Angehängte Dateien:
Gast
> 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
OP
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
Gast
> 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.
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
@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!
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

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 8 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.