PDCA for uc3a1256 using USART?

Go To Last Post
25 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all...I have a situation where I am going to be receiving burst mode strings from a sensor device (in ascii) via usart port.

I am thinking of PDCA option....the thing is I have never used the PDCA interface....still learning. Do you recommend using it or should I just do a interrupt driven USART interface?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

the thing is the incoming strings arent same length all the time...so sounds like PDCA is not good?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I got transmit working using PDCA...as I know the length of buffer before I transmit...
might just use interrupt for receive...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi luvocean1

PDCA is the way to go.

You should plan to interrupt on two events, buffer full, which is part of the PDCA system, and USART receive idle, which is part of the USART system. The first is fairly simple, the second you need to set the idle timeout (using RTOR register for the USART).

Have code for both if you need it.

Regards.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh I didnt know about the idle timeout register for usart...I will read up the datasheet on that then.

In terms of buffer full, you mean to raise the interrupt when the counter reaches zero? This is for receive data we are talking about?

For transmit data I am using the address counter reach zero to raise interrupt once the desired number of bytes have been transmitted. And inside the interrupt then I disable the interrupt and I also reset the address pointer to the start of the buffer. This interrupt is enabled later again whenever a certain number of char is desired to be sent. I am not using the reload address pointer or the reload counter at all..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The buffer full interrupt needs to be enabled, and then when you set up the receive buffer you specify the size as part of the structure used. The PDCA then keeps track, and if it receives that amount of data (having placed it in the memory pointed to), it then fires the interrupt to signal that the data needs to be read.

For TX, what your doing sounds correct.

(I use this system for sending and receiving data from a modem, which has variable length packets and timing.)

Regards.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok I have run into problems now...
I initialize my uart with the following: (only showing last few step) in the init function...

USART2->rtor = USART2_RX_TIMEOUT;
// Enable USART Rx interrupt.
USART2->ier = AVR32_USART_IER_RXRDY_MASK | 
	      AVR32_USART_IER_TIMEOUT_MASK;

and then in the interrupt handler:

