I’m currently having a major problem with the Esp32, and using a mouse pointer in regards to getting the Esp32 to display a cursor upon my VGA or Video Graphics Array screen, I have successfully implemented similar resistances to allow for proper VGA signalling, and thus far can get both the Mouse and Keyboard to work via baseline Signalling, however the Mouse cursor will not show properly upon my VGA screen. I’ve tried going to similar forums, and posting similar questions on those Arduino forums as well, however, to this day I have not received a proper response from any such user on this forum. Here is the link to when I have posted the original question back in the year of 2021:
The main difference between the other post is of course be being able to get baseline functionality, more specifically IR functionality to work within the PS2 mouse and not graphical functionality to work properly for the FabGL PC Emulator example, in addition to this post not bearing fruit, here is both the example code provided by Mr. Fabrizo himself, my current pinout using the alternative 680, 150, 2000, and 470 ohm resistors for the RGB Signals, and of course the normal pinout for the FabGl library:
- to run this application you need an ESP32 with PSRAM installed and an SD-CARD slot (ie TTGO VGA32 v1.4 or FabGL Development Board with WROVER)
- open this with Arduino and make sure PSRAM is DISABLED
- partition scheme must be: Huge App
- compile and upload the sketch
#pragma message "This sketch requires Tools->Partition Scheme = Huge APP"
#include <memory>
#include "esp32-hal-psram.h"
extern "C" {
#include "esp_spiram.h"
}
#include "esp_sntp.h"
#include <Preferences.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include "fabgl.h"
#include "mconf.h"
#include "machine.h"
// UART Pins for USB serial
#define UART_URX 3
#define UART_UTX 1
using std::unique_ptr;
using fabgl::StringList;
using fabgl::imin;
using fabgl::imax;
Preferences preferences;
InputBox ibox;
Machine * machine;
// noinit! Used to maintain datetime between reboots
__NOINIT_ATTR static timeval savedTimeValue;
static bool wifiConnected = false;
static bool downloadOK = false;
// try to connected using saved parameters
bool tryToConnect()
{
bool connected = WiFi.status() == WL_CONNECTED;
if (!connected) {
char SSID[32] = "";
char psw[32] = "";
if (preferences.getString("SSID", SSID, sizeof(SSID)) && preferences.getString("WiFiPsw", psw, sizeof(psw))) {
ibox.progressBox("", "Abort", true, 200, [&](fabgl::ProgressForm * form) {
WiFi.begin(SSID, psw);
for (int i = 0; i < 32 && WiFi.status() != WL_CONNECTED; ++i) {
if (!form->update(i * 100 / 32, "Connecting to %s...", SSID))
break;
delay(500);
if (i == 16)
WiFi.reconnect();
}
connected = (WiFi.status() == WL_CONNECTED);
});
// show to user the connection state
if (!connected) {
WiFi.disconnect();
ibox.message("", "WiFi Connection failed!");
}
}
}
return connected;
}
bool checkWiFi()
{
wifiConnected = tryToConnect();
if (!wifiConnected) {
// configure WiFi?
if (ibox.message("WiFi Configuration", "Configure WiFi?", "No", "Yes") == InputResult::Enter) {
// repeat until connected or until user cancels
do {
// yes, scan for networks showing a progress dialog box
int networksCount = 0;
ibox.progressBox("", nullptr, false, 200, [&](fabgl::ProgressForm * form) {
form->update(0, "Scanning WiFi networks...");
networksCount = WiFi.scanNetworks();
});
// are there available WiFi?
if (networksCount > 0) {
// yes, show a selectable list
StringList list;
for (int i = 0; i < networksCount; ++i)
list.appendFmt("%s (%d dBm)", WiFi.SSID(i).c_str(), WiFi.RSSI(i));
int s = ibox.menu("WiFi Configuration", "Please select a WiFi network", &list);
// user selected something?
if (s > -1) {
// yes, ask for WiFi password
char psw[32] = "";
if (ibox.textInput("WiFi Configuration", "Insert WiFi password", psw, 31, "Cancel", "OK", true) == InputResult::Enter) {
// user pressed OK, connect to WiFi...
preferences.putString("SSID", WiFi.SSID(s).c_str());
preferences.putString("WiFiPsw", psw);
wifiConnected = tryToConnect();
// show to user the connection state
if (wifiConnected)
ibox.message("", "Connection succeeded!");
} else
break;
} else
break;
} else {
// there is no WiFi
ibox.message("", "No WiFi network found!");
break;
}
WiFi.scanDelete();
} while (!wifiConnected);
}
}
return wifiConnected;
}
// handle soft restart
void shutdownHandler()
{
// save current datetime into Preferences
gettimeofday(&savedTimeValue, nullptr);
}
void updateDateTime()
{
// Set timezone
setenv("TZ", "CET-1CEST,M3.5.0,M10.5.0/3", 1);
tzset();
// get datetime from savedTimeValue? (noinit section)
if (esp_reset_reason() == ESP_RST_SW) {
// adjust time taking account elapsed time since ESP32 started
savedTimeValue.tv_usec += (int) esp_timer_get_time();
savedTimeValue.tv_sec += savedTimeValue.tv_usec / 1000000;
savedTimeValue.tv_usec %= 1000000;
settimeofday(&savedTimeValue, nullptr);
return;
}
if (checkWiFi()) {
// we need time right now
ibox.progressBox("", nullptr, true, 200, [&](fabgl::ProgressForm * form) {
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, (char*)"pool.ntp");
sntp_init();
for (int i = 0; i < 12 && sntp_get_sync_status() != SNTP_SYNC_STATUS_COMPLETED; ++i) {
form->update(i * 100 / 12, "Getting date-time from SNTP...");
delay(500);
}
sntp_stop();
ibox.setAutoOK(2);
ibox.message("", "Date and Time updated. Restarting...");
#ifndef FABGL_EMULATED
esp_restart();
#endif
});
} else {
// set default time
auto tm = (struct tm){ .tm_sec = 0, .tm_min = 0, .tm_hour = 8, .tm_mday = 14, .tm_mon = 7, .tm_year = 84 };
auto now = (timeval){ .tv_sec = mktime(&tm) };
settimeofday(&now, nullptr);
}
}
// download specified filename from URL
bool downloadURL(char const * URL, FILE * file)
{
downloadOK = false;
char const * filename = strrchr(URL, '/') + 1;
ibox.progressBox("", "Abort", true, 380, [&](fabgl::ProgressForm * form) {
form->update(0, "Preparing to download %s", filename);
HTTPClient http;
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
http.begin(URL);
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
if (file) {
int tlen = http.getSize();
int len = tlen;
auto buf = (uint8_t*) SOC_EXTRAM_DATA_LOW; // use PSRAM as buffer
WiFiClient * stream = http.getStreamPtr();
int dsize = 0;
while (http.connected() && (len > 0 || len == -1)) {
size_t size = stream->available();
if (size) {
int c = stream->readBytes(buf, size);
auto wr = fwrite(buf, 1, c, file);
if (wr != c) {
dsize = 0;
break; // writing failure!
}
dsize += c;
if (len > 0)
len -= c;
if (!form->update((int64_t)dsize * 100 / tlen, "Downloading %s (%.2f / %.2f MB)", filename, (double)dsize / 1048576.0, tlen / 1048576.0))
break;
}
}
downloadOK = (len == 0 || (len == -1 && dsize > 0));
}
}
http.end();
});
return downloadOK;
}
// return filename if successfully downloaded or already exist
char const * getDisk(char const * url)
{
FileBrowser fb(SD_MOUNT_PATH);
char const * filename = nullptr;
if (url) {
if (strncmp("http://", url, 7) == 0 || strncmp("https://", url, 7) == 0) {
// this is actually an URL
filename = strrchr(url, '/') + 1;
if (filename && !fb.exists(filename, false)) {
// disk doesn't exist, try to download
if (!checkWiFi())
return nullptr;
auto file = fb.openFile(filename, "wb");
bool success = downloadURL(url, file);
fclose(file);
if (!success) {
fb.remove(filename);
return nullptr;
}
}
} else {
// this is just a file
if (fb.filePathExists(url))
filename = url;
}
}
return filename;
}
// user pressed SYSREQ (ALT + PRINTSCREEN)
void sysReqCallback()
{
machine->graphicsAdapter()->enableVideo(false);
ibox.begin(VGA_640x480_60Hz, 500, 400, 4);
int s = ibox.menu("", "Select a command", "Restart Emulator;Restart Machine;Mount Disk;Continue");
switch (s) {
// Restart Emulator
case 0:
esp_restart();
break;
// Restart Machine
case 1:
machine->trigReset();
break;
// Mount Disk
case 2:
{
int s = ibox.menu("", "Select Drive", "Floppy A (fd0);Floppy B (fd1)");
if (s > -1) {
constexpr int MAXNAMELEN = 256;
unique_ptr<char[]> dir(new char[MAXNAMELEN + 1] { '/', 'S', 'D', 0 } );
unique_ptr<char[]> filename(new char[MAXNAMELEN + 1] { 0 } );
if (machine->diskFilename(s))
strcpy(filename.get(), machine->diskFilename(s));
if (ibox.fileSelector("Select Disk Image", "Image Filename", dir.get(), MAXNAMELEN, filename.get(), MAXNAMELEN) == InputResult::Enter) {
machine->setDriveImage(s, filename.get());
}
}
break;
}
// Continue
default:
break;
}
ibox.end();
PS2Controller::keyboard()->enableVirtualKeys(false, false); // don't use virtual keys
machine->graphicsAdapter()->enableVideo(true);
}
void setup()
{
Serial.begin(115200); delay(500); printf("\n\n\nReset\n\n");// DEBUG ONLY
disableCore0WDT();
delay(100); // experienced crashes without this delay!
disableCore1WDT();
preferences.begin("PCEmulator", false);
// uncomment to clear preferences
//preferences.clear();
// save some space reducing UI queue
fabgl::BitmappedDisplayController::queueSize = 128;
ibox.begin(VGA_640x480_60Hz, 500, 400, 4);
ibox.setBackgroundColor(RGB888(0, 0, 0));
ibox.onPaint = [&](Canvas * canvas) { drawInfo(canvas); };
// we need PSRAM for this app, but we will handle it manually, so please DO NOT enable PSRAM on your development env
#ifdef BOARD_HAS_PSRAM
ibox.message("Warning!", "Please disable PSRAM to improve performance!");
#endif
// note: we use just 2MB of PSRAM so the infamous PSRAM bug should not happen. But to avoid gcc compiler hack (-mfix-esp32-psram-cache-issue)
// we enable PSRAM at runtime, otherwise the hack slows down CPU too much (PSRAM_HACK is no more required).
if (esp_spiram_init() != ESP_OK)
ibox.message("Error!", "This app requires a board with PSRAM!", nullptr, nullptr);
#ifndef BOARD_HAS_PSRAM
esp_spiram_init_cache();
#endif
if (!FileBrowser::mountSDCard(false, SD_MOUNT_PATH, 8)) // @TODO: reduce to 4?
ibox.message("Error!", "This app requires a SD-CARD!", nullptr, nullptr);
// uncomment to format SD!
//FileBrowser::format(fabgl::DriveType::SDCard, 0);
esp_register_shutdown_handler(shutdownHandler);
updateDateTime();
// machine configurations
MachineConf mconf;
// show a list of machine configurations
ibox.setAutoOK(6);
int idx = preferences.getInt("dconf", 0);
for (bool showDialog = true; showDialog; ) {
loadMachineConfiguration(&mconf);
StringList dconfs;
for (auto conf = mconf.getFirstItem(); conf; conf = conf->next)
dconfs.append(conf->desc);
dconfs.select(idx, true);
ibox.setupButton(0, "Files");
ibox.setupButton(1, "Machine", "Edit;New;Remove", 52);
auto r = ibox.select("Machine Configurations", "Please select a machine configuration", &dconfs, nullptr, "Run");
idx = dconfs.getFirstSelected();
switch (r) {
case InputResult::ButtonExt0:
// Browse Files
ibox.folderBrowser("Browse Files", SD_MOUNT_PATH);
break;
case InputResult::ButtonExt1:
// Machine
switch (ibox.selectedSubItem()) {
// Edit
case 0:
editConfigDialog(&ibox, &mconf, idx);
break;
// New
case 1:
newConfigDialog(&ibox, &mconf, idx);
break;
// Remove
case 2:
delConfigDialog(&ibox, &mconf, idx);
break;
};
break;
case InputResult::Enter:
// Run
showDialog = false;
break;
default:
break;
}
// next selection will not have timeout
ibox.setAutoOK(0);
}
idx = imax(idx, 0);
preferences.putInt("dconf", idx);
// setup selected configuration
auto conf = mconf.getItem(idx);
char const * diskFilename[DISKCOUNT];
downloadOK = true;
for (int i = 0; i < DISKCOUNT && downloadOK; ++i)
diskFilename[i] = getDisk(conf->disk[i]);
if (!downloadOK || (!diskFilename[0] && !diskFilename[2])) {
// unable to get boot disks
ibox.message("Error!", "Unable to get system disks!");
esp_restart();
}
if (wifiConnected) {
// disk downloaded from the Internet, need to reboot to fully disable wifi
ibox.setAutoOK(2);
ibox.message("", "Disks downloaded. Restarting...");
#ifndef FABGL_EMULATED
esp_restart();
#endif
}
ibox.end();
// without WiFi it is possible to increase SD card speed
FileBrowser::setSDCardMaxFreqKHz(SDMMC_FREQ_DEFAULT);
FileBrowser::remountSDCard();
machine = new Machine;
machine->setBaseDirectory(SD_MOUNT_PATH);
for (int i = 0; i < DISKCOUNT; ++i)
machine->setDriveImage(i, diskFilename[i], conf->cylinders[i], conf->heads[i], conf->sectors[i]);
machine->setBootDrive(conf->bootDrive);
auto serial1 = new SerialPort;
serial1->setSignals(UART_URX, UART_UTX);
machine->setCOM1(serial1);
/*
printf("MALLOC_CAP_32BIT : %d bytes (largest %d bytes)\r\n", heap_caps_get_free_size(MALLOC_CAP_32BIT), heap_caps_get_largest_free_block(MALLOC_CAP_32BIT));
printf("MALLOC_CAP_8BIT : %d bytes (largest %d bytes)\r\n", heap_caps_get_free_size(MALLOC_CAP_8BIT), heap_caps_get_largest_free_block(MALLOC_CAP_8BIT));
printf("MALLOC_CAP_DMA : %d bytes (largest %d bytes)\r\n\n", heap_caps_get_free_size(MALLOC_CAP_DMA), heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
heap_caps_dump_all();
machine->setSysReqCallback(sysReqCallback);
machine->run();
}
#if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK
namespace fabgl {
extern volatile uint64_t s_vgapalctrlcycles;
}
using fabgl::s_vgapalctrlcycles;
#endif
void loop()
{
#if FABGLIB_VGAXCONTROLLER_PERFORMANCE_CHECK
static uint32_t tcpu = 0, s1 = 0, count = 0;
tcpu = machine->ticksCounter();
s_vgapalctrlcycles = 0;
s1 = fabgl::getCycleCount();
delay(1000);
printf("%d\tCPU: %d", count, machine->ticksCounter() - tcpu);
printf(" Graph: %lld / %d (%d%%)\n", s_vgapalctrlcycles, fabgl::getCycleCount() - s1, (int)((double)s_vgapalctrlcycles/240000000*100));
++count;
#else
vTaskDelete(NULL);
#endif
}
In addition to the code included above, I've also tried to see if there are any other commonalities in how the Mouse and Keyboard drivers work within the original source code as seen within this link: but so far, I have seen no piece of code that provides me with a proper understanding of what the problem could be, and in addition no mentions of this issue are mentioned within the Issues tab of the FabGl library, so I am unable to implement proper fixes for this as well.
Again I wish to stress the only variables I have changed is the 120 ohm resistors for both the ps2 keyboard and mouse, and finally replacing the 800 ohm resistors, 400 ohm resistors, to 470, and 680 ohm resistors as seen in these references, as of right now. Here are how the resistors are supposed to be implemented within the FabGl libaray:
Here is what the normal FabGL screen should look like with a Mouse Pointer whereas this is what my screen looks like after I boot my PC Emulator screen up for the first time:
As you can see from the picture above the Screen includes a White Mouse cursor, however my screen does not possess such a cursor as seen here:
Is this a problem with the Resistors? If so why do the mouse IR Sensors operated as intended and light up when I right and left click? If this problem is not solveable here, would there perhaps be another place or fourm in which I may solve this problem? Thank you very much, and any help would be appretiated.