Notes in advance
- I use 3.3V/8MHz Pro Micros; therefore I had to install the SparkFun AVR board package and this post is basically based on that.
- This is tested using a portable install of IDE 1.8.19; same principles should apply for a non-portable install of any IDE
- I'm not a specialist in the area of board packages; I've just hacked till such a time that I had a workable solution.
- I'm no powershell specialist
Naming
There are a few things when it comes to naming; in 'boards.txt' (for Arduino's AVR 'boards.txt' file, replace promicro
by leonardo
).
promicro.name=SparkFun Pro Micro
; this sets the name that the IDE displays in the status bar as well as for the ports.
promicro.build.variant=promicro
will be used in the name of a hex file when you use sketch / export compiled binary in the IDE; it has more purposes.
promicro.build.usb_product="SparkFun Pro Micro"
; this is the name that is programmed into the board and will show in Control Panel / Devices and Printers.
- The name that you see in the Device Manager is, to my knowledge, determined by the driver.
Solution
There are two functionalities regarding this solution. The first one is to program the board with the usb_description
so it can be recognised as a specific board; the second one is a dedicated powershell script that can detect that usb_product
and determine the upload port based on that.
Modifying 'boards.txt'
Edit 'boards.txt'.
For each specific board, make a copy of the 'leonardo' entry
Edit the entry according to needs so it looks like below; please note that the below is based on sparkfun's AVR board package and the vid/pid and build variant differ
################################################################################
################################## EN57 Door Switches #######################
################################################################################
EN57.name=EN57 Door Switches
# sterretje attempt to add port identification
EN57.vid.0=0x1B4F
EN57.pid.0=0x9204
# sterretje end
EN57.upload.tool=avrdude
EN57.upload.protocol=avr109
EN57.upload.maximum_size=28672
EN57.upload.maximum_data_size=2560
EN57.upload.speed=57600
EN57.upload.disable_flushing=true
EN57.upload.use_1200bps_touch=true
EN57.upload.wait_for_upload_port=true
EN57.bootloader.tool=avrdude
EN57.bootloader.unlock_bits=0x3F
EN57.bootloader.lock_bits=0x2F
EN57.bootloader.low_fuses=0xFF
EN57.bootloader.high_fuses=0xD8
EN57.build.board=AVR_PROMICRO
EN57.build.core=arduino:arduino
EN57.build.variant=promicro
EN57.build.mcu=atmega32u4
EN57.build.usb_product="EN57_Door_Switches"
EN57.build.vid=0x1b4f
EN57.build.extra_flags={build.usb_flags}
######################### Pro Micro 3.3V / 8MHz ################################
EN57.menu.cpu.8MHzatmega32U4=ATmega32U4 (3.3V, 8 MHz)
EN57.menu.cpu.8MHzatmega32U4.build.pid.0=0x9203
EN57.menu.cpu.8MHzatmega32U4.build.pid.1=0x9204
EN57.menu.cpu.8MHzatmega32U4.build.pid=0x9204
EN57.menu.cpu.8MHzatmega32U4.build.f_cpu=8000000L
EN57.menu.cpu.8MHzatmega32U4.bootloader.extended_fuses=0xFE
EN57.menu.cpu.8MHzatmega32U4.bootloader.file=caterina/Caterina-promicro8.hex
############################# Pro Micro 5V / 16MHz #############################
EN57.menu.cpu.16MHzatmega32U4=ATmega32U4 (5V, 16 MHz)
EN57.menu.cpu.16MHzatmega32U4.build.pid.0=0x9205
EN57.menu.cpu.16MHzatmega32U4.build.pid.1=0x9206
EN57.menu.cpu.16MHzatmega32U4.build.pid=0x9206
EN57.menu.cpu.16MHzatmega32U4.build.f_cpu=16000000L
EN57.menu.cpu.16MHzatmega32U4.bootloader.extended_fuses=0xCB
EN57.menu.cpu.16MHzatmega32U4.bootloader.file=caterina/Caterina-promicro16.hex
- Each of your boards needs a unique identifier in 'boards.txt'. In the above example, it is
EN57
; for the power controller I used EU07
.
EN57.name=EN57 Door Switches
is used by the IDE to show the name of the board in the status bar.
EN57.build.usb_product="EN57_Door_Switches"
is used by the verify (compile) process and eventually ends up in the HEX code after a compile. For the powershell upload script to work correktly, this needs to be the name of the sketch.
EN57.build.variant=promicro
is (amongs other things) used to create the file name of the hex file.
Restart the IDE.
After restarting the IDE, you should have new entries for your boards; select the correct one based on the needs.
As said, I'm using the SparkFun AVR board package. I have also stripped the board package down to the bare minimum needed for Sparkfun Pro Micro boards (hence only three entries).
Compiling / Exporting compiled binary
You can now work on the correct board and compile as you always do. Before you upload using the provided powershell script, you need to use Sketch / Export Compiled Binary; this will create a hex file in the sketch directory; the reason for using Sketch / Export Compiled Binary is that the hex file that you need to upload ends in a standardised directory instead of in a temp directory. E.g. after compiling for the board 'EN57 Door Switches' you will find 2 hex files.
D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710>tree /F /A
Folder PATH listing for volume Photos
Volume serial number is B246-DA42
D:.
+---EN57_Door_Switches
| EN57_Door_Switches.ino
| EN57_Door_Switches.ino.promicro.hex
| EN57_Door_Switches.ino.with_bootloader.promicro.hex
|
\---EU07_power_controller
EU07_power_controller.ino
Notes
- Because I used a portable installation, the root directory for sketches is 'sketchbook'. In your case the usual directory is 'C:\Users\yourUsername\Documents\Arduino'; I do not know how you have organised your project so it can be different.
- In IDE 2.x, (from memory, not checked) your sketch directory will have a new directory called 'Build' and the hex files will be in there.
If you have two or more instances of the IDE open, changing the board in one will also change the board in the other one.
See post #10 for correction
Uploading
Your first upload to any of the boards needs to be done using the IDE; you can use e.g. the BareMinimum example or your code; just make sure that you use the correct port. In this way, the boards will get their usb_product.
Before the upload, 'Devices and Printers' on my system looks like

