Pololu Robotics & Electronics
Menu
My account Comments or questions? About Pololu Contact Ordering information Distributors

Pololu Forum

Is it safe to edit fuse.c?


#1

Hi!
I have a pololu 3pi robot and I am programming using Ubuntu 16.04, Codeblocks, AVRDude, and, of course, my Pololu USBAVR programmer. I was trying to run this program: /* This program will be used to calibrate turning and to test functions. */ #define F_CPU 20000000 //Do not modify this line #include <avr/io.h> //Do not modify this line. #include <pololu/3pi.h> #include <pololu/buzzer.h> #include <pololu/lcd.h> #include <pololu/leds.h> #include <pololu/motors.h> #include <pololu/pulsein.h> #include <pololu/pushbuttons.h> #include <pololu/qtr.h> const time 1000 int main(void) { lcd_init_printf(); lcd_goto_xy(0,0); print("I am"); lcd_goto_xy(0,1); print("awesome!") play_frequency(2000,500,10); while(1) red_led(1); green_led(1); set_motors(255,255); delay_ms(1000); set_motors(0,0); delay_ms(1000); set_motors(255,0); delay_ms(time); set_motors(0,0); delay_ms(1000); set_motors(255,-255); delay_ms(time); set_motors(0,0); delay_ms(0,0); return 0; }

But I ran into this error:

And my fuse.h is: [code]
/* Copyright © 2007, Atmel Corporation
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

  • Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  • Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution.

  • Neither the name of the copyright holders nor the names of
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */

/* $Id$ */

/* avr/fuse.h - Fuse API */

#ifndef AVR_FUSE_H
#define AVR_FUSE_H 1

/* This file must be explicitly included by <avr/io.h>. */
#if !defined(AVR_IO_H)
#error “You must #include <avr/io.h> and not <avr/fuse.h> by itself.”
#endif

