I’m pulling my hair out over here. I’ve got a TTGO ESP32 board (the one with the cellular modem) and an Arducam MEGA SPI 3Mpx camera. I’ve tried everything to get them to talk to each other but the camera just never initializes. SPI seems dead. I tried changing spi.begin(MOSI, MISO, SCK, CS) with different pin assignments but it still doesn’t work. Has anyone gotten this combo to work?
That’s a classic issue with the TTGO/LilyGo boards! Quick question - are you using GPIO 23 as your MOSI pin by any chance? Can you paste the relevant SPI initialization code you’re using?
Yeah, I’m using the default SPI pins. Let me check… Here’s my setup:
#define CS 5
#define SCK 18
#define MOSI 23
#define MISO 19
SPI.begin(SCK, MISO, MOSI, CS);
And the camera just hangs on init. I tried assigning different pins like MOSI 13 or 21, but no luck.
Okay, I think I know what’s going on. On the TTGO boards (especially the ones with SIM modules), GPIO 23 is physically hardwired to the cellular modem’s POWER_ON circuit. So when you’re using GPIO 23 as your SPI MOSI, you’re creating a hardware conflict between the camera and the modem. That’s why both devices end up not working properly.
Before we jump to a solution though - you mentioned you tried assigning MOSI to pin 13. Did you change it in the SPI.begin() call only, or did you also modify something else? Because there’s a trap here where some libraries just ignore the SPI.begin parameters.
Ohhhh that makes so much sense. I just changed it in the SPI.begin() args and it still didn’t work… so you’re saying the library is ignoring my pin assignments? That would explain a lot. What’s the actual fix then?
Exactly! The Arducam MEGA library, like many Arduino libraries, has its own hardcoded pin definitions it reads from the board variant file. Changing arguments in your sketch code won’t override those internal mappings.
Here’s the fix:
-
Navigate to your Arduino15 folder where the ESP32 core packages are installed. The exact path will look something like:
.../Arduino15/packages/esp32/hardware/esp32/3.1.3/variants/esp32/pins_arduino.h -
Open
pins_arduino.hand find line 13. It should show:
static const uint8_t MOSI = 23; -
Change it to a free GPIO pin that’s physically available on your TTGO headers and NOT used by the OLED or modem. For example, change it to GPIO 13:
static const uint8_t MOSI = 13; // Changed from 23 to 13 to avoid modem conflict -
Save the file and restart the Arduino IDE.
-
Then wire your Arducam’s MOSI line to GPIO 13 physically.
This forces the Arducam library to use the new pin as the default MOSI for all your projects. You won’t need to manually pass pins to SPI.begin() anymore since the library will read the correct value from the variant file.
Wow, that’s such a deep fix. Would never have thought to dig into the core variant files. So just to confirm - GPIO 23 is physically tied to the modem’s power control circuit and can’t be used for anything else on these TTGO boards? I’ll try changing to GPIO 13 and report back. Thanks a ton for the help!
Yep, exactly right. On the TTGO ESP32 boards with the cellular modem, GPIO 23 is connected to the SIM module’s POWER_ON pin internally on the PCB. There’s no way to disconnect it - it’s a hardware-level trace on the board. So any device trying to drive that pin for SPI MOSI will conflict with the modem’s power management logic.
GPIO 13 should work great as long as nothing else on your board is using it (it’s usually available on the headers on most TTGO variants). Just make sure you physically connect your camera’s MOSI wire to GPIO 13 instead of GPIO 23, and you should be good to go. Let me know how the test goes!