Browse Source

Firmware: optimize non-sector-aligned SD DMA reads

ikari 12 years ago
parent
commit
b272a6fc1c
3 changed files with 58 additions and 16 deletions
  1. 11 5
      src/fpga_spi.c
  2. 2 0
      src/main.c
  3. 45 11
      src/sdnative.c

+ 11 - 5
src/fpga_spi.c

@@ -47,9 +47,15 @@
                                 s: Bit 2 = partial, Bit 1:0 = target
                                 target: see above
 
-	60	sssseeee	set SD DMA partial transfer start+end
-				ssss = start offset (msb first)
-				eeee = end offset (msb first)
+	60	xsssyeee	set SD DMA partial transfer parameters
+				x: 0 = read from sector start (skip until
+				       start offset reached)
+				   8 = assume mid-sector position and read
+				       immediately
+				sss = start offset (msb first)
+				y: 0 = skip rest of SD sector
+				   8 = stop mid-sector if end offset reached
+				eee = end offset (msb first)
 
 	8p	-		read (RAM only)
 				p: 0 = no increment after read
@@ -98,7 +104,7 @@
 	 15	SD DMA busy (0=idle, 1=busy)
 	 14	DAC read pointer MSB
 	 13	MSU read pointer MSB
-	 12	[TODO SD DMA CRC status (0=ok, 1=error); valid after bit 15 -> 0]
+	 12	reserved (0)
 	 11	reserved (0)
 	 10	reserved (0)
 	  9	reserved (0)
@@ -239,7 +245,7 @@ void fpga_sddma(uint8_t tgt, uint8_t partial) {
   }
   DBG_SD printf("...complete\n");
   FPGA_DESELECT();
-  if(test<5)printf("loopy: %ld %02x\n", test, status);
+//  if(test<5)printf("loopy: %ld %02x\n", test, status);
   BITBAND(SD_CLKREG->FIODIR, SD_CLKPIN) = 1;
 }
 

+ 2 - 0
src/main.c

@@ -35,6 +35,8 @@ int i;
 
 int sd_offload = 0, ff_sd_offload = 0, sd_offload_tgt = 0;
 int sd_offload_partial = 0;
+int sd_offload_start_mid = 0;
+int sd_offload_end_mid = 0;
 uint16_t sd_offload_partial_start = 0;
 uint16_t sd_offload_partial_end = 0;
 

+ 45 - 11
src/sdnative.c

@@ -115,11 +115,12 @@ uint8_t cid[17];
 uint8_t ccs=0;
 uint32_t rca;
 
-enum trans_state { TRANS_NONE = 0, TRANS_READ, TRANS_WRITE };
+enum trans_state { TRANS_NONE = 0, TRANS_READ, TRANS_WRITE, TRANS_MID };
 enum cmd_state { CMD_RSP = 0, CMD_RSPDAT, CMD_DAT };
 
 int during_blocktrans = TRANS_NONE;
 uint32_t last_block = 0;
+uint16_t last_offset = 0;
 
 volatile int sd_changed;
 
@@ -395,7 +396,6 @@ int send_command_fast(uint8_t* cmd, uint8_t* rsp, uint8_t* buf){
       printf("CMD%d timed out\n", cmdno);
       return 0; /* no response within timeout */
     }
