Pro Mini - is the 8MHz or 16MHz bootloader installed?

There's another thread asking how to tell the difference between an 8MHz and 16MHz Pro Mini if the crystal/resonator isn't marked, or isn't legible. I was going to answer, but realized that I don't actually know the answer.

So I have what I know is a 3.3V 8MHz Pro Mini (the crystal is marked). When I identify it as such in the IDE, and flash a slightly modified Blink.ino example, the LED blinks at the correct rate, I can read data on the serial monitor at the same baud rate as I specify in Serial.begin(9600), and printing the value of F-CPU yields 8000000. All of that is as expected.

But if I identify it as a 16MHz Pro Mini in the IDE, I can still flash the sketch just fine, but the blink rate is slow, I have to set the serial monitor to 4800, and F_CPU is 16000000.

At first I thought this was how to identify the crystal, and I think it is, but I wonder about the bootloader. It seems to me that the bootloader has to match the crystal no matter what the IDE thinks the board is. Is that right? The 8MHz and 16MHz bootloaders are in fact different, and I don't believe the bootloader is changed if I mis-identify the board when flashing sketch.

So my conclusion is that if I can identify the crystal speed, then I know the installed bootloader has to match. Otherwise I wouldn't be able to communicate with the board at all via the bootloader. Is that right, or am I missing something?

Yes. The bootloader has to match the “board” frequency which is a function of the crystal frequency (and any fuses which divide that down). It is insensitive to the F_CPU setting.

What I have done in a couple of projects where I need to run an ATmega328p at 4MHz because the battery voltage could get down to 2 volts, but I still want the convenience of having the standard bootloader (optiboot complied for 16MHz) for uploading code, I use a 16 MHz crystal. I then use a boards.txt file to set F_CPU to 4MHz when uploading the sketch (in some cores this is a simple menu selection). I also then in setup() of the sketch, set the system clock prescaler to divide the “crystal” frequency down by a factor of 4. That way, all the timing based functions work correctly because the effective (divided down) clock rate now matches F_CPU.

For the initial activity of loading the bootloader onto such a board, I just treat it as a Uno. Obviously for low voltage operation, it is also necessary to adjust the brown out fuses.

I got the idea from post #2 here: https://forum.arduino.cc/index.php?topic=271364.0 . Maybe that helps to make the topic a bit clearer.

Incidentally, if you treat an 8MHz pro mini a 16MHz for uploading code, apart from the timing issues which you’ve mentioned, you may get another problem if the 8MHz bootloader is bulkier than the 16Mhz one (as is the case with Nanos) and your sketch is very large. The sketch will be truncated if it attempts to encroach into the bootloader area which is defined by the fuse settings on the mcu and may not match the settings in boards.txt.

Thanks for the reply. I'm still on v1.8.8 of the IDE, and use the stock bootloaders. I've looked in boards.txt, and don't see any difference in fuses for the new Nano and the "old bootloader" Nano. The same is true for the 8MHz Pro Mini and the 16 MHz. But I don't know if any of these bootloaders are Optiboot. Anyway, you've confirmed that the bootloader must match the crystal frequency.

My memory about the Nano (I think) is that when they went to the new small bootloader, they forgot to change the memory allocated to the bootloader. So while it's only 512 bytes long, it still takes up 2K.

Yes. I was wrong about the Nano. The issue with that is, as you say, that although it uses the 512 byte optiboot, it reserves a 2kB chunk of flash for the bootloader. The consequence is that large programs which work on the Uno may not work on the Nano.
That can of course be fixed by adjusting the fuses, say using Avrdude, and then treating the Nano as a Uno for uploading sketches.

## Arduino Nano w/ ATmega328P
## --------------------------
nano.menu.cpu.atmega328=ATmega328P

nano.menu.cpu.atmega328.upload.maximum_size=30720        <=====  2K missing instead of only 512Bytes.
nano.menu.cpu.atmega328.upload.maximum_data_size=2048
nano.menu.cpu.atmega328.upload.speed=115200

nano.menu.cpu.atmega328.bootloader.low_fuses=0xFF
nano.menu.cpu.atmega328.bootloader.high_fuses=0xDA
nano.menu.cpu.atmega328.bootloader.extended_fuses=0xFD
nano.menu.cpu.atmega328.bootloader.file=optiboot/optiboot_atmega328.hex   <===== OPTIBOOT

Check out MiniCore also.

Only uses 512 bytes of memory.