Browse Source

more F810 support. Perf improvements

SD -> EVE bandwidth is now about 150 KByte/s
GD.begin() now takes ~178 ms
eliminated white flash on FT810 startup
jamesbowman 3 years ago
parent
commit
fac8baf27f
4 changed files with 426 additions and 81 deletions
  1. 281 41
      GD2.cpp
  2. 100 28
      GD2.h
  3. 18 4
      transports/dump.h
  4. 27 8
      transports/wiring.h

+ 281 - 41
GD2.cpp

@@ -6,20 +6,20 @@
 #define VERBOSE       0
 #include <GD2.h>
 
-#define SD_PIN        9   // pin used for the microSD enable signal
+#define SD_PIN        9    // pin used for the microSD enable signal
 
 #define BOARD_FTDI_80x    0
-#define BOARD_GAMEDUINO2  1
+#define BOARD_GAMEDUINO23 1
 #define BOARD_EVITA_0     2
 
-#define BOARD         BOARD_GAMEDUINO2 // board, from above
-#define STORAGE       1                // Want SD storage?
-#define CALIBRATION   1                // Want touchscreen?
+#define BOARD         BOARD_GAMEDUINO23 // board, from above
+#define STORAGE       1                 // Want SD storage?
+#define CALIBRATION   1                 // Want touchscreen?
 
 // EVITA_0 has no storage or calibration
 #if (BOARD == BOARD_EVITA_0)
-#undef STORAGE
-#define STORAGE 0
+// #undef STORAGE
+// #define STORAGE 0
 #undef CALIBRATION
 #define CALIBRATION 0
 #endif
@@ -60,6 +60,118 @@ byte ft8xx_model;
 static GDTransport GDTR;
 
 GDClass GD;
