Forum: Mikrocontroller und Digitale Elektronik AVR32 PDCA USART Problem


von wolfi (Gast)


Lesenswert?

Hi,

ich programmiere mit einem AT32UC3A1512 und nutze das ATMEL AVR 
Softwareframework. Mein Problem ist folgendes, ich will ein DMX Signal 
(512 Byte Länge + 1 Startbyte ) empfangen und dieses manipuliert 
wiedergeben. Hierfür nutze ich den PDCA und USART1.

Hier die Initialisierung der USART:


  // USART options.
  usart_options_t USART_OPTIONS =
  {
    .baudrate     = 250000uL,
    .charlength   = 8,
    .paritytype   = USART_NO_PARITY,
    .stopbits     = USART_2_STOPBITS,
    .channelmode  = USART_NORMAL_CHMODE
  };




  portENTER_CRITICAL();
  {
    // first byte is reserved for the pdca
    CurrentDmxFrame_u8p = &TxChannels_u8[ 0 ][ 1 ];
    NextDmxFrame_u8p = &TxChannels_u8[ 1 ][ 1 ];

    CurrentReceiveFrame_u8p = &RxChannels_u8[ 0 ][ 0 ];
    IdleReceivingFrame_u8p = &RxChannels_u8[ 1 ][ 0 ];
    FinishedReceiveFrame_u8p = &RxChannels_u8[ 2 ][ 0 ];
    IdleReceivedFrame_u8p = &RxChannels_u8[ 3 ][ 0 ];

    DmxInitPdca_v();

    // Configure USART.
    //
    // Enable USART RXD & TXD pins.
    if(UsartId == serCOM1)
    {
      xUsart = &AVR32_USART0;
      gpio_enable_module_pin(AVR32_USART0_RXD_0_0_PIN, 
AVR32_USART0_RXD_0_0_FUNCTION);
      gpio_enable_module_pin(AVR32_USART0_TXD_0_0_PIN, 
AVR32_USART0_TXD_0_0_FUNCTION);
      Irq_u32 = AVR32_USART0_IRQ;
    }
    else
    {
      xUsart = &AVR32_USART1;
      gpio_enable_module_pin(AVR32_USART1_RXD_0_0_PIN, 
AVR32_USART1_RXD_0_0_FUNCTION);
      gpio_enable_module_pin(AVR32_USART1_TXD_0_0_PIN, 
AVR32_USART1_TXD_0_0_FUNCTION);
      Irq_u32 = AVR32_USART1_IRQ;
    }

    // Initialize USART in RS232 mode.
    usart_init_rs232(xUsart, &USART_OPTIONS, CP_PBA_SPEED);

    // We're not fully done yet: disable receiver and transmitter.
    xUsart->cr  |= AVR32_USART_CR_RXDIS_MASK | 
AVR32_USART_CR_TXDIS_MASK;

    // Register the USART interrupt handler to the interrupt controller 
and
    // enable the USART interrupt.
    INTC_register_interrupt((__int_handler)&vUSART_ISR, Irq_u32, 
AVR32_INTC_INT1);

    // Enable USART interrupt sources (but not Tx for now)...
    // xUsart->ier = AVR32_USART_IER_RXRDY_MASK | 
AVR32_USART_IER_RXBRK_MASK;
    xUsart->ier = AVR32_USART_IER_RXBRK_MASK;

    // Enable receiver and transmitter...
    xUsart->cr |= AVR32_USART_CR_RXEN_MASK | AVR32_USART_CR_TXEN_MASK;
  }
  portEXIT_CRITICAL();

Wie man sieht, benutz ich für den Empfang 4 Buffer, welche jeweils ein 
komplettes Frame halten können. Grund dafür ist, ich dachte das Senden 
und Empfang auf dem gleichen Speicherbereich könnte problematisch 
werden, darum ein "Ringbuffer" der immer ein Frame zwischen den 
aktuellen Schreib bzw. Lesebuffer hält.


Hier die Initialisierung für den RX PDCA:

  // PDCA channel options for RX and receiving the start byte
  const pdca_channel_options_t pdca_options_0 =
  {
    .addr   = 0,                                // memory address
    .pid    = AVR32_PDCA_PID_USART1_RX,         // select peripheral - 
data are transmit on USART RX line.
    .size   = 0,                                // transfer counter
    .r_addr = 0,                                // next memory address
    .r_size = 0,                                // next transfer counter
    .mode   = PDCA_MODE_BYTE,                   // select size of the 
transfer
  };

  pdca_init_channel( DMX_PDCA_CHANNEL_RX, &pdca_options_0 );
  INTC_register_interrupt((__int_handler)&pdca_int_handler_rx, 
AVR32_PDCA_IRQ_0, AVR32_INTC_INT1);

Allerdings aktiviere ich für den RX PDCA kein Interrupt, da ich die 
Überprüfung des empfangenen Frames und zusätzlich die Synchronsation des 
Frames im RXBRK machen wollte. Es klappt eigentlich auch ganz gut, 
allerdings hab ich manchmal ein Glitch drinnen, d.h. das erste Datenbyte 
stehen manchmal auf der 1. Position im Buffer oder manchmal auch im 2. 
Dass ich mit dieser Sequenz auch in den im ERRATA Beschriebenen Fall 
komme (kein TTGR gesetzt und ich deswegen ein BRK mehr bekomme, ist mir 
bewusst, wird auch ausgeblendet).


Hier der Bereich der ISR, die den Receive Break behandelt:


  // received BREAK
  if( ulStatus & AVR32_USART_IER_RXBRK_MASK )
  {
    if( ValidBreak_u8 == FALSE )
    {
      ValidBreak_u8 = TRUE;
      return ( retVal );
    }
    else
    {
      ValidBreak_u8 = FALSE;
    }

    portENTER_CRITICAL();
    {
      Temp_u8p = FinishedReceiveFrame_u8p;
      FinishedReceiveFrame_u8p = IdleReceivedFrame_u8p;
      IdleReceivedFrame_u8p = CurrentReceiveFrame_u8p;
      CurrentReceiveFrame_u8p = IdleReceivingFrame_u8p;
      IdleReceivingFrame_u8p = Temp_u8p;

      pdca_load_channel( DMX_PDCA_CHANNEL_RX, CurrentReceiveFrame_u8p, 
514 );
      pdca_enable( DMX_PDCA_CHANNEL_RX );
    }
    portEXIT_CRITICAL();
  }


andere Interrupts wurden für diesen Bereich deaktiviert. Setze ich nun 
die Timeguard auf 1, ist dieser Effekt (wechselnde Position des 1. 
Datenbytes im Buffer) auf ein Minimum reduziert, allerdings ist dann das 
Verhalten so träge, dass es für meinen Einsatzzweck nicht ausreicht. 
Jetzt hab ich die Frage, mache ich noch etwas falsch oder hat jmd. noch 
eine Idee?

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.