Closed justcallmekoko closed 5 years ago
There are a number of reasons why an ESP32 will crash, the usual one is a watchdog timeout, in that case adding yield() or delay(0) at an appropriate point fixxes it. Other causes include high use of RAM leaving insufficient free and and running off the end of an array.
Please provide a simplified sketch that I can run and determine the root cause.
I have pasted a simplified version of the code like you asked. It replicates the same issue perfectly. The crash you described is a watchdog timeout. I could not figure out where exactly to place the delay or yield.
I am also including the exact crash message:
RSSI: -83 Ch: 2 Client: 68:e7:c2:66:da:b3E (8571) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (8571) task_wdt: - IDLE0 (CPU 0)
E (8571) task_wdt: Tasks currently running:
E (8571) task_wdt: CPU 0: wifi
E (8571) task_wdt: CPU 1: loopTask
E (8571) task_wdt: Aborting.
abort() was called at PC 0x400dc277 on core 0
Backtrace: 0x4008c50c:0x3ffbe290 0x4008c73d:0x3ffbe2b0 0x400dc277:0x3ffbe2d0 0x4008165d:0x3ffbe2f0 0x400d2585:0x00000000
Rebooting...
Here is the example code. The issue lies in the checkTouch function.
#include <TFT_eSPI.h>
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320
#define TEXT_HEIGHT 16 // Height of text to be printed and scrolled
#define BOT_FIXED_AREA 0 // Number of lines in bottom fixed area (lines counted from bottom of screen)
#define TOP_FIXED_AREA 16 // Number of lines in top fixed area (lines counted from top of screen)
#define YMAX 320 // Bottom of screen area
#define minimum(a,b) (((a) < (b)) ? (a) : (b))
TFT_eSPI tft = TFT_eSPI();
const wifi_promiscuous_filter_t filt = {.filter_mask=WIFI_PROMIS_FILTER_MASK_MGMT | WIFI_PROMIS_FILTER_MASK_DATA};
uint32_t initTime = 0;
uint32_t currentTime = 0;
int set_channel = 1;
uint16_t yDraw = YMAX - BOT_FIXED_AREA - TEXT_HEIGHT;
// Keep track of the drawing x coordinate
uint16_t xPos = 0;
// The initial y coordinate of the top of the scrolling area
uint16_t yStart = TOP_FIXED_AREA;
// yArea must be a integral multiple of TEXT_HEIGHT
uint16_t yArea = YMAX - TOP_FIXED_AREA - BOT_FIXED_AREA;
// We have to blank the top line each time the display is scrolled, but this takes up to 13 milliseconds
// for a full width line, meanwhile the serial buffer may be filling... and overflowing
// We can speed up scrolling of short text lines by just blanking the character we drew
int blank[19]; // We keep all the strings pixel lengths to optimise the speed of the top line blanking
typedef struct
{
int16_t fctl;
int16_t duration;
uint8_t da;
uint8_t sa;
uint8_t bssid;
int16_t seqctl;
unsigned char payload[];
} __attribute__((packed)) WifiMgmtHdr;
typedef struct {
WifiMgmtHdr hdr;
uint8_t payload[0];
} wifi_ieee80211_packet_t;
void clearScreen()
{
tft.fillScreen(TFT_BLACK);
tft.setCursor(0, 0);
}
void initScrollValues()
{
yDraw = YMAX - BOT_FIXED_AREA - TEXT_HEIGHT;
xPos = 0;
yStart = TOP_FIXED_AREA;
yArea = YMAX - TOP_FIXED_AREA - BOT_FIXED_AREA;
for(int i = 0; i < 18; i++) blank[i] = 0;
}
// Function to execute hardware scroll for TFT screen
int scroll_line(uint32_t color) {
int yTemp = yStart; // Store the old yStart, this is where we draw the next line
// Use the record of line lengths to optimise the rectangle size we need to erase the top line
tft.fillRect(0,yStart,blank[(yStart-TOP_FIXED_AREA)/TEXT_HEIGHT],TEXT_HEIGHT, color);
// Change the top of the scroll area
yStart+=TEXT_HEIGHT;
// The value must wrap around as the screen memory is a circular buffer
if (yStart >= YMAX - BOT_FIXED_AREA) yStart = TOP_FIXED_AREA + (yStart - YMAX + BOT_FIXED_AREA);
// Now we can scroll the display
scrollAddress(yStart);
return yTemp;
}
// Function to setup hardware scroll for TFT screen
void setupScrollArea(uint16_t tfa, uint16_t bfa) {
tft.writecommand(ILI9341_VSCRDEF); // Vertical scroll definition
tft.writedata(tfa >> 8); // Top Fixed Area line count
tft.writedata(tfa);
tft.writedata((YMAX-tfa-bfa)>>8); // Vertical Scrolling Area line count
tft.writedata(YMAX-tfa-bfa);
tft.writedata(bfa >> 8); // Bottom Fixed Area line count
tft.writedata(bfa);
}
void scrollAddress(uint16_t vsp) {
tft.writecommand(ILI9341_VSCRSADD); // Vertical scrolling pointer
tft.writedata(vsp>>8);
tft.writedata(vsp);
}
void getMAC(char *addr, uint8_t* data, uint16_t offset) {
sprintf(addr, "%02x:%02x:%02x:%02x:%02x:%02x", data[offset+0], data[offset+1], data[offset+2], data[offset+3], data[offset+4], data[offset+5]);
}
void showMetadata(wifi_promiscuous_pkt_t *snifferPacket, wifi_promiscuous_pkt_type_t type) {
WifiMgmtHdr *frameControl = (WifiMgmtHdr*)snifferPacket->payload;
wifi_pkt_rx_ctrl_t ctrl = (wifi_pkt_rx_ctrl_t)snifferPacket->rx_ctrl;
int len = snifferPacket->rx_ctrl.sig_len;
if (type == WIFI_PKT_MGMT)
{
int fctl = ntohs(frameControl->fctl);
const wifi_ieee80211_packet_t *ipkt = (wifi_ieee80211_packet_t *)snifferPacket->payload;
const WifiMgmtHdr *hdr = &ipkt->hdr;
if (snifferPacket->payload[0] == 0x40)
{
xPos = 0;
yDraw = scroll_line(TFT_RED);
tft.setCursor(xPos, yDraw);
Serial.print("RSSI: ");
Serial.print(snifferPacket->rx_ctrl.rssi);
Serial.print(" Ch: ");
Serial.print(snifferPacket->rx_ctrl.channel);
Serial.print(" Client: ");
char addr[] = "00:00:00:00:00:00";
getMAC(addr, snifferPacket->payload, 10);
Serial.print(addr);
tft.print(addr);
Serial.print(" Requesting: ");
tft.print(" -> ");
for (int i = 0; i < snifferPacket->payload[25]; i++)
{
Serial.print((char)snifferPacket->payload[26 + i]);
tft.print((char)snifferPacket->payload[26 + i]);
}
// Print spaces because of the rotating lines of the hardware scroll.
// The same characters print from previous lines so I just overwrite them
// with spaces.
for (int i = 0; i < 19 - snifferPacket->payload[25]; i++)
{
tft.print(" ");
}
Serial.println();
blank[(18+(yStart - TOP_FIXED_AREA) / TEXT_HEIGHT)%19] = xPos;
}
}
}
// This is part of the callback function for the WiFi sniffer
void sniffer_callback(void* buf, wifi_promiscuous_pkt_type_t type) {
wifi_promiscuous_pkt_t *snifferPacket = (wifi_promiscuous_pkt_t*)buf;
showMetadata(snifferPacket, type);
}
void channelHop()
{
set_channel = set_channel + 1;
if (set_channel > 13) {
set_channel = 1;
}
esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
delay(1);
}
// This function has the problem
void checkTouch()
{
// This is code from bodmer's keypad example
uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
// This is one of the things that causes the issue
// If you comment out this line and the if statement below,
// The code works no problem.
boolean pressed = tft.getTouch(&t_x, &t_y);
// Normally I would do something else here
// But just checking for screen press is what causes the problem
if (pressed)
Serial.println("Screen touched");
}
void setup() {
Serial.begin(115200);
tft.init();
tft.setRotation(0); // Portrait
tft.setCursor(0, 0);
//tft.setFreeFont(&FreeMonoBold9pt7b);
// Calibration data
//uint16_t calData[5] = { 390, 3516, 253, 3520, 7 }; tft.setRotation(1); // Portrait
uint16_t calData[5] = { 275, 3494, 361, 3528, 4 }; // tft.setRotation(0); // Portrait
tft.setTouch(calData);
//tft.fillScreen(TFT_BLACK);
clearScreen();
Serial.println("Preparing WiFiScan...");
clearScreen();
initScrollValues();
tft.setTextWrap(false);
tft.setTextColor(TFT_WHITE, TFT_RED);
tft.fillRect(0,0,240,16, TFT_RED);
tft.drawCentreString(" Probe Request Sniffer ",120,0,2);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
setupScrollArea(TOP_FIXED_AREA, BOT_FIXED_AREA);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
esp_wifi_init(&cfg);
esp_wifi_set_storage(WIFI_STORAGE_RAM);
esp_wifi_set_mode(WIFI_MODE_NULL);
esp_wifi_set_promiscuous(true);
esp_wifi_set_promiscuous_filter(&filt);
esp_wifi_set_promiscuous_rx_cb(&sniffer_callback);
esp_wifi_set_channel(set_channel, WIFI_SECOND_CHAN_NONE);
initTime = millis();
}
void loop() {
checkTouch();
currentTime = millis();
if (currentTime - initTime >= 1000)
{
initTime = millis();
channelHop();
}
delay(1);
}
OK. I can see the problem. Using the callback is effectively like and interrupt and if the callback includes SPI transactions (eg writes to TFT), then these might occur during SPI exchanges with the touch controller, so things get messed up because the chip select lines are software controlled.
You need to ensure the TFT and touch controller commands do not get interrupted by the callback. This can be achieved by leaving TFT display and touch controller commands out of the callback function. You would then need to queue up the text in a buffer for display on the TFT within the main loop().
I have part of your vertical scrolling code from your terminal example running as an rx_callback function for my ESP32 when it sniffs for packets.
While the sniffer sniffs packets, it displays them on the screen using your vertical scrolling code.
This is all happening in the rx_callback function so it runs parallel to the main loop.
The problem comes when I run getTouch in the main loop. I don't know if this is causing some sort of race condition, but if getTouch in loop runs at the same as the tft.print statement in the rx_callback, it causes the device to crash and reboot. If I comment out getTouch, it runs fine. If I comment out all of the tft.print statements but keep getTouch, it runs fine. I just can't have both.