+
+// The GD3 has a tiny configuration EEPROM - AT24C01D
+// It is programmed at manufacturing time with the setup
+// commands for the connected panel. The SCL,SDA lines
+// are connected to thye FT81x GPIO0, GPIO1 signals.
+// This is a read-only driver for it.  A single method
+// 'read()' initializes the RAM and reads all 128 bytes
+// into an array.
+
+class ConfigRam {
+private:
+  uint8_t gpio, gpio_dir, sda;
+  void set_SDA(byte n)
+  {
+    if (sda != n) {
+      GDTR.__wr16(REG_GPIO_DIR, gpio_dir | (0x03 - n));    // Drive SCL, SDA low
+      sda = n;
+    }
+  }
+
+  void set_SCL(byte n)
+  {
+    GDTR.__wr16(REG_GPIO, gpio | (n << 1));
+  }
+
+  int get_SDA(void)
+  {
+    return GDTR.__rd16(REG_GPIO) & 1;
+  }
+
+  void i2c_start(void) 
+  {
+    set_SDA(1);
+    set_SCL(1);
+    set_SDA(0);
+    set_SCL(0);
+  }
+
+  void i2c_stop(void) 
+  {
+    set_SDA(0);
+    set_SCL(1);
+    set_SDA(1);
+    set_SCL(1);
+  }
+
+  int i2c_rx1()
+  {
+    set_SDA(1);
+    set_SCL(1);
+    byte r = get_SDA();
+    set_SCL(0);
+    return r;
+  }
+
+  void i2c_tx1(byte b)
+  {
+    set_SDA(b);
+    set_SCL(1);
+    set_SCL(0);
+  }
+
+  int i2c_tx(byte x)
+  {
+    for (byte i = 0; i < 8; i++, x <<= 1)
+      i2c_tx1(x >> 7);
+    return i2c_rx1();
+  }
+
+  int i2c_rx(int nak)
+  {
+    byte r = 0;
+    for (byte i = 0; i < 8; i++)
+      r = (r << 1) | i2c_rx1();
+    i2c_tx1(nak);
+    return r;
+  }
+
+public:
+  void read(byte *v)
+  {
+    GDTR.__end();
+    gpio = GDTR.__rd16(REG_GPIO) & ~3;
+    gpio_dir = GDTR.__rd16(REG_GPIO_DIR) & ~3;
+    sda = 2;
+
+    // 2-wire software reset
+    i2c_start();
+    i2c_rx(1);
+    i2c_start();
+    i2c_stop();
+
+    int ADDR = 0xa0;
+
+    i2c_start();
+    if (i2c_tx(ADDR))
+      return;
+    if (i2c_tx(0))
+      return;
+
+    i2c_start();
+    if (i2c_tx(ADDR | 1))
+      return;
+    for (int i = 0; i < 128; i++) {
+      *v++ = i2c_rx(i == 127);
+      // Serial.println(v[-1], DEC);
+    }
+    i2c_stop();
+    GDTR.resume();
+  }
+};
+
 void GDClass::flush(void)
 {
   GDTR.flush();
@@ -71,6 +183,9 @@ void GDClass::swap(void) {
   cmd_loadidentity();
   cmd_dlstart();
   GDTR.flush();
+#ifdef DUMPDEV
+  GDTR.swap();
+#endif
 }
 
 uint32_t GDClass::measure_freq(void)
@@ -88,50 +203,78 @@ uint32_t GDClass::measure_freq(void)
 void GDClass::tune(void)
 {
   uint32_t f;
-  for (byte i = 0; (i < 31) && ((f = measure_freq()) < LOW_FREQ_BOUND); i++)
+  for (byte i = 0; (i < 31) && ((f = measure_freq()) < LOW_FREQ_BOUND); i++) {
     GDTR.wr(REG_TRIM, i);
+  }
   GDTR.wr32(REG_FREQUENCY, f);
 }
 
 void GDClass::begin(uint8_t options) {
 #if STORAGE && defined(ARDUINO)
+  GDTR.begin0();
+
   if (options & GD_STORAGE) {
     GDTR.ios();
     SD.begin(SD_PIN);
   }
 #endif
 
-  GDTR.begin();
+  GDTR.begin1();
 
-#if VERBOSE
+#if 0
   Serial.println("ID REGISTER:");
   Serial.println(GDTR.rd(REG_ID), HEX);
 #endif
 
-  // Generate a blank screen
-  cmd_dlstart();
-#ifndef DUMPDEV
-  Clear();
-  swap();
-#endif
-  finish();
-
 #if (BOARD == BOARD_FTDI_80x)
-  w = 480, h = 272;
   GDTR.wr(REG_PCLK_POL, 1);
   GDTR.wr(REG_PCLK, 5);
 #endif
-
-#if (BOARD == BOARD_GAMEDUINO2)
-  w = 480, h = 272;
-  GDTR.wr(REG_PCLK_POL, 1);
-  GDTR.wr(REG_PCLK, 5);
-  GDTR.wr(REG_ROTATE, 1);
-  GDTR.wr(REG_SWIZZLE, 3);
+  GDTR.wr(REG_PWM_DUTY, 0);
+  GDTR.wr(REG_GPIO_DIR, 0x83);
+  GDTR.wr(REG_GPIO, GDTR.rd(REG_GPIO) | 0x80);
+
+#if (BOARD == BOARD_GAMEDUINO23)
+  ConfigRam cr;
+  byte v8[128] = {0};
+  cr.read(v8);
+  if ((v8[1] == 0xff) && (v8[2] == 0x01)) {
+    options &= ~(GD_TRIM | GD_CALIBRATE);
+    if (v8[3] & 2) {
+      GDTR.__end();
+      GDTR.hostcmd(0x44); // switch to external crystal
+      GDTR.resume();
+    }
+    copyram(v8 + 4, 124);
+    finish();
+  } else {
+    GDTR.wr(REG_PCLK_POL, 1);
+    GDTR.wr(REG_PCLK, 5);
+    GDTR.wr(REG_ROTATE, 1);
+    GDTR.wr(REG_SWIZZLE, 3);
+  }
 #endif
 
+  if (0) {
+    GDTR.wr16(REG_HCYCLE, 928);
+    GDTR.wr16(REG_HOFFSET, 88);
+    GDTR.wr16(REG_HSIZE, 800);
+    GDTR.wr16(REG_HSYNC0, 0);
+    GDTR.wr16(REG_HSYNC1, 48);
+
+    GDTR.wr16(REG_VCYCLE, 525);
+    GDTR.wr16(REG_VOFFSET, 32);
+    GDTR.wr16(REG_VSIZE, 480);
+    GDTR.wr16(REG_VSYNC0, 0);
+    GDTR.wr16(REG_VSYNC1, 3);
+
+    GDTR.wr16(REG_CSPREAD, 0);
+    GDTR.wr16(REG_DITHER, 1);
+    GDTR.wr16(REG_PCLK_POL, 1);
+    GDTR.wr16(REG_PCLK, 2);
+  }
+
 #if (BOARD == BOARD_EVITA_0)
-  w = 1024, h = 768;
   GDTR.wr16(REG_HCYCLE,  1344);
   GDTR.wr16(REG_HSIZE,   1024);
   GDTR.wr16(REG_HSYNC0,  0   );
@@ -145,15 +288,23 @@ void GDClass::begin(uint8_t options) {
   GDTR.wr16(REG_CSPREAD, 0   );
   GDTR.wr16(REG_PCLK_POL,0   );
   GDTR.wr16(REG_PCLK,    1   );
+  GDTR.wr(REG_GPIO, GDTR.rd(REG_GPIO) | 0x10);
 #endif
 
-  GDTR.wr(REG_GPIO_DIR, 0x83);
-  GDTR.wr(REG_GPIO, 0x80);
+  w = GDTR.rd16(REG_HSIZE);
+  h = GDTR.rd16(REG_VSIZE);
+  // w = 480, h = 272;
+  Clear(); swap();
+  Clear(); swap();
+  Clear(); swap();
+  cmd_regwrite(REG_PWM_DUTY, 128);
+  GD.flush();
+// Serial.println("STOP"); for(;;);
 
   if (CALIBRATION & (options & GD_CALIBRATE)) {
 
 #if defined(ARDUINO) && !defined(__DUE__)
-    if (EEPROM.read(0) != 0x7c) {
+    if ((EEPROM.read(0) != 0x7c)) {
       self_calibrate();
       // for (int i = 0; i < 24; i++) Serial.println(GDTR.rd(REG_TOUCH_TRANSFORM_A + i), HEX);
       for (int i = 0; i < 24; i++)
@@ -208,7 +359,7 @@ void GDClass::begin(uint8_t options) {
 
   rseed = 0x77777777;
 
-  if (options & GD_TRIM) {
+  if ((BOARD == BOARD_GAMEDUINO23) && (options & GD_TRIM)) {
     tune();
   }
 }
@@ -416,6 +567,11 @@ void GDClass::BitmapSize(byte filter, byte wrapx, byte wrapy, uint16_t width, ui
   b[2] = (3 & (width >> 7)) | (fxy << 2);
   b[3] = 8;
   cI(c);
+  if (ft8xx_model) {
+    b[0] = ((width >> 9) << 2) | (3 & (height >> 9));
+    b[3] = 0x29;
+    cI(c);
+  }
 }
 void GDClass::BitmapSource(uint32_t addr) {
   cI((1UL << 24) | ((addr & 1048575L) << 0));
@@ -561,6 +717,27 @@ void GDClass::Vertex2ii(uint16_t x, uint16_t y, byte handle, byte cell) {
   b[3] = (2 << 6) | (x >> 3);
   cI(c);
 }
+void GDClass::VertexFormat(byte frac) {
+  cI((39UL << 24) | (((frac) & 7) << 0));
+}
+void GDClass::BitmapLayoutH(byte linestride, byte height) {
+  cI((40 << 24) | (((linestride) & 3) << 2) | (((height) & 3) << 0));
+}
+void GDClass::BitmapSizeH(byte width, byte height) {
+  cI((41UL << 24) | (((width) & 3) << 2) | (((height) & 3) << 0));
+}
+void GDClass::PaletteSource(uint32_t addr) {
+  cI((42UL << 24) | (((addr) & 4194303UL) << 0));
+}
+void GDClass::VertexTranslateX(uint32_t x) {
+  cI((43UL << 24) | (((x) & 131071UL) << 0));
+}
+void GDClass::VertexTranslateY(uint32_t y) {
+  cI((44UL << 24) | (((y) & 131071UL) << 0));
+}
+void GDClass::Nop(void) {
+  cI((45UL << 24));
+}
 
 void GDClass::cmd_append(uint32_t ptr, uint32_t num) {
   cFFFFFF(0x1e);
@@ -842,6 +1019,60 @@ void GDClass::cmd_translate(int32_t tx, int32_t ty) {
   ci(tx);
   ci(ty);
 }
+void GDClass::cmd_playvideo(int32_t options) {
+  cFFFFFF(0x3a);
+  cI(options);
+}
+void GDClass::cmd_romfont(uint32_t font, uint32_t romslot) {
+  cFFFFFF(0x3f);
+  cI(font);
+  cI(romslot);
+}
+void GDClass::cmd_mediafifo(uint32_t ptr, uint32_t size) {
+  cFFFFFF(0x39);
+  cI(ptr);
+  cI(size);
+}
+void GDClass::cmd_setbase(uint32_t b) {
+  cFFFFFF(0x38);
+  cI(b);
+}
+void GDClass::cmd_videoframe(uint32_t dst, uint32_t ptr) {
+  cFFFFFF(0x41);
+  cI(dst);
+  cI(ptr);
+}
+void GDClass::cmd_snapshot2(uint32_t fmt, uint32_t ptr, int16_t x, int16_t y, int16_t w, int16_t h) {
+  cFFFFFF(0x37);
+  cI(fmt);
+  cI(ptr);
+  ch(x);
+  ch(y);
+  ch(w);
+  ch(h);
+}
+void GDClass::cmd_setfont2(uint32_t font, uint32_t ptr, uint32_t firstchar) {
+  cFFFFFF(0x3b);
+  cI(font);
+  cI(ptr);
+  cI(firstchar);
+}
+void GDClass::cmd_setbitmap(uint32_t source, uint16_t fmt, uint16_t w, uint16_t h) {
+  cFFFFFF(0x43);
+  cI(source);
+  ch(fmt);
+  ch(w);
+  ch(h);
+  ch(0);
+}
+
+void GDClass::cmd_setrotate(uint32_t r) {
+  cFFFFFF(0x36);
+  cI(r);
+}
+void GDClass::cmd_videostart() {
+  cFFFFFF(0x40);
+}
 
 byte GDClass::rd(uint32_t addr) {
   return GDTR.rd(addr);
@@ -965,9 +1196,11 @@ void GDClass::reset() {
 byte GDClass::load(const char *filename, void (*progress)(long, long))
 {
 #if defined(RASPBERRY_PI) || defined(DUMPDEV)
-  FILE *f = fopen(filename, "rb");
+  char full_name[2048]  = "sdcard/";
+  strcat(full_name, filename);
+  FILE *f = fopen(full_name, "rb");
   if (!f) {
-    perror(filename);
+    perror(full_name);
     exit(1);
   }
   byte buf[512];
@@ -1038,13 +1271,14 @@ void GDClass::safeload(const char *filename)
   }
 }
 
-#define REG_SCREENSHOT_EN    0x00102410UL // Set to enable screenshot mode
-#define REG_SCREENSHOT_Y     0x00102414UL // Y line register
-#define REG_SCREENSHOT_START 0x00102418UL // Screenshot start trigger
-#define REG_SCREENSHOT_BUSY  0x001024d8UL // Screenshot ready flags
-#define REG_SCREENSHOT_READ  0x00102554UL // Set to enable readout
-#define RAM_SCREENSHOT       0x001C2000UL // Screenshot readout buffer
+#define REG_SCREENSHOT_EN    (ft8xx_model ? 0x302010UL : 0x102410UL) // Set to enable screenshot mode
+#define REG_SCREENSHOT_Y     (ft8xx_model ? 0x302014UL : 0x102414UL) // Y line register
+#define REG_SCREENSHOT_START (ft8xx_model ? 0x302018UL : 0x102418UL) // Screenshot start trigger
+#define REG_SCREENSHOT_BUSY  (ft8xx_model ? 0x3020e8UL : 0x1024d8UL) // Screenshot ready flags
+#define REG_SCREENSHOT_READ  (ft8xx_model ? 0x302174UL : 0x102554UL) // Set to enable readout
+#define RAM_SCREENSHOT       (ft8xx_model ? 0x3c2000UL : 0x1C2000UL) // Screenshot readout buffer
 
+#if 0 // ndef DUMPDEV
 void GDClass::dumpscreen(void)    
 {
   {
@@ -1052,7 +1286,11 @@ void GDClass::dumpscreen(void)
 
     wr(REG_SCREENSHOT_EN, 1);
     Serial.write(0xa5);
-    for (int ly = 0; ly < 272; ly++) {
+    Serial.write(GD.w & 0xff);
+    Serial.write((GD.w >> 8) & 0xff);
+    Serial.write(GD.h & 0xff);
+    Serial.write((GD.h >> 8) & 0xff);
+    for (int ly = 0; ly < GD.h; ly++) {
       wr16(REG_SCREENSHOT_Y, ly);
       wr(REG_SCREENSHOT_START, 1);
       delay(2);
@@ -1061,7 +1299,7 @@ void GDClass::dumpscreen(void)
       wr(REG_SCREENSHOT_READ, 1);
       bulkrd(RAM_SCREENSHOT);
       SPI.transfer(0xff);
-      for (int x = 0; x < 480; x += 8) {
+      for (int x = 0; x < GD.w; x += 8) {
         union {
           uint32_t v;
           struct {
@@ -1074,6 +1312,7 @@ void GDClass::dumpscreen(void)
           block[i].r = SPI.transfer(0xff);
           block[i].a = SPI.transfer(0xff);
         }
+        // if (x == 0) block[0].r = 0xff;
         byte difference = 1;
         for (int i = 1, mask = 2; i < 8; i++, mask <<= 1)
           if (block[i].v != block[i-1].v)
@@ -1093,3 +1332,4 @@ void GDClass::dumpscreen(void)
     wr16(REG_SCREENSHOT_EN, 0);
   }
 }
+#endif

+ 100 - 28
GD2.h

@@ -239,11 +239,11 @@ class sdcard {
       appcmd(41, sdhc ? (1UL << 30) : 0); // card init
       r1 = R1();
 #if VERBOSE
-    Serial.println(r1, HEX);
+      Serial.println(r1, HEX);
 #endif
       if ((r1 & 1) == 0)
         break;
-      delay(100);
+      delay(1);
     }
     INFO("OK");
 
@@ -260,6 +260,7 @@ class sdcard {
 
     // Test point: dump sector 0 to serial.
     // should see first 512 bytes of card, ending 55 AA.
+#if 0
     if (0) {
       cmd17(0);
       for (int i = 0; i < 512; i++) {
@@ -273,6 +274,12 @@ class sdcard {
       desel();
       for (;;);
     }
+#endif
+
+#if !defined(__DUE__)
+    SPI.setClockDivider(SPI_CLOCK_DIV2);
+    SPSR = (1 << SPI2X);
+#endif
 
     type_code = rd(0x1be + 0x4);
     switch (type_code) {
@@ -315,10 +322,6 @@ class sdcard {
   finished:
     INFO("finished");
     ;
-#if !defined(__DUE__)
-    SPI.setClockDivider(SPI_CLOCK_DIV2);
-    SPSR = (1 << SPI2X);
-#endif
   }
   void cmd17(uint32_t off) {
     if (ccs)
@@ -489,6 +492,14 @@ public:
   void Vertex2f(int16_t x, int16_t y);
   void Vertex2ii(uint16_t x, uint16_t y, byte handle = 0, byte cell = 0);
 
+  void VertexFormat(byte frac);
+  void BitmapLayoutH(byte linestride, byte height);
+  void BitmapSizeH(byte width, byte height);
+  void PaletteSource(uint32_t addr);
+  void VertexTranslateX(uint32_t x);
+  void VertexTranslateY(uint32_t y);
+  void Nop(void);
+
   // Higher-level graphics commands
 
   void cmd_append(uint32_t ptr, uint32_t num);
@@ -536,6 +547,17 @@ public:
   void cmd_track(int16_t x, int16_t y, uint16_t w, uint16_t h, byte tag);
   void cmd_translate(int32_t tx, int32_t ty);
 
+  void cmd_playvideo(int32_t options);
+  void cmd_romfont(uint32_t font, uint32_t romslot);
+  void cmd_mediafifo(uint32_t ptr, uint32_t size);
+  void cmd_setbase(uint32_t b);
+  void cmd_videoframe(uint32_t dst, uint32_t ptr);
+  void cmd_snapshot2(uint32_t fmt, uint32_t ptr, int16_t x, int16_t y, int16_t w, int16_t h);
+  void cmd_setfont2(uint32_t font, uint32_t ptr, uint32_t firstchar);
+  void cmd_setrotate(uint32_t r);
+  void cmd_videostart();
+  void cmd_setbitmap(uint32_t source, uint16_t fmt, uint16_t w, uint16_t h);
+
   byte rd(uint32_t addr);
   void wr(uint32_t addr, uint8_t v);
   uint16_t rd16(uint32_t addr);
@@ -601,18 +623,22 @@ public:
     } while (de.name[0]);
     return 0;
   }
+
   void begin(dirent &de) {
+    nseq = 0;
     size = de.size;
     cluster0 = de.cluster;
     if (GD.SD.type == FAT32)
       cluster0 |= ((long)de.cluster_hi << 16);
     rewind();
   }
+
   void rewind(void) {
     cluster = cluster0;
     sector = 0;
     offset = 0;
   }
+
   void nextcluster() {
     if (GD.SD.type == FAT16)
       cluster = GD.SD.rd2(GD.SD.o_fat + 2 * cluster);
@@ -623,10 +649,61 @@ public:
     Serial.println(cluster, DEC);
 #endif
   }
+
+  void fetch512(byte *dst) {
+#if defined(__DUE__) || defined(TEENSYDUINO)
+    for (int i = 0; i < 512; i++)
+      *dst++ = SPI.transfer(0xff);
+    SPI.transfer(0xff);   // consume CRC
+    SPI.transfer(0xff);
+#else
+    SPDR = 0xff;
+    while (!(SPSR & _BV(SPIF))) ;
+    for (int i = 0; i < 512; i++) {
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      *dst++ = SPDR;
+      SPDR = 0xff;
+    }
+    while (!(SPSR & _BV(SPIF))) ;
+    SPI.transfer(0xff);
+#endif
+    GD.SD.desel();
+  }
+
+  void nextcluster2(byte *dst) {
+    if (nseq) {
+      nseq--;
+      cluster++;
+      return;
+    }
+    uint32_t off = GD.SD.o_fat + 4 * cluster;
+    GD.SD.cmd17(off & ~511L);
+    fetch512(dst);
+    int i = off & 511;
+    cluster = *(uint32_t*)&dst[i];
+    uint32_t c = cluster;
+    nseq = 0;
+    for (uint32_t c = cluster;
+         (i < 512) && *(uint32_t*)&dst[i] == c; 
+         i += 4, c++)
+      nseq++;
+  }
+
   void skipcluster() {
     nextcluster();
     offset += GD.SD.cluster_size;
   }
+
   void skipsector() {
     if (sector == GD.SD.sectors_per_cluster) {
       sector = 0;
@@ -635,6 +712,7 @@ public:
     sector++;
     offset += 512;
   }
+
   void seek(uint32_t o) {
     union {
       uint8_t buf[512];
@@ -662,41 +740,28 @@ public:
         skipsector();
     }
   }
-  void readsector() {
+
+  void readsector(byte *dst) {
     if (sector == GD.SD.sectors_per_cluster) {
       sector = 0;
-      nextcluster();
+      nextcluster2(dst);
     }
     uint32_t off = GD.SD.o_data + ((long)GD.SD.cluster_size * cluster) + (512L * sector);
-#if VERBOSE
-    Serial.print("off=0x");
-    Serial.println(off, HEX);
-#endif
     GD.SD.cmd17(off & ~511L);
-// Serial.println(2 * (micros() - t0), DEC);
     sector++;
     offset += 512;
+    fetch512(dst);
   }
-  void readsector(byte *dst) {
-    readsector();
-    for (int i = 0; i < 64; i++) {
-      *dst++ = SPI.transfer(0xff);
-      *dst++ = SPI.transfer(0xff);
-      *dst++ = SPI.transfer(0xff);
-      *dst++ = SPI.transfer(0xff);
-      *dst++ = SPI.transfer(0xff);
-      *dst++ = SPI.transfer(0xff);
-      *dst++ = SPI.transfer(0xff);
-      *dst++ = SPI.transfer(0xff);
-    }
-    SPI.transfer(0xff);   // consume CRC
-    SPI.transfer(0xff);
-    GD.SD.desel();
+
+  int eof(void) {
+    return size <= offset;
   }
+
   uint32_t cluster, cluster0;
   uint32_t offset;
   uint32_t size;
   byte sector;
+  byte nseq;
 };
 #endif
 
@@ -793,6 +858,10 @@ typedef struct {
 #define OPT_RIGHTX           2048
 #define OPT_SIGNED           256
 
+#define OPT_NOTEAR           4
+#define OPT_FULLSCREEN       8
+#define OPT_MEDIAFIFO        16
+
 #define LINEAR_SAMPLES       0
 #define ULAW_SAMPLES         1
 #define ADPCM_SAMPLES        2
@@ -912,6 +981,9 @@ typedef struct {
 #define REG_VSYNC0            (ft8xx_model ? 0x30204cUL : 0x102448UL)
 #define REG_VSYNC1            (ft8xx_model ? 0x302050UL : 0x10244cUL)
 
+#define REG_MEDIAFIFO_READ    0x309014
+#define REG_MEDIAFIFO_WRITE   0x309018
+
 #define VERTEX2II(x, y, handle, cell) \
         ((2UL << 30) | (((x) & 511UL) << 21) | (((y) & 511UL) << 12) | (((handle) & 31) << 7) | (((cell) & 127) << 0))
 

+ 18 - 4
transports/dump.h

@@ -1,13 +1,22 @@
 class GDTransport {
   FILE *dumpfile;
-public:
-  void begin(void) {
-    dumpfile = fopen("dump", "wb");
+  int counter;
+  void hose(void) {
+    char fn[2048];
+    sprintf(fn, "%04d.cmd", counter);
+    dumpfile = fopen(fn, "wb");
     if (!dumpfile) {
-      perror("dump");
+      perror(fn);
       exit(1);
     }
   }
+public:
+  void begin(void) {
+    counter = 0;
+    ft8xx_model = 1;
+    hose();
+  }
+  static void hostcmd(byte a) {}
   void cmdbyte(byte x) {
     putc(x, dumpfile);
   }
@@ -35,5 +44,10 @@ public:
   uint32_t getwp(void) { return 0; }
   void bulk(uint32_t addr) {}
   void resume(void) {}
+  void swap() {
+    fclose(dumpfile);
+    counter++;
+    hose();
+  }
 };
 

+ 27 - 8
transports/wiring.h

@@ -15,7 +15,7 @@ public:
     SPI.begin();
     // for (;;) SPI.transfer(0x33);
   }
-  void begin() {
+  void begin0() {
     ios();
 
     SPI.begin();
@@ -29,11 +29,18 @@ public:
 #endif
 
     hostcmd(0x00);
-#if (BOARD != BOARD_GAMEDUINO2)
-    hostcmd(0x44); // from external crystal
+#if (BOARD != BOARD_GAMEDUINO23)
+ hostcmd(0x44); // from external crystal
 #endif
     hostcmd(0x68);
+  }
+  void begin1() {
+#if 0
     delay(120);
+#else
+    while ((__rd16(0xc0000UL) & 0xff) != 0x08)
+      ;
+#endif
 
     // Test point: saturate SPI
     while (0) {
@@ -42,6 +49,7 @@ public:
       digitalWrite(CS, HIGH);
     }
 
+#if 0
     // Test point: attempt to wake up FT8xx every 2 seconds
     while (0) {
       hostcmd(0x00);
@@ -60,10 +68,11 @@ public:
       digitalWrite(CS, HIGH);
       delay(2000);
     }
+#endif
 
     // So that FT800,801      FT81x
     // model       0            1
-    ft8xx_model = rd(0x0c0001) >> 4;  
+    ft8xx_model = __rd16(0x0c0000) >> 12;  
 
     wp = 0;
     freespace = 4096 - 4;
@@ -203,8 +212,20 @@ public:
   {
     __end(); // stop streaming
     __wstart(addr);
-    while (n--)
-      SPI.transfer(*src++);
+    while (n--) {
+      SPDR = *src++;
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+      asm volatile("nop");
+    }
+    while (!(SPSR & _BV(SPIF))) ;
     stream();
   }
 
@@ -292,7 +313,6 @@ public:
     SPI.transfer(0x00);
     SPI.transfer(0x00);
     digitalWrite(CS, HIGH);
-    delay(60);
   }
 
   void getfree(uint16_t n)
@@ -311,4 +331,3 @@ public:
   uint16_t wp;
   uint16_t freespace;
 };
-