diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index ac1eb09aff02856ef8eda652607dbb8e07c3599e..8b0b20deee2754510a6b1dd51b62f351b83d8d5a 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -554,26 +554,47 @@ API(API_FILE_TELL, int epic_file_tell(int fd));
 
 /** */
 enum epic_stat_type {
-	/** */
+	/** basically NOENT 
+	 * although epic_file_stat returns an error for 'none', the type will still be set
+	 * to none additinally.
+	 * This is also used internally to track open FS objects, where we use ``EPICSTAT_NONE``
+	 * to mark free objects.
+	 */
+	EPICSTAT_NONE,
+	/** normal file */
 	EPICSTAT_FILE,
-	/** */
+	/** directory */
 	EPICSTAT_DIR,
 };
 
 /** */
 typedef struct epic_stat_t {
-	/** */
+	/** type: file, directory or none */
 	enum epic_stat_type type;
+	/* note about padding & placement of uint32_t size:
+	 * to accomodate for future expansion, we want padding at the end of
+	 * this struct. Since sizeof(enum epic_stat_type) can not be
+	 * assumed to be have a certain size,
+	 * we're placing uint32_t size here so we can be sure it will be at
+	 * offset 4, and therefore the layout of the other fields is predictable.
+	 */
+	/** size in bytes */
+	uint32_t size;
+	/** the FAT volume (will be needed later once we distinguish
+	 *  between system and user volume)*/
+	uint8_t volume;
+	uint8_t _reserved[9];
 } epic_stat_t;
 
+#ifndef __cplusplus
+#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
+_Static_assert(sizeof(epic_stat_t) == 20, "");
+#endif
+#endif
+
 /**
  * stat path
  *
- * This does not follow posix convention, but rather takes
- * a path as parameter. This aligns more with libff's API and
- * also this has been implemented for python import support, which
- * passes the filename as well.
- *
  * :param const char* filename: path to stat
  * :param epic_stat_t* stat: pointer to result
  *
diff --git a/epicardium/modules/fatfs.c b/epicardium/modules/fatfs.c
index e9f7205d771f98bf153b3fc3bec3b6b8a996581a..1962f4939781097178602e7646c5f1af0f6886b9 100644
--- a/epicardium/modules/fatfs.c
+++ b/epicardium/modules/fatfs.c
@@ -26,61 +26,21 @@ static const TCHAR *rcstrings =
 	_T("NOT_ENABLED\0NO_FILESYSTEM\0MKFS_ABORTED\0TIMEOUT\0LOCKED\0")
 	_T("NOT_ENOUGH_CORE\0TOO_MANY_OPEN_FILES\0INVALID_PARAMETER\0");
 
-// this table converts from FRESULT to POSIX errno
-const int fresult_to_errno_table[20] = {
-	[FR_OK]                  = 0,
-	[FR_DISK_ERR]            = EIO,
-	[FR_INT_ERR]             = EIO,
-	[FR_NOT_READY]           = EBUSY,
-	[FR_NO_FILE]             = ENOENT,
-	[FR_NO_PATH]             = ENOENT,
-	[FR_INVALID_NAME]        = EINVAL,
-	[FR_DENIED]              = EACCES,
-	[FR_EXIST]               = EEXIST,
-	[FR_INVALID_OBJECT]      = EINVAL,
-	[FR_WRITE_PROTECTED]     = EROFS,
-	[FR_INVALID_DRIVE]       = ENODEV,
-	[FR_NOT_ENABLED]         = ENODEV,
-	[FR_NO_FILESYSTEM]       = ENODEV,
-	[FR_MKFS_ABORTED]        = EIO,
-	[FR_TIMEOUT]             = EIO,
-	[FR_LOCKED]              = EIO,
-	[FR_NOT_ENOUGH_CORE]     = ENOMEM,
-	[FR_TOO_MANY_OPEN_FILES] = EMFILE,
-	[FR_INVALID_PARAMETER]   = EINVAL,
-};
-
-enum FatObjectType { FO_Nil, FO_File, FO_Dir };
-struct FatObject {
-	enum FatObjectType type;
-	union {
-		FIL file;
-		DIR dir;
-	};
-};
-
 static bool mount(void);
-static int
-get_fat_object(int i, enum FatObjectType expected, struct FatObject **res);
 
 DIR dir;
 FATFS FatFs;
-static struct FatObject s_openedObjects[EPIC_FAT_MAX_OPENED];
 
 #if (EPIC_FAT_STATIC_SEMAPHORE == 1)
 StaticSemaphore_t xSemaphoreBuffer;
 #endif
 
-static volatile struct {
-	bool initiaized;
-} s_state = {
-	.initiaized = false,
-};
+static volatile bool s_fatfs_initiaized = false;
 
 void fatfs_init()
 {
 	if (mount()) {
-		s_state.initiaized = true;
+		s_fatfs_initiaized = true;
 		printf("FatFs mounted\n");
 	}
 }
@@ -188,195 +148,3 @@ void ff_rel_grant(FF_SYNC_t sobj)
 	/* FreeRTOS */
 	xSemaphoreGive(sobj);
 }
