ESP32 Arduino Woes

Just got my hardware in and started testing a lot of my code. I found out a few things.

  1. Can't use UART0, 1 and 2 at the same time unless you changes the flash to DIO instead of QIO, which seems to cut flash size in half. works for now. sketch is 75%

  2. Can't run this line "pinMode(6, OUTPUT)" without causing Core1 to panic. i dont know why.

  3. running wificlient.connect() causes a wdt reset in 5 seconds, if the server doesnt respond.

I wanted to confirm that #1 is true. UART0 is my programming port, UART1 is my display port, and UART2 TX is debugging. I dont need an RX. also if anyone has any info for #2 and #3.

theskaz:
2. Can't run this line "pinMode(6, OUTPUT)" without causing Core1 to panic. i dont know why.

I thought that pin was used by the Flash ?

And whilst the ESP32 can be programmed from the Arduino IDE, its not actually an Arduino ..........

srnet:
I thought that pin was used by the Flash ?

And whilst the ESP32 can be programmed from the Arduino IDE, its not actually an Arduino ..........

I havent seen anything regarding that... yet....

as far as the comment about the esp32 not being an arduino, i get that. I usually come here due to the fact that I usually have programming questions that are with the IDE, or simply c/c++ questions. There is a very large following here, and a lot of experience.

in this instance, my question may be programming related, but the answer may be hardware related. I just wanted to ensure I'm not doing something dumb in my code.

Using GPIOs 6-8 will indeed be problematic because these pins are internally connected to SPI flash chip.
Read more on Kolban's book on ESP32

says 6-11 is no-go.

i didnt get that on my previous read through.

the pinout can be a bit confusing. so.. yeah.. i get to cut traces...

theskaz:
Just got my hardware in and started testing a lot of my code. I found out a few things.

  1. Can't use UART0, 1 and 2 at the same time unless you changes the flash to DIO instead of QIO, which seems to cut flash size in half. works for now. sketch is 75%

  2. Can't run this line "pinMode(6, OUTPUT)" without causing Core1 to panic. i dont know why.

  3. running wificlient.connect() causes a wdt reset in 5 seconds, if the server doesnt respond.

I wanted to confirm that #1 is true. UART0 is my programming port, UART1 is my display port, and UART2 TX is debugging. I dont need an RX. also if anyone has any info for #2 and #3.

First don't use GPIO 6, 7, 8, 9, 10, 11. They are used for flash.

Serial on the ESP32:

There are 4 serial ports Serial, Serial1, Serial2, Serial3

Serial3 is on GPIO pins 9,10 ( see above ).
Serial is on pins GPiO 1 and 3 used to communicate with the monitor and flash, native, do not use
Serial2 is on pins GPIO 16,17
Serial1 is on GPIO pins 12, 13

Define your serial ports in the following fashion to use them:

#include <HardwareSerial.h>
HardwareSerial SerialTFMini( 2 );
HardwareSerial SerialGPS( 1 );
//// serial(1) = pin12=RX, pin13=TX
//// serial(2) = pin16=RX, pin17=TX
Serial and Serial3 can be redefined and used, with the ESP32 API.
Serial is used for the monitor, Serial3 native is shared with a flash pin.

Both serial ports (1,2) can be used at the same time.

ALso, look into using freeRTOS, it is native to the ESP32 and allows tasks to be assigned to a spicific core.

There are 2 SPI ports, HSPI and VSPI. Both can be used at the same time. Default SPI is VSPI and does not require declaring to use.

// Serial.println(MOSI); // 23 Master Out Slave In, SDI, DIN
// Serial.println(MISO); // 19 Master In Slave Out, SDO
// Serial.println(SCK); // 18 Clock
// Serial.println(SS); // 5 Slave Select, Chip Seclect

For those libraries that take a SPI port as a input parameter HSPI is the one to use.

Such as the MPU9250 Bolderflight 9250 library:
//SPIClass SPI0(VSPI);
SPIClass SPI1(HSPI);
// HSPI: CS 15, MOSI 13, MISO 12, SCK 14
// MPU9250 IMU( SPI1, 15 );
MPU9250FIFO IMU( SPI1, 15);

// Wire.setClock( 100000 );
Wire.setClock( 2000000 ); // should use pullups << wire runs real well at this speed on the ESP32
//Wire.setClock( 3400000 ); // pullups needed

Adafruit libraries like to give Guru Meditation errors.

