ASF USART example problem

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

I've been trying to get the ASF-USART for my ATxmega128A4U to work. I followed the quick start guide found here http://asf.atmel.com/docs/3.31.0...

 

My code is an exact copy of this, the only difference is that my USART is on port E.

 

The problem is that usart_getchar() is working just fine (tested this by controlling a LED from the USART), but usart_putchar() is not. I've debugged this with the oscilloscope and there is simply nothing present on the TX pin when I call usart_putchar().

conf_clock.h:

#define CONFIG_SYSCLK_SOURCE          SYSCLK_SRC_RC2MHZ

#define CONFIG_SYSCLK_PSADIV          SYSCLK_PSADIV_1
#define CONFIG_SYSCLK_PSBCDIV         SYSCLK_PSBCDIV_1_1

main.c:

#define USART_SERIAL                     &USARTE0
#define USART_SERIAL_BAUDRATE            9600
#define USART_SERIAL_CHAR_LENGTH         USART_CHSIZE_8BIT_gc
#define USART_SERIAL_PARITY              USART_PMODE_DISABLED_gc
#define USART_SERIAL_STOP_BIT            true

int main (void)
{
	sysclk_init();

	 static usart_rs232_options_t USART_SERIAL_OPTIONS = {
		 .baudrate = USART_SERIAL_BAUDRATE,
		 .charlength = USART_SERIAL_CHAR_LENGTH,
		 .paritytype = USART_SERIAL_PARITY,
		 .stopbits = USART_SERIAL_STOP_BIT
	 };
	 
	 sysclk_enable_module(SYSCLK_PORT_E,PR_USART0_bm);
	 usart_init_rs232(USART_SERIAL, &USART_SERIAL_OPTIONS);
	 	
	while(1){
		usart_putchar(USART_SERIAL, 'U');
	}

}

I know the USART is working because when I configure it manually without ASF it is also working just fine, both RX and TX. Any ideas? 

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

Wow, brave man trying to use ASF for AVR8!

 

Anyway one possible "gotcha" on Xmega (I believe) is that for UART you also have to set the direction of the IO pins (unlike tiny/mega just enabling UART for TX does not affect the pin direction). Now maybe deep in the depths of usart_init_rs232() it handles this for you - but I would be checking for something like that. It might explain why get() works but put() doesn't as the pins likely default to inputs not outputs.

without ASF it is also working just fine, both RX and TX.

that does make me wonder what you see as the advantage of trying to use ASF then? I think Atmel's idea behind it is to present a common API so if you migrate from Xmega to UC3 to ARM you effectively do the same thing - but beyond that there's not a lot of reason for using ASF for a peripheral as simple as a UART.

Last Edited: Thu. Jun 2, 2016 - 03:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Setting the pin direction was indeed the solution, thanks a lot! I figured this would've indeed be handled in the init routine, but I guess not.

Anyway, the reason I'm using ASF is simply because I was trying to make myself acquainted with it because for a future project I have to write similar code for an Xmega and a regular mega, and I figured ASF would allow me to easily recycle the code, like you already indicated. However, if quirks like this also exist in other peripheral modules, then it may be easier to just stick with legacy code.

Last Edited: Thu. Jun 2, 2016 - 04:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Joeshoe wrote:
I figured this would've indeed be handled in the init routine, but I guess not.

And there, my friend, is what I see as the exact problem with ASF.

 

If you read the datasheet about "bare metal programming" and setting up a UART for Xmega directly it will tell you all the registers and bits to be accessed. If you do that it just works.

 

If you just read the API documentation for ASF then it is all just one great big black box (more like a black hole!). You have no idea what it might or might not be doing inside. If the documentation were very well written then in the example it would say something like "you can initialise most UART parameters with a call to uart_init_rs232 but of course, for Xmega, it is still your responsibility to configure the pin directions". On the whole it doesn't.

 

I would invest my time in learning how to do it directly and as a bonus you'll probably find you can do it in 5..10 lines of C when the ASF stuff is using 50..100 because it's too busy trying to be all things to all people.

 