After the two uploads from the IDE, 'Devices and Printers' on my system looks like

You can use the upload script from the command line like powershell -file upload.ps1 EU07_power_controller
or powershell -file upload.ps1 EN57_Door_Switches
The script takes one argument which serves two purposes
- Determine the full path for the hex file
- Know what the
usb_product
is.
Therefore the usb_description
and the name of your sketch need to be exactly the same. 
The script is written in a linear fashion; reason is that I had to refresh my basic knowledge of powershell and did not feel figuring functions out.
# powershell script to upload hex files to AVR based boards with native USB
# Author: sterretje
# command line argument
param($sketch)
if ($sketch -eq $null -or $sketch -eq "")
{
Write-Output "Please specify the sketch"
return
}
# powershell version
Get-Host | Select-Object Version
Write-Output "==="
# configuration
###################################################
#$sketch = "EU07_power_controller"
#$sketch = "EN57_Door_Switches"
$projectDir = "D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710\"
$buildDir = $projectDir + $sketch + "\"
#$buildDir = $projectDir + $sketch + "\Build\"
$avrdudeExe = "D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\packages\arduino\tools\avrdude\6.3.0-arduino17\bin\avrdude"
$avrdudeConf = "D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\packages\arduino\tools\avrdude\6.3.0-arduino17\etc\avrdude.conf"
$hexFile = $sketch + ".ino.promicro.hex"
# print configuration
###################################################
Write-Output "Configuration"
$txt = "{0,-15} {1}" -f "sketch", $sketch
Write-Output $txt
$txt = "{0,-15} {1}" -f "projectDir", $projectDir
Write-Output $txt
$txt = "{0,-15} {1}" -f "buildDir", $buildDir
Write-Output $txt
$txt = "{0,-15} {1}" -f "avrdudExe", $avrdudeExe
Write-Output $txt
$txt = "{0,-15} {1}" -f "avrdudConf", $avrdudeConf
Write-Output $txt
$txt = "{0,-15} {1}" -f "hexFile", $hexFile
Write-Output $txt
Write-Output "==="
# checking sketch directory
$uploadFile = $buildDir + $hexFile
$x = Test-Path -Path $uploadFile -PathType Leaf
if($x -eq $false)
{
$txt = "Hex file '{0}' not found" -f $uploadFile
Write-Output $txt
return
}
# get ports
Write-Output "Detecting boards"
$mydevices = Get-PnpDevice -PresentOnly -Class 'Ports' | Where-Object { $_.InstanceId -match '^USB' } | Select-Object FriendlyName, instanceID
foreach($device in $mydevices)
{
Write-Output $device.FriendlyName
}
# loop through the devices
foreach($device in $mydevices)
{
# parse FriendlyName
$regexp = "(^.+)\((COM\d+)\)$"
$result = $device.FriendlyName -match $regexp
if($result -eq $false)
{
$txt = "Parsing of FriendlyName '{0}' failed; skipping" -f $device.FriendlyName
Write-Output $txt
continue
}
# get the usb_description property
$name = Get-PnpDeviceProperty -InstanceId $device.InstanceId -KeyName "DEVPKEY_Device_BusReportedDeviceDesc" | Select-Object data
$txt = "{0,-10}{1,-30}{2}" -f $Matches[2], $Matches[1], $name.data
Write-Output $txt
# $matches[2] contains the comport
$portName = $matches[2]
# $matches[1] contains board (as in device manager)
$boardName = $matches[1]
# $name.data contains the usb_description
# check if we have the correct board (based on usb_description)
if ($name.data -ne $null -and $name.data.Equals($sketch))
{
$txt = "Reset board on '{0}'" -f $portName
Write-Output $txt
# invoke bootloader
$port= new-Object System.IO.Ports.SerialPort $matches[2],1200,None,8,one
$port.Open()
Start-Sleep -Milliseconds 500
$port.Close()
# get new list of ports
$uploadDevices = Get-PnpDevice -PresentOnly -Class 'Ports' | Where-Object { $_.InstanceId -match '^USB' } | Select-Object FriendlyName, instanceID
# loop through the devices
foreach($uploadDevice in $uploadDevices)
{
# parse FriendlyName to find bootloader
$regexp = "(^.+)bootloader \((COM\d+)\)$"
$result = $uploadDevice.FriendlyName -match $regexp
# if a board in bootloader mode is found
if($result -eq $true)
{
$txt = "Got upload port '{0}'" -f $matches[2]
$uploadPortname = $matches[2]
Write-Output $txt
$flash = "-Uflash:w:{0}:i" -f $uploadFile
Write-Output $flash
& "$avrdudeExe" "-v" "-C$avrdudeConf" "-cavr109" "-patmega32u4" "-P$uploadPortname" "-b57600" "-D" "$flash"
}
}
}
else
{
$txt = "No match for '{0}' on '{1}'" -f $sketch, $Matches[2]
Write-Output $txt
}
}
The script is also attached for your convenience at the end. The basic steps are outlined below in case you're not familiar with powershell.
Retrieve list of com ports
The script retrieves a list of ports using Get-PnpDevice
; this list of ports will not contain serial-to-usb converters but that is not relevant for the intended purpose.
The result (based on the FriendlyName
)
SparkFun Pro Micro (COM4)
Arduino Mega 2560 (COM3)
SparkFun Pro Micro (COM12)
Arduino Leonardo (COM8)
Parse com ports and get usb_description
The script loops through the list of com ports and parses them using a regular expression to extract the port. It will use this port later to reset the board.
Next it extracts the usb_description (DEVPKEY_Device_BusReportedDeviceDesc
) based on the vid/pid (instanceId
) using Get-PnpDeviceProperty
.
Upload
If it finds a matching usb_description
, it will start the upload; it resets the board using the com port, gets a new list of devices and tried to find one (using a regular expression) that contains the word 'bootloader'.
If found, it starts the upload on the com port that was extracted using the regular expression.
Example output
D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\_batch_files>powershell -file upload.ps1 EU07_power_controller
Version
-------
5.1.19041.3803
===
Configuration
sketch EU07_power_controller
projectDir D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710\
buildDir D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710\EU07_power_controller\
avrdudExe D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\packages\arduino\tools\avrdude\6.3.0-arduino17\bin\avrdude
avrdudConf D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\packages\arduino\tools\avrdude\6.3.0-arduino17\etc\avrdude.conf
hexFile EU07_power_controller.ino.promicro.hex
===
Detecting boards
SparkFun Pro Micro (COM4)
Arduino Mega 2560 (COM3)
SparkFun Pro Micro (COM12)
Arduino Leonardo (COM8)
COM4 SparkFun Pro Micro EN57_Door_Switches
No match for 'EU07_power_controller' on 'COM4'
COM3 Arduino Mega 2560
No match for 'EU07_power_controller' on 'COM3'
COM12 SparkFun Pro Micro EU07_power_controller
Reset board on 'COM12'
Got upload port 'COM17'
-Uflash:w:D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710\EU07_power_controller\EU07_power_controller.ino.promicro.hex:i
avrdude.exe: Version 6.3-20190619
Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
Copyright (c) 2007-2014 Joerg Wunsch
System wide configuration file is "D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\packages\arduino\tools\avrdude\6.3.0-arduino17\etc\avrdude.conf"
Using Port : COM17
Using Programmer : avr109
Overriding Baud Rate : 57600
AVR Part : ATmega32U4
Chip Erase delay : 9000 us
PAGEL : PD7
BS2 : PA0
RESET disposition : dedicated
RETRY pulse : SCK
serial program mode : yes
parallel program mode : yes
Timeout : 200
StabDelay : 100
CmdexeDelay : 25
SyncLoops : 32
ByteDelay : 0
PollIndex : 3
PollValue : 0x53
Memory Detail :
Block Poll Page Polled
Memory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack
----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
eeprom 65 20 4 0 no 1024 4 0 9000 9000 0x00 0x00
flash 65 6 128 0 yes 32768 128 256 4500 4500 0x00 0x00
lfuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00
hfuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00
efuse 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00
lock 0 0 0 0 no 1 0 0 9000 9000 0x00 0x00
calibration 0 0 0 0 no 1 0 0 0 0 0x00 0x00
signature 0 0 0 0 no 3 0 0 0 0 0x00 0x00
Programmer Type : butterfly
Description : Atmel AppNote AVR109 Boot Loader
Connecting to programmer: .
Found programmer: Id = "CATERIN"; type = S
Software Version = 1.0; No Hardware Version given.
Programmer supports auto addr increment.
Programmer supports buffered memory access with buffersize=128 bytes.
Programmer supports the following devices:
Device code: 0x44
avrdude.exe: devcode selected: 0x44
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.00s
avrdude.exe: Device signature = 0x1e9587 (probably m32u4)
avrdude.exe: safemode: lfuse reads as DE
avrdude.exe: safemode: hfuse reads as D8
avrdude.exe: safemode: efuse reads as CB
avrdude.exe: reading input file "D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710\EU07_power_controller\EU07_power_controller.ino.promicro.hex"
avrdude.exe: writing flash (3634 bytes):
Writing | ################################################## | 100% 0.43s
avrdude.exe: 3634 bytes of flash written
avrdude.exe: verifying flash memory against D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710\EU07_power_controller\EU07_power_controller.ino.promicro.hex:
avrdude.exe: load data flash data from input file D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710\EU07_power_controller\EU07_power_controller.ino.promicro.hex:
avrdude.exe: input file D:\_ArduinoPortable\arduino-1.8.19-sparkfun-avr.topic1201710\portable\sketchbook\1201710\EU07_power_controller\EU07_power_controller.ino.promicro.hex contains 3634 bytes
avrdude.exe: reading on-chip flash data:
Reading | ################################################## | 100% 0.19s
avrdude.exe: verifying ...
avrdude.exe: 3634 bytes of flash verified
avrdude.exe: safemode: lfuse reads as DE
avrdude.exe: safemode: hfuse reads as D8
avrdude.exe: safemode: efuse reads as CB
avrdude.exe: safemode: Fuses OK (E:CB, H:D8, L:DE)
avrdude.exe done. Thank you.
COM8 Arduino Leonardo Arduino Leonardo
No match for 'EU07_power_controller' on 'COM8'
Note
There is no indication (!!) that an upload fails; you will have to dig through the avrdude results to find the error.
Final comments
- This is not perfect; especially the fact that there is no error check (or change of colour on error) on avrdude is highly annoying. It also doesn't stop iterating once a an upload is done.
- Upgrading the boards package will result in the changing being lost.
- A possible improvement can be to integrate Arduino-CLI so you do not have to do 'export compiled binary'; I'm not familiar with the Arduino-CLI.
- Running the powershell script might result in errors regarding the executions policy (see e.g. about Execution Policies - PowerShell | Microsoft Learn). I can not remember the reasons why mine is set as shown below, I suggest that you play with them if you get the errors.
PS C:\Users\Wim> Get-ExecutionPolicy -List
Scope ExecutionPolicy
----- ---------------
MachinePolicy Undefined
UserPolicy Undefined
Process Undefined
CurrentUser RemoteSigned
LocalMachine AllSigned
Changing those settings is your own responsibility / risk 
script
upload.zip (1.6 KB)
example boards.txt
project.boards.txt (6.3 KB)