The ESP8266 -- Weird bootrom baud rate

This is a bit of esoteric information that most people won't care about.

Many people have noticed that if you fire up a terminal emulator program to watch the boot messages from an ESP8266 at some standard baud rate like 115200 you just see garbage. This is because the bootrom is transmitting messages at the odd baud rate of 74880 baud.

If you are curious (like me) you would like to see the messages, but this is a significant problem given that no linux utility that I have found has 74880 as an available baud rate option. But there is a way. What you do is to write a short C program to make a call to termios to set the baud rate for the port, then you start up picocom with the --noinit option so it simply takes the port "as is" without trying to reinitialize it.

Grab this and compile and run it like this:

cc -o baud baud.c
baud /dev/ttyUSB0 74880
picocom --noinit /dev/ttyUSB0
If you do this, you should see:
 ets Jan  8 2013,rst cause:2, boot mode:(1,6)
At least that is what I see on my unit when I hit reset with GPIO-0 grounded. If I pull GPIO-0 high and let it load my application, I see:
 ets Jan  8 2013,rst cause:2, boot mode:(3,7)

load 0x40100000, len 27188, room 16 
tail 4
chksum 0xc0
load 0x3ffe8000, len 884, room 4 
tail 0
chksum 0x30
load 0x3ffe8378, len 280, room 8 
tail 0
chksum 0x12
csum 0x12
Sometimes I get different messages to start things off, namely:
 ets Jan  8 2013,rst cause:2, boot mode:(3,6)
 ets Jan  8 2013,rst cause:2, boot mode:(3,0)
And this seems to depend on how long the unit has been running or more likely what the unit is doing when I hit reset. If it is still in the midst of booting and I hit reset again quickly, I get the zero.

Not 76800 but 74880 baud

A number of people have reported this baud rate as 76800, but this is incorrect, it is 74880. 76800 is close enough though for the characters to be assembled by a uart, so it does the job.

The weird rate is because the CPU clock is running at 52 Mhz in the bootrom. Some unknown thing in the SDK kicks the clock up to 80 Mhz later.

Whoever wrote the bootrom code wrongly thought the bootrom was running at 80 Mhz and (as it turns out) the serial port clock is derived from the CPU clock so we end up with 52/80 * 115200 = 74880 baud.

I have set up experiments and timed this with a stopwatch getting 51.7 seconds and 52.3 seconds (nicely averaging to 52.0 seconds) when I expect a 52 second delay (using the CCOUNT register in the ESP8266 processor). If the baud rate was 76800 we would measure 53.33 seconds.

Why did they do this?

I have spent some time scratching my head and wondering just why they did this crazy thing. I got an email from Edouard Gora, YO3HCV in early 2018 who suggested a reasonable and completely logical explanation.

Most likely they developed the bootrom code on a system with a 20 or 40 Mhz crystal. The default PLL multiplier in the chip seems to be 2x, giving a 40 or 80 Mhz CPU clock. This would have given sane baud rates.

Later for some unknown reason, the modules we use were all manufactured using 26 Mhz crystals. Edouard guesses that either 26 Mhz crystals were cheaper and/or the modules did not meet EMI requirements with a 40 Mhz crystal. Whatever the reason, it would seem that the crystal was changed later from 40 to 26 and this is the reason for the strange baud rate.

Other resources

A search on "esp8266 52 Mhz" yields some interesting results in 11-2017. In particular, a fellow on Github "CNLohr" has done a fair bit of ESP8266 hacking, including a "nosdk8266" project. Like me, he discovered that the bootrom is running at 52 Mhz. This bit of code is recommended:
    if(rom_i2c_readReg(103,4,1) != 136) { // 8: 40MHz, 136: 26MHz
        //if(get_sys_const(sys_const_crystal_26m_en) == 1) { // soc_param0: 0: 40MHz, 1: 26MHz, 2: 24MHz
            // set 80MHz PLL CPU
            rom_i2c_writeReg(103,4,1,136);
            rom_i2c_writeReg(103,4,2,145);
        //}
    }
The esp8266 memory map wiki suggests that 0x60000d00 is the base address of internal i2c controller registers, and is used by rom_i2c_readReg and rom_i2c_writeReg, which are ROM functions.