platformio / platformio-core

Your Gateway to Embedded Software Development Excellence :alien:
https://platformio.org
Apache License 2.0
7.84k stars 789 forks source link

Settings fuses for Atmel AVR MCUs #865

Closed MCUdude closed 7 years ago

MCUdude commented 7 years ago

Hi! I'm struggling to find any information on how to write and upload code to a generic AVR, such as the ATmega32, without depending on the Arduino framework.

Does there exist/is it possible to create something like this:

[env:avr-gcc]
platform = atmelavr
board = atmega324
framework = avr-libc
f_cpu = 8000000L
h_fuse = 0xd6
l_fuse = 0xf7
upload_protocol = stk500v2
upload_flags = -Pusb

Where I can define the microcontroller, low fuse, high fuse and clock frequency, and be able to compile and upload within PlatformIO? Compiling for a generic AVR microcontroller with a specific clock frequency is as simple as running a single command using avr-gcc. Same goes with uploading. How can this be done be using PlatformIO?

ivankravets commented 7 years ago

How about this example?

MCUdude commented 7 years ago

It's a good example, but I'm limited to just a couple of ATtiny chips. I also want to be able to run something like platformio run -t fuses to set the fuses, if that's possible. This platformIO command will simply "trigger" an Avrdude command based on the fuse settings defined in platformio.ini. Is it possible to issue a PlatformIO command to just set the correct fuses, like the example above?

I've created a lot of Arduino cores, to add support for the most popular AVRs out there. My philosophy has allways been to keep it simple, but easily confurable. I'll love to add support for some AVR microcontrollers under the "Atmel AVR" category. Does there exist any guides out there on how to add support for mor hardware? avr-gcc and avrdude is allready working, so there shouldn't be a huge job get it to work.

In the first round I'd like to add the ATmega1284/P, ATmega644/P/PA, ATmega324/P/PA, ATmega164P/PA, ATmega32, ATmega16 and ATmega8535 😃

MCUdude commented 7 years ago

I found this JSON file (mightycore324.json) in my system folder, and I guess it can be used as a template for a non-arduino environment:

{
  "build": {
    "core": "MightyCore", 
    "extra_flags": "-DARDUINO_ARCH_AVR -DARDUINO_AVR_ATmega324", 
    "f_cpu": "16000000L", 
    "mcu": "atmega324p", 
    "variant": "mightycore"
  }, 
  "frameworks": [
    "arduino"
  ], 
  "name": "MightyCore ATmega324", 
  "upload": {
    "maximum_ram_size": 2048, 
    "maximum_size": 32256, 
    "protocol": "arduino", 
    "require_upload_port": true, 
    "speed": 115200
  }, 
  "url": "https://www.tindie.com/products/MCUdude/dip-40-arduino-compatible-development-board", 
  "vendor": "Mcudude"
}

I still got some questions though. Which fields are mandatory and/or which can be moved to the platform.ini file? What options can I use for the "core" and "frameworks" field? Is "avr-libc" a valid option for instance? Thanks!

EDIT: It turned out it was easier to start by modifying the JSON file for the generic ATtiny85. The file (attiny85.json) was located at C:/Users/Username/.platformio/platforms/atmelavr/boards on my Windows computer. I still haven't figured out how to burn the fuses using a separate (platformio) command, but I'm able to build and upload to an ATmega8515 I had lying around.

The modified JSON file (atmega8515.json) looks like this:

{
  "build": 
  {
    "mcu": "atmega8515",
    "f_cpu": "",
    "variant": ""
  },

  "name": "Generic ATmega8515",
  "upload": 
  {
    "maximum_size": 8192,
    "maximum_ram_size": 512,
    "protocol": "",
    "extra_flags": ""

  },
  "url": "https://github.com/MCUdude/PlatformIO_AVR",
  "vendor": "Generic ATmega8515"
}

Does it looks OK? It compiles without any errors, but does is miss anything significant?

The platfromio.ini file looks like this:

[env:native_avr]
;Platform
platform = atmelavr
;Microcontroller
board_mcu = atmega8515
;Clock frequency
board_f_cpu = 16000000L
;Programming tool
upload_protocol = stk500
;Avrdude extra options
upload_flags = -P COM7 -e

How can I change/add a new environment name, such as avr_atmega8515?

ivankravets commented 7 years ago

What is a difference between this manifest?

Here are located all AVR-based manifests for boards:

I also want to be able to run something like platformio run -t fuses to set the fuses, if that's possible.

PlatformIO is very flexible build system. You can extend it with an own target, such as fuses. See

