janb
Full Member
Retiree, born 1948, mostly HW/FW oriented programming for > 50 years, 25+ for IBM
Posts: 33
|
Post by janb on Feb 18, 2021 17:29:07 GMT -8
I’m using a GD3X ”on top of” an ESP32 board with an Arduino Uno ”footprint”, as a touch screen with keyboard & cmd buttons.
I’m using SdFat to ”drive” the GD3X’s builtin SD reader, sharing the SPI with the LCD screen.
I have created various file & directory handling commands, similar to PC/Dos, for the SD card, including a File Copy command. It's Read/Write transfer rate is only about 600.000 bytes/sec with a 2048 bytes i/o buffer. A 150MB FileCopy takes 9 minutes, while with the SD card in my Laptop PC it takes around 20 secs! Anyway, my file & directory handling commands do work!
EXCEPT for this File Copy command! Often, when I try to ”show” a copied file, like ’fishCOPY.avi’, with GD.begin();
MoviePlayer mp;
mp.begin("fishCOPY.avi");
mp.play();
it fails with
”Coprocessor exception:” ”ERROR: corrupted JPEG in cmd_playvideo()”.
It doesn’t happen immediately, but after 5-15 secs… Some copies ALWAYS fail, a few ALWAYS work!
If I compare the copies with the source files, with the SD card in my Laptop PC, the files are IDENTICAL! How is it possible???
|
|
|
Post by jamesbowman on Feb 18, 2021 18:43:45 GMT -8
Interesting!
The GD's Movieplayer uses the GD's optimized read-only FAT32 implementation.
It's possible that there is a bug in that implementation, triggered by something that SdFat does in the file layout.
I think that would explain what you're seeing?
|
|
janb
Full Member
Retiree, born 1948, mostly HW/FW oriented programming for > 50 years, 25+ for IBM
Posts: 33
|
Post by janb on Feb 19, 2021 3:00:05 GMT -8
James, ONE difference between SdFat and GD's FAT32 implementation is the 'Sd.begin' stmt, that contains a "speed" parameter:
// Initialize at the highest speed supported by the board that is not over 50 MHz. Try a lower speed if SPI errors occur.
if (!Sd.begin(SD_CHIP_SELECT, SD_SCK_MHZ(26))) sdErrorMsg("Sd.begin failed"); //<== 26MHz works with my Setup, 27 FAILS!
Could this make a difference while WRITING data to the SDcard? (I think I found in GD2.h that YOU set Frequency=25MHz for ESP32 and 40 for ESP8266...)
OR, could "data fragmentation" when re-using freed card space while creating a new file cause "speed"/other problems for the MoviePlayer when READING this file? I assume that ALL files on the SD cards that you ship out with the GD3X'es have CONSECUTIVE data sectors, i.e NO "data fragmentation"?!?
|
|
|
Post by jamesbowman on Feb 19, 2021 8:19:10 GMT -8
Right, I tend to agree that the most likely cause is a fragmentation issue. *However* the GD filesystem code I wrote does support files that have non-consecutive sectors. One way we could debug this is if you can capture an the binary image of a microSD with a "fish.avi" copy that does not play, and upload it (maybe using transfer.sh ) Then I can run it on my code here in the debugger, to see what is tripping it up.
|
|
janb
Full Member
Retiree, born 1948, mostly HW/FW oriented programming for > 50 years, 25+ for IBM
Posts: 33
|
Post by janb on Feb 19, 2021 13:01:47 GMT -8
James, it's definitely about "fragmented" data files; even your 'video2' sample program will do it! Here's how: 1) Use a "fresh" SDcard with all sample files on it 2) Delete a rather small file in the beginning of the file list, like 'tra-1500.avi' 3) Rename the bigger 'fish.avi' file as 'tst.avi' and copy it to the SDcard 4) Run the 'video2' sample program; it will show up to 12 .avi files. 5) Now try to "show" the 'tst.avi' file; after a while it will HANG (stop)!
I've made additions to the 'mp.play()' routine in my 'GD2.h' file. I wanted to be able to "stop" viewing a "long movie" by just touching the screen. With this change active, I get the "blue screen" with the "ERROR: corrupted JPEG in cmd_playvideo()" msg. With the change inactive, the player just "hangs"/stops.
For the "fun of it", I tried the 'video2' program with the same SDcard in the GD3X reader, "on top of" an Arduino Uno board; EXACTLY the same results!
|
|
janb
Full Member
Retiree, born 1948, mostly HW/FW oriented programming for > 50 years, 25+ for IBM
Posts: 33
|
Post by janb on Feb 20, 2021 6:53:47 GMT -8
James, on a slightly different note. I mentioned that I use 26MHz for 'Sd.begin()', while 27MHz fail. I also saw in 'GD2.h' that YOU seem to use 25MHz for ESP32 and 40MHz for ESP8266. A VERY strange thing is, that if I choose a lower Frequency, like down to 15MHz, the Movieplayer still work normally, BUT if I choose 25MHz, suddenly everything is like in "slow motion"! It takes "forever" just to get the Movieplayer started, then it runs with normal speed for a couple of secs, then suddenly it starts "slow motion" again; I can actually see every frame change and it takes "forever" before the Movieplayer ends, normally! What's so special about EXACTLY 25MHz???
|
|
|
Post by tftlcdcyg on Feb 21, 2021 0:48:07 GMT -8
When migrating from SD to SdFat beta, in order to use the SDIO reader of the teensy 4 or teensy 4.1 boards, I ran into errors similar to the one you comment during video playback, in my case the video was not displayed on the screen and only passed directly to the coprocessor error screen.
Inside the wiring.h file, there is a wr_n routine. I reduced it to these lines:
void wr_n (uint32_t addr, byte * src, uint16_t n) { __end (); // stop streaming __wstart (addr); while (n--) SPI.transfer (* src ++); stream (); } wr_n is used at the beginning of the Movieplayer class. This is the routine that I migrated to SdFat beta
class MoviePlayer { uint32_t mf_size, mf_base, wp;
File32 r;
void loadsector() { byte buf[512]; GD.__end();
int32_t c = r.curPosition(); int32_t p = r.peek(); int n = r.read(buf,512);
GD.resume();
GD.wr_n(mf_base + wp, buf, 512);
wp = (wp + 512) & (mf_size - 1); } Some part of your code may be missing from migrating to SdFat.
|
|
janb
Full Member
Retiree, born 1948, mostly HW/FW oriented programming for > 50 years, 25+ for IBM
Posts: 33
|
Post by janb on Feb 23, 2021 17:14:46 GMT -8
tftlcdcyg, what does it stand for?
I wasn't aware that I "migrated" to SdFat... I aim to use the GD3X touch screen as a kbd i/f and for showing information and events logging, and the SDcard to store data & log files. I'm not into video, images, pictures, audio at all. Early 80's I used to be a PC/Dos guy, using an external kbd and a crude display... I want proper files & directories handling capabilities, so I just tried to use SdFat library with its various code samples to help. But, just being curious, I tried to "show" the distributed .avi & .jpg files, looking at & copying the sample code files, like 'video1' & 'video2'. It was so simple to incorporate the needed code so I just tried it... I even modified 'MoviePlayer' so I can stop an .avi by touching the screen. I'm not sure that I'll keep this "show" code, though. The asset converter seem "tricky" to use; I don't understand all the acronyms. And I don't understand how to create .avi files that could be displayed, using the MoviePlayer...
Anyway, the code samples you showed above, I assume they are for Teensy? Looking at 'wiring.h' and the'wr_n' routine, for ESP8266 & ESP32 it seems to need 'SPI.writeBytes(src, n);', instead of 'while (n--) SPI.transfer (* src ++);' Also, I tried to modify 'Movieplayer' code, but ran into problems; the SdFat 1.1.4 version doesn't "have" a 'File32' class. I tried 'File' instead, used 'r.open(...)' instead of 'r.openfile(...)' but got stuck on 'r.eof()'...
|
|
|
Post by tftlcdcyg on Feb 23, 2021 18:26:54 GMT -8
The SdFat beta library has a different architecture than the traditional SdFat. In SdFat beta the File32 class allows the use of higher capacity microSD cards and you can even access USB memory sticks or SSD disks. So that you can get videos in suitable conditions for use with movieplayer, you can convert let's say an mpg file for example, with the EVE Asset Builder
|
|
janb
Full Member
Retiree, born 1948, mostly HW/FW oriented programming for > 50 years, 25+ for IBM
Posts: 33
|
Post by janb on Feb 24, 2021 8:37:37 GMT -8
tftlcdcyg, I tried oncemore... Below is my updated 'MoviePlayer' code within 'GD2.h'. I also had to #include <SdFat.h> near the top of the file.
BUT, the "fragmented" .avi files that earlier gave the "blue screen" error message now executes OK!
At the bottom of my code, you also can see what I did to be able to "stop" an ongoing, looooong .avi file "show session"... (like '70s_tv18.avi' sample file).
So, maybe I'll keep this "show feature" in my code anyway, now that it works! I will even take a look at the EVE Asset Builder as well!
Thanks for your interrest!
class MoviePlayer { uint32_t mf_size, mf_base, wp; //Reader r; //JBn File r; //JBn void loadsector() { byte buf[512]; GD.__end(); // r.readsector(buf); //JBn int32_t c = r.curPosition(); //JBn int32_t p = r.peek(); //JBn int n = r.read(buf,512); //JBn
GD.resume(); GD.wr_n(mf_base + wp, buf, 512); wp = (wp + 512) & (mf_size - 1); } public: int begin(const char *filename) { mf_size = 0x40000UL; mf_base = 0x100000UL - mf_size; GD.__end(); // if (!r.openfile(filename)) { //JBn if (!r.open(filename)) { //JBn // Serial.println("Open failed"); return 0; } GD.resume(); wp = 0; while (wp < (mf_size - 512)) { loadsector(); } GD.cmd_mediafifo(mf_base, mf_size); GD.cmd_regwrite(REG_MEDIAFIFO_WRITE, wp); GD.finish(); return 1; } int service() { // if (r.eof()) { //JBn if (!r.available()) { //JBn return 0; } else { uint32_t fullness = (wp - GD.rd32(REG_MEDIAFIFO_READ)) & (mf_size - 1); while (fullness < (mf_size - 512)) { loadsector(); fullness += 512; GD.wr32(REG_MEDIAFIFO_WRITE, wp); } return 1; } } //void play() { //JBn void play(uint8_t StopCapability=0) { //JBn int Continue=1; //JBn // GD.cmd_playvideo(OPT_MEDIAFIFO | OPT_FULLSCREEN); //JBn GD.cmd_playvideo(OPT_MEDIAFIFO | OPT_FULLSCREEN | OPT_SOUND);//JBn-Make sound available GD.flush(); // while (service()); //JBn while (Continue==1) { //JBn Continue = service(); //JBn if (StopCapability!=0) { //JBn-'S'top Capability Requested! GD.get_inputs(); //JBn if (GD.inputs.tag > 0) Continue = -1; //JBn-LCD "touched": 'S'top Playing... } } //JBn if(Continue!=-1) //JBn-If 'S'topped, next stmt seem to "hang"! GD.cmd_memcpy(0, 0, 4); GD.finish(); } };
|
|
janb
Full Member
Retiree, born 1948, mostly HW/FW oriented programming for > 50 years, 25+ for IBM
Posts: 33
|
Post by janb on Feb 24, 2021 10:46:48 GMT -8
By modifying 'GDClass::load(...)' in 'GD2.cpp' (see code below), I now also use SdFat:File... to LOAD the .JPG picture files, instead of GD2's 'Reader class'!
This means that I've also done away with the 'Dos 8.3' Filename "limitation" that 'Reader' has...!
// Load named file from storage
// returns 0 on failure (e.g. file not found), 1 on success
byte GDClass::load(const char *filename, void (*progress)(long, long))
{
#if defined(RASPBERRY_PI) || defined(DUMPDEV) || defined(SPIDRIVER)
char full_name[2048] = "sdcard/";
strcat(full_name, filename);
FILE *f = fopen(full_name, "rb");
if (!f) {
perror(full_name);
exit(1);
}
byte buf[512];
int n;
while ((n = fread(buf, 1, 512, f)) > 0) {
GDTR.cmd_n(buf, (n + 3) & ~3);
}
fclose(f);
return 1;
#else
GD.__end();
//Reader r; //JBn
File r; //JBn
uint32_t offset=0; //JBn
uint32_t size; //JBn
//if (r.openfile(filename)) { //JBn
if (r.open(filename)) { //JBn
byte buf[512];
size = r.available(); //JBn
// while (r.offset < r.size) { //JBn
while ( offset < size) { //JBn
// uint16_t n = min(512U, r.size - r.offset); //JBn
// n = (n + 3) & ~3; // force 32-bit alignment //JBn
// r.readsector(buf); //JBn
int32_t c = r.curPosition(); //JBn
int32_t p = r.peek(); //JBn
int n = r.read(buf,512); //JBn
offset+=n; //JBn
GD.resume();
if (progress)
// (*progress)(r.offset, r.size); //JBn
(*progress)( offset, size); //JBn
n = (n + 3) & ~3; // force 32-bit alignment //JBn
GD.copyram(buf, n); //JBn
GDTR.stop();
}
GD.resume();
return 1;
}
GD.resume();
return 0;
#endif
}
|
|
janb
Full Member
Retiree, born 1948, mostly HW/FW oriented programming for > 50 years, 25+ for IBM
Posts: 33
|
Post by janb on Feb 24, 2021 15:15:10 GMT -8
One FINAL note. On Feb 20 I mentioned that 25MHz "SPI i/o speed" causes "slow motion" for showing the .avi+.jpg files; it still does, even though I now use SdFat's FileRead routines, instead of GD2's 'Reader Class' routines! I don't understand WHY, but it's not important, since 26MHz works OK for me.
HOW Can I "flag" this 'thread' as 'SOLVED'?
|
|
|
Post by tftlcdcyg on Feb 25, 2021 7:52:42 GMT -8
Do you have a link to Github to take a look at your project? Good to know that it worked for you. Did you use SdFat beta or the normal version? Upload some examples to put them into practice, maybe other eyes will help. In the project that I am working with the library, I linked a GPS with real-time maps, with a video player , to relax in what I work at home or during long trips to work My project focused on teensy 4 (4 or 4.1) and SdFat beta: GDTeesny4X
|
|