Redirecting assert errors to UART.

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

Hi,

 

I'm trying to use UART in order to get assert mesages. I never used assert in embedded systems an what to change that.

 

My project is configured via Atmel Start :

  • Device: Atmel Studio 7
  • Microcontroller: ATXMEGA256A3BU-AU
  • Clock: External 10MHz multiplied by 3 (PLL) -> 30Mhz
  • UART (UART_DEBUG): USARTF0 | Async Polled Mode | TX pin : PF3 | RX pin : PF2 | 9600 bauds | 8 data bits | No Parity | 1 stop bit

 

 

Here is what i tested:

#include <atmel_start.h>
#include <stdio.h>
#include <string.h>
#include <util/delay.h>

int main(void)
{
    // System initialisation via atmel start
    atmel_start_init();

//    #define __ASSERT_USE_STDERR

    // Redirecting stdout and stderr to uart output
    FILE UartDebug = FDEV_SETUP_STREAM(UART_DEBUG_write,NULL,_FDEV_SETUP_WRITE);
    stdout = &UartDebug;
    stderr = &UartDebug;

    // Print every 2s on the terminal
    while (1)
    {
        fprintf(stdout, "Output Standard Test 1\r\n");

        printf("Output Standard Test 2\r\n");

        fprintf(stderr, "Error Standard Test 1\r\n");
//	assert (false);
        _delay_ms(2000);
    }

    return EXIT_SUCCESS;
}

 

Here is what is shown in the terminal :

 

 

Look like the printf line work fine but not fprintf lines, only the first character of the string argument is printed.

I don't really understand how "printf("Output Standard Test 2\r\n")" work fine but not "fprintf(stdout, "Output Standard Test 1\r\n")".

Did I miss something ?

 

This topic has a solution.
Last Edited: Fri. Sep 18, 2020 - 09:41 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you seen this recent thread: https://www.avrfreaks.net/forum/how-use-assert ?

and https://www.avrfreaks.net/forum/what-does-exacly-assert-do - to which it refers?

 

 

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: 0

I guess it doesn't matter as you only really pass its address but usually:

    FILE UartDebug = FDEV_SETUP_STREAM(UART_DEBUG_write,NULL,_FDEV_SETUP_WRITE);

would be given global scope.

 

To be honest I cannot immediately see what you are doing wrong here. The usual thing IS to assign the output stream to both stdout and stderr just as you are doing and because plain printf(...) is really just fprintf(stdout, ...) then I would expect fprintf()s to stderr to work exactly the same as fprintf() to stdout.

 

BTW how can that FDEV_SETUP refer to UART_DEBUG_write() when I don't see any kind of extern declaration for it? Is it hidden inside atmel_start.h then?

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

Have you seen this recent thread: https://www.avrfreaks.net/forum/how-use-assert ?

and https://www.avrfreaks.net/forum/what-does-exacly-assert-do - to which it refers?

Yes, I had a look on these thread before, posting mine.

For the moment, I'm just trying to redirect stdout and stderr to UART.

The use of assert is the next step.

 

BTW how can that FDEV_SETUP refer to UART_DEBUG_write() when I don't see any kind of extern declaration for it? Is it hidden inside atmel_start.h then?

That's it, atmel_start.h include it.

Last Edited: Fri. Sep 18, 2020 - 09:07 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


I just tried to recreate what you are seeing:

 

 

and it seems I succeeded. However I think I got myFake_UART_putchar() wrong. It has an "int" return and I'm not returning anything. If I remind myself about the user manual example:

 

https://www.nongnu.org/avr-libc/...

 

and look at the uart.c they give in particular:

 

https://www.nongnu.org/avr-libc/...

 

then you will notice that their uart_putchar:

/*
 * Send character c down the UART Tx, wait until tx holding register
 * is empty.
 */
int
uart_putchar(char c, FILE *stream)
{

  if (c == '\a')
    {
      fputs("*ring*\n", stderr);
      return 0;
    }

  if (c == '\n')
    uart_putchar('\r', stream);
  loop_until_bit_is_set(UCSRA, UDRE);
  UDR = c;

  return 0;
}

so when I remembered to end my fake version with a return 0:

 

 

So I would suggest that the issue is in the UART_DEBUG_write() that you forgot to show in #1

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

clawson wrote:
The usual thing IS to assign the output stream to both stdout and stderr

 

As a test, how about defining two separate streams - using two UARTs - and see if that works ... ?

 

Something like

    // Redirect stdout  to uart1 output
    FILE UartDebug1 = FDEV_SETUP_STREAM( UART1_DEBUG_write, NULL, _FDEV_SETUP_WRITE );
    stdout = &UartDebug1;

    // Redirect stderr to uart2 output
    FILE UartDebug2 = FDEV_SETUP_STREAM( UART2_DEBUG_write, NULL, _FDEV_SETUP_WRITE );
    stderr = &UartDebug2;

 

EDIT

 

The forum had a "moment"  and temporarily lost this; in the meantime, it seems that clawson may have found the answer ...

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...
Last Edited: Fri. Sep 18, 2020 - 09:10 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


If I test the idea proposed by awneil :

  • The code :
#include <atmel_start.h>

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <util/delay.h>

