Using PDCA for USART RX?

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

After many hours of "playing", I have my USART TIMEOUT working - and I understand it!  The next piece of my puzzle is to get PDCA running, receiving data from the USART.  In my first application, I have about 1000 bytes of data coming in with a 320ms delay between cycles of data.  The plan is to use two alternating buffers to have PDCA write into, allowing me more time to massage the data.  The USART TIMEOUT will switch buffers and flag the main program that receiving data on a buffer is done.  The problem is I am not sure how to setup the PDCA to do what I want.  Here is what I have so far - which of the USART TIMEOUT is working, but not so with the PDCA. 

 

int Buffer_1[1000];  //receive buffer 1
int Buffer_2[1000];  //receiver buffer 2
char buffer_ready;  //status of buffers 0=buffer 1 ready, 1=buffer 2 ready 2 = no buffer ready
char buffer_ptr;    //which buffer is being used 0 = buffer 1, 1 = buffer 2
void main(void)
{
    board_init();
    while(1)
    {
        if buffer_ready != 2)
        {
            if(buffer_ready ==0)
            {
                //massage buffer 1
            }
            else
            {
                //massage buffer 2
            }
            buffer_ready = 2;
        }
    }
}
void board_init(void)
{
		flashc_set_wait_state(1);       //slow down flash reads
		sysclk_init();                  //set clocks and PLL
		buffer_ready = 2;               //set flag to no buffer ready
		Disable_global_interrupt();     //disable all interrupts
		INTC_init_interrupts();         //prepare to register interrupts
        PDCA_Init();
		init_USART_0();
		Enable_global_interrupt();      // Enable all interrupts.
		return;
}