As for your motive of moving from X to tiny/mega. Be warned ASF has almost NOTHING to offer for tiny/mega. I think Atmel figured that the tiny/mega peripherals are SO simple everyone would just choose to bare metal program them anyway.

 

The place ASF actually comes into its own is when you try to use a really complex peripheral like USB or CAN on a "big chip". It takes a load of workload off your hands as there could be 20..50 registers to be programmed and working out the sequence "by hand" could be very complex indeed - so you are getting the potted knowledge of the Atmel engineers who designed the USB/CAN/.. peripheral. But for simple stuff like ADC, UART, etc it gains you nothing and, as shown here, introduces potentially hard to trace options. When something does not work you are now facing the prospect of having to try and work through someone else's (overly convoluted) code to find out what it does/doesn't do.

 

Then again some people actually pay money to be beaten with a stick so I can see how a masochist might love this kind of thing :-)

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

Clawson said:

Then again some people actually pay money to be beaten with a stick

I myself prefer a cat-of-nine-tails! 

 

 

Joeshoe,

 

My first experience with embedded C was a few years ago with an Xmega-A1 Xplained and Atmel Studio 5 dot something.  As my only C experience was a number of years ago and always in a hosted environment (Unix, VMS, MSDOS), I relied heavily on the ASF examples.  I learned a lot about working with the peripherals by learning the ASF code.  I also got bit by a number of gotchas, one of which you just learned.  BTW, usart_init_rs232() enables the peripheral clock for you, so there is no need to call sysclk_enable_module().

 

The ASF way of configuring an USART is to edit conf_board.h and enable the USART there.  Of course all that does is set the direction of the I/O pins.  You still need to call usart_init_rs232() to actually configure the USART.  If you are using an unsupported board, you will need to create a "User Board" project and populate conf_board.h with meaningful configuration macros, and you will also need to but the appropriate init code in  ...\src\ASF\xmega\boards\user_board\init.c.  Oh, and don't expect to find any interrupt-driven code for the USART, I2C, SPI, and so on...  With a few exceptions all ASF I/O is polled.

 

Another gotcha is sysclk_init().  It uses the configuration macros in conf_clock.h to set the system clocking to your liking.  What the ASF documentation doesn't tell you is that it also TURNS OFF THE PERIPHERAL CLOCK FOR EVERY PERIPHERAL.  If you use the ASF init functions the peripheral clock is turned on for you, which begs the question why so many of the Quick Starts tell you to explicitly enable the peripheral clock with a call to sysclk_enable_module().  If you write your own peripheral init code, you may spend hours or (in my case) days trying to figure out why the peripheral you are trying to configure is completely ignoring your attempt to do so.

 

Unless you've got lots of time to learn the ins and outs of using ASF, you're better off writing your own code.  ASF code does come in handy for learning the "official Atmel way" of initializing peripherals however.

 

 

EDIT:

 

I missed your use of conf_clock.h on my first read.  And it appears you're not using an Atmel board, so I changed my response to reflect that.

 