I think that we can have built-in fuses target and fill "fuses" data to board manifests.

Here is a list of default targets for ATMEL AVR development platform:

MCUdude commented 7 years ago

What is a difference between this manifest?

MightyCore is the name of an Arduino add-on for adding support for a handful of pin compatible micro controllers, including the ATmega8535. While the MightyCore add-on for Arduino IDE lets the user configure clock frequencies, brown-out detection and pinout, the PlatformIO doesn't have any. TL;DR MightyCore is an Arduino add-on. This issue is for native AVR support with all necessary configurations

I'm a Mac user which uses Arduino IDE and avr-gcc+ make files to program AVRs. At work I'm using a windows machine, and everybody knows that the windows command line is just terrible. I was hoping that I could use PlatformIO at work (on my PC) and at home (on my mac), and still be able to configure the microcontroller options like I can with my own MightyCore and with avr-gcc+makefiles. I'm really close, but I'm not able to set the fuses using PlatformIO yet. I'm sure a lot of AVR devs would love using PlatformIO if the MCU settings was more configurable. If its possible to run something like $ platformio fuses, I think all this would be solved. I've created JSON files for all variants (same name, different device signature) for ATmega8535, ATmega16, ATmega32, ATmega324, ATmega644 and ATmega1284. I'm going to create some examples with different configurations if this gets added to this repo.

ivankravets commented 7 years ago

In this case, a manifest will look like:

{
  "build": 
  {
    "mcu": "atmega8515",
    "f_cpu": "16000000L",
    "variant": "standard"
  },

  "name": "Generic ATmega8515",
  "upload": 
  {
    "maximum_size": 8192,
    "maximum_ram_size": 512,
    "protocol": "stk500",
    "extra_flags": "-e"

  },
  "url": "http://www.atmel.com/devices/atmega8515.aspx",
  "vendor": "Generic ATmega8515"
}

and platformio.ini as

[env:native_avr]
platform = atmelavr

P.S: Before pulling a request to PIO Atmel AVR repo, you can test own manifests from boards directory that is located in project folder.


I was hoping that I could use PlatformIO at work (on my PC) and at home (on my mac)

That is why PlatformIO was developed - to provide the same workflow on the different host machines (Win, Linux, FreeBSD, macOS, etc)

That is very easy. Please explain me how final avrdude command should look and which arguments are dynamic. I'll create "base" for you, the only one thing will be needed, is to prefill all these fuses to board manfiests.

MCUdude commented 7 years ago

This is great, thank you!! 😃 The Avrdude command template for setting the fuses looks like this: avrdude -p {mcu} -c {programmer} -P {port} {extra_arguments} -Ulock:w:0x3f:m -Uefuse:w:{extended_fuse}:m -Uhfuse:w:{high_fuse}:m -Ulfuse:w:{low_fuse}:m

This only issue here is that "older" AVRs, such as ATmega8535, ATmega8515, ATmega16 and ATmega32 doesnt have an extended fuse. Avrdude will return an error if the command above is used to set the fuses for the 8535, 16 or 32. I solved this by doing a small change to avrdude.conf - the file where all microcontroller info is stored. If this mod is applied, Avrdude would just ignore the empty efuse field.

When all this is wraped up and finished; will it be possible to make PlatformIO automatically add these extra parameters to the platformio.ini file, so that the user doesn't have to type them manually in order to build, set fuses and upload code?

Another question, I tried setting the f_cpu field in the json file as 16 MHz default ("f_cpu": "16000000L"), but then I wasn't able to redefine the f_cpu inside the main.c or platformio.ini file.

MCUdude commented 7 years ago

I tried to add the atmega8515.json file (embedded below) to the atmelavr/boards directory, but I get this error message when trying to create a new project using Atom. If I remove the file, everything is working just fine. Are there any files missing?