Run the A:D converters using the ESP32 API for stable operations.
#include <driver/adc.h>

in setup:
// https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
// set up A:D channel
adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_11db);

reading the a:d:
Vbatt = ( (uPvolts * float(adc1_get_raw(ADC1_CHANNEL_0)) / ADbits) / r2 * ( r1 + r2) );

Run the ESP32 on its own 5 volt power source. Connect a hub between the ESP32 and the computer used to program the ESP32. If you look at the ESP32 schematic you'll see that the 5V is a straight from your programming computer to the ESP32. Blow something up on the ESP32 and your programming computer takes a hit.

If you use the ESP32 WROVER (the +4MB RAM for a total of 8MB RAM), there are 2 more pins on the WROVER so ware the pin out is slightly different.

Overall, I am very happy with the ESP32. Using freeRTOS it reads 50ish FIFO readings from the MPU9250, averages the readings, does the MahonyQuaternionUpdate, calculates and send servo torque values all in about 240uSeconds.

Oh, and when developing tasks use:
// Serial.print(uxTaskGetStackHighWaterMark( NULL ));
// Serial.println();
// Serial.flush();

Also, flush all serial prints. The uxTaskGetStackHighWaterMark( NULL ) will give you an idea of how much stack size to set. Using the U8G2_SSD1327_EA_W128128_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); with full buffer size takes a good chunk of stack: xTaskCreatePinnedToCore( fUpdateDisplay, "fUpdateDisplay", TaskStack15K, NULL, Priority4, NULL, TaskCore1 ); // assigned to core 1. On the other hand I got 4MB RAM to work with.

Also, note there are 3 cores on a ESP32. The third core is the ULP and only takes assembly code for programming.

holy cow...

THANK YOU! that is a lot of info, that should help me out.

On a different note:

I am using xTaskCreate to create my tasks (opting not to use pinnedToCore function just yet) and vTaskDelay() within them to keep things humming along.

not using SPI, but using I2C with 2 external ADCs (ADS1015). The ADC internally was having issues at the time that I made the decision. I think it was arduino-esp32 based, and not esp-idf based.

I have SDA and SCL pulled up with 3k3 resistors.

I am debugging my tasks now (I have 9) and use the high watermark to set the stack depth.

the 3rd core (I believe it's the RTC core) isn't of any use in my implementation, but I am aware of it.

again, thank you for the notes!

If you use the hardware timer:

/* create a hardware timer */
hw_timer_t * timer = NULL;

volatile int iTicCount = 0;
//*************************************************
////////////////////////////////////////////////////////////////
// timer ISR callback set at 1000X a second
void IRAM_ATTR onTimer()
{
  BaseType_t xHigherPriorityTaskWoken;
  //
  //  xEventGroupSetBitsFromISR(eg, OneMilliGroupBits, &xHigherPriorityTaskWoken); // trigger every mS a second
  iTicCount++;
  if ( (iTicCount % 100) == 0 )
  {
    if ( (xSemaphoreTakeFromISR( sema_GetIMU, &xHigherPriorityTaskWoken)) == pdTRUE ) // grab semaphore, no wait
    {
      xEventGroupSetBitsFromISR(eg, evtGetIMU, &xHigherPriorityTaskWoken);
    }
  }
  if ( iTicCount == AnalogVoltReadPeorid )
  {
    xEventGroupSetBitsFromISR(eg, AnalogVoltReadTask, &xHigherPriorityTaskWoken);
  }
  if ( iTicCount == OneK )
  {
    // xEventGroupSetBitsFromISR(eg, evtBMP085, &xHigherPriorityTaskWoken);
    iTicCount = 0;
  }
} // void IRAM_ATTR onTimer()
void setup()
{

 /* Use 4th timer of 4.
    1 tick 1/(80MHZ/80) = 1us set divider 80 and count up.
    Attach onTimer function to timer
    Set alarm to call timer ISR, every 1000uS and repeat / reset ISR (true) after each alarm
    Start an timer alarm
  */
  timer = timerBegin( TIMER_FOUR, TimerDivider, true );
  timerAttachInterrupt( timer, &onTimer, true );
  timerAlarmWrite(timer, OneK, true);
  timerAlarmEnable(timer);
}

note: some variables named are not listed in my code postings.
The hardware timer is a lot more accurate then vTaskDelay.
You can get uSec timmings if you want. There is also a way to get nano second timings.

I run the workhorse code in round robin instead of task delay. That way the work horse code runs as fast as it can be processed.