-
-int get_fat_object(int i, enum FatObjectType expected, struct FatObject **res)
-{
-	if (i < 0 || i >= EPIC_FAT_MAX_OPENED) {
-		*res = NULL;
-		return EBADF;
-	}
-	if (s_openedObjects[i].type != expected) {
-		*res = NULL;
-		return EBADF;
-	}
-	*res = &s_openedObjects[i];
-	return 0;
-}
-
-int epic_file_open(const char *filename, const char *modeString)
-{
-	struct FatObject *o = NULL;
-	const char *mode_s  = modeString;
-	int i;
-	int mode = 0;
-
-	//find free object to use
-	for (i = 0; i < EPIC_FAT_MAX_OPENED; ++i) {
-		if (s_openedObjects[i].type == FO_Nil) {
-			break;
-		}
-	}
-	if (i == EPIC_FAT_MAX_OPENED) {
-		return -fresult_to_errno_table[FR_TOO_MANY_OPEN_FILES];
-	}
-	o = &s_openedObjects[i];
-
-	while (*mode_s) {
-		switch (*mode_s++) {
-		case 'r':
-			mode |= FA_READ;
-			break;
-		case 'w':
-			mode |= FA_WRITE | FA_CREATE_ALWAYS;
-			break;
-		case 'x':
-			mode |= FA_WRITE | FA_CREATE_NEW;
-			break;
-		case 'a':
-			mode |= FA_WRITE | FA_OPEN_ALWAYS;
-			break;
-		case '+':
-			mode |= FA_READ | FA_WRITE;
-			break;
-		}
-	}
-
-	int res = f_open(&o->file, filename, mode);
-	if (res != FR_OK) {
-		return -fresult_to_errno_table[res];
-	}
-	o->type = FO_File;
-
-	// for 'a' mode, we must begin at the end of the file
-	if ((mode & FA_OPEN_ALWAYS) != 0) {
-		f_lseek(&o->file, f_size(&o->file));
-	}
-
-	return i;
-}
-
-int epic_file_close(int fd)
-{
-	int res;
-	struct FatObject *o;
-	res = get_fat_object(fd, FO_File, &o);
-	if (res) {
-		return -res;
-	}
-
-	res = f_close(&o->file);
-	if (res != FR_OK) {
-		return -fresult_to_errno_table[res];
-	}
-
-	o->type = FO_Nil;
-	return 0;
-}
-
-int epic_file_read(int fd, void *buf, size_t nbytes)
-{
-	unsigned int nread = 0;
-
-	int res;
-	struct FatObject *o;
-	res = get_fat_object(fd, FO_File, &o);
-	if (res) {
-		return -res;
-	}
-
-	res = f_read(&o->file, buf, nbytes, &nread);
-	if (res != FR_OK) {
-		return -fresult_to_errno_table[res];
-	}
-
-	return nread;
-}
-
-int epic_file_write(int fd, const void *buf, size_t nbytes)
-{
-	unsigned int nwritten = 0;
-
-	int res;
-	struct FatObject *o;
-	res = get_fat_object(fd, FO_File, &o);
-	if (res) {
-		return -res;
-	}
-	res = f_write(&o->file, buf, nbytes, &nwritten);
-	if (res != FR_OK) {
-		return -fresult_to_errno_table[res];
-	}
-
-	return nwritten;
-}
-
-int epic_file_flush(int fd)
-{
-	int res;
-	struct FatObject *o;
-	res = get_fat_object(fd, FO_File, &o);
-	if (res) {
-		return -res;
-	}
-	res = f_sync(&o->file);
-	if (res != FR_OK) {
-		return -fresult_to_errno_table[res];
-	}
-
-	return 0;
-}
-
-int epic_file_seek(int fd, long offset, int whence)
-{
-	int res;
-	struct FatObject *o;
-	res = get_fat_object(fd, FO_File, &o);
-	if (res) {
-		return -res;
-	}
-
-	switch (whence) {
-	case SEEK_SET:
-		res = f_lseek(&o->file, offset);
-		return -fresult_to_errno_table[res];
-	case SEEK_CUR:
-		res = f_lseek(&o->file, f_tell(&o->file) + offset);
-		return -fresult_to_errno_table[res];
-	case SEEK_END:
-		res = f_lseek(&o->file, f_size(&o->file) + offset);
-		return -fresult_to_errno_table[res];
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-int epic_file_tell(int fd)
-{
-	int res;
-	struct FatObject *o;
-	res = get_fat_object(fd, FO_File, &o);
-	if (res) {
-		return -1;
-	}
-
-	return f_tell(&o->file);
-}
-
-int epic_file_stat(const char *filename, epic_stat_t *stat)
-{
-	int res;
-	FILINFO finfo;
-	res = f_stat(filename, &finfo);
-	if (res != FR_OK) {
-		return -fresult_to_errno_table[res];
-	}
-
-	if (finfo.fattrib & AM_DIR) {
-		stat->type = EPICSTAT_DIR;
-	} else {
-		stat->type = EPICSTAT_FILE;
-	}
-
-	return 0;
-}
diff --git a/epicardium/modules/fatfs_fileops.c b/epicardium/modules/fatfs_fileops.c
new file mode 100644
index 0000000000000000000000000000000000000000..dadc22c682a27961ed51f78fd8b39b52c8fd9406
--- /dev/null
+++ b/epicardium/modules/fatfs_fileops.c
@@ -0,0 +1,299 @@
+#include <errno.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include <ff.h>
+
+#include "modules.h"
+#include "epicardium.h"
+
+#define EPIC_FAT_FD_GENERATION_BITS (31 - (EPIC_FAT_FD_INDEX_BITS))
+#define EPIC_FAT_MAX_OPENED (1 << (EPIC_FAT_FD_INDEX_BITS))
+#define EPIC_FAT_FD_INDEX_MASK (uint32_t)((1u << EPIC_FAT_FD_INDEX_BITS) - 1)
+#define EPIC_FAT_FD_INDEX(fd) ((uint32_t)(fd)&EPIC_FAT_FD_INDEX_MASK)
+#define EPIC_FAT_FD_GENERATION(fd) ((uint32_t)(fd) >> EPIC_FAT_FD_INDEX_BITS)
+#define EPIC_FAT_FD_MAX_GENERATION                                             \
+	(uint32_t)((1u << EPIC_FAT_FD_GENERATION_BITS) - 1)
+#define EPIC_FAT_FD(idx, gen)                                                  \
+	(int)(((uint32_t)(gen) << EPIC_FAT_FD_INDEX_BITS) |                    \
+	      ((uint32_t)(idx)&EPIC_FAT_FD_INDEX_MASK))
+
+// this table converts from FRESULT to POSIX errno
+const int fresult_to_errno_table[20] = {
+	[FR_OK]                  = 0,
+	[FR_DISK_ERR]            = EIO,
+	[FR_INT_ERR]             = EIO,
+	[FR_NOT_READY]           = EBUSY,
+	[FR_NO_FILE]             = ENOENT,
+	[FR_NO_PATH]             = ENOENT,
+	[FR_INVALID_NAME]        = EINVAL,
+	[FR_DENIED]              = EACCES,
+	[FR_EXIST]               = EEXIST,
+	[FR_INVALID_OBJECT]      = EINVAL,
+	[FR_WRITE_PROTECTED]     = EROFS,
+	[FR_INVALID_DRIVE]       = ENODEV,
+	[FR_NOT_ENABLED]         = ENODEV,
+	[FR_NO_FILESYSTEM]       = ENODEV,
+	[FR_MKFS_ABORTED]        = EIO,
+	[FR_TIMEOUT]             = EIO,
+	[FR_LOCKED]              = EIO,
+	[FR_NOT_ENOUGH_CORE]     = ENOMEM,
+	[FR_TOO_MANY_OPEN_FILES] = EMFILE,
+	[FR_INVALID_PARAMETER]   = EINVAL,
+};
+
+struct FatObject {
+	uint32_t generation;
+	enum epic_stat_type type;
+	union {
+		FIL file;
+		DIR dir;
+	};
+};
+
+static int
+get_fat_object(int i, enum epic_stat_type expected, struct FatObject **res);
+
+static struct FatObject s_openedObjects[EPIC_FAT_MAX_OPENED];
+static uint32_t s_fatfs_generationCount = 1;
+
+int get_fat_object(int fd, enum epic_stat_type expected, struct FatObject **res)
+{
+	uint32_t index      = EPIC_FAT_FD_INDEX(fd);
+	uint32_t generation = EPIC_FAT_FD_GENERATION(fd);
+	if (index >= EPIC_FAT_MAX_OPENED) {
+		*res = NULL;
+		return EBADF;
+	}
+	if (generation >= EPIC_FAT_FD_MAX_GENERATION) {
+		*res = NULL;
+		return EBADF;
+	}
+	if (s_openedObjects[index].type != expected) {
+		*res = NULL;
+		return EBADF;
+	}
+	if (s_openedObjects[index].generation != generation) {
+		*res = NULL;
+		return EBADF;
+	}
+	*res = &s_openedObjects[index];
+	return 0;
+}
+
+/* here we're trying to mirror glibc's behaviour:
+ * any combination of rwax parses but only the first of those flags wins:
+ *    - rw, ra, rr all open read-only
+ * a `+` at any position but the first turns into read-write
+ * any other character at any position yields EINVAL
+ */
+static inline bool parse_mode(const char *mstring, int *mode)
+{
+	switch (mstring[0]) {
+	case 'r':
+		*mode = FA_READ;
+		break;
+	case 'w':
+		*mode = FA_CREATE_ALWAYS | FA_WRITE;
+		break;
+	case 'x':
+		//in constrast to FA_CREATE_ALWAYS, FA_CREATE_NEW fails for existing files
+		*mode = FA_WRITE | FA_CREATE_NEW;
+		break;
+	case 'a':
+		//in constrast to FA_CREATE_ALWAYS, FA_CREATE_NEW fails for existing files
+		*mode = FA_WRITE | FA_OPEN_APPEND;
+		break;
+	default:
+		return false;
+	}
+	while (*mstring) {
+		switch (*mstring++) {
+		case '+': //turns any of r,w,x into read&write
+			*mode |= FA_READ | FA_WRITE;
+			break;
+		case 'r': //fallthrough intentional
+		case 'w': //fallthrough intentional
+		case 'a': //fallthrough intentional
+		case 'x': //fallthrough intentional
+			break;
+		default:
+			return false;
+		}
+	}
+	return true;
+}
+
+int epic_file_open(const char *filename, const char *modeString)
+{
+	struct FatObject *o = NULL;
+	uint32_t index, generation;
+	int mode = 0;
+	int res;
+
+	//find free object to use
+	for (index = 0; index < EPIC_FAT_MAX_OPENED; ++index) {
+		if (s_openedObjects[index].type == EPICSTAT_NONE) {
+			break;
+		}
+	}
+	if (index == EPIC_FAT_MAX_OPENED) {
+		return -fresult_to_errno_table[FR_TOO_MANY_OPEN_FILES];
+	}
+	generation = s_fatfs_generationCount++;
+	if (generation == EPIC_FAT_FD_MAX_GENERATION) {
+		s_fatfs_generationCount = 1;
+	}
+	o = &s_openedObjects[index];
+
+	if (!parse_mode(modeString, &mode)) {
+		return -EINVAL;
+	}
+
+	res = f_open(&o->file, filename, mode);
+	if (res != FR_OK) {
+		return -fresult_to_errno_table[res];
+	}
+	o->type       = EPICSTAT_FILE;
+	o->generation = generation;
+
+	// for 'a' mode, we must begin at the end of the file
+	if ((mode & FA_OPEN_APPEND) != 0) {
+		f_lseek(&o->file, f_size(&o->file));
+	}
+
+	return EPIC_FAT_FD(index, generation);
+}
+
+int epic_file_close(int fd)
+{
+	int res;
+	struct FatObject *o;
+	res = get_fat_object(fd, EPICSTAT_FILE, &o);
+	if (res) {
+		return -res;
+	}
+
+	res = f_close(&o->file);
+	if (res != FR_OK) {
+		return -fresult_to_errno_table[res];
+	}
+
+	o->type       = EPICSTAT_NONE;
+	o->generation = 0;
+	return 0;
+}
+
+int epic_file_read(int fd, void *buf, size_t nbytes)
+{
+	unsigned int nread = 0;
+
+	int res;
+	struct FatObject *o;
+	res = get_fat_object(fd, EPICSTAT_FILE, &o);
+	if (res) {
+		return -res;
+	}
+
+	res = f_read(&o->file, buf, nbytes, &nread);
+	if (res != FR_OK) {
+		return -fresult_to_errno_table[res];
+	}
+
+	return (int)nread;
+}
+
+int epic_file_write(int fd, const void *buf, size_t nbytes)
+{
+	unsigned int nwritten = 0;
+
+	int res;
+	struct FatObject *o;
+	res = get_fat_object(fd, EPICSTAT_FILE, &o);
+	if (res) {
+		return -res;
+	}
+	res = f_write(&o->file, buf, nbytes, &nwritten);
+	if (res != FR_OK) {
+		return -fresult_to_errno_table[res];
+	}
+
+	return (int)nwritten;
+}
+
+int epic_file_flush(int fd)
+{
+	int res;
+	struct FatObject *o;
+	res = get_fat_object(fd, EPICSTAT_FILE, &o);
+	if (res) {
+		return -res;
+	}
+	res = f_sync(&o->file);
+	if (res != FR_OK) {
+		return -fresult_to_errno_table[res];
+	}
+
+	return 0;
+}
+
+int epic_file_seek(int fd, long offset, int whence)
+{
+	int res;
+	struct FatObject *o;
+	res = get_fat_object(fd, EPICSTAT_FILE, &o);
+	if (res) {
+		return -res;
+	}
+	switch (whence) {
+	case SEEK_SET:
+		res = f_lseek(&o->file, offset);
+		break;
+
+	case SEEK_CUR:
+		res = f_lseek(&o->file, f_tell(&o->file) + offset);
+		break;
+
+	case SEEK_END:
+		res = f_lseek(&o->file, f_size(&o->file) + offset);
+		break;
+	default:
+		return -EINVAL;
+	}
+	if (res != FR_OK) {
+		return -fresult_to_errno_table[res];
+	}
+
+	return 0;
+}
+
+int epic_file_tell(int fd)
+{
+	int res;
+	struct FatObject *o;
+	res = get_fat_object(fd, EPICSTAT_FILE, &o);
+	if (res) {
+		return -res;
+	}
+	//f_tell simply accesses fp->fptr so no errors are expected - return directly
+	return f_tell(&o->file);
+}
+
+int epic_file_stat(const char *filename, epic_stat_t *stat)
+{
+	int res;
+	FILINFO finfo;
+	res = f_stat(filename, &finfo);
+	if (res != FR_OK) {
+		return -fresult_to_errno_table[res];
+	}
+
+	if (finfo.fattrib & AM_DIR) {
+		stat->type = EPICSTAT_DIR;
+	} else {
+		stat->type = EPICSTAT_FILE;
+	}
+
+	return 0;
+}
diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build
index 807e9b8c77f386b3894288d2b9765a9d61b397df..113e3cb8ecaebc932a65ce9e6124cc2ff3be60ce 100644
--- a/epicardium/modules/meson.build
+++ b/epicardium/modules/meson.build
@@ -1,6 +1,7 @@
 module_sources = files(
   'display.c',
   'fatfs.c',
+  'fatfs_fileops.c',
   'leds.c',
   'log.c',
   'pmic.c',
diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index f02298e36b2e538237fc75bfe0710517c11e33ab..e273146fdd0d97bae3cfbfad3de3b5a510fa4a53 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -2,8 +2,12 @@
 #define MODULES_H
 
 /* ---------- FAT fs ------------------------------------------------------ */
-/* max no. of descriptors (file & directory) that can be open at a time */
-#define EPIC_FAT_MAX_OPENED 16
+/* Number of bits to use for indexing into our internal pool of files/directories
+ * This indirectly specifies the size of the pool as 1^EPIC_FAT_FD_INDEX_BITS
+ * Increase if number of open file descriptors is not enough, but be aware of
+ * memory usage of the pool!
+ */
+#define EPIC_FAT_FD_INDEX_BITS 8
 #define EPIC_FAT_STATIC_SEMAPHORE 1
 void fatfs_init(void);
 
diff --git a/pycardium/modules/fat_file.c b/pycardium/modules/fat_file.c
index e1d42f3efcc33c16f1425d23e061767d1eb6d5ad..a5ddcd8ae7684f183b00a38ff5c3eba64568d5ca 100644
--- a/pycardium/modules/fat_file.c
+++ b/pycardium/modules/fat_file.c
@@ -1,27 +1,5 @@
 /*
- * This file is part of the MicroPython project, http://micropython.org/
- *
- * The MIT License (MIT)
- *
- * Copyright (c) 2013, 2014 Damien P. George
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
+ * based on micropytohn/ports/unix/file.c
  */
 
 #include <stdio.h>
@@ -34,15 +12,15 @@
 
 #include "epicardium.h"
 
-extern const mp_obj_type_t mp_type_fat_textio;
+extern const mp_obj_type_t mp_type_textio;
 #if MICROPY_PY_IO_FILEIO
-extern const mp_obj_type_t mp_type_fat_fileio;
+extern const mp_obj_type_t mp_type_fileio;
 #endif
 
-typedef struct _pyb_file_obj_t {
+typedef struct _fat_py_file_obj_t {
 	mp_obj_base_t base;
 	int fd;
-} pyb_file_obj_t;
+} fat_py_file_obj_t;
 
 STATIC void
 file_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
@@ -59,8 +37,8 @@ file_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind)
 STATIC mp_uint_t
 file_obj_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode)
 {
-	pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
-	int res              = epic_file_read(self->fd, buf, size);
+	fat_py_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+	int res                 = epic_file_read(self->fd, buf, size);
 	if (res < 0) {
 		*errcode = -res;
 		return MP_STREAM_ERROR;
@@ -71,8 +49,8 @@ file_obj_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode)
 STATIC mp_uint_t
 file_obj_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode)
 {
-	pyb_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
-	int res              = epic_file_write(self->fd, buf, size);
+	fat_py_file_obj_t *self = MP_OBJ_TO_PTR(self_in);
+	int res                 = epic_file_write(self->fd, buf, size);
 	if (res < 0) {
 		*errcode = -res;
 		return MP_STREAM_ERROR;
@@ -92,7 +70,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
 STATIC mp_uint_t
 file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode)
 {
-	pyb_file_obj_t *self = MP_OBJ_TO_PTR(o_in);
+	fat_py_file_obj_t *self = MP_OBJ_TO_PTR(o_in);
 	int res;
 	switch (request) {
 	case MP_STREAM_FLUSH:
@@ -109,29 +87,22 @@ file_obj_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode)
 			return MP_STREAM_ERROR;
 		}
 		return 0;
+	case MP_STREAM_SEEK: {
+		struct mp_stream_seek_t *s =
+			(struct mp_stream_seek_t *)(uintptr_t)arg;
+		//it "just so happens" that MP's whence values are 0,1,2 for SET,CUR,END, just like in epicardium
+		res = epic_file_seek(self->fd, s->offset, s->whence);
+		if (res < 0) {
+			*errcode = -res;
+			return MP_STREAM_ERROR;
+		}
+		s->offset = epic_file_tell(self->fd);
+		return 0;
+	}
 	}
 	//every valid case returns either success or error, so this is EINVAL land:
 	*errcode = MP_EINVAL;
 	return MP_STREAM_ERROR;
-	// if (request == MP_STREAM_SEEK) {
-	//     struct mp_stream_seek_t *s = (struct mp_stream_seek_t*)(uintptr_t)arg;
-
-	//     switch (s->whence) {
-	//         case 0: // SEEK_SET
-	//             f_lseek(&self->fp, s->offset);
-	//             break;
-
-	//         case 1: // SEEK_CUR
-	//             f_lseek(&self->fp, f_tell(&self->fp) + s->offset);
-	//             break;
-
-	//         case 2: // SEEK_END
-	//             f_lseek(&self->fp, f_size(&self->fp) + s->offset);
-	//             break;
-	//     }
-
-	//     s->offset = f_tell(&self->fp);
-	//     return 0;
 }
 
 // Note: encoding is ignored for now; it's also not a valid kwarg for CPython's FileIO,