/C:/Users/user/.atom/packages/platformio-ide/lib/utils.js:248
Hide Stack Trace
Error: Failed to get boards
    at getBoards (C:/Users/user/.atom/packages/platformio-ide/lib/utils.js:181:13)
    at InitializeNewProjectView.initializeBoardsSelect (C:/Users/user/.atom/packages/platformio-ide/lib/init/view.js:59:20)
    at InitializeNewProjectView.initialize (C:/Users/user/.atom/packages/platformio-ide/lib/init/view.js:55:10)
    at InitializeNewProjectView.BaseView (C:/Users/user/.atom/packages/platformio-ide/lib/base-view.js:25:20)
    at new InitializeNewProjectView (C:/Users/user/.atom/packages/platformio-ide/lib/init/view.js:25:38)
    at Object.command (C:/Users/user/.atom/packages/platformio-ide/lib/init/command.js:49:14)
    at atom-workspace.platformioIdeInitializeNewProject (C:/Users/user/.atom/packages/platformio-ide/lib/main.js:67:59)
    at CommandRegistry.module.exports.CommandRegistry.handleCommandEvent (C:\Users\user\AppData\Local\atom\app-1.12.7\resources\app.asar\src\command-registry.js:259:29)
    at CommandRegistry.handleCommandEvent (C:\Users\user\AppData\Local\atom\app-1.12.7\resources\app.asar\src\command-registry.js:3:59)
    at CommandRegistry.module.exports.CommandRegistry.dispatch (C:\Users\user\AppData\Local\atom\app-1.12.7\resources\app.asar\src\command-registry.js:160:19)
    at runAtomCommand (C:/Users/user/.atom/packages/platformio-ide/lib/utils.js:111:24)
    at HTMLAnchorElement.callback (C:/Users/user/.atom/packages/platformio-ide/lib/home-screen/quick-links.js:41:25)

atmega8515.json:

{
  "build": 
  {
    "mcu": "atmega8515",
    "f_cpu": "",
    "variant": ""
  },

  "name": "Generic ATmega8515",
  "upload": 
  {
    "maximum_size": 8192,
    "maximum_ram_size": 512,
    "protocol": "",
    "extra_flags": ""

  },
  "url": "https://github.com/MCUdude/PlatformIO_AVR",
  "vendor": "Generic ATmega8515"
}
ivankravets commented 7 years ago
  1. Please run pio platform uninstall
  2. Install development version of Atmel AVR dev platform: pio platform install https://github.com/platformio/platform-atmelavr/archive/develop.zip
  3. Add "bootloader" data to board manifest.
  4. Set fuses using pio run -t fuses.

See my changes:

ivankravets commented 7 years ago

Another question, I tried setting the f_cpu field in the json file as 16 MHz default ("f_cpu": "16000000L"), but then I wasn't able to redefine the f_cpu inside the main.c or platformio.ini file.

If you want to overwrite some data, you should specify them. I see you didn't do that. Please specify board = ??? in platformio.ini.

MCUdude commented 7 years ago

Please run pio platform uninstall Install development version of Atmel AVR dev platform: pio platform install https://github.com/platformio/platform-atmelavr/archive/develop.zip Add "bootloader" data to board manifest. Set fuses using pio run -t fuses.

bootloader? The native AVRs doesn't use a bootloader. Is this to unify all "avr boards", so that the ones that doesn't use a bootloader simply just leaves a blank field?

ivankravets commented 7 years ago

bootloader? The native AVRs doesn't use a bootloader.

OK, how we should name this section in board config? Just fuses?

MCUdude commented 7 years ago

I think fuses is ok. It's self explaining 👍 If a bootloader option is going to be added some day I think it should be simply named bootloader

ivankravets commented 7 years ago

I think fuses is ok. It's self explaining

Thanks, done! Please test it. Later we will discuss PRs with your generic boards and make final release of Atmel AVR development platform.

https://github.com/platformio/platform-atmelavr/commit/4b924dd820f524b9ebc2a319c7b78ef0464b319f

ivankravets commented 7 years ago

I tried to add the atmega8515.json file (embedded below) to the atmelavr/boards directory, but I get this error message when trying to create a new project using Atom.

Please specify "f_cpu": "16000000L".

MCUdude commented 7 years ago

Great, I'll dig out my old UNO and test it tomorrow. It's past midnight here in Norway 😉

Thank you for the fast response and even bothering implementing this!

MCUdude commented 7 years ago

~~I'm able to set the fuses on my Arduino uno using the pio run -t fuses -v. However I'm not able to set the fuses on the ATmega8515. It returns "Sucess", but I can tell from the blink program running on the microcontroller that no fuses where changed. ~~

It turned out I had to use the term board instead of _boardmcu.

[env:avr_atmega8515]
;Platform
platform = atmelavr
;Microcontroller
board = atmega8515
;Clock frequency
board_f_cpu = 16000000L
;Programming tool
upload_protocol = stk500
;Avrdude extra options
upload_flags = -P COM7 -e -v

The current atmega8515.json file looks like this:

{
  "build": 
  {
    "mcu": "atmega8515",
    "f_cpu": "1000000L",
    "variant": "standard"
  },

  "upload": 
  {
    "maximum_size": 8192,
    "maximum_ram_size": 512,
    "protocol": "",
    "extra_flags": ""
  },

  "fuses": 
  {
    "low": "0xC1",
    "high": "0xD9",
    "extended": "0xff",
    "unlock": "0x3F"
  },

  "name": "ATmega8515",
  "url": "http://atmel.com",
  "vendor": "Atmel AVR"
}