static void DebugPortIntHandler(void)
{
  int c;	
  if(USART2->csr & AVR32_USART_CSR_RXRDY_MASK)
  {
     usart_read_char(USART2, &c);
     usart_putchar(USART2, c);
     USART2->cr |= AVR32_USART_CR_STTTO_MASK;	
  }
  else if(USART2->csr & AVR32_USART_CSR_TIMEOUT_MASK)
  {
     //this part does not seem to be firing!
  }

in the interrupt handler the first part, of reading and printing the char back is working...but the 2nd part where I catch the timeout is never firing. :(

any thoughts?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

my USART2_RX_TIMEOUT is defined as 115200/2 which is 0.5second when my baud rate is 115200.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok looks like upon every firing of timeout interrupt I need to start off the timeout timer again in order to get this to work...

so USART2->cr |= AVR32_USART_CR_STTTO_MASK; should be placed in the 2nd part in above code...strange.

Also noticed if I activate the PDCA for rx buffer I can no longer raise usart RXRDY interrupt...this is bad for my case...because this usart is a user interface/debug port, I need it to be able to monitor every char incoming. For example the user may press backspace char...so the usart rx interrupt routine needs to output "\b \b" in that case to wipe and move the cursor etc...

so I am thinking I will do this debug rx port without pdca, but will keep pdca for tx buffer only.

I do have to use another usart port as rs485 however to talk to a sensor device...so I might just use pdca for rx tx buffers there. Since there is no way I could expect a backspace char...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Luvocean1

PDCA initialisation and interrupt handler registering code as follows :

pdca_disable(PDCA_CHANNEL_MODEM_RX);

		PDCA_MODEM_OPTIONS_RX.addr = (void *)MODEMRxBuffer; // memory address
		PDCA_MODEM_OPTIONS_RX.pid = AVR32_PDCA_PID_USART1_RX; // select peripheral - data are transmit on USART TX line
		PDCA_MODEM_OPTIONS_RX.size = MODEM_RX_BUFFER_SIZE; // transfer counter
		PDCA_MODEM_OPTIONS_RX.r_addr = NULL; // next memory address
		PDCA_MODEM_OPTIONS_RX.r_size = 0; // next transfer counter
		PDCA_MODEM_OPTIONS_RX.transfer_size = PDCA_TRANSFER_SIZE_BYTE; // Transfer size

		// Init the PDCA channels with the pdca_options.
		pdca_init_channel(PDCA_CHANNEL_MODEM_RX, &PDCA_MODEM_OPTIONS_RX);

		portENTER_CRITICAL();
		{
			INTC_register_interrupt((__int_handler)&vMODEM_ISR, MODEM_USART_IRQ, AVR32_INTC_INT0);
			INTC_register_interrupt((__int_handler)&vPDCA_MODEM_RX_ISR, AVR32_PDCA_IRQ_1, AVR32_INTC_INT0);

		}
		portEXIT_CRITICAL();

The to enable the USART I do this :

portENTER_CRITICAL();
		{
			/* Enable the time out interrupt */
			MODEM_USART->cr = (MODEM_USART->cr | 1 << AVR32_USART_CR_STTTO_OFFSET);
			MODEM_USART->rtor = 250 << AVR32_USART_RTOR_TO_OFFSET;
			MODEM_USART->idr = 0xFFFFFFFF;
			MODEM_USART->ier = 1 << AVR32_USART_IER_TIMEOUT_OFFSET;


			/* Load the PDCA channel */
			pdca_load_channel(PDCA_CHANNEL_MODEM_RX, (void *)MODEMRxBuffer, MODEM_RX_BUFFER_SIZE);
			pdca_enable_interrupt_transfer_complete(PDCA_CHANNEL_MODEM_RX);
			pdca_enable(PDCA_CHANNEL_MODEM_RX);
		}
		portEXIT_CRITICAL();

Then received code :

if (pdPASS == xSemaphoreTake(xMODEMRXSem, portMAX_DELAY)) {
				vMODEMBufferSave();
				portENTER_CRITICAL();
				{
					/* Load the PDCA channel */
					pdca_load_channel(PDCA_CHANNEL_MODEM_RX, (void *)MODEMRxBuffer, MODEM_RX_BUFFER_SIZE);
					/* Re-enable PDCA interrupt */
					pdca_enable_interrupt_transfer_complete(PDCA_CHANNEL_MODEM_RX);
				}
				portEXIT_CRITICAL();

				process_result = uiMODEMProcess();
}

My interrupt handles both cause the receive semaphore to be given (I'm using FreeRTOS) so that the task processes the data and when done re-enables the interrupts (as you can see in the code above).

The timeout interrupt handler looks like this :

portENTER_CRITICAL();
		xSemaphoreGiveFromISR(xMODEMRXSem, &xHigherPriorityTaskWoken);
		portEXIT_CRITICAL();

		/* Reset the time-out interrupt */
		pxUsart->cr = (pxUsart->cr | 1 << AVR32_USART_CR_STTTO_OFFSET);

NOTE: I use two separate interrupt handlers, one for buffer full (from the PDCA) and one for time out (from the USART). Both effectively do the same thing (wake up the receive task to process the data in the buffer), but the issue I suspect you are running into is that you have registered the same interrupt handler for both, but it is only firing for one (the buffer full rather than the time out).

The value I used for RTOR is a bit of trial and error, really, I worked on 10 times the timeout of a single character receive at the baud rate expected, but for one of my interfaces I had to go much longer than that. It is really the sending devices limitation rather than the USART or micro. Just set a value that means you have everything you should have after that delay.

Hope that sorts it for you.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

it seems you only set the AVR32_USART_CR_STTTO_OFFSET once....but if I do that it doesnt fire... I have to set it everytime timeout interrupt executes....thanks for the sample code. mine is not so different except that I am not using FreeRTOS.

But also as I said I cant do PDCA on rx buffer as I have to check every incoming char (from hyperterm) incase its a backspace for example...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Luvocena1

Actually AVR32_USART_CR_STTTO_OFFSET is set twice. Firstly when I enable the USART (when Im ready to receive), and then again after every interrupt that occurs. (last line in the interrupt handler)

Ok understand about the PDCA, though your first post indicated that you were receiving from a sensor, didn't realise it would be sending backspace's. PDCA is really geared towards data packets that need to be processed. There is no restriction or requirement on packet size, as the above code shows, as long as you can use the USART timeout option. If you are processing the characters as they arrive, then a single interrupt on USART is all you will need (this was the first way I implemented the Modem logic as I thought I had to wait for the end on line character in each packet)

Regards.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ok i have it sorted for receive now...
i am a bit confused how the TXBUFE works...how do you raise that interrupt? I now configured my PDCA for transmit buffer without TRC interrupt. Is that meant to signal the usart TXBUFE when PDCA channel counter runs to zero??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are two options for Transmitting using PDCA, and of course the choice just to use the standard USART put_line/put_char option as well.

(I use all three).

For the PDCA, you only need to interrupt if sending more than you buffer size of data, in which case you will have to load the rest of the data to send, when the interrupt occurs.

You do not have to use the PDCA buffer empty interrupt tho, if you always completely send the data in one buffer. Although in this case it is useful to know when the data has completed sending, in case you need to do something else at this point, however as your application isn't using an RTOS, you could just periodically check and therefore not need the interrupt.

You may also find that the USART put options are easier to use (less configuring), and are simpler to use.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

but still how does TXBUFE get set?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When the PDC finishes the transfer and the USART has finished sending the last byte.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

that is strange...because my Usart interrupt for TXBUFE didnt get set when the PDCA tcr went to zero... :|

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Works ok for me on a UC32A.

Try using the TXEMPTY interrupt., that one must work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok I initialize the usart with the following interrupt options:

USART2->ier = AVR32_USART_IER_RXRDY_MASK |  //received char
              AVR32_USART_IER_TXBUFE_MASK | //transmit buffer empty (triggered by PDCA)
              AVR32_USART_IER_TIMEOUT_MASK; //receive timeout
USART2->rtor = USART2_RX_TIMEOUT;  //RX stream timeout register value
USART2->cr |= AVR32_USART_CR_STTTO_MASK;  //Start of the timeout counter feature

In my PDCA transmit init function I have do not have any interrupt setup for transmit counter reaching to zero, or any other interrupt at all.

So I expect when PDCA counter goes to zero it should signal the USART TXBUFE to be set, which should raise an interrupt on usart interrupt handler....but for me it never gets called. :(

my usart Interrupt handler is like this:

#if __GNUC__
__attribute__((__interrupt__))
#elif __ICCAVR32__
__interrupt
#endif
static void DebugPortIntHandler(void)
{
   int c;
   unsigned long intCause = USART2->csr & 
			(AVR32_USART_CSR_RXRDY_MASK |
			 AVR32_USART_CSR_TXBUFE_MASK	|
			 AVR32_USART_CSR_TIMEOUT_MASK);

   switch(intCause)
   {
      case AVR32_USART_CSR_RXRDY_MASK:
      {
         //do whats required for receive
         break;
      }
      case AVR32_USART_CSR_TIMEOUT_MASK:
      {
         //new line detection logic etc.
         break;
      }
      case AVR32_USART_CSR_TXBUFE_MASK:
      {
         //this never gets fired! :(
         //want to reset PDCA address pointer etc here.
         //DebugPDCA_Chnl->mar = (unsigned long)(void *)DebugPortTxBuf;
         //DebugPDCA_Chnl->cr = AVR32_PDCA_ECLR_MASK;
         break;
      }
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Or why not use the PDCA interrupt when the counter reaches 0, that will also work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was wrong., my usart interrupt used TXEMPTY to indicate end-of-transmission and then disable an RS485 driver., using TXBUFE doesn't work.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes thats what I am doing right now... but I wish I could use usart interrupt... :|

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

mikech wrote:
I was wrong., my usart interrupt used TXEMPTY to indicate end-of-transmission and then disable an RS485 driver., using TXBUFE doesn't work.

worth reporting as a bug?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

http://support.atmel.no/bin/cust...

ahh the errata says its not available:

Quote:

Sections ADC, SPI, SSC, TWI and USART
The ENDTX, TXBUFE, ENDRX and RXBUFF status and interrupt bits and the TCR, TNCR, RCR and RNCR registers of the above peripherals are not available.
The associated functionality is handled by the Peripheral DMA Controller.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Grrrrrr..
I wish Atmel would update the actual product PDF with those important little details.

Thanks luvocean1