/** \file /
/
* \defgroup avr_fuse <avr/fuse.h>: Fuse Support

\par Introduction

The Fuse API allows a user to specify the fuse settings for the specific
AVR device they are compiling for. These fuse settings will be placed
in a special section in the ELF output file, after linking.

Programming tools can take advantage of the fuse information embedded in
the ELF file, by extracting this information and determining if the fuses
need to be programmed before programming the Flash and EEPROM memories.
This also allows a single ELF file to contain all the
information needed to program an AVR. 

To use the Fuse API, include the <avr/io.h> header file, which in turn
automatically includes the individual I/O header file and the <avr/fuse.h>
file. These other two files provides everything necessary to set the AVR
fuses.

\par Fuse API

Each I/O header file must define the FUSE_MEMORY_SIZE macro which is
defined to the number of fuse bytes that exist in the AVR device.

A new type, __fuse_t, is defined as a structure. The number of fields in 
this structure are determined by the number of fuse bytes in the 
FUSE_MEMORY_SIZE macro.

If FUSE_MEMORY_SIZE == 1, there is only a single field: byte, of type
unsigned char.

If FUSE_MEMORY_SIZE == 2, there are two fields: low, and high, of type
unsigned char.

If FUSE_MEMORY_SIZE == 3, there are three fields: low, high, and extended,
of type unsigned char.

If FUSE_MEMORY_SIZE > 3, there is a single field: byte, which is an array
of unsigned char with the size of the array being FUSE_MEMORY_SIZE.

A convenience macro, FUSEMEM, is defined as a GCC attribute for a 
custom-named section of ".fuse".

A convenience macro, FUSES, is defined that declares a variable, __fuse, of
type __fuse_t with the attribute defined by FUSEMEM. This variable
allows the end user to easily set the fuse data.

\note If a device-specific I/O header file has previously defined FUSEMEM,
then FUSEMEM is not redefined. If a device-specific I/O header file has
previously defined FUSES, then FUSES is not redefined.

Each AVR device I/O header file has a set of defined macros which specify the
actual fuse bits available on that device. The AVR fuses have inverted
values, logical 1 for an unprogrammed (disabled) bit and logical 0 for a
programmed (enabled) bit. The defined macros for each individual fuse
bit represent this in their definition by a bit-wise inversion of a mask.
For example, the FUSE_EESAVE fuse in the ATmega128 is defined as:
\code
#define FUSE_EESAVE      ~_BV(3)
\endcode
\note The _BV macro creates a bit mask from a bit number. It is then 
inverted to represent logical values for a fuse memory byte.

To combine the fuse bits macros together to represent a whole fuse byte,
use the bitwise AND operator, like so:
\code
(FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN)
\endcode

Each device I/O header file also defines macros that provide default values
for each fuse byte that is available. LFUSE_DEFAULT is defined for a Low
Fuse byte. HFUSE_DEFAULT is defined for a High Fuse byte. EFUSE_DEFAULT
is defined for an Extended Fuse byte.

If FUSE_MEMORY_SIZE > 3, then the I/O header file defines macros that
provide default values for each fuse byte like so:
FUSE0_DEFAULT
FUSE1_DEFAULT
FUSE2_DEFAULT
FUSE3_DEFAULT
FUSE4_DEFAULT
....

\par API Usage Example

Putting all of this together is easy. Using C99's designated initializers:

\code
#include <avr/io.h>

FUSES = 
{
    .low = LFUSE_DEFAULT,
    .high = (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN),
    .extended = EFUSE_DEFAULT,
};

int main(void)
{
    return 0;
}
\endcode

Or, using the variable directly instead of the FUSES macro,

\code
#include <avr/io.h>

__fuse_t __fuse __attribute__((section (".fuse"))) = 
{
    .low = LFUSE_DEFAULT,
    .high = (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN),
    .extended = EFUSE_DEFAULT,
};

int main(void)
{
    return 0;
}
\endcode

If you are compiling in C++, you cannot use the designated intializers so
you must do:

\code
#include <avr/io.h>

FUSES = 
{
    LFUSE_DEFAULT, // .low
    (FUSE_BOOTSZ0 & FUSE_BOOTSZ1 & FUSE_EESAVE & FUSE_SPIEN & FUSE_JTAGEN), // .high
    EFUSE_DEFAULT, // .extended
};

int main(void)
{
    return 0;
}
\endcode


However there are a number of caveats that you need to be aware of to
use this API properly.

Be sure to include <avr/io.h> to get all of the definitions for the API.
The FUSES macro defines a global variable to store the fuse data. This 
variable is assigned to its own linker section. Assign the desired fuse 
values immediately in the variable initialization.

The .fuse section in the ELF file will get its values from the initial 
variable assignment ONLY. This means that you can NOT assign values to 
this variable in functions and the new values will not be put into the
ELF .fuse section.

The global variable is declared in the FUSES macro has two leading 
underscores, which means that it is reserved for the "implementation",
meaning the library, so it will not conflict with a user-named variable.

You must initialize ALL fields in the __fuse_t structure. This is because
the fuse bits in all bytes default to a logical 1, meaning unprogrammed. 
Normal uninitialized data defaults to all locgial zeros. So it is vital that
all fuse bytes are initialized, even with default data. If they are not,
then the fuse bits may not programmed to the desired settings.

Be sure to have the -mmcu=<em>device</em> flag in your compile command line and
your linker command line to have the correct device selected and to have 
the correct I/O header file included when you include <avr/io.h>.

You can print out the contents of the .fuse section in the ELF file by
using this command line:
\code
avr-objdump -s -j .fuse <ELF file>
\endcode
The section contents shows the address on the left, then the data going from
lower address to a higher address, left to right.

*/

#ifndef ASSEMBLER

#ifndef FUSEMEM
#define FUSEMEM attribute((used, section (".fuse")))
#endif

#if FUSE_MEMORY_SIZE > 3

typedef struct
{
unsigned char byte[FUSE_MEMORY_SIZE];
} __fuse_t;

#elif FUSE_MEMORY_SIZE == 3

typedef struct
{
unsigned char low;
unsigned char high;
unsigned char extended;
} __fuse_t;

#elif FUSE_MEMORY_SIZE == 2

typedef struct
{
unsigned char low;
unsigned char high;
} __fuse_t;

#elif FUSE_MEMORY_SIZE == 1