I inserted the default (factory set) clock frequency and fuses (internal 1 MHz oscillator), so that these settings is applied if no fuses or clock frequency are specified. The only "fuses related" issue it to deal with the missing efuse on older AVRs. when setting the fuses for the ATmega8515, I get this warning and error:

avrdude: verifying ...
avrdude: 1 bytes of hfuse verified
"efuse" memory type not defined for part "ATmega8515"

avrdude: safemode: hfuse reads as D9
avrdude: safemode: Fuses OK (E:FF, H:D9, L:C1)

avrdude done.  Thank you.

*** [fuses] Error 1
=================================================================================================================== [ERROR] Took 1.83 seconds ===================================================================================================================
ivankravets commented 7 years ago

upload_flags = -P COM7 -e -v

Please totally remove this line from config. See pio run -t fuses --verbose

ivankravets commented 7 years ago

when setting the fuses for the ATmega8515

We can check all these fuses. If a board doesn't have "extended" fuse, we will not add it to command. WDYT?

ivankravets commented 7 years ago

Ok, now all fuses are dynamic. Please be careful and specify correct keys for fuses. See my latest commit

MCUdude commented 7 years ago

We can check all these fuses. If a board doesn't have "extended" fuse, we will not add it to command. WDYT?

IMO this is the correct way of doing it!

I've reinstalled the atmelavr package, but now I get this error:

Collected 0 compatible libraries
Looking for dependencies...
Project does not have dependencies
BeforeUpload(["fuses"], [])
avrdude -v -p atmega8515 -C avrdude.conf -c stk500 -P COM9 -e -Ulock:w:0x0F:m -Uhfuse:w:0xD9:m -Ulfuse:w:0xC1:m
'avrdude' is not recognized as an internal or external command,
operable program or batch file.
*** [fuses] Error 1

the atmega8515.json file looks like this:

{
  "build": 
  {
    "mcu": "atmega8515",
    "f_cpu": "16000000L",
    "variant": "standard"
  },

  "upload": 
  {
    "maximum_size": 8192,
    "maximum_ram_size": 512,
    "protocol": "",
    "extra_flags": ""
  },

  "fuses": 
  {
    "lfuse": "0xC1",
    "hfuse": "0xD9",
    "lock": "0x0F"
  },

  "name": "ATmega8515",
  "url": "http://atmel.com",
  "vendor": "Atmel AVR"
}

and the ini file looks like this:

[env:avr_atmega8515]
;Platform
platform = atmelavr
;Microcontroller
board = atmega8515
;Clock frequency
board_f_cpu = 16000000L
;Programming tool
upload_protocol = stk500
;Avrdude extra options
upload_flags = -P COM9
;Fuses
;lfuse = 0xFF
;hfuse = 0xd4
;lock = 0x0f

Oh! What's the magic keyword for changing the lfuse, hfuse and lock fuse inside the ini file?

ivankravets commented 7 years ago

'avrdude' is not recognized as an internal or external command,

Fixed in https://github.com/platformio/platform-atmelavr/commit/b8596f03f1ac13a9c669b68c81be96cbd9844de2

Oh! What's the magic keyword for changing the lfuse, hfuse and lock fuse inside the ini file?

You can't set fuses in platformio.ini. Only in board manifest. Also, you don't need to create own manifest for atmega8515. Just use board = mightycore8535 and don't specify framework option in platformio.ini.

What is more, I think that we can rename existing mightycore*.json manifests to something general to avoid duplicated manifests. What do you think?

MCUdude commented 7 years ago

You're absolutely sure it's not possible to find a way to change the fuses within the initial file? Configurable fuses is very important when developing for AVR. On the Arduino platform all the fuses and settings are allready preset, but on bare bone AVR you need the full control.

Let's say I've been working with a project at work, and have done some changes to the fuses in the manifest file. When I get home and continue to work on the same project (shared on Dropbox or Drive), I'm working with an other manifest file with different fuses. If I'm going to set the fuses again, I'll have to edit this manifest file as well. This is a huge downside, because I might have multiple projects that uses the same manifest file, but have different fuses, depending on application. Fuses are highly project dependent (unlike the Arduino platform), and should be configurable within the project file. This is crucial for an AVR developer.

What is more, I think that we can rename existing mightycore*.json manifests to something general to avoid duplicated manifests. What do you think?

