"mystdout" FILE declaration returning error

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

Dear freaks

I was trying to implement printf function in my uart code to make it more easy.I write code in modular style.But the problem is whenever i am declaring the buffer for printf (i.e mystdout in my case) in a uart.h header file and using extern in the main file,it is returning error that "multiple definition of mystdout".

But

Whenever i am declaring mystdout within the main.c file,the code is working properly.What is getting wrong?

Please take a look at the non working code below...
 

 

uart.h

#ifndef UART_H
#define UART_H

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

void uart_init(void);
void uart_send(unsigned char data);
void uart_sendstring(char*str);

int uart_putchar(char c, FILE *stream);
FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE);

#endif

uart.c

#include "uart.h"

volatile uint8_t rcv_flag;
volatile uint8_t uart_data;

void uart_init(void)
{
UCSR0B = (1<<TXEN0)|(1<<RXEN0);
UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
UBRR0L = 0x67;//UBRRL is 0x67 for 9600 baud @ 16Mhz crystal
UCSR0B |=(1<<RXCIE0);//receive interrupt enable
}

void uart_send(unsigned char data)
{
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = data;
}

void uart_sendstring(char*str)
{
unsigned char a = 0;
while(str[a] != 0)
{
uart_send(str[a]);
a++;
}
}

ISR (USART_RX_vect)
{
rcv_flag=1;
uart_data=UDR0;
}

int uart_putchar(char data, FILE *stream)
{
	while(!(UCSR0A & (1<<UDRE0)));
	UDR0 = data;
	return 0;
}

main.c

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "uart.h"

extern FILE mystdout;

int main(void)
{
    /* Replace with your application code */
    uart_init();
	stdout = &mystdout;
	int data = 100;
	while (1)
    {

	printf("Test success %d\r\n",data);

	_delay_ms(1000);

	}
}

error screenshot

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

Go on. Remove the mystdout assignment from usart.h
Put it as a global in main.c
.
Alternatively put it in usart.c
.
Never in an H file.
.
David.

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

SHARANYADAS wrote:
whenever i am declaring (sic) the buffer for printf (i.e mystdout in my case) in a uart.h header

you are not declaring it - you are defining it!

 

So, obviously, if you #include it in more than one file you will get more than one definition - ie, multiple definitions

 

 

using extern in the main file

is totally the wrong way around!

 

The extern is the declaration - and that should go in the header.

 

http://c-faq.com/decl/decldef.html

 

http://www.avrfreaks.net/forum/tut-modularizing-c-code-managing-large-projects

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

SHARANYADAS wrote:

uart.h

FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE); // this is a DEFINITION!!

uart.c

#include "uart.h" // So this gives you a DEFINITION here

main.c

#include "uart.h" // and this gives you *another* DEFINITION here

So, clearly, you have multiple definitions!

 

EDIT

 

Note that your screenshot shows that AS actually tells you where the two definitions are - one in main.o (the result of compiling main.c), and the other in uart.o (the result of compiling uart.c),

Last Edited: Thu. Sep 7, 2017 - 09:30 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Alternatively put it in usart.c
That would be my suggestion. It's really "internal" to the UART operation. So simply:

#ifndef UART_H
#define UART_H

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

void uart_init(void);
void uart_send(unsigned char data);
void uart_sendstring(char*str);

int uart_putchar(char c, FILE *stream);

extern volatile uint8_t rcv_flag;
extern volatile uint8_t uart_data;

#endif
#include "uart.h"

volatile uint8_t rcv_flag;
volatile uint8_t uart_data;
FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE);

void uart_init(void)
{
    UCSR0B = (1 << TXEN0) | (1 << RXEN0);
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
    UBRR0L = 0x67;//UBRRL is 0x67 for 9600 baud @ 16Mhz crystal
    UCSR0B |= (1 << RXCIE0);//receive interrupt enable
    
    stdout = &mystdout;
}

void uart_send(unsigned char data)
{
    while(!(UCSR0A & (1<<UDRE0)));
    UDR0 = data;
}

void uart_sendstring(char*str)
{
    // dropping 'a' from this means you are not limited
    // to 256 character strings
    while(*str)
    {
        uart_send(*str++);
    }
}

ISR (USART_RX_vect)
{
    rcv_flag = 1;
    uart_data = UDR0;
}

int uart_putchar(char data, FILE *stream)
{
    while(!(UCSR0A & (1 << UDRE0)));
    UDR0 = data;
    return 0;
}
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "uart.h"

int main(void)
{
    /* Replace with your application code */
    uart_init();
    int data = 100;
    while (1)
    {
        printf("Test success %d\r\n",data);
        _delay_ms(1000);
    }
}

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

Thanks a lot guys for your time.Now my problem is resolved.

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

If you need it in the uart module, you can

 

static int uart_fputc (char c, FILE *stream)
{
  (void) stream;
  uart_putchar (c);
  return 0;
}

static void __attribute__ ((__constructor__,__used__))
uart_init_stdout (void)
{
  static FILE mystdout
    = FDEV_SETUP_STREAM (uart_fputc, NULL, _FDEV_SETUP_WRITE);

  stdout = &mystdout;
}

 

avrfreaks does not support Opera. Profile inactive.

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

Is the use of the constructor attribute assuming C++ rather than C and, if it is, does this mean uart_init_stdout() does not need to be called directly because it's called as a c'tor? 

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

clawson wrote:
Is the use of the constructor attribute assuming C++ rather than C
The constructor attribute works in C too.

clawson wrote:
does this mean uart_init_stdout() does not need to be called directly because it's called as a c'tor?
  Yes.

Stefan Ernst

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

You can have c'tor in C? Oh wow, you could write some really obfuscated code where the path of execution was quite tricky to follow! cheeky

 

Thanks guys, that definitely counts as today's "learn something new every day" for me. 

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

clawson wrote:
that definitely counts as today's "learn something new every day" for me

+1!

 

clawson wrote:
You can have c'tor in C?

I would like to think of it as there being a difference between a "constructor" (does not apply to C) and a "function having the __constructor__ attribute" (if applied in C actually should be read as "call this on system startup"). Perhaps I'm being to philosophical?

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Also learned that there's __constructor(4)__ where 4 sets the priority/execution order.

 

Similarly __destructor__ (also optional (N) variant) to run functions after exit from main(). 

 

The cleanup attribute on a variable could also prove fun for "unexpected" execution flow. 

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

Oh, great. More obfuscated code flow!

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

The cleanup attribute on a variable could also prove fun for "unexpected" execution flow. 

Used by atomic.h.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"Read a lot.  Write a lot."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

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

You know that thing you do with c'tor then d'tor in a C++ class to time code in a statement block? You could almost do the same in C with cleanup - interesting. Not sure how this passed me by, I guess I never studied atomic.h in sufficient detail.

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

C constructors are handled at the same stage as C++ static constructors, same for destructors (there is attribute destructor) and static destructors.

 

avr-gcc doesn't support init priority, so avr-gcc will throw a warning at constructor(prio). There is a PR to support that, but IIRC it needs Binutils support like extension of linker script.

 

avr tools run static constructors at .init6, i.e. after .init4 which clears .bss and inits .data. The bit of startup-code that runs static constructors/destructors is __do_global_ctors/dtors, and the respective addresses reside in .ctors/.dtors.
 

avrfreaks does not support Opera. Profile inactive.

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

clawson wrote:
You know that thing you do with c'tor then d'tor in a C++ class to time code in a statement block?

 

I'd like to create a "sidetrack" for that (i.e. new thread): http://www.avrfreaks.net/forum/t...

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

Last Edited: Sat. Sep 9, 2017 - 11:03 PM