Good Luck!  (You'll need it.)

 

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

Last Edited: Fri. Jun 3, 2016 - 02:32 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Greg_Muth: I had already found another post by you regarding the issue with sysclk_init(), but thanks for your response. laugh

I'm indeed using a homemade board. I really like the idea of ASF, especially not having to look up every single register again when switching between micro's, but the documentation (or lack thereof) is really giving me a headache. Especially the lack of documentation regarding configuration of custom boards is making it really difficult. 

 

I spend the entire day yesterday playing around with ASF, and as clawson already suggested, I think I'm gonna stick with bare metal programming for now for the "easy" peripherals since it's proving to be more hassle than it's worth.

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

Greg_Muth wrote:
The ASF way of configuring an USART is to edit conf_board.h and enable the USART there. Of course all that does is set the direction of the I/O pins.

I wonder how you learn such interesting facts? If you simply use the quick start for the UART that he linked to in #1:

 

http://asf.atmel.com/docs/3.31.0...

 

(which the URL name suggests is specifically for Xmega) is makes no mention of any mechanism by which the I/O direction is set.

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

I wonder how you learn such interesting facts?

Trial and error, looking at the ASF source code, ritualistic sacrifices on the altar of the MCU gods...  Anything but looking at the documentation, which is somewhere between poor and abysmal.

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

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

hi Joeshoe

    CAN YOU SHARE WITH ME THE CODE FOR ATxmega128A4U UART WITHOUT USING ASF?.

I tried your above code with ASF . But on HyperTerminal I am getting some error values like ©i('G+#xhb`#lh B::c`. Can you anyone please suggest for solution?

 

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

mayurisb024 wrote:
But on HyperTerminal I am getting some error values like ©i('G+#xhb`#lh B::c`.
Well for one thing ditch Hyperterminal as it was only ever supposed to be a joke that Microsoft inflicted on the world. There are lots of good terminal programs that actually work. But in this case the error looks a lot like a baud rate that is close but not quite correct so I'd look at both (a) how the Xmega overall is being set up to be clocked and (b) specifically how the baud rate for the UART is being calculated and set.

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

hi clawson

 

thanks for the reply. 

I have just taken the code from ASF UART, changed the port from PORTE to PORTC. 

Regarding Baudrate these are the MACROS defined. Except this I have done nothing related BSEL or BSCALE for BAUDRATE

#define USART_SERIAL_EXAMPLE            &USARTC0
#define USART_SERIAL_EXAMPLE_BAUDRATE   9600
#define USART_SERIAL_CHAR_LENGTH        USART_CHSIZE_8BIT_gc
#define USART_SERIAL_PARITY             USART_PMODE_DISABLED_gc
#define USART_SERIAL_STOP_BIT           true.

 

I am new to this. So I need your suggestion how to walk through this

 

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

mayurisb024 said:

I have just taken the code from ASF UART, changed the port from PORTE to PORTC. 

Does this mean you are using ASF..?  Or you grabbed the contents of conf_usart.h?

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

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

Yes Greg. I am using ASF. the same code posted for Xmega128a4u  i am using. I have configured PortC Pin2, and 3 or Rx Tx respectively. Not doing anything with conf_usart.h

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

mayurisb024, post your code.

 

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

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

Hi,

 

Posted my code below. I am using MT-DB-X4  Evaluation Board which has xmega128a4u Controller 16MHz crystal Oscillator

 

 

 

#include <asf.h>
#include <SYS_Time.h>
#include "sysclk.h"

 #define USART_SERIAL_EXAMPLE            &USARTC0
 #define USART_SERIAL_EXAMPLE_BAUDRATE   9600
 #define USART_SERIAL_CHAR_LENGTH        USART_CHSIZE_8BIT_gc
 #define USART_SERIAL_PARITY             USART_PMODE_DISABLED_gc
 #define USART_SERIAL_STOP_BIT           true

#define SET_TX() ioport_configure_pin(IOPORT_CREATE_PIN(PORTC, 3), IOPORT_DIR_OUTPUT )
#define SET_RX() ioport_configure_pin(IOPORT_CREATE_PIN(PORTC, 2), IOPORT_DIR_INPUT)

#define DS_SET_led()         ioport_configure_port_pin(&PORTE, PIN1_bm, IOPORT_DIR_OUTPUT )//included for testing
#define DS_ENABLE_led()      ioport_set_pin_high(IOPORT_CREATE_PIN(PORTE, PIN1_bp))
#define DS_DISABLE_led()     ioport_set_pin_low(IOPORT_CREATE_PIN(PORTE, PIN1_bp))

 

 

 void main(void)
 
  {
    uint8_t tx_buf[] = "\n\rHello ";
     uint8_t tx_length = 10;

     uint8_t i;
                                                  
    

      DS_SET_led();
  SET_TX();
  SET_RX();

      sysclk_init();

    // USART options.
      static usart_rs232_options_t USART_SERIAL_OPTIONS = {
          .baudrate = USART_SERIAL_EXAMPLE_BAUDRATE,
         .charlength = USART_SERIAL_CHAR_LENGTH,
          .paritytype = USART_SERIAL_PARITY,
         .stopbits = USART_SERIAL_STOP_BIT
      };
     sysclk_enable_module(SYSCLK_PORT_C, PR_USART0_bm);

     // Initialize usart driver in RS232 mode
       usart_init_rs232(USART_SERIAL_EXAMPLE, &USART_SERIAL_OPTIONS);
 
    // Send "message header"
      while(1){
     for (i = 0; i < tx_length; i++) {
            usart_putchar(USART_SERIAL_EXAMPLE, tx_buf[i]);

          }

Last Edited: Mon. Jun 5, 2017 - 04:39 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

tx_length is 10. So your for() loop tries to send 10 characters. Exactly how many characters are there in:

uint8_t tx_buf[] = "\n\rHello ";

and do you even want to send the 0x00 on the end? '\n' is ONE character, '\r' is ONE character.

 

Also \n\r is a curious sequence. The "normal" ones are either \n on its own or \r\n but not \n\r. Also sending it at the start not the end is "unusual" too.

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

OK Clawson, I will try and let you know the result. I am assuming that there is no need to calculate baudrate select value and defining a macro for baud rate  is only what we need to do

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

mayurisb024 said:

defining a macro for baud rate  is only what we need to do

 No.  usart_init_rs232() sets the bit rate for you.  It also enables the peripheral clock for you, so you don't need to call sysclk_enable_module().

 

You do not need to #include "sysclk.h" as asf.h includes the headers for all ASF modules in the project.

 

What does conf_clock.h look like?  If it is unchanged, you are using the internal RC2M oscillator, not the external oscillator.

 

 

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

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

If you want to get away from ASF, the following compiles, but is untested:

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdio.h>

#define BAUDCTRL_VALUE		1	// set accordingly

void clock_init(void);
FILE* usart_init(void);
int usart_get(FILE* f);
int usart_put(char c, FILE* f);

FILE us = FDEV_SETUP_STREAM(usart_put, usart_get, _FDEV_SETUP_RW);

int main(void)
{
	char line[128];

    clock_init();
	stdin = stdout = stderr = usart_init();

    do
	{
		puts_P(PSTR("\n\nHello, World!\nType something then press 'Enter'.\n"));
		gets(line);
		puts_P(PSTR("You typed:\n"));
		puts(line);

	} while (1);

	return 0;
}

void clock_init(void)
{
	OSC_XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;
	OSC_CTRL |= OSC_XOSCEN_bm;
	while(!(OSC_STATUS & OSC_XOSCRDY_bm));
	_PROTECTED_WRITE(CLK_CTRL, CLK_SCLKSEL_XOSC_gc);
	OSC_CTRL &= ~OSC_RC2MEN_bm;
}

FILE* usart_init(void)
{
	PORTC.OUTSET = PIN3_bm;
	PORTC.DIRSET = PIN3_bm;
	PORTC.DIRCLR = PIN2_bm;
	USARTC0.BAUDCTRLB = BAUDCTRL_VALUE >> 8;
	USARTC0.BAUDCTRLA = BAUDCTRL_VALUE & 255;
	USARTC0.CTRLC = USART_CMODE_ASYNCHRONOUS_gc | USART_PMODE_DISABLED_gc | USART_CHSIZE_8BIT_gc;
	USARTC0.CTRLB = USART_RXEN_bm | USART_TXEN_bm;

	return &us;
}

int usart_get(FILE* f)
{
	int c;

	while (!(USARTC0.STATUS & USART_RXCIF_bm));
	c = USARTC0.DATA;
	if (c == '\r') c = '\n';
	usart_put((char)c, f);

	return c;
}

int usart_put(char c, FILE* f)
{
	if (c == '\n') usart_put('\r', f);
	while (!(USARTC0.STATUS & USART_DREIF_bm));
	USARTC0.DATA = c;

	return 0;
}

 

EDIT: corrected a few obvious errors above, didn't update attachment.

 

Attachment(s): 

Greg Muth

Portland, OR, US

Atmel Studio 7.0 on Windows 10

Xplained/Pro/Mini Boards mostly

 

 

Last Edited: Mon. Jun 5, 2017 - 02:38 PM