typedef struct
{
unsigned char byte;
} __fuse_t;

#endif

#if !defined(FUSES)
#if defined(AVR_XMEGA)
#define FUSES NVM_FUSES_t __fuse FUSEMEM
#else
#define FUSES __fuse_t __fuse FUSEMEM
#endif
#endif

#endif /* !ASSEMBLER */

#endif /* AVR_FUSE_H */
[/code]

What does this file do? and is it safe to edit?


#2

Hello.

You can read the comments at the top of the avr/fuse.h file which states what that file does, or for a user-friendly version, you can see the avr/fuse.h documentation on avr-libc’s official website.

I looked over your code and noticed some mistakes, which you should fix:

  1. const time 1000 is wrong and should be const int time = 1000;.

  2. You are missing a semi-colon after print("awesome!").

  3. You defined too many parameters in delay_ms(0,0).

For now, I do not recommend editing fuse.h or any of the other AVR header files in /usr/lib/avr. Where is the fuse.c file on your system? Can you resize the columns in the error output showing the full filenames that are being referred to and attach copies of those files to your post? Also, can you post the full build output you get in your IDE, including the commands that run avr-gcc?

- Amanda


#3

Thanks for the corrections to my program. The fuse.c was a typo and I meant fuse.h. I have not edited the fuse.h file, as I did not even know this file existed. I have shown you the full output in the “build messages” section. My code is on my other computer, so I’ll be back shortly.


#4

Here is my build log.

-------------- Build: Debug in Pololu 3pi hello world (compiler: GNU GCC Compiler for AVR)---------------

avr-gcc -Wall -mmcu=atmega328p -DF_CPU=20000000UL -g -I/usr/include -c fuse.c -o obj/Debug/fuse.o
In file included from /usr/lib/avr/include/avr/io.h:638:0,
                 from fuse.c:1:
/usr/lib/avr/include/avr/fuse.h: In function ‘strtoumax’:
/usr/lib/avr/include/avr/fuse.h:244:3: error: storage class specified for parameter ‘__fuse_t’
 } __fuse_t;
   ^
fuse.c:3:1: error: expected declaration specifiers before ‘__fuse_t’
 FUSES = {
 ^
fuse.c:7:2: error: expected declaration specifiers before ‘;’ token
 };
  ^
In file included from /usr/lib/avr/include/avr/sfr_defs.h:126:0,
                 from /usr/lib/avr/include/avr/io.h:99,
                 from fuse.c:1:
/usr/include/inttypes.h:301:18: error: old-style parameter declarations in prototyped function definition
 extern uintmax_t strtoumax (const char *__restrict __nptr,
                  ^
fuse.c:7:2: error: expected ‘{’ at end of input
 };
  ^
fuse.c:7:2: warning: control reaches end of non-void function [-Wreturn-type]
 };
  ^
Process terminated with status 1 (0 minute(s), 0 second(s))
5 error(s), 1 warning(s) (0 minute(s), 0 second(s))

#5

It looks like one of the errors is coming from /usr/include/inttypes.h. The /usr/include directory contains header files for your system’s native C compiler (e.g. stdio.h), not AVR-specific header files. You should remove -I/usr/include argument from the avr-gcc command-line before recompiling your project to see if that changes anything.

Also, can you please attach copies of the files mentioned in the error output so that we can get a better understanding of how your environment is configured and what might be causing the issue?

- Amanda


#6

How would I do that?
My network is not fast enough to attach any of my files, sorry.


#7

We are not familiar with Code::Blocks, so we cannot tell you where to configure your compiler options in that IDE. You might try posting on the Code::Blocks forum.

If your Internet connection is fast enough to read this forum, then it is fast enough to upload a few source code files.

- Amanda


#8

I upgraded to Ubuntu 16.10 and my fuse.h errors went away! But I got more errors. I will try reinstalling your library and head over to the code::blocks forum if I need help. Also, would it be possible to copy an example project from your library and replace main.c or test.c with my code?


#9

Yes, it is possible; you can modify any of the example templates for the 3pi in the Pololu AVR Library.

- Amanda


#10

I tried it and it worked! I have another question which I will ask in a new thread.