-
     i=rsplen;
     uint8_t cmddata=0, datdata=0;
     while(i--) { /* process response */
@@ -460,20 +460,31 @@ int send_command_fast(uint8_t* cmd, uint8_t* rsp, uint8_t* buf){
       state=CMD_DAT;
       j=datcnt;
       datshift=8;
+      timeout=2000000;
       DBG_SD printf("response over, waiting for data...\n");
       /* wait for data start bit on DAT0 */
       while((BITBAND(SD_DAT0REG->FIOPIN, SD_DAT0PIN)) && --timeout) {
         wiggle_fast_neg1();
       }
+//printf("%ld\n", timeout);
       DBG_SD if(!timeout) printf("timed out!\n");
       wiggle_fast_neg1(); /* eat the start bit */
       if(sd_offload) {
         if(sd_offload_partial) {
+          if(sd_offload_partial_start != 0) {
+            if(during_blocktrans == TRANS_MID) sd_offload_partial_start |= 0x8000;
+          }
+          if(sd_offload_partial_end != 512) {
+            sd_offload_partial_end |= 0x8000;
+          }
+          DBG_SD printf("new partial %d - %d\n", sd_offload_partial_start, sd_offload_partial_end);
           fpga_set_sddma_range(sd_offload_partial_start, sd_offload_partial_end);
           fpga_sddma(sd_offload_tgt, 1);
-          sd_offload_partial=0;
+//          sd_offload_partial=0;
+          last_offset=sd_offload_partial_end;
         } else {
           fpga_sddma(sd_offload_tgt, 0);
+          last_offset=0;
         }
         state=CMD_RSP;
         return rsplen;
@@ -597,17 +608,24 @@ int stream_datablock(uint8_t *buf) {
   uint32_t timeout=1000000;
 
   DBG_SD printf("stream_datablock: wait for ready...\n");
-  while((BITBAND(SD_DAT0REG->FIOPIN, SD_DAT0PIN)) && --timeout) {
-    wiggle_fast_neg1();
+  if(during_blocktrans != TRANS_MID) {
+    while((BITBAND(SD_DAT0REG->FIOPIN, SD_DAT0PIN)) && --timeout) {
+      wiggle_fast_neg1();
+    }
+    DBG_SD if(!timeout) printf("timeout!\n");
+    wiggle_fast_neg1(); /* eat the start bit */
   }
-  DBG_SD if(!timeout) printf("timeout!\n");
-
-  wiggle_fast_neg1(); /* eat the start bit */
   if(sd_offload) {
     if(sd_offload_partial) {
+      if(sd_offload_partial_start != 0) {
+        if(during_blocktrans == TRANS_MID) sd_offload_partial_start |= 0x8000;
+      }
+      if(sd_offload_partial_end != 512) {
+        sd_offload_partial_end |= 0x8000;
+      }
+      DBG_SD printf("str partial %d - %d\n", sd_offload_partial_start, sd_offload_partial_end);
       fpga_set_sddma_range(sd_offload_partial_start, sd_offload_partial_end);
       fpga_sddma(sd_offload_tgt, 1);
-      sd_offload_partial=0;
     } else {
       fpga_sddma(sd_offload_tgt, 0);
     }
@@ -772,7 +790,21 @@ void read_block(uint32_t address, uint8_t *buf) {
 #else
     stream_datablock(buf);
 #endif
-    last_block=address;
+    last_block = address;
+    last_offset = sd_offload_partial_end & 0x1ff;
+    if(sd_offload_partial && sd_offload_partial_end != 512) {
+      during_blocktrans = TRANS_MID;
+    }
+    sd_offload_partial = 0;
+  } else if (during_blocktrans == TRANS_MID
+             && last_block == address
+             && last_offset == sd_offload_partial_start
+             && sd_offload_partial) {
+    stream_datablock(buf);
+    last_offset = sd_offload_partial_end & 0x1ff;
+    sd_offload_partial_start |= 0x8000;
+    during_blocktrans = TRANS_READ;
+    sd_offload_partial = 0;
   } else {
     if(during_blocktrans) {
 //      uart_putc('_');
@@ -780,7 +812,7 @@ void read_block(uint32_t address, uint8_t *buf) {
       /* send STOP_TRANSMISSION to end an open READ/WRITE_MULTIPLE_BLOCK */
       cmd_fast(STOP_TRANSMISSION, 0, 0x61, NULL, rsp);
     }
-    last_block=address;
+    last_block = address;
     if(!ccs) {
       address <<= 9;
     }
@@ -792,8 +824,10 @@ void read_block(uint32_t address, uint8_t *buf) {
 #else
     cmd_fast(READ_MULTIPLE_BLOCK, address, 0, buf, rsp);
 #endif
+    sd_offload_partial = 0;
     during_blocktrans = TRANS_READ;
   }
+//  printf("trans state = %d\n", during_blocktrans);
 }
 
 void write_block(uint32_t address, uint8_t* buf) {