int PDCA_Init(void)
{
	const pdca_channel_options_t PDCA_OPTIONS = {
		/* Select peripheral - data is received on USART RX line */
		.pid = AVR32_PDCA_PID_USART0_RX ,
		/* Select size of the transfer */
		.transfer_size = PDCA_TRANSFER_SIZE_BYTE,	//for 8 bits
		/* Memory address */
		.addr = (void *)Buffer_1,
		/* Transfer counter */
		.size = sizeof(Buffer_1),
		/* Next memory address */
		.r_addr = NULL,
		/* Next transfer counter */
		.r_size = 0,
	};
	INTC_register_interrupt(&PDCA_Interrupt, AVR32_PDCA_IRQ_0, AVR32_INTC_INT0);
	/* Initialize the PDCA channel with the requested options. */
	pdca_init_channel( PDCA_CHANNEL_NUMBER, &PDCA_OPTIONS);
	pdca_enable( PDCA_CHANNEL_NUMBER);
	return;
}
void init_USART_0(void)
{
	static const gpio_map_t USART_GPIO_MAP =
	{
		{USART_0_RX_PIN, USART_0_RX_FUNCTION},
		{USART_0_TX_PIN, USART_0_TX_FUNCTION},
	};
		static const usart_options_t USART_0_OPTIONS =
		{
			.baudrate		= USART_0_BAUD_RATE,
			.charlength		= USART_0_CHARLENGTH,
			.paritytype		= USART_0_PARITY,
			.stopbits		= USART_0_STOPBITS,
			.channelmode    = USART_0_MODE
		};
	INTC_register_interrupt(&usart_0_int_handler, USART_0_IRQ, AVR32_INTC_INT0);
	USART_0->rtor =39;	//interrupt 4ms after last char @9600 baud
	USART_0->ier = 256<<AVR32_USART_IER_TIMEOUT_MASK;
	USART_0->cr =  AVR32_USART_RETTO_MASK;
	gpio_enable_module(USART_GPIO_MAP, sizeof(USART_GPIO_MAP) / sizeof(USART_GPIO_MAP[0]));
	usart_init_rs232(USART_0, &USART_0_OPTIONS, CLOCK_PBA_FREQ);
	return;
}
__attribute__((__interrupt__))
void usart_0_int_handler(void)
{
	if (USART_0->csr & AVR32_USART_TIMEOUT_MASK)
	{   //timeout occured - switch PDCA RX Buffer
			if (buffer_pointer)  //if buffer 2, then switch to buffer 1
			 {
				pdca_reload_channel( PDCA_CHANNEL_NUMBER,
				(void *)Buffer_1, sizeof(Buffer_1));
			}
			else    //if buffer 1, then switch to buffer 2
			 {
				pdca_reload_channel( PDCA_CHANNEL_NUMBER,
				(void *)Buffer_2, sizeof(Buffer_2));
			 }

			// Switch buffer pointer
			buffer_pointer = !buffer_pointer;
			buffer_ready = !buffer_pointer;  //flag for which buffer is ready
			USART_0->cr = AVR32_USART_STTTO_MASK;
	}
	

I am collecting data, alternating between Buffer_1 and Buffer_2 - BUT every cycle of data starts with '$' and since it is a 4ms timeout that switches Buffers for the PDCA, I would expect for the Buffers to start with a '$' - but they don't!  Something is amiss!  Suggestions please!

David

This topic has a solution.
Last Edited: Thu. Sep 24, 2020 - 03:35 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'd use pdca_load_channel(,,) instead of pdca_reload_channel(,,) because the reload operation will queue the PDC transfer if the previous transfer has not completed.

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

"buffer_ready" needs to be volatile.

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

dfansler wrote:

char buffer_ready;  //status of buffers 0=buffer 1 ready, 1=buffer 2 ready 2 = no buffer ready	

wouldn't it be clearer to have 0 = no buffer ready ?

 

then you could do:

if( buffer_ready )
{
   // we know that one of the buffers must be ready
   if( 1 == buffer_ready )
   {
      // it's buffer 1
   }
   else
   {
      // it must be buffer 2
   }
}

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Thanks guys, I have it working now!

David

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

dfansler wrote:
 I have it working now!

Jolly good - what was the secret?

 

Please mark the solution - see Tip #5 in my signature, below, for instructions:

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Since we all (ok, so I do) look thru previous posts for answers before posting a questionwink, here is my working code for

1.  reading a number of GPS sentences using USART 0 in a PDCA (direct from usart to one of two alternating memory buffers. 

2.  There is ~320ms between bursts of data.  I will use that time to decode one buffer, while the other buffer is being filled. 

3.  Data from my GPS is 9600,8,N,1. 

4.  A usart timeout interrupt is set for 4 ms and occurs after the last data has been received for that burst.

5.  Buffers are zeroed out when they are about to be used.

6. After the timeout interrupt has occurred, the receive buffers of the UC3 are cleared - failing to do so, the buffers did not start with the correct data.

7.  There is only one interrupt - timeout on the usart.  Since the usart interrupt code resets the PDCA, the PDCA does not need an interrupt.

8. Using the "Board Wizard", I use "User Board Template" for my custom designed UC3A board - specs at the end 

9. Using the "ASF Wizard", include:

     - CPU Cycle Counter
    - Delay routines
    - FLASHC - Flash Controller
    - GPIO - General-Purpose Input/Output
    - Generic board support
    - INTC - Interrupt Controller
    - Interrupt management - UC3 implementation
    - PDCA - Peripheral DMA Controller

    - System Clock Control - UC3 A implementation
    - USART - Universal Synchronous/Asynchronous Receiver/Transmitter

 And now, the house presents "The Code"

 /* file  "conf_clock.h" */
#ifndef CONF_CLOCK_H_INCLUDED
#define CONF_CLOCK_H_INCLUDED
    #define CONFIG_SYSCLK_SOURCE        SYSCLK_SRC_PLL0

    /* Fbus = Fsys / (2 ^ BUS_div) */
    #define CONFIG_SYSCLK_CPU_DIV         0
    #define CONFIG_SYSCLK_PBA_DIV         0
    #define CONFIG_SYSCLK_PBB_DIV         0
    #define CONFIG_USBCLK_SOURCE          USBCLK_SRC_PLL1
    #define CONFIG_USBCLK_DIV             1
    #define CONFIG_PLL0_SOURCE            PLL_SRC_OSC0
    #define CONFIG_PLL0_MUL               16
    #define CONFIG_PLL0_DIV               3  //processor runs at 64MHz

    #define CONFIG_PLL1_SOURCE            PLL_SRC_OSC0
    #define CONFIG_PLL1_MUL               (48000000UL / BOARD_OSC0_HZ)
    #define CONFIG_PLL1_DIV               1
#endif /* CONF_CLOCK_H_INCLUDED */
-----------------------------------------------------------------------------
/*file "conf_board" */
#ifndef CONF_BOARD_H
#define CONF_BOARD_H
    /* Clock Speed */
    #define APPLI_CPU_SPEED	64000000
    #define APPLI_PBA_SPEED 64000000

    /* These are documented in services/basic/clock/uc3b0_b1/osc.h */
    #define BOARD_OSC0_HZ           12000000
    #define BOARD_OSC0_STARTUP_US   17000
    #define BOARD_OSC0_IS_XTAL      true
    #define BOARD_OSC32_HZ          32768
    #define BOARD_OSC32_STARTUP_US  71000
    #define BOARD_OSC32_IS_XTAL     true
    #define FOSC0			12000000
#endif
----------------------------------------------------------------------------- 
/*file "main.c" */
#include <asf.h>
#include "FunctionPrototypes.h"
#include "USART0-3.h"
int main(void)
{
    board_init();//initiaize subsystems

    while (1)
    {
        delay_ms(300);              //delay between data burst
        if(buffer_ready !=2)
        {
            if (buffer_ready == 0)
            {
                //decode data from buffer 1
                buffer_ready = 2;   //set flag to no data ready
            }
            else
            {
                //decode data from buffer 2
                buffer_ready = 2;   //set the flag to no data ready
            }
        }
    }
}
----------------------------------------------------------------------------- 
/* file "init.c" */
#include <asf.h>
#include <conf_board.h>
#include "FunctionPrototypes.h"
#include "USART0-3.h"

void board_init(void)
{
    int x;
        flashc_set_wait_state(1);   // slow down reads to flash memory
        sysclk_init();              //intialize clocks
    for (x=0;x<2500;x++)            //zero out the buffers
        {
            Buffer_1[x]=Buffer_2[x]=0;
        }
        TimeOutFlag = 0;            //clear flag
        gpio_local_init()           //allow high speed gpio
        delay_init(64000000UL);     //calibrate the delay routines
        buffer_ready = 2;           //set flag to no buffer ready
        //Initialize sub systems
        init_USART_0();             //initialize usart
        PDCA_Init();                //initialize PDCA
        Disable_global_interrupt(); //disable all interrupts
        INTC_init_interrupts();     //prepare to register interrupts
        USART_0_Interrupt_Init();   //register usart 0 
        USART_0_Finish_Init();      //USART_0->cr = (USART_0->cr | 1 << AVR32_USART_CR_STTTO_OFFSET);
        PDCA_Init_Finish();         //finish with PDCA
        buffer_ctr = 0;             //set buffer counter to 0
        Enable_global_interrupt();  // Enable all interrupts.
        return;
}
----------------------------------------------------------------------------- 
    /* file  "USART0-3.c    */
#ifndef USART0-3_H_
#define USART0-3_H_

#define CLOCK_PBA_FREQ          64000000
#define TARGET_PBACLK_FREQ_HZ FOSC0  // PBA clock target frequency, in Hz
#define PDCA_CLOCK_HSB			 AVR32_PDCA_CLK_HSB
#define PDCA_CLOCK_PB			 AVR32_PDCA_CLK_PBA


// OPTIONS
#define USART_0					(&AVR32_USART0)
#define USART_0_RX_PIN			AVR32_USART0_RXD_0_0_PIN
#define USART_0_RX_FUNCTION		AVR32_USART0_RXD_0_0_FUNCTION
#define USART_0_TX_PIN			AVR32_USART0_TXD_0_0_PIN
#define USART_0_TX_FUNCTION		AVR32_USART0_TXD_0_0_FUNCTION
#define USART_0_CLOCK_MASK		AVR32_USART0_CLK_PBA
#define USART_0_BAUD_RATE		9600
#define USART_0_PARITY			USART_NO_PARITY
#define USART_0_STOPBITS		0
#define USART_0_MODE			USART_NORMAL_CHMODE
#define USART_0_CHARLENGTH		8
#define USART_0_CLOCK_MASK		AVR32_USART0_CLK_PBA
#define USART_0_IRQ				AVR32_USART0_IRQ
#define AVR32_PDCA_PID_USART0_TX       AVR32_PDCA_PID_USART0_TX
#endif /* USART0-3_H_ */
----------------------------------------------------------------------------- 
/* file "USART0-3.c" */


 
 /* USART0_3.c
 *
 * Created: 9/15/2020 9:23:38 PM
 *  Author: dfans
 */ 
#include <asf.h>
#include "conf_board.h"
#include "USART0-3.h"
#include "FunctionPrototypes.h"
// ==================================
// USART interrupt handlers
// ==================================

__attribute__((__interrupt__))
void usart_0_int_handler(void)
{
    int c,b,x;

    if (USART_0->csr & AVR32_USART_TIMEOUT_MASK)
    {
            if (buffer_pointer)
             {
                for (x=0;x<2500;x++)          //zero out the buffer
                {
                    Buffer_1[x]=0;
                }
                pdca_load_channel( PDCA_CHANNEL_NUMBER,void *)Buffer_1, sizeof(Buffer_1)); //load address for buffer to use
                b = usart_read_char(USART_0, &c);        //clear out any characters in usart holding register
                b = usart_read_char(USART_0, &c);        //clear out any characters in usart holding register
                buffer_pointer = !buffer_pointer;        //switch buffers being used flag
                buffer_ready = !buffer_pointer;          //set buffer ready to read flag
                USART_0->cr = AVR32_USART_STTTO_MASK;    //reload PDCA counter but do not start counting
                TimeOutFlag = 1;                         //flag to indicate usart timeout occured
            }
            else
             {
                for (x=0;x<2500;x++)                     //same as above, but with buffer 2
                {
                    Buffer_2[x]=0;
                }
                pdca_load_channel( PDCA_CHANNEL_NUMBER,(void *)Buffer_2, sizeof(Buffer_2));
                b = usart_read_char(USART_0, &c);
                b = usart_read_char(USART_0, &c);
                buffer_pointer = !buffer_pointer;
                buffer_ready = !buffer_pointer;
                USART_0->cr = AVR32_USART_STTTO_MASK;
                TimeOutFlag = 1;
             }
    }
}


//USART 0 interrupt init
void USART_0_Interrupt_Init(void)
{
    INTC_register_interrupt(&usart_0_int_handler, USART_0_IRQ, AVR32_INTC_INT1);
}
void USART_0_Finish_Init(void)
{
    USART_0->rtor =39;    //interrupt 4ms after last char
    USART_0->ier = 256<<AVR32_USART_IER_TIMEOUT_MASK;
    USART_0->cr =  AVR32_USART_RETTO_MASK;
    return;
}
void init_USART_0(void)
{
    static const gpio_map_t USART_GPIO_MAP =
    {
        {USART_0_RX_PIN, USART_0_RX_FUNCTION},
        {USART_0_TX_PIN, USART_0_TX_FUNCTION},
    };
        static const usart_options_t USART_0_OPTIONS =
        {
            .baudrate        = USART_0_BAUD_RATE,
            .charlength        = USART_0_CHARLENGTH,
            .paritytype        = USART_0_PARITY,
            .stopbits        = USART_0_STOPBITS,
            .channelmode   = USART_0_MODE
        };
        
    gpio_enable_module(USART_GPIO_MAP, sizeof(USART_GPIO_MAP) / sizeof(USART_GPIO_MAP[0]));
    usart_init_rs232(USART_0, &USART_0_OPTIONS, CLOCK_PBA_FREQ);
    return;
}
----------------------------------------------------------------------------- 
 /* file FunctionPrototypes.h */
#include <pdca.h>
#include <asf.h>
#ifndef FUNCTIONPROTOTYPES_H_
#define FUNCTIONPROTOTYPES_H_
//main file
/USART0-3
void usart_0_int_handler(void);
void USART_0_Interrupt_Init(void);
void init_USART_0(void);
void USART_0_Finish_Init(void);
extern volatile int buffer_ctr;
extern volatile char buffer_pointer;
extern volatile char buffer_ready;
extern volatile char TimeOutFlag;

//PDCA file
int PDCA_Init(void);
void pdca_enable(uint8_t pdca_ch_number);
void pdca_enable_interrupt_reload_counter_zero(uint8_t pdca_ch_number);
void pdca_reload_channel(uint8_t pdca_ch_number,volatile void *addr, uint32_t size);
void PDCA_Init_Finish(void);
char Buffer_1[2500];
char Buffer_2[2500];
#define PDCA_CHANNEL_NUMBER 0  //  was PDCA_CHANNEL_USART_EXAMPLE 0
#endif /* FUNCTIONPROTOTYPES_H_ */

I designed and had made a 4 layer PCB that is 4"x1.25".  It holds the 100 pin UC3 processors.  All I/O pins are brought out to the edges of the board.  A transceiver provides RS-232 levels for USART0 and USART3.  USB connector is on board.  A 10 pin JTAG header is available for programming and debugging.  In addition to the main oscillator (I use a 12Mhz unit), the foot print for the 32KHz oscillator is present.  There are two leds - power and for a WDT, of anything else I choose.  The board requires an external 3.3v supply.  An earlier version would take up to 12v and had an onboard voltage regulator - but it was a pain in the wazoo.  I use male header pins on the board, which mates to any project I am working on.  This saves a lot of time not having to design a new board with processor for every project I embark on.

Attachment(s): 

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

and mark the solution ?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...