Treiber für at25df041a (rev. 0.0.0-erster-anlauf-voellig-ungetestet)
authorWintermute <wintermute@hannover.ccc.de>
Fri, 11 Oct 2013 18:53:47 +0000 (20:53 +0200)
committerWintermute <wintermute@hannover.ccc.de>
Fri, 11 Oct 2013 18:53:47 +0000 (20:53 +0200)
Makefile
dataflash/at25df041a.c [new file with mode: 0644]

index affa70b..8241138 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -43,9 +43,10 @@ SRCS = \
   badge/ui/sprite.c\r
 \r
 SRCS += \\r
-  dataflash/at45db041d.c \\r
   dataflash/iobase.c \\r
-  dataflash/diskio.c\r
+  dataflash/diskio.c \\r
+  dataflash/at25df041a.c\r
+#  dataflash/at45db041d.c\r
 \r
 SRCS += \\r
   project/commands.c\r
diff --git a/dataflash/at25df041a.c b/dataflash/at25df041a.c
new file mode 100644 (file)
index 0000000..04ef300
--- /dev/null
@@ -0,0 +1,239 @@
+#include "projectconfig.h"
+#include "diskio.h"
+#include "iobase.h"
+#include "core/ssp/ssp.h"
+
+#include <r0ketports.h>
+
+/* Opcodes */
+enum {
+  OP_READARRAY        = 0x0b,
+  OP_READARRAY_SLOW   = 0x03,
+
+  OP_ERASE_BLOCK_4K   = 0x20,
+  OP_ERASE_BLOCK_32K  = 0x52,
+  OP_ERASE_BLOCK_64k  = 0xd8,
+  OP_ERASE_CHIP       = 0x60,
+  OP_ERASE_CHIP2      = 0xc7,
+
+  OP_PROGRAM_PAGE     = 0x02,
+  OP_PROGRAM_SEQ      = 0xad,
+  OP_PROGRAM_SEQ2     = 0xaf,
+
+  OP_WRITE_ENABLE     = 0x06,
+  OP_WRITE_DISABLE    = 0x04,
+
+  OP_SECTOR_PROTEXT   = 0x36,
+  OP_SECTOR_UNPROTECT = 0x39,
+  OP_SECTOR_STATUS    = 0x3c,
+
+  OP_STATUS_READ      = 0x05,
+  OP_STATUS_WRITE     = 0x01,
+
+  OP_DEVICEID_READ    = 0x9f,
+
+  OP_POWERDOWN        = 0xb9,
+  OP_RESUME           = 0xab,
+};
+
+enum {
+  STATUS_SPRL = 1 << 7, // sector protection registers locked
+  STATUS_SPM  = 1 << 6, // sequential program mode
+  STATUS_EPE  = 1 << 5, // erase/program error
+  STATUS_WPP  = 1 << 4, // write protect pin
+  STATUS_SWP  = 3 << 2, // software protection
+  STATUS_WEL  = 1 << 1, // write enable latch
+  STATUS_BSY  = 1 << 0, // ready/busy
+
+  STATUS_SWP_NONE = 0,      //   no sectors are software-protected
+  STATUS_SWP_SOME = 1 << 2, // some sectors are software-protected
+  STATUS_SWP_ALL  = 3 << 2  //  all sectors are software-protected
+};
+
+enum {
+  PAGE_MAX  = 2048,
+  PAGE_SIZE = 256,
+
+  SECTOR_SIZE_FATFS = 512
+};
+
+#define CS_LOW()    gpioSetValue(RB_SPI_CS_DF, 0)
+#define CS_HIGH()   gpioSetValue(RB_SPI_CS_DF, 1)
+
+static volatile DSTATUS status = STA_NOINIT;
+
+static void wait_for_ready() {
+  BYTE reg_status = 0xFF;
+
+  CS_LOW();
+  xmit_spi(OP_STATUS_READ);
+  do {
+    rcvr_spi_m((uint8_t *) &reg_status);
+  } while (reg_status & STATUS_BSY);
+  CS_HIGH();
+}
+
+static void dataflash_powerdown() {
+  CS_LOW();
+  xmit_spi(OP_POWERDOWN);
+  CS_HIGH();
+}
+
+static void dataflash_resume() {
+  CS_LOW();
+  xmit_spi(OP_RESUME);
+  CS_HIGH();
+}
+
+DSTATUS dataflash_initialize() {
+  sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
+
+  gpioSetDir(RB_SPI_CS_DF, gpioDirection_Output);
+  dataflash_resume();
+  status &= ~STA_NOINIT;
+
+  return status;
+}
+
+DSTATUS dataflash_status() {
+  return status;
+}
+
+DRESULT dataflash_random_read(BYTE *buff, DWORD offset, DWORD length) {
+  if (!length) return RES_PARERR;
+  if (status & STA_NOINIT) return RES_NOTRDY;
+  if (offset + length > PAGE_MAX * PAGE_SIZE) return RES_PARERR;
+
+  wait_for_ready();
+  CS_LOW();
+  xmit_spi(OP_READARRAY);
+  xmit_spi((BYTE)(offset >> 16));
+  xmit_spi((BYTE)(offset >> 8));
+  xmit_spi((BYTE)offset);
+  xmit_spi(0x00); // follow up with don't care byte
+
+  do {
+    rcvr_spi_m(buff++);
+  } while (--length);
+  CS_HIGH();
+
+  return RES_OK;
+}
+
+DRESULT dataflash_read(BYTE *buff, DWORD sector, BYTE count) {
+  return dataflash_random_read(buff, sector * SECTOR_SIZE_FATFS, count * SECTOR_SIZE_FATFS);
+}
+
+#if _READONLY == 0
+DRESULT dataflash_random_write(const BYTE *buff, DWORD offset, DWORD length) {
+  if (!length) return RES_PARERR;
+  if (status & STA_NOINIT) return RES_NOTRDY;
+  if (offset + length > PAGE_MAX * PAGE_SIZE) return RES_PARERR;
+
+  do {
+    wait_for_ready();
+
+    DWORD pageaddr = (offset / PAGE_SIZE) * PAGE_SIZE;
+    DWORD remaining = PAGE_SIZE - offset % PAGE_SIZE;
+
+    if (remaining > length) {
+      remaining = length;
+    }
+
+    length -= remaining;
+    offset += remaining;
+
+    CS_LOW();
+    xmit_spi(OP_WRITE_ENABLE);
+    CS_HIGH();
+
+    // read page into the internal buffer
+    CS_LOW();
+    xmit_spi(OP_PROGRAM_PAGE);
+    xmit_spi((BYTE)(pageaddr >> 16));
+    xmit_spi((BYTE)(pageaddr >>  8));
+    xmit_spi((BYTE) pageaddr       );
+
+    do {
+      xmit_spi(*buff++);
+    } while (--remaining);
+
+    CS_HIGH();
+  } while (length);
+
+  return RES_OK;
+}
+
+DRESULT dataflash_write(const BYTE *buff, DWORD sector, BYTE count) {
+  return dataflash_random_write(buff, sector * SECTOR_SIZE_FATFS, count * SECTOR_SIZE_FATFS);
+}
+#endif /* _READONLY */
+
+#if _USE_IOCTL != 0
+DRESULT dataflash_ioctl(BYTE ctrl, void *buff) {
+  DRESULT res;
+  BYTE *ptr = buff;
+
+  res = RES_ERROR;
+
+  if (ctrl == CTRL_POWER) {
+    switch (*ptr) {
+    case 0: /* Sub control code == 0 (POWER_OFF) */
+      dataflash_powerdown();
+      res = RES_OK;
+      break;
+    case 1: /* Sub control code == 1 (POWER_ON) */
+      dataflash_resume();
+      res = RES_OK;
+      break;
+    case 2: /* Sub control code == 2 (POWER_GET) */
+      // TODO: figure out a way to retrieve the powerstate
+      *(ptr+1) = (BYTE)1;
+      res = RES_OK;
+      break;
+    default :
+      res = RES_PARERR;
+    }
+  } else {
+    if (status & STA_NOINIT) return RES_NOTRDY;
+
+    switch (ctrl) {
+    case CTRL_SYNC:
+      wait_for_ready();
+      res = RES_OK;
+      break;
+    case GET_SECTOR_COUNT:
+      // TODO: read from device ID register
+      *(WORD*)buff = PAGE_MAX * PAGE_SIZE / SECTOR_SIZE_FATFS;
+      res = RES_OK;
+      break;
+    case GET_SECTOR_SIZE:
+      *(WORD*)buff = SECTOR_SIZE_FATFS;
+      res = RES_OK;
+      break;
+    case GET_BLOCK_SIZE:
+      *(WORD*)buff = 1;
+      res = RES_OK;
+      break;
+    default:
+      res = RES_PARERR;
+    }
+  }
+
+  return res;
+}
+#endif /* _USE_IOCTL != 0 */
+
+DWORD get_fattime () {
+  return 0;
+  /*
+    struct tm* tm=mygmtime(getSeconds());
+    DWORD t= (((tm->tm_year-80)<<9)|
+            ((tm->tm_mon+1)<<5)|
+            (tm->tm_mday))<<16 |
+            ((tm->tm_hour<<11)|
+            (tm->tm_min<<5)|
+            (tm->tm_sec>>1));
+    return t;
+  */
+}
This page took 0.026237 seconds and 4 git commands to generate.