@@ -157,22 +128,22 @@ STATIC mp_obj_t file_open(const mp_obj_type_t *type, mp_arg_val_t *args)
 		switch (*mode_s++) {
 #if MICROPY_PY_IO_FILEIO
 		case 'b':
-			type = &mp_type_fat_fileio;
+			type = &mp_type_fileio;
 			break;
 #endif
 		case 't':
-			type = &mp_type_fat_textio;
+			type = &mp_type_textio;
 			break;
 		}
 	}
 
-	pyb_file_obj_t *o = m_new_obj_with_finaliser(pyb_file_obj_t);
-	o->base.type      = type;
+	fat_py_file_obj_t *o = m_new_obj_with_finaliser(fat_py_file_obj_t);
+	o->base.type         = type;
 
 	const char *fname = mp_obj_str_get_str(args[0].u_obj);
 	int res           = epic_file_open(fname, modeString);
 	if (res < 0) {
-		m_del_obj(pyb_file_obj_t, o);
+		m_del_obj(fat_py_file_obj_t, o);
 		mp_raise_OSError(-res);
 	}
 	o->fd = res;
@@ -226,7 +197,7 @@ STATIC const mp_stream_p_t fileio_stream_p = {
 	.ioctl = file_obj_ioctl,
 };
 
-const mp_obj_type_t mp_type_fat_fileio = {
+const mp_obj_type_t mp_type_fileio = {
 	{ &mp_type_type },
 	.name        = MP_QSTR_FileIO,
 	.print       = file_obj_print,
@@ -245,7 +216,7 @@ STATIC const mp_stream_p_t textio_stream_p = {
 	.is_text = true,
 };
 
-const mp_obj_type_t mp_type_fat_textio = {
+const mp_obj_type_t mp_type_textio = {
 	{ &mp_type_type },
 	.name        = MP_QSTR_TextIOWrapper,
 	.print       = file_obj_print,
@@ -269,6 +240,6 @@ mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs)
 		file_open_args,
 		arg_vals
 	);
-	return file_open(&mp_type_fat_textio, arg_vals);
+	return file_open(&mp_type_textio, arg_vals);
 }
 MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
diff --git a/pycardium/modules/fat_reader_import.c b/pycardium/modules/fat_reader_import.c
index bb35aec22ff8cd66c11c02924b8ce3eeb944b430..656cbe236925dbb619f3f3c0b9012c13175db236 100644
--- a/pycardium/modules/fat_reader_import.c
+++ b/pycardium/modules/fat_reader_import.c
@@ -4,14 +4,13 @@
 #include <py/reader.h>
 #include <py/lexer.h>
 
-/** ported from picropython's posic implementation */
+#define EPICFAT_READER_BUFFER_SIZE 128
 
 typedef struct _mp_reader_epicfat_t {
-	bool close_fd;
 	int fd;
 	size_t len;
 	size_t pos;
-	byte buf[20];
+	byte buf[EPICFAT_READER_BUFFER_SIZE];
 } mp_reader_epicfat_t;
 
 STATIC mp_uint_t mp_reader_epicfat_readbyte(void *data)
@@ -50,7 +49,7 @@ void mp_reader_new_file(mp_reader_t *reader, const char *filename)
 	}
 	mp_reader_epicfat_t *rp = m_new_obj(mp_reader_epicfat_t);
 	rp->fd                  = fd;
-	int n                   = epic_file_read(rp->fd, rp->buf, sizeof(rp->buf));
+	int n = epic_file_read(rp->fd, rp->buf, sizeof(rp->buf));
 	if (n < 0) {
 		epic_file_close(fd);
 	}
diff --git a/pycardium/mpconfigport.h b/pycardium/mpconfigport.h
index 9bed1f600fd79535f4f53d6792f0ded869cf99d0..233c01bbb82dd986e9ec54c53275ffef96631269 100644
--- a/pycardium/mpconfigport.h
+++ b/pycardium/mpconfigport.h
@@ -35,6 +35,7 @@
 #define MICROPY_PY_URE_MATCH_SPAN_START_END (1)
 #define MICROPY_PY_URE_SUB                  (1)
 #define MICROPY_PY_UTIME_MP_HAL             (1)
+#define MICROPY_PY_IO_FILEIO                (1)
 
 /* Modules */
 #define MODULE_UTIME_ENABLED                (1)