After many hours I can proudly say that I have a functional prototype! Several days were spent getting all of the components on the board working properly and working towards the point where the soil probe board is programmable.
Thankfully not many issues were encountered getting the programmer board working. The first board I populated did have an issue with a defective transistor for the ESP32's autoprogrammer. The two transistors on the board toggled the enable and io0 pins on the ESP32, triggering the ESP32 to enter bootloader mode. The defective transistor was not pulling the io0 pin all the way down. This issue was found by trying to use the programmer board to program the ESP32 DevkitC I had. This allowed me to test the programmer without having the soil probe board acting as a random variable. The transistor issue was diagnosed with an oscilloscope. When I tried to remove the defective transistor, I accidentally ripped off one of its pads, ruining the board. Thankfully I had a couple extra boards and was able to populate a second board that worked properly.
The next issue I found was I made the classic mistake of not swapping the Tx and Rx pins between the programmer and soil probe, connecting Tx to Tx and Rx to Rx. To solve this mistake I made a wire bus and crossed the two wires. I will plan to permanently fix this issue in the next soil probe revision.
The most frustrating problems I encountered were on the soil probe board. The first problem came from an improperly soldered switch mode power supply (SMPS). After populating the soil probe, I noticed from the test points that the battery management controller was working properly, but its output voltage was not regulated by the SMPS. Using my multimeter to check for continuity issues or solder bridges, I found that two pins were not properly seated and connected to one side of the inductor. Using a hot air rework station, I was able to properly re-seat the component. Probing the board again showed that the correct voltage was now being output from the SMPS.
Excited as I thought this would be the only issue, I was disappointed to find that my board was still not able to program. Another setback was encountered when I improperly connected the soil probe to the programmer, reversing the polarity and frying the battery management controller. After swapping out the battery management controller with a new component, I was still having issues.
I checked that both the enable and io0 pins were toggling properly, the TX and RX pins were correctly connected between the USB to UART chip and the ESP32, and any other possible issues.
The final issue was found after watching the incoming serial debug messages coming from the ESP32. I saw that the device was able to enter some type of bootloader mode, but was unable to be programmed by the ESP-IDF. After reading the documentation online, I found my mistake. When designing the board, I allocated io2 on the ESP32 as the pin to receive interrupts from the real-time clock (RTC). The RTC's interrupt pin is configured to act as a drain, and I used a pull-up resistor with the pin. The problem I found in the documentation stated that io2 must be held low to enter serial programming mode. Testing if this was my issue, I soldered a wire to connect io2 to ground. Sure enough, the board programmed correctly!
This goes to show that you should always read all the documentation and be careful with your pin assignments!
Will give another update soon documenting how well the board works once the final code is programmed on the board.