I personally would add a couple of extra manifest files in order to make the list as self explaining clean as possible. Like mentioned earlier, the MightyCore*.Json. Files have all settings pre-configured, and doesn't need to be changed (Arduino). I think it's best to separate the generic AVR manifests and the Arduino manifests, because the default configurations are so different.

ivankravets commented 7 years ago

You're absolutely sure it's not possible to find a way to change the fuses within the initial file?

PlatformIO allows overriding of built-in manifests. You can clone default manifest to ~/.platformio/boards/ or to /project/boads folder and specify custom options.

Another way is to use extra_script and specify custom FUSESCMD.

I think it's best to separate the generic AVR manifests and the Arduino manifests, because the default configurations are so different.

Could you explain a difference between mightycore8535 and generic atmega8515? I don't remember why we called manifest with "core" name. This a big mistake because 1 board can support multiple frameworks/cores. Later, developer decides which framework to use or ignores it to use in native mode.

MCUdude commented 7 years ago

Could you explain a difference between mightycore8535 and generic atmega8515? I don't remember why we called manifest with "core" name. This a big mistake because 1 board can support multiple frameworks/cores. Later, developer decides which framework to use or ignores it to use in native mode.

IMO I think the whose board list is quite messy. There are hundreds of boards, and many skared the same hardware (read: microcontroller), but with different configurations such as fuse settings, frameworks (native AVR, Arduino, Espressif SDK etc).

Ideally the user should select what kind of hardware he/she's using when creating a project. Then the user should specify what kind of platform he/she's using. This may be harder to understand for beginners, but much more intuitive and elegant for the rest of us. What do you think?

ivankravets commented 7 years ago

Do you mean PlatformIO IDE? Yes, it asks only about board now. However, we have started big work on PlatformIO IDE 2.0. I think that "New Project" wizard will be rewritten from a scratch. See

P.S: What do wee need for resovling this issue?

MCUdude commented 7 years ago

P.S: What do wee need for resovling this issue?

if it's possible to override the manifest by adding it to the project manually, the problem will be solved, as long as the user is able to find proper documentation on this. Is PlatformIO able to automatically copy the manifest file to the /project/boards, when a project with the ATmega8515 (or similar AVR) is created?

I'm curious to see how an extra script may be implemented. will this be as elegant as running a single command in the terminal?

ivankravets commented 7 years ago

See http://docs.platformio.org/en/latest/platforms/atmelavr.html#fuses.

You can use existing mightycore8535 and override default values.

MCUdude commented 7 years ago

Great! Now should we add a separate section called "Atmel AVR", where we could add the following microcontrollers to the list:

I'm happy to create JSON files for these with the correct factory fuses, if they're going to be added to the list. All these are Arduino compatible, so there's a lot of resources online.

ivankravets commented 7 years ago

How about to merge mighty*.json with your new board list mentioned above?

MCUdude commented 7 years ago

The only problem by doing that is that the "Arduino" variants have different fuse settings than the native ones (16 MHz external oscillator vs. 1 MHz internal oscillator).

ivankravets commented 7 years ago

I like this board IDs, like ATmega8, ATmega16, ATmega32, etc...

How about to have ATmega8, ATmega16, ATmega32, etc...and use native fuses by default? In any case, user will be able to override default fuses.

neilyoung commented 7 years ago

To be honest I find that a bit misleading info regarding how to set fuses.

Tried this in my platform.ini (as suggested):

[env:custom_fuses]
platform = atmelavr
extra_script = extra_script_fuses.py

Content of extra_script_fuses.py:

Import('env')

env.Replace(FUSESCMD="avrdude $UPLOADERFLAGS -e -Uhfuse:w:0x9F:m -Uefuse:w:0xFF:m -Ulfuse:w:0x64:m")

Running "platformio run --target fuses" gives this:

[Tue May  9 10:48:11 2017] Processing custom_fuses (extra_script: extra_script_fuses.py, platform: atmelavr)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
Collected 0 compatible libraries
Looking for dependencies...
Project does not have dependencies
Looking for upload port...
Auto-detected: /dev/cu.usbserial-FTGXQ6S9
Setting FUSEs
avrdude: can't open config file "/Users/jenkins/jenkins/workspace/avrdude/label/mac-mini/objdir/etc/avrdude.conf": No such file or directory
avrdude: error reading system wide configuration file "/Users/jenkins/jenkins/workspace/avrdude/label/mac-mini/objdir/etc/avrdude.conf"
*** [fuses] Error 1

Ehem... jenkins?? That's not me :)