int main(void)
{
 	atmel_start_init();

//	#define __ASSERT_USE_STDERR

	// Redirect stdout to UartDebug output
	FILE UartDebug = FDEV_SETUP_STREAM(UART_DEBUG_write,NULL,_FDEV_SETUP_WRITE);
	stdout = &UartDebug;

	// Redirect stderr to UartCDE output
	FILE UartCDE  = FDEV_SETUP_STREAM(UART_CDE_write,NULL,_FDEV_SETUP_WRITE);
	stderr = &UartCDE;

	while (1)
	{
		fprintf(stdout, "Output Standard Test 1\r\n");
		printf("Output Standard Test 2\r\n");

		fprintf(stderr, "Error Standard Test 1\r\n");
//		assert (false);
		_delay_ms(2000);
	}

	return EXIT_SUCCESS;
}
  • The outputs:

UartDebug(COM 3)

 

UartCDE(COM 10)

 

The first print on UartDebug is "{=ÕÑÁÕсšÑ…¹‘…É‘¢•Íс’j¤ü" . frown

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

Umm, I already demonstrated the fault / solution ?!?

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


If I test the idea proposed by clawson :

 

The function UART_DEBUG_write() is automaticly generated and don't return 0 :

void UART_DEBUG_write(const uint8_t data)
{
	while (!(USARTF0.STATUS & USART_DREIF_bm))
		;
	USARTF0.DATA = data;
}

So I wrote two more functions that return 0 :

  • The code :
#include <atmel_start.h>

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <util/delay.h>

int UART_DEBUG_putchar(const uint8_t data);
int UART_CDE_putchar(const uint8_t data);


int main(void)
{
	// System initialisation via atmel start
 	atmel_start_init();

//	#define __ASSERT_USE_STDERR
	
	// Redirect stdout to UartDebug output
	FILE UartDebug = FDEV_SETUP_STREAM(UART_DEBUG_putchar,NULL,_FDEV_SETUP_WRITE);
	stdout = &UartDebug;
	
	// Redirect stderr to UartCDE output 
	FILE UartCDE  = FDEV_SETUP_STREAM(UART_CDE_putchar,NULL,_FDEV_SETUP_WRITE);
	stderr = &UartCDE;


	while (1)
	{
		fprintf(stdout, "Output Standard Test 1\r\n");
		printf("Output Standard Test 2\r\n");
		
		fprintf(stderr, "Error Standard Test 1\r\n");
//		assert (false);
		_delay_ms(2000);
	}
	
	return EXIT_SUCCESS;
}

int UART_DEBUG_putchar(const uint8_t data)
{
	UART_DEBUG_write(data);
	return 0;
}

int UART_CDE_putchar(const uint8_t data)
{
	UART_CDE_write(data);
	return 0;
}

 

  • The output:

UartDebug(COM 3)

 

UartCDE(COM 10)

 

Look like, it resolves the problem.

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

BTW the weird character at the begging can be ignored by changing the place of my delay :

#include <atmel_start.h>

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <util/delay.h>

int UART_DEBUG_putchar(const uint8_t data);
int UART_CDE_putchar(const uint8_t data);


int main(void)
{
	// System initialisation via atmel start
 	atmel_start_init();

//	#define __ASSERT_USE_STDERR
	
	// Redirect stdout to UartDebug output
	FILE UartDebug = FDEV_SETUP_STREAM(UART_DEBUG_putchar,NULL,_FDEV_SETUP_WRITE);
	stdout = &UartDebug;
	
	// Redirect stderr to UartCDE output 
	FILE UartCDE  = FDEV_SETUP_STREAM(UART_CDE_putchar,NULL,_FDEV_SETUP_WRITE);
	stderr = &UartCDE;


	while (1)
	{
                _delay_ms(2000);

		fprintf(stdout, "Output Standard Test 1\r\n");
		printf("Output Standard Test 2\r\n");
		
		fprintf(stderr, "Error Standard Test 1\r\n");
//		assert (false);
	}
	
	return EXIT_SUCCESS;
}

int UART_DEBUG_putchar(const uint8_t data)
{
	UART_DEBUG_write(data);
	return 0;
}

int UART_CDE_putchar(const uint8_t data)
{
	UART_CDE_write(data);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1


Now I can use assert as wanted :

 

#include <atmel_start.h>
#include <stdio.h>
#include <string.h>

#define __ASSERT_USE_STDERR
#include <assert.h>
#include <util/delay.h>

int UART_DEBUG_putchar(const uint8_t data);
int UART_CDE_putchar(const uint8_t data);


int main(void)
{
	// System initialisation via atmel start
 	atmel_start_init();
	
	// Redirect stdout to UartDebug output
	FILE UartDebug = FDEV_SETUP_STREAM(UART_DEBUG_putchar,NULL,_FDEV_SETUP_WRITE);
	stdout = &UartDebug;
	stderr = &UartDebug;


	while (1)
	{
		_delay_ms(2000);
		fprintf(stdout, "Output Standard Test 1\r\n");
		printf("Output Standard Test 2\r\n");
		assert (false);
	}
	
	return EXIT_SUCCESS;
}

int UART_DEBUG_putchar(const uint8_t data)
{
	UART_DEBUG_write(data);
	return 0;
}

int UART_CDE_putchar(const uint8_t data)
{
	UART_CDE_write(data);
	return 0;
}

 

Thanks awneil. Thanks clawson. You helped me a lot.