Updated FatFS, and new SD support... able to read directories

This commit is contained in:
Peter Weingartner 2024-07-08 16:56:37 -04:00
parent 153e905411
commit a5531fb1be
31 changed files with 3322 additions and 949 deletions

1
.gitignore vendored
View file

@ -51,3 +51,4 @@ Module.symvers
Mkfile.old Mkfile.old
dkms.conf dkms.conf
.vscode/settings.json .vscode/settings.json
/misc/F256xE_Kernal_Code

View file

@ -37,7 +37,7 @@ else ifeq ($(UNIT),F256)
AS=as65816 AS=as65816
AR=nlib AR=nlib
SRCS_FOR_UNIT=txt_f256.c kbd_f256k.c indicators_c256.c interrupts_f256.c # timers_c256.c SRCS_FOR_UNIT=txt_f256.c kbd_f256k.c indicators_c256.c interrupts_f256.c sdc_f256.c # timers_c256.c
CFLAGS_FOR_UNIT=-DMODEL=2 -DCPU=255 --code-model large --data-model large # --target Foenix CFLAGS_FOR_UNIT=-DMODEL=2 -DCPU=255 --code-model large --data-model large # --target Foenix
endif endif

View file

@ -9,6 +9,8 @@
#include "log.h" #include "log.h"
#include "block.h" #include "block.h"
#include "uart.h"
#include <stdio.h>
t_dev_block g_block_devs[BDEV_DEVICES_MAX]; t_dev_block g_block_devs[BDEV_DEVICES_MAX];
@ -41,6 +43,7 @@ SYSTEMCALL short bdev_register(p_dev_block device) {
p_dev_block bdev = &g_block_devs[dev]; p_dev_block bdev = &g_block_devs[dev];
bdev->number = device->number; bdev->number = device->number;
bdev->name = device->name; bdev->name = device->name;
bdev->data = device->data;
bdev->init = device->init; bdev->init = device->init;
bdev->read = device->read; bdev->read = device->read;
bdev->write = device->write; bdev->write = device->write;
@ -71,8 +74,9 @@ short bdev_init(short dev) {
if (dev < BDEV_DEVICES_MAX) { if (dev < BDEV_DEVICES_MAX) {
p_dev_block bdev = &g_block_devs[dev]; p_dev_block bdev = &g_block_devs[dev];
if (bdev->number == dev) if (bdev->number == dev) {
ret = bdev->init(); ret = bdev->init(bdev);
}
} }
TRACE1("bdev_init returning %d", (int)ret); TRACE1("bdev_init returning %d", (int)ret);
@ -99,7 +103,7 @@ SYSTEMCALL short bdev_read(short dev, long lba, unsigned char * buffer, short si
if (dev < BDEV_DEVICES_MAX) { if (dev < BDEV_DEVICES_MAX) {
p_dev_block bdev = &g_block_devs[dev]; p_dev_block bdev = &g_block_devs[dev];
if (bdev->number == dev) if (bdev->number == dev)
ret = bdev->read(lba, buffer, size); ret = bdev->read(bdev, lba, buffer, size);
} }
TRACE1("bdev_read returning %d", (int)ret); TRACE1("bdev_read returning %d", (int)ret);
@ -126,7 +130,7 @@ SYSTEMCALL short bdev_write(short dev, long lba, const unsigned char * buffer, s
if (dev < BDEV_DEVICES_MAX) { if (dev < BDEV_DEVICES_MAX) {
p_dev_block bdev = &g_block_devs[dev]; p_dev_block bdev = &g_block_devs[dev];
if (bdev->number == dev) if (bdev->number == dev)
ret = bdev->write(lba, buffer, size); ret = bdev->write(bdev, lba, buffer, size);
} }
TRACE1("bdev_write returning %d", (int)ret); TRACE1("bdev_write returning %d", (int)ret);
@ -150,7 +154,7 @@ SYSTEMCALL short bdev_status(short dev) {
if (dev < BDEV_DEVICES_MAX) { if (dev < BDEV_DEVICES_MAX) {
p_dev_block bdev = &g_block_devs[dev]; p_dev_block bdev = &g_block_devs[dev];
if (bdev->number == dev) if (bdev->number == dev)
ret = bdev->status(); ret = bdev->status(bdev);
} }
TRACE1("bdev_status returning %d", (int)ret); TRACE1("bdev_status returning %d", (int)ret);
@ -174,7 +178,7 @@ SYSTEMCALL short bdev_flush(short dev) {
if (dev < BDEV_DEVICES_MAX) { if (dev < BDEV_DEVICES_MAX) {
p_dev_block bdev = &g_block_devs[dev]; p_dev_block bdev = &g_block_devs[dev];
if (bdev->number == dev) if (bdev->number == dev)
return bdev->flush(); return bdev->flush(bdev);
} }
TRACE1("bdev_flush returning %d", (int)ret); TRACE1("bdev_flush returning %d", (int)ret);
@ -201,7 +205,7 @@ SYSTEMCALL short bdev_ioctrl(short dev, short command, unsigned char * buffer, s
if (dev < BDEV_DEVICES_MAX) { if (dev < BDEV_DEVICES_MAX) {
p_dev_block bdev = &g_block_devs[dev]; p_dev_block bdev = &g_block_devs[dev];
if (bdev->number == dev) if (bdev->number == dev)
ret = bdev->ioctrl(command, buffer, size); ret = bdev->ioctrl(bdev, command, buffer, size);
} }
TRACE1("bdev_ioctrl returning %d", (int)ret); TRACE1("bdev_ioctrl returning %d", (int)ret);

View file

@ -6,6 +6,9 @@
* *
*/ */
#include "log_level.h"
#define DEFAULT_LOG_LEVEL LOG_INFO
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -239,6 +242,7 @@ SYSTEMCALL short fsys_opendir(const char * path) {
} }
if (fres != FR_OK) { if (fres != FR_OK) {
/* If there was a problem, return an error number */ /* If there was a problem, return an error number */
ERROR1("FATFS Error: %d", fres);
return fatfs_to_foenix(fres); return fatfs_to_foenix(fres);
} else { } else {
/* Otherwise, allocate and return the handle */ /* Otherwise, allocate and return the handle */
@ -827,8 +831,9 @@ short fsys_mount(short bdev) {
drive[2] = 0; drive[2] = 0;
fres = f_mount(&g_drive[bdev], drive, 0); fres = f_mount(&g_drive[bdev], drive, 0);
INFO1("fsys_mount called f_mount: %d", fres);
if (fres != FR_OK) { if (fres != FR_OK) {
DEBUG1("Unable to mount drive: %s", drive); ERROR2("Unable to mount drive %s, FatFS Error: %d", drive, fres);
return fatfs_to_foenix(fres); return fatfs_to_foenix(fres);
} else { } else {
return 0; return 0;
@ -1507,7 +1512,7 @@ short fsys_init() {
/* Set the default working directory. /* Set the default working directory.
* TODO: set this based on the boot drive. * TODO: set this based on the boot drive.
*/ */
strcpy(g_current_directory, "/sd"); strcpy(g_current_directory, "/sd0");
/* Mark all directories as available */ /* Mark all directories as available */
for (i = 0; i < MAX_DIRECTORIES; i++) { for (i = 0; i < MAX_DIRECTORIES; i++) {
@ -1524,7 +1529,11 @@ short fsys_init() {
for (i = 0; i < MAX_DRIVES; i++) { for (i = 0; i < MAX_DRIVES; i++) {
short res = sys_bdev_status((short)i); short res = sys_bdev_status((short)i);
if (res >= 0) { if (res >= 0) {
fsys_mount(i); INFO1("Mounting drive #%d", i);
short result = fsys_mount(i);
if (result < 0) {
ERROR2("Could not mount device %d: %d", i, result);
}
} }
} }

View file

@ -2,6 +2,9 @@
* Definitions for access the bq4802LY real time clock * Definitions for access the bq4802LY real time clock
*/ */
#include "log_level.h"
#define DEFAULT_LOG_LEVEL LOG_ERROR
#include "log.h" #include "log.h"
#include "interrupt.h" #include "interrupt.h"
#include "gabe_reg.h" #include "gabe_reg.h"
@ -121,13 +124,13 @@ SYSTEMCALL void rtc_set_time(p_time time) {
minute_bcd = i_to_bcd(time->minute); minute_bcd = i_to_bcd(time->minute);
second_bcd = i_to_bcd(time->second); second_bcd = i_to_bcd(time->second);
log_num(LOG_INFO, "Century: ", century_bcd); INFO1("Century: %02d", century_bcd);
log_num(LOG_INFO, "Year: ", year_bcd); INFO1("Year: %04d", year_bcd);
log_num(LOG_INFO, "Month: ", month_bcd); INFO1("Month: %02d", month_bcd);
log_num(LOG_INFO, "Day: ", day_bcd); INFO1("Day: %02d", day_bcd);
log_num(LOG_INFO, "Hour: ", hour_bcd); INFO1("Hour: %02d", hour_bcd);
log_num(LOG_INFO, "Minute: ", minute_bcd); INFO1("Minute: %02d", minute_bcd);
log_num(LOG_INFO, "Second: ", second_bcd); INFO1("Second: %02d", second_bcd);
if (!time->is_24hours) { if (!time->is_24hours) {
if (time->is_pm) { if (time->is_pm) {
@ -140,11 +143,11 @@ SYSTEMCALL void rtc_set_time(p_time time) {
/* Temporarily disable updates to the clock */ /* Temporarily disable updates to the clock */
ctrl = *RTC_CTRL; ctrl = *RTC_CTRL;
*RTC_CTRL = ctrl | RTC_UTI; *RTC_CTRL = ctrl | RTC_UTI;
log(LOG_INFO, "RTC Disabled"); INFO("RTC Disabled");
log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES); INFO1("RTC Rates: %02x", *RTC_RATES);
log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES); INFO1("RTC Enables: %02x", *RTC_ENABLES);
log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS); INFO1("RTC Flags: %02x", *RTC_FLAGS);
log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL); INFO1("RTC Control: %02x", *RTC_CTRL);
/* Set the time in the RTC */ /* Set the time in the RTC */
@ -165,13 +168,13 @@ SYSTEMCALL void rtc_set_time(p_time time) {
hour_bcd = *RTC_HOUR; hour_bcd = *RTC_HOUR;
minute_bcd = *RTC_MIN; minute_bcd = *RTC_MIN;
second_bcd = *RTC_SEC; second_bcd = *RTC_SEC;
log_num(LOG_INFO, "REG Century: ", century_bcd); INFO1("REG Century: %02d", century_bcd);
log_num(LOG_INFO, "REG Year: ", year_bcd); INFO1("REG Year: %02d", year_bcd);
log_num(LOG_INFO, "REG Month: ", month_bcd); INFO1("REG Month: %02d", month_bcd);
log_num(LOG_INFO, "REG Day: ", day_bcd); INFO1("REG Day: %02d", day_bcd);
log_num(LOG_INFO, "REG Hour: ", hour_bcd); INFO1("REG Hour: %02d", hour_bcd);
log_num(LOG_INFO, "REG Minute: ", minute_bcd); INFO1("REG Minute: %02d", minute_bcd);
log_num(LOG_INFO, "REG Second: ", second_bcd); INFO1("REG Second: %02d", second_bcd);
/* Set the 24/12 hour control bit if needed */ /* Set the 24/12 hour control bit if needed */
if (time->is_24hours) { if (time->is_24hours) {
@ -180,11 +183,11 @@ SYSTEMCALL void rtc_set_time(p_time time) {
/* Re-enable updates to the clock */ /* Re-enable updates to the clock */
*RTC_CTRL = (ctrl & 0x07) | RTC_STOP; *RTC_CTRL = (ctrl & 0x07) | RTC_STOP;
log(LOG_INFO, "RTC Enabled"); INFO("RTC Enabled");
log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES); INFO1("RTC Rates: %02x", *RTC_RATES);
log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES); INFO1("RTC Enables: %02x", *RTC_ENABLES);
log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS); INFO1("RTC Flags: %02x", *RTC_FLAGS);
log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL); INFO1("RTC Control: %02x", *RTC_CTRL);
} }
/* /*
@ -201,11 +204,11 @@ SYSTEMCALL void rtc_get_time(p_time time) {
/* Temporarily disable updates to the clock */ /* Temporarily disable updates to the clock */
ctrl = *RTC_CTRL; ctrl = *RTC_CTRL;
*RTC_CTRL = ctrl | RTC_UTI; *RTC_CTRL = ctrl | RTC_UTI;
log(LOG_INFO, "RTC Disabled"); INFO("RTC Disabled");
log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES); INFO1("RTC Rates: %02x", *RTC_RATES);
log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES); INFO1("RTC Enables: %02x", *RTC_ENABLES);
log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS); INFO1("RTC Flags: %02x", *RTC_FLAGS);
log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL); INFO1("RTC Control: %02x", *RTC_CTRL);
if (*RTC_CTRL & RTC_2412) { if (*RTC_CTRL & RTC_2412) {
time->is_24hours = 1; time->is_24hours = 1;
@ -223,19 +226,19 @@ SYSTEMCALL void rtc_get_time(p_time time) {
/* Re-enable updates to the clock */ /* Re-enable updates to the clock */
*RTC_CTRL = (ctrl & 0x07) | RTC_STOP; *RTC_CTRL = (ctrl & 0x07) | RTC_STOP;
log(LOG_INFO, "RTC Enabled"); INFO("RTC Enabled");
log_num(LOG_INFO, "RTC Rates: ", *RTC_RATES); INFO1("RTC Rates: %02x", *RTC_RATES);
log_num(LOG_INFO, "RTC Enables: ", *RTC_ENABLES); INFO1("RTC Enables: %02x", *RTC_ENABLES);
log_num(LOG_INFO, "RTC Flags: ", *RTC_FLAGS); INFO1("RTC Flags: %02x", *RTC_FLAGS);
log_num(LOG_INFO, "RTC Control: ", *RTC_CTRL); INFO1("RTC Control: %02x", *RTC_CTRL);
log_num(LOG_INFO, "Century: ", century_bcd); INFO1("Century: %02d", century_bcd);
log_num(LOG_INFO, "Year: ", year_bcd); INFO1("Year: %02d", year_bcd);
log_num(LOG_INFO, "Month: ", month_bcd); INFO1("Month: %02d", month_bcd);
log_num(LOG_INFO, "Day: ", day_bcd); INFO1("Day: %02d", day_bcd);
log_num(LOG_INFO, "Hour: ", hour_bcd); INFO1("Hour: %02d", hour_bcd);
log_num(LOG_INFO, "Minute: ", minute_bcd); INFO1("Minute: %02d", minute_bcd);
log_num(LOG_INFO, "Second: ", second_bcd); INFO1("Second: %02d", second_bcd);
/* Fill out the time record */ /* Fill out the time record */

View file

@ -421,7 +421,7 @@ short sdc_ioctrl(short command, unsigned char * buffer, short size) {
short sdc_install() { short sdc_install() {
t_dev_block dev; // bdev_register copies the data, so we'll allocate this on the stack t_dev_block dev; // bdev_register copies the data, so we'll allocate this on the stack
TRACE("sdc_install"); INFO("old sdc_install");
/* Install an interrupt handler to catch insertion of a card */ /* Install an interrupt handler to catch insertion of a card */
int_register(INT_SDC_INS, sdc_handler); int_register(INT_SDC_INS, sdc_handler);

570
src/dev/sdc_f256.c Normal file
View file

@ -0,0 +1,570 @@
/**
* @file sdc_f256.c
* @author your name (you@domain.com)
* @brief
* @version 0.1
* @date 2024-07-05
*
* @copyright Copyright (c) 2024
*
*/
#include <stdint.h>
#include "log_level.h"
#define DEFAULT_LOG_LEVEL LOG_ERROR
#include "log.h"
#include "constants.h"
#include "errors.h"
#include "dev/block.h"
#include "indicators.h"
#include "interrupt.h"
#include "F256/sdc_spi.h"
#include "sdc_f256.h"
/* MMC/SD command (SPI mode) */
#define CMD0 (0) /* GO_IDLE_STATE */
#define CMD1 (1) /* SEND_OP_COND */
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
#define CMD8 (8) /* SEND_IF_COND */
#define CMD9 (9) /* SEND_CSD */
#define CMD10 (10) /* SEND_CID */
#define CMD12 (12) /* STOP_TRANSMISSION */
#define CMD13 (13) /* SEND_STATUS */
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
#define CMD16 (16) /* SET_BLOCKLEN */
#define CMD17 (17) /* READ_SINGLE_BLOCK */
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (23) /* SET_BLOCK_COUNT */
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (24) /* WRITE_BLOCK */
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
#define CMD32 (32) /* ERASE_ER_BLK_START */
#define CMD33 (33) /* ERASE_ER_BLK_END */
#define CMD38 (38) /* ERASE */
#define CMD55 (55) /* APP_CMD */
#define CMD58 (58) /* READ_OCR */
static t_sd_card_info sd0_card_info;
/**
* @brief Transmit Busy Flag Check
*
* @param sd pointer to the SPI device to check
*/
static void SD0_Wait_SDx_Busy(p_sdc_spi sd) {
uint8_t i = (sd->ctrl & SDx_BUSY);
do {
i = (sd->ctrl & SDx_BUSY);
} while (i == SDx_BUSY);
}
/**
* @brief Transmit bytes to the card
*
* @param sd pointer to the SPI device to write to
* @param buff buffer of data to write
* @param bc number of bytes to write
*/
static void SD0_Tx(p_sdc_spi sd, const uint8_t * buff, unsigned int bc) {
do {
uint8_t d = *buff++; // Get a byte to be sent
sd->data = d; // Set the Data in the Transmit Register
SD0_Wait_SDx_Busy(sd); // Wait for the transmit to be over with
} while (--bc);
}
/**
* @brief Receive bytes from the card
*
* @param sd pointer to the SPI device to read from
* @param buff buffer of data to read into
* @param bc number of bytes to read
*/
static void SD0_Rx(p_sdc_spi sd, uint8_t *buff, unsigned int bc) {
do {
sd->data = 0xff; // Set the Data in the Transmit Register
SD0_Wait_SDx_Busy(sd); // Wait for the transmit to be over with
*buff++ = sd->data; // Store a received byte
} while (--bc);
}
/* Delay n microseconds (avr-gcc -Os) */
static void dly_us (unsigned int n) {
do {
// Add Timer Routine for 1us (6x Clock @ 6.29Mhz)
__asm(" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n");
} while (--n);
}
/*-----------------------------------------------------------------------*/
/* Wait for card ready Using - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
/**
* @brief Wait for card ready Using
*
* @param sd pointer to the SPI device
* @return int
*/
static int SD0_wait_ready (p_sdc_spi sd) {
uint8_t d;
int tmr;
for (tmr = 5000; tmr; tmr--) { // Wait for ready in timeout of 500ms
SD0_Rx(sd, &d, 1);
if (d == 0xFF) break;
dly_us(100); // 100us
}
return tmr ? 1 : 0;
}
/**
* @brief Deselect the card and release SPI bus
*
* @param sd pointer to the SPI device
*/
static void SD0_deselect(p_sdc_spi sd) {
uint8_t d;
ind_set(IND_SDC, IND_OFF);
sd->ctrl = sd->ctrl & ~SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active)
SD0_Rx(sd, &d, 1); // Dummy clock (force DO hi-z for multiple slave SPI)
}
/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
/* */
/**
* @brief Select the card and wait for ready
*
* @param sd pointer to the SPI device
* @return int 1:OK, 0:Timeout
*/
static int SD0_select(p_sdc_spi sd) {
uint8_t d;
ind_set(IND_SDC, IND_ON);
sd->ctrl = sd->ctrl | SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active)
SD0_Rx(sd, &d, 1); // Dummy clock (force DO enabled)
if (SD0_wait_ready(sd)) { // Wait for card ready
return 1;
}
SD0_deselect(sd);
return 0; // Failed
}
/**
* @brief Receive a data packet from the card
*
* @param sd pointer to the SPI device
* @param buff buffer of bytes to read into
* @param btr number of bytes to transfer
* @return int 1 on success, 0 on failure
*/
static int SD0_Rx_datablock (p_sdc_spi sd, uint8_t * buff, unsigned int btr) {
uint8_t d[2];
int tmr;
for (tmr = 1000; tmr; tmr--) { // Wait for data packet in timeout of 100ms
SD0_Rx(sd, d, 1);
if (d[0] != 0xFF) {
break;
}
dly_us(100); // 100us
}
if (d[0] != 0xFE) { // If not valid data token, return with error
return 0;
}
SD0_Rx(sd, buff, btr); // Receive the data block into buffer
SD0_Rx(sd, d, 2); // Discard CRC
return 1; // Return with success
}
/**
* @brief Send a data packet to the card
*
* @param sd pointer to the SPI device
* @param buff buffer of bytes to write to the card
* @param token token byte to transmit
* @return int 1 on success, 0 on failure
*/
static int SD0_Tx_datablock (p_sdc_spi sd, const uint8_t *buff, uint8_t token) {
uint8_t d[2];
if (!SD0_wait_ready(sd)) {
return 0;
}
d[0] = token;
SD0_Tx(sd, d, 1); // Xmit a token
if (token != 0xFD) { // Is it data token?
SD0_Tx(sd, buff, 512); // Xmit the 512 byte data block to MMC
SD0_Rx(sd, d, 2); // Xmit dummy CRC (0xFF,0xFF)
SD0_Rx(sd, d, 1); // Receive data response
if ((d[0] & 0x1F) != 0x05) { // If not accepted, return with error
return 0;
}
}
return 1;
}
/*-----------------------------------------------------------------------*/
/* Send a command packet to the card */
/*-----------------------------------------------------------------------*/
/* Returns command response (bit7==1:Send failed)*/
/**
* @brief Send a command packet to the card
*
* @param sd pointer to the SPI device
* @param cmd command to send
* @param arg
* @return uint8_t command response (bit7==1:Send failed)
*/
static uint8_t SD0_Tx_cmd (p_sdc_spi sd, uint8_t cmd, uint32_t arg) {
uint8_t n, d, buf[6];
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
n = SD0_Tx_cmd(sd, CMD55, 0);
if (n > 1) {
return n;
}
}
/* Select the card and wait for ready except to stop multiple block read */
if (cmd != CMD12) {
SD0_deselect(sd);
if (!SD0_select(sd)) {
return 0xFF;
}
}
/* Send a command packet */
buf[0] = 0x40 | cmd; /* Start + Command index */
buf[1] = (uint8_t)(arg >> 24); /* Argument[31..24] */
buf[2] = (uint8_t)(arg >> 16); /* Argument[23..16] */
buf[3] = (uint8_t)(arg >> 8); /* Argument[15..8] */
buf[4] = (uint8_t)arg; /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) {
n = 0x95; /* (valid CRC for CMD0(0)) */
}
if (cmd == CMD8) {
n = 0x87; /* (valid CRC for CMD8(0x1AA)) */
}
buf[5] = n;
SD0_Tx(sd, buf, 6);
/* Receive command response */
if (cmd == CMD12)
SD0_Rx(sd, &d, 1); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do {
SD0_Rx(sd, &d, 1);
} while ((d & 0x80) && --n);
return d; /* Return with the response value */
}
/**
* @brief pointer to the device driver structure for this device
*
* @param dev initialize the device
* @return short 0 for success, negative number for error
*/
static short sdc_init(p_dev_block dev) {
p_sd_card_info card = (p_sd_card_info)dev->data;
p_sdc_spi sd = card->reg;
uint8_t n, cmd, buf[4];
int tmr;
short s;
dly_us(10000); /* 10ms */
sd->ctrl |= SDx_SLOW; // Set the SPI in Slow Mode
for (n = 10; n; n--) {
SD0_Rx(sd, buf, 1); // Apply 80 dummy clocks and the card gets ready to receive command
}
card->type = 0;
if (SD0_Tx_cmd(sd, CMD0, 0) == 1) { /* Enter Idle state */
if (SD0_Tx_cmd(sd, CMD8, 0x1AA) == 1) { /* SDv2? */
SD0_Rx(sd, buf, 4); /* Get trailing return value of R7 resp */
if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */
if (SD0_Tx_cmd(sd, ACMD41, 1UL << 30) == 0) {
break;
}
dly_us(1000);
}
if (tmr && SD0_Tx_cmd(sd, CMD58, 0) == 0) { /* Check CCS bit in the OCR */
SD0_Rx(sd, buf, 4);
card->type = (buf[0] & 0x40) ? (CT_SDC2 | CT_BLOCK) : CT_SDC2; /* SDv2+ */
}
}
} else { /* SDv1 or MMCv3 */
if (SD0_Tx_cmd(sd, ACMD41, 0) <= 1) {
/* SDv1 */
card->type = CT_SDC2;
cmd = ACMD41;
} else {
/* MMCv3 */
card->type = CT_MMC3;
cmd = CMD1;
}
/* Wait for leaving idle state */
for (tmr = 1000; tmr; tmr--) {
if (SD0_Tx_cmd(sd, cmd, 0) == 0) {
break;
}
dly_us(1000);
}
/* Set R/W block length to 512 */
if (!tmr || SD0_Tx_cmd(sd, CMD16, 512) != 0) {
card->type = 0;
}
}
}
sd->ctrl &= ~SDx_SLOW; // Bring back the Fast Mode - 25Mhz
card->status = card->type ? 0 : SDC_STAT_NOINIT;
INFO1("SD0_CardType: %x", card->type);
INFO1("SD0_Stat: %x", card->status);
SD0_deselect(sd);
return card->status;
}
/**
* @brief Read a block from the device
*
* @param dev pointer to the device driver structure for this device
* @param lba the LBA number of the sector to read
* @param buffer buffer to write
* @param size number of bytes to try to read
* @return short the number of bytes read (negative number for error)
*/
static short sdc_read(p_dev_block dev, long lba, uint8_t * buffer, short size) {
p_sd_card_info card = (p_sd_card_info)dev->data;
p_sdc_spi sd = card->reg;
uint8_t cmd;
short count = size % 512 + 1;
if (card->status & SDC_STAT_NOINIT) {
return ERR_NOT_READY;
}
if (!(card->type & CT_BLOCK)) {
lba *= 512; /* Convert LBA to byte address if needed */
}
cmd = (count > 1) ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
if (SD0_Tx_cmd(sd, cmd, (uint32_t)lba) == 0) {
do {
if (!SD0_Rx_datablock(sd, buffer, 512)) {
break;
}
buffer += 512;
} while (--count);
if (cmd == CMD18) {
SD0_Tx_cmd(sd, CMD12, 0); /* STOP_TRANSMISSION */
}
}
SD0_deselect(sd);
return size;
}
/**
* @brief Write a block to the device
*
* @param dev pointer to the device driver structure for this device
* @param lba the LBA number of the sector to write
* @param buffer buffer to read
* @param size number of bytes to try to write
* @return short the number of bytes write (negative number for error)
*/
static short sdc_write(p_dev_block dev, long lba, const uint8_t * buffer, short size) {
p_sd_card_info card = (p_sd_card_info)dev->data;
p_sdc_spi sd = card->reg;
uint8_t cmd;
short count = size % 512 + 1;
if (card->status & SDC_STAT_NOINIT) {
return ERR_NOT_READY;
}
if (!(card->type & CT_BLOCK)) {
/* Convert LBA to byte address if needed */
lba *= 512;
}
if (count == 1) {
/* Single block write */
if ((SD0_Tx_cmd(sd, CMD24, lba) == 0) && SD0_Tx_datablock(sd, buffer, 0xFE)) {
count = 0;
}
} else {
/* Multiple block write */
if (card->type & CT_SDC) {
SD0_Tx_cmd(sd, ACMD23, count);
}
if (SD0_Tx_cmd(sd, CMD25, lba) == 0) { /* WRITE_MULTIPLE_BLOCK */
do {
if (!SD0_Tx_datablock(sd, buffer, 0xFC)) {
break;
}
buffer += 512;
} while (--count);
if (!SD0_Tx_datablock(sd, 0, 0xFD)) {
/* STOP_TRAN token */
count = 1;
}
}
}
SD0_deselect(sd);
return size;
}
/**
* @brief Get the status of the device
*
* @param dev pointer to the device driver structure for this device
* @return short the status of the driver
*/
static short sdc_status(p_dev_block dev) {
p_sd_card_info card = (p_sd_card_info)dev->data;
return card->status;
}
/**
* @brief Ensure that any pending writes to teh device have been completed
*
* @param dev pointer to the device driver structure for this device
* @return 0 on success, negative number for error
*/
static short sdc_flush(p_dev_block dev) {
return 0;
}
/**
* @brief Issue a control command to the device
*
* @param dev pointer to the device driver structure for this device
* @param command
* @param buffer
* @param size
* @return short
*/
static short sdc_ioctrl(p_dev_block dev, short command, unsigned char * buffer, short size) {
p_sd_card_info card = (p_sd_card_info)dev->data;
p_sdc_spi sd = card->reg;
uint8_t n, csd[16];
uint32_t cs;
if (card->status & SDC_STAT_NOINIT) {
return ERR_NOT_READY; /* Check if card is in the socket */
}
short res = ERR_GENERAL;
switch (command) {
case IOCTRL_CTRL_SYNC:
/* Make sure that no pending write process */
if (SD0_select(sd)) {
res = 0;
}
break;
case IOCTRL_GET_SECTOR_COUNT:
/* Get number of sectors on the disk (DWORD) */
if ((SD0_Tx_cmd(sd, CMD9, 0) == 0) && SD0_Rx_datablock(sd, csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
cs = csd[9] + ((uint32_t)csd[8] << 8) + ((uint32_t)(csd[7] & 63) << 16) + 1;
*(uint32_t *)buffer = cs << 10;
} else { /* SDC ver 1.XX or MMC */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
cs = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
*(uint32_t*)buffer = cs << (n - 9);
}
res = 0;
}
break;
case IOCTRL_GET_SECTOR_SIZE:
/* Get erase block size in unit of sector (DWORD) */
*(uint32_t*)buffer = 128;
res = 0;
break;
default:
res = ERR_BAD_ARGUMENT;
}
SD0_deselect(sd);
return 0;
}
//
// Install the SDC driver
//
short sdc_install() {
t_dev_block dev; // bdev_register copies the data, so we'll allocate this on the stack
INFO("sdc_install");
/* Install an interrupt handler to catch insertion of a card */
// int_register(INT_SDC_INS, sdc_handler);
// int_enable(INT_SDC_INS);
sd0_card_info.reg = SD1_REG;
sd0_card_info.status = 0;
sd0_card_info.type = 0;
dev.number = BDEV_SD0;
dev.name = "SD0";
dev.data = &sd0_card_info;
dev.init = sdc_init;
dev.read = sdc_read;
dev.write = sdc_write;
dev.flush = sdc_flush;
dev.status = sdc_status;
dev.ioctrl = sdc_ioctrl;
return bdev_register(&dev);
}

41
src/dev/sdc_f256.h Normal file
View file

@ -0,0 +1,41 @@
/**
* Definitions support low level SDC device driver for the F256
*/
#ifndef __SDC_F256_H
#define __SDC_F256_H
#include "F256/sdc_spi.h"
#include "sys_types.h"
//
// Definitions for GABE's internal SD card controller
//
#define SDC_SECTOR_SIZE 512 // Size of a block on the SDC
#define SDC_STAT_NOINIT 0x01 // SD has not been initialized
#define SDC_STAT_PRESENT 0x02 // SD is present
#define SDC_STAT_PROTECTED 0x04 // SD is write-protected
/* MMC card type flags (MMC_GET_TYPE) */
#define CT_MMC3 0x01 /* MMC ver 3 */
#define CT_MMC4 0x02 /* MMC ver 4+ */
#define CT_MMC 0x03 /* MMC */
#define CT_SDC1 0x04 /* SD ver 1 */
#define CT_SDC2 0x08 /* SD ver 2+ */
#define CT_SDC 0x0C /* SD */
#define CT_BLOCK 0x10 /* Block addressing */
typedef struct s_sd_card_info {
p_sdc_spi reg;
uint8_t type;
uint8_t status;
} t_sd_card_info, *p_sd_card_info;
//
// Install the SDC driver
//
extern short sdc_install();
#endif

View file

@ -357,3 +357,13 @@ R0.14b (April 17, 2021)
Fixed some compiler warnings. Fixed some compiler warnings.
R0.15 (November 6, 2022)
Changed user provided synchronization functions in order to completely eliminate the platform dependency from FatFs code.
FF_SYNC_t is removed from the configuration options.
Fixed a potential error in f_mount when FF_FS_REENTRANT.
Fixed file lock control FF_FS_LOCK is not mutal excluded when FF_FS_REENTRANT && FF_VOLUMES > 1 is true.
Fixed f_mkfs() creates broken exFAT volume when the size of volume is >= 2^32 sectors.
Fixed string functions cannot write the unicode characters not in BMP when FF_LFN_UNICODE == 2 (UTF-8).
Fixed a compatibility issue in identification of GPT header.

View file

@ -1,4 +1,4 @@
FatFs Module Source Files R0.14b FatFs Module Source Files R0.15
FILES FILES

View file

@ -1,5 +1,5 @@
UNIT := C256U_PLUS UNIT := F256
# Define OS-dependent variables # Define OS-dependent variables
@ -13,19 +13,29 @@ endif
ifeq ($(UNIT),C256U) ifeq ($(UNIT),C256U)
CPU=w65816 CPU=w65816
SRCS_FOR_UNIT= SRCS_FOR_UNIT=c256_diskio.c
CFLAGS_FOR_UNIT=-DMODEL=1 -DCPU=255 --target Foenix --code-model large --data-model large CFLAGS_FOR_UNIT=-DMODEL=1 -DCPU=255 --target Foenix --code-model large --data-model large
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_u.scm clib-lc-ld.a LDFLAGS_FOR_UNIT=C256/ld_lc_c256_u.scm clib-lc-ld.a
else ifeq ($(UNIT),C256U_PLUS) else ifeq ($(UNIT),C256U_PLUS)
CPU=w65816 CPU=w65816
SRCS_FOR_UNIT= SRCS_FOR_UNIT=c256_diskio.c
CFLAGS_FOR_UNIT=-DMODEL=5 -DCPU=255 --target Foenix --code-model large --data-model large CFLAGS_FOR_UNIT=-DMODEL=5 -DCPU=255 --target Foenix --code-model large --data-model large
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a --rtattr printf=medium LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a --rtattr printf=medium
else ifeq ($(UNIT),C256_FMX) else ifeq ($(UNIT),C256_FMX)
CPU=w65816 CPU=w65816
SRCS_FOR_UNIT= SRCS_FOR_UNIT=c256_diskio.c
CFLAGS_FOR_UNIT=-DMODEL=0 -DCPU=255 --target Foenix --code-model large --data-model large CFLAGS_FOR_UNIT=-DMODEL=0 -DCPU=255 --target Foenix --code-model large --data-model large
LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a LDFLAGS_FOR_UNIT=C256/ld_lc_c256_fmx.scm clib-lc-ld.a
else ifeq ($(UNIT),F256)
CPU=w65816
SRCS_FOR_UNIT=toolbox_bdev.c
CFLAGS_FOR_UNIT=-DMODEL=0 -DCPU=255 --code-model large --data-model large
ifeq ($(MEMORY),ROM)
LDFLAGS_FOR_UNIT=C256/flash-f256.scm clib-lc-ld.a --rtattr printf=medium
else
LDFLAGS_FOR_UNIT=C256/ld_lc_f256.scm clib-lc-ld.a --rtattr printf=medium
endif
endif endif
ifeq ($(CPU),w65816) ifeq ($(CPU),w65816)
@ -39,7 +49,7 @@ INCLUDES=-I.. -I../include
CFLAGS=$(INCLUDES) $(CFLAGS_FOR_UNIT) -l CFLAGS=$(INCLUDES) $(CFLAGS_FOR_UNIT) -l
ASFLAGS=$(INCLUDES) ASFLAGS=$(INCLUDES)
SRCS = c256_diskio.c ff.c ffsystem.c ffunicode.c $(SRCS_FOR_UNIT) SRCS = ff.c ffsystem.c ffunicode.c $(SRCS_FOR_UNIT)
OBJS = $(patsubst %.c,%.o,$(SRCS)) OBJS = $(patsubst %.c,%.o,$(SRCS))
OBJS4RM = $(subst /,\\,$(OBJS)) OBJS4RM = $(subst /,\\,$(OBJS))

View file

@ -1,152 +0,0 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "log.h"
#include "dev/block.h"
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
#include "simpleio.h"
/* Definitions of physical drive number for each drive */
#define DEV_SDC 0 /* Example: Map Ramdisk to physical drive 0 */
// #define DEV_FDC 1
// #define DEV_HDC 2
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
TRACE("disk_status");
stat = bdev_status(pdrv);
return stat;
}
/*-----------------------------------------------------------------------*/
/* Initialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
TRACE("disk_initialize");
return bdev_init(pdrv);
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res;
int result;
int i;
TRACE("disk_read");
for (i = 0; i < count; i++) {
result = bdev_read(pdrv, sector, buff, 512);
if (result < 0) {
log_num(LOG_ERROR, "disk_read error: ", result);
if (result == ERR_MEDIA_CHANGE) {
log(LOG_ERROR, "disk changed.");
return RES_NOTRDY;
} else {
log(LOG_ERROR, "gerneral error");
return RES_PARERR;
}
} else {
sector++;
}
}
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res;
int i;
int result;
TRACE("disk_write");
for (i = 0; i < count; i++) {
result = bdev_write(pdrv, sector, buff, 512);
if (result < 0) {
return RES_PARERR;
} else {
sector += result;
}
}
return RES_OK;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
int result;
TRACE("disk_ioctl");
result = bdev_ioctrl(pdrv, cmd, buff, 0);
if (result < 0) {
return RES_PARERR;
} else {
return RES_OK;
}
}

View file

@ -1,229 +0,0 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs (C)ChaN, 2019 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "ff.h" /* Obtains integer types */
#include "diskio.h" /* Declarations of disk functions */
/* Definitions of physical drive number for each drive */
#define DEV_RAM 0 /* Example: Map Ramdisk to physical drive 0 */
#define DEV_MMC 1 /* Example: Map MMC/SD card to physical drive 1 */
#define DEV_USB 2 /* Example: Map USB MSD to physical drive 2 */
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv) {
case DEV_RAM :
result = RAM_disk_status();
// translate the reslut code here
return stat;
case DEV_MMC :
result = MMC_disk_status();
// translate the reslut code here
return stat;
case DEV_USB :
result = USB_disk_status();
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
int result;
switch (pdrv) {
case DEV_RAM :
result = RAM_disk_initialize();
// translate the reslut code here
return stat;
case DEV_MMC :
result = MMC_disk_initialize();
// translate the reslut code here
return stat;
case DEV_USB :
result = USB_disk_initialize();
// translate the reslut code here
return stat;
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to read */
)
{
DRESULT res;
int result;
switch (pdrv) {
case DEV_RAM :
// translate the arguments here
result = RAM_disk_read(buff, sector, count);
// translate the reslut code here
return res;
case DEV_MMC :
// translate the arguments here
result = MMC_disk_read(buff, sector, count);
// translate the reslut code here
return res;
case DEV_USB :
// translate the arguments here
result = USB_disk_read(buff, sector, count);
// translate the reslut code here
return res;
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if FF_FS_READONLY == 0
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
LBA_t sector, /* Start sector in LBA */
UINT count /* Number of sectors to write */
)
{
DRESULT res;
int result;
switch (pdrv) {
case DEV_RAM :
// translate the arguments here
result = RAM_disk_write(buff, sector, count);
// translate the reslut code here
return res;
case DEV_MMC :
// translate the arguments here
result = MMC_disk_write(buff, sector, count);
// translate the reslut code here
return res;
case DEV_USB :
// translate the arguments here
result = USB_disk_write(buff, sector, count);
// translate the reslut code here
return res;
}
return RES_PARERR;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
int result;
switch (pdrv) {
case DEV_RAM :
// Process of the command for the RAM drive
return res;
case DEV_MMC :
// Process of the command for the MMC/SD card
return res;
case DEV_USB :
// Process of the command the USB drive
return res;
}
return RES_PARERR;
}

832
src/fatfs/f256xe_diskio.c Normal file
View file

@ -0,0 +1,832 @@
/*------------------------------------------------------------------------/
/ Foolproof MMCv3/SDv1/SDv2 (in SPI mode) control module
/-------------------------------------------------------------------------/
/
/ Copyright (C) 2019, ChaN, all right reserved.
/
/ * This software is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/-------------------------------------------------------------------------/
Features and Limitations:
* Easy to Port Bit-banging SPI
It uses only four GPIO pins. No complex peripheral needs to be used.
* Platform Independent
You need to modify only a few macros to control the GPIO port.
* Low Speed
The data transfer rate will be several times slower than hardware SPI.
* No Media Change Detection
Application program needs to perform a f_mount() after media change.
/-------------------------------------------------------------------------*/
#include <stdio.h>
#include "ff.h" /* Obtains integer types for FatFs */
#include "f256xe_diskio.h" /* Common include file for FatFs and disk I/O layer */
#include "../dev/rtc.h"
/*-------------------------------------------------------------------------*/
/* Platform dependent macros and functions needed to be modified */
/*-------------------------------------------------------------------------*/
/* System Control Registers - to ger CD & WP from SD0 */
#define SD0_STAT (*(volatile __far uint8_t *)0xF016A0)
#define SD0_STAT_CD 0x40 // When 1 = No Card, 0 = Card is Present
#define SD0_STAT_WP 0x80 // When 0 = Writeable, 1 = Card is Protected
/* SPI Controler 0 Registers - External Access (Front of Unit)*/
#define SD0_CTRL (*(volatile __far uint8_t *)0xF01D00)
#define SD0_DATA (*(volatile __far uint8_t *)0xF01D01)
/* SPI Controler 1 Registers - Internal Access (underneath of Unit - uSDCard) */
// Specific to the F256xE - Internal SDCard (Permanent Disk)
#define SD1_CTRL (*(volatile __far uint8_t *)0xF01D80)
#define SD1_DATA (*(volatile __far uint8_t *)0xF01D81)
#define SDx_CS 0x01 // 1 = Enable
#define SDx_SLOW 0x02 // 1 = Slow 400Khz, 0 = 25Mhz
#define SDx_BUSY 0x80 // 1 = Busy
//
#define DEV_SD0 0 /* Frontal SDCard - Removable Media 0 - SDCARD */
#define DEV_SD1 1 /* Underneath SDCard - Permanent Media 1 - SDCARD */
//
/* MMC card type flags (MMC_GET_TYPE) */
#define CT_MMC3 0x01 /* MMC ver 3 */
#define CT_MMC4 0x02 /* MMC ver 4+ */
#define CT_MMC 0x03 /* MMC */
#define CT_SDC1 0x04 /* SD ver 1 */
#define CT_SDC2 0x08 /* SD ver 2+ */
#define CT_SDC 0x0C /* SD */
#define CT_BLOCK 0x10 /* Block addressing */
/* Delay n microseconds (avr-gcc -Os) */
static void dly_us (UINT n) {
do {
// Add Timer Routine for 1us (6x Clock @ 6.29Mhz)
__asm(" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n"
" nop\n");
} while (--n);
}
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
/* MMC/SD command (SPI mode) */
#define CMD0 (0) /* GO_IDLE_STATE */
#define CMD1 (1) /* SEND_OP_COND */
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
#define CMD8 (8) /* SEND_IF_COND */
#define CMD9 (9) /* SEND_CSD */
#define CMD10 (10) /* SEND_CID */
#define CMD12 (12) /* STOP_TRANSMISSION */
#define CMD13 (13) /* SEND_STATUS */
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
#define CMD16 (16) /* SET_BLOCKLEN */
#define CMD17 (17) /* READ_SINGLE_BLOCK */
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (23) /* SET_BLOCK_COUNT */
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (24) /* WRITE_BLOCK */
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
#define CMD32 (32) /* ERASE_ER_BLK_START */
#define CMD33 (33) /* ERASE_ER_BLK_END */
#define CMD38 (38) /* ERASE */
#define CMD55 (55) /* APP_CMD */
#define CMD58 (58) /* READ_OCR */
static DSTATUS SD0_Stat = STA_NOINIT; /* Disk status */
static DSTATUS SD1_Stat = STA_NOINIT; /* Disk status */
static BYTE SD0_CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */
static BYTE SD1_CardType; /* b0:MMC, b1:SDv1, b2:SDv2, b3:Block addressing */
/*-----------------------------------------------------------------------*/
/* Transmit Busy Flag Check - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
static void SD0_Wait_SDx_Busy( void ) {
unsigned char i;
i = (SD0_CTRL & SDx_BUSY);
do {
i = (SD0_CTRL & SDx_BUSY);
} while (i == SDx_BUSY);
}
/*-----------------------------------------------------------------------*/
/* Transmit bytes to the card - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
static void SD0_Tx ( const BYTE* buff, UINT bc ) {
BYTE d;
do {
d = *buff++; /* Get a byte to be sent */
SD0_DATA = d; // Set the Data in the Transmit Register
SD0_Wait_SDx_Busy(); // Wait for the transmit to be over with
} while (--bc);
}
/*-----------------------------------------------------------------------*/
/* Receive bytes from the card - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
static void SD0_Rx ( BYTE *buff, UINT bc ) {
BYTE r;
do {
SD0_DATA = 0xff; // Set the Data in the Transmit Register
SD0_Wait_SDx_Busy(); // Wait for the transmit to be over with
*buff++ = SD0_DATA; /* Store a received byte */
} while (--bc);
}
/*-----------------------------------------------------------------------*/
/* Wait for card ready Using - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
static int SD0_wait_ready (void) {
BYTE d;
UINT tmr;
for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */
SD0_Rx(&d, 1);
if (d == 0xFF) break;
dly_us(100); // 100us
}
return tmr ? 1 : 0;
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
static void SD0_deselect ( void ) {
BYTE d;
SD0_CTRL = SD0_CTRL & ~ SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active)
SD0_Rx(&d, 1); /* Dummy clock (force DO hi-z for multiple slave SPI) */
}
/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
/* 1:OK, 0:Timeout */
static int SD0_select (void) {
BYTE d;
SD0_CTRL = SD0_CTRL | SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active)
SD0_Rx(&d, 1); /* Dummy clock (force DO enabled) */
if (SD0_wait_ready())
return 1; /* Wait for card ready */
SD0_deselect();
return 0; /* Failed */
}
/*-----------------------------------------------------------------------*/
/* Receive a data packet from the card - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
/* 1:OK, 0:Failed */
static int SD0_Rx_datablock ( BYTE *buff, UINT btr ) {
BYTE d[2];
UINT tmr;
for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */
SD0_Rx(d, 1);
if (d[0] != 0xFF) break;
dly_us(100); // 100us
}
if (d[0] != 0xFE)
return 0; /* If not valid data token, return with error */
SD0_Rx(buff, btr); /* Receive the data block into buffer */
SD0_Rx(d, 2); /* Discard CRC */
return 1; /* Return with success */
}
/*-----------------------------------------------------------------------*/
/* Send a data packet to the card - SPI Controler 0 */
/*-----------------------------------------------------------------------*/
/* 1:OK, 0:Failed */
static int SD0_Tx_datablock ( const BYTE *buff, BYTE token ) {
BYTE d[2];
if (!SD0_wait_ready())
return 0;
d[0] = token;
SD0_Tx(d, 1); /* Xmit a token */
if (token != 0xFD) { /* Is it data token? */
SD0_Tx(buff, 512); /* Xmit the 512 byte data block to MMC */
SD0_Rx(d, 2); /* Xmit dummy CRC (0xFF,0xFF) */
SD0_Rx(d, 1); /* Receive data response */
if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */
return 0;
}
return 1;
}
/*-----------------------------------------------------------------------*/
/* Send a command packet to the card */
/*-----------------------------------------------------------------------*/
/* Returns command response (bit7==1:Send failed)*/
static BYTE SD0_Tx_cmd ( BYTE cmd, DWORD arg ) {
BYTE n, d, buf[6];
//printf("Processing Command: %d\r", cmd);
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
n = SD0_Tx_cmd(CMD55, 0);
if (n > 1)
return n;
}
/* Select the card and wait for ready except to stop multiple block read */
if (cmd != CMD12) {
//printf("Processing Command: %d\r", cmd);
SD0_deselect();
if (!SD0_select())
return 0xFF;
}
/* Send a command packet */
buf[0] = 0x40 | cmd; /* Start + Command index */
buf[1] = (BYTE)(arg >> 24); /* Argument[31..24] */
buf[2] = (BYTE)(arg >> 16); /* Argument[23..16] */
buf[3] = (BYTE)(arg >> 8); /* Argument[15..8] */
buf[4] = (BYTE)arg; /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0)
n = 0x95; /* (valid CRC for CMD0(0)) */
if (cmd == CMD8)
n = 0x87; /* (valid CRC for CMD8(0x1AA)) */
buf[5] = n;
SD0_Tx(buf, 6);
/* Receive command response */
if (cmd == CMD12)
SD0_Rx(&d, 1); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
SD0_Rx(&d, 1);
while ((d & 0x80) && --n);
return d; /* Return with the response value */
}
/*-----------------------------------------------------------------------*/
/* Transmit bytes to the card - SPI Controler 1 */
/*-----------------------------------------------------------------------*/
static void SD1_Tx ( const BYTE* buff, UINT bc ) {
BYTE d;
do {
d = *buff++; /* Get a byte to be sent */
SD1_DATA = d; // Set the Data in the Transmit Register
while ( SD1_CTRL & SDx_BUSY); // Wait for the transmit to be over with
} while (--bc);
}
/*-----------------------------------------------------------------------*/
/* Receive bytes from the card - SPI Controler 1 */
/*-----------------------------------------------------------------------*/
static void SD1_Rx ( BYTE *buff, UINT bc ) {
BYTE r;
do {
SD1_DATA = 0xff; // Set the Data in the Transmit Register
while ( SD1_CTRL & SDx_BUSY); // Wait for the transmit to be over with
*buff++ = SD1_DATA; /* Store a received byte */
} while (--bc);
}
/*-----------------------------------------------------------------------*/
/* Wait for card ready Using - SPI Controler 1 */
/*-----------------------------------------------------------------------*/
static int SD1_wait_ready (void) {
BYTE d;
UINT tmr;
for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */
SD1_Rx(&d, 1);
if (d == 0xFF) break;
dly_us(100); // 100us
}
return tmr ? 1 : 0;
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus - SPI Controler 1 */
/*-----------------------------------------------------------------------*/
static void SD1_deselect ( void ) {
BYTE d;
SD1_CTRL = SD1_CTRL & ~ SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active)
SD1_Rx(&d, 1); /* Dummy clock (force DO hi-z for multiple slave SPI) */
}
/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready - SPI Controler 1 */
/*-----------------------------------------------------------------------*/
/* 1:OK, 0:Timeout */
static int SD1_select (void) {
BYTE d;
SD1_CTRL = SD1_CTRL | SDx_CS; // SDx_CS = 0 ( Disabled ), SDx = 1 (Active)
SD1_Rx(&d, 1); /* Dummy clock (force DO enabled) */
if (SD1_wait_ready())
return 1; /* Wait for card ready */
SD1_deselect();
return 0; /* Failed */
}
/*-----------------------------------------------------------------------*/
/* Receive a data packet from the card - SPI Controler 1 */
/*-----------------------------------------------------------------------*/
/* 1:OK, 0:Failed */
static int SD1_Rx_datablock ( BYTE *buff, UINT btr ) {
BYTE d[2];
UINT tmr;
for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */
SD1_Rx(d, 1);
if (d[0] != 0xFF) break;
dly_us(100); // 100us
}
if (d[0] != 0xFE)
return 0; /* If not valid data token, return with error */
SD1_Rx(buff, btr); /* Receive the data block into buffer */
SD1_Rx(d, 2); /* Discard CRC */
return 1; /* Return with success */
}
/*-----------------------------------------------------------------------*/
/* Send a data packet to the card - SPI Controler 1 */
/*-----------------------------------------------------------------------*/
/* 1:OK, 0:Failed */
static int SD1_Tx_datablock ( const BYTE *buff, BYTE token ) {
BYTE d[2];
if (!SD1_wait_ready())
return 0;
d[0] = token;
SD1_Tx(d, 1); /* Xmit a token */
if (token != 0xFD) { /* Is it data token? */
SD1_Tx(buff, 512); /* Xmit the 512 byte data block to MMC */
SD1_Rx(d, 2); /* Xmit dummy CRC (0xFF,0xFF) */
SD1_Rx(d, 1); /* Receive data response */
if ((d[0] & 0x1F) != 0x05) /* If not accepted, return with error */
return 0;
}
return 1;
}
/*-----------------------------------------------------------------------*/
/* Send a command packet to the card - SPI Controler 1 */
/*-----------------------------------------------------------------------*/
/* Returns command response (bit7==1:Send failed)*/
static BYTE SD1_Tx_cmd ( BYTE cmd, DWORD arg ) {
BYTE n, d, buf[6];
//printf("Processing Command: %d\r", cmd);
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
n = SD1_Tx_cmd(CMD55, 0);
if (n > 1)
return n;
}
/* Select the card and wait for ready except to stop multiple block read */
if (cmd != CMD12) {
//printf("Enabling CSn for Command: %d\r", cmd);
SD1_deselect();
if (!SD1_select()) {
//printf("*** Enabling CSn Timed out ***\r");
return 0xFF;
}
}
/* Send a command packet */
buf[0] = 0x40 | cmd; /* Start + Command index */
buf[1] = (BYTE)(arg >> 24); /* Argument[31..24] */
buf[2] = (BYTE)(arg >> 16); /* Argument[23..16] */
buf[3] = (BYTE)(arg >> 8); /* Argument[15..8] */
buf[4] = (BYTE)arg; /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0)
n = 0x95; /* (valid CRC for CMD0(0)) */
if (cmd == CMD8)
n = 0x87; /* (valid CRC for CMD8(0x1AA)) */
buf[5] = n;
SD1_Tx(buf, 6);
/* Receive command response */
if (cmd == CMD12)
SD1_Rx(&d, 1); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
SD1_Rx(&d, 1);
while ((d & 0x80) && --n);
return d; /* Return with the response value */
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
//#define SD0_STAT (*(volatile __far uint8_t *)0xF016A0)
//#define SD0_STAT_CD 0x40 // When 1 = No Card, 0 = Card is Present
//#define SD0_STAT_WP 0x80 // When 1 = Writeable, 0 = Card is Protected
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
/* Drive number (always 0) */
DSTATUS disk_status ( BYTE drv ) {
if ( drv == DEV_SD0) {
// CHeck for Card Present
if ( SD0_STAT & SD0_STAT_CD )
SD0_Stat = SD0_Stat | STA_NODISK;
else
SD0_Stat = SD0_Stat & ~STA_NODISK;
if ( SD0_STAT & SD0_STAT_WP )
SD0_Stat = SD0_Stat | STA_PROTECT;
else
SD0_Stat = SD0_Stat & ~STA_PROTECT;
return SD0_Stat;
}
if ( drv == DEV_SD1) {
//printf("Drive: %d, disk_status: %x\r", drv, SD0_Stat);
return 0x00; // There is always a card in the drive
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE drv /* Physical drive nmuber (0) */
)
{
BYTE n, ty, cmd, buf[4];
UINT tmr;
DSTATUS s;
if ( drv == DEV_SD0) {
//printf("Init Drive %d\r", drv);
dly_us(10000); /* 10ms */
SD0_CTRL = SD0_CTRL | SDx_SLOW; // Set the SPI in Slow Mode
for (n = 10; n; n--) {
SD0_Rx(buf, 1); /* Apply 80 dummy clocks and the card gets ready to receive command */
}
ty = 0;
if (SD0_Tx_cmd(CMD0, 0) == 1) { /* Enter Idle state */
if (SD0_Tx_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
SD0_Rx(buf, 4); /* Get trailing return value of R7 resp */
if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */
if (SD0_Tx_cmd(ACMD41, 1UL << 30) == 0) break;
dly_us(1000);
}
if (tmr && SD0_Tx_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
SD0_Rx(buf, 4);
ty = (buf[0] & 0x40) ? CT_SDC2 | CT_BLOCK : CT_SDC2; /* SDv2+ */
}
}
} else { /* SDv1 or MMCv3 */
if (SD0_Tx_cmd(ACMD41, 0) <= 1) {
ty = CT_SDC2; cmd = ACMD41; /* SDv1 */
} else {
ty = CT_MMC3; cmd = CMD1; /* MMCv3 */
}
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */
if (SD0_Tx_cmd(cmd, 0) == 0) break;
dly_us(1000);
}
if (!tmr || SD0_Tx_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
ty = 0;
}
}
SD0_CTRL = SD0_CTRL & ~SDx_SLOW; // Bring back the Fast Mode - 25Mhz
SD0_CardType = ty;
s = ty ? 0 : STA_NOINIT;
SD0_Stat = s;
//printf("SD0_CardType: %x\r", ty);
//printf("SD0_Stat: %x\r", SD0_Stat);
SD0_deselect();
return s;
}
if ( drv == DEV_SD1) {
//printf("Initializing Internal Drive\r");
//printf("Init Drive %d\r", drv);
dly_us(10000); /* 10ms */
SD1_CTRL = SD1_CTRL | SDx_SLOW; // Set the SPI in Slow Mode
for (n = 10; n; n--) {
SD1_Rx(buf, 1); /* Apply 80 dummy clocks and the card gets ready to receive command */
}
ty = 0;
if (SD1_Tx_cmd(CMD0, 0) == 1) { /* Enter Idle state */
if (SD1_Tx_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
SD1_Rx(buf, 4); /* Get trailing return value of R7 resp */
if (buf[2] == 0x01 && buf[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state (ACMD41 with HCS bit) */
if (SD1_Tx_cmd(ACMD41, 1UL << 30) == 0) break;
dly_us(1000);
}
if (tmr && SD1_Tx_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
SD1_Rx(buf, 4);
ty = (buf[0] & 0x40) ? CT_SDC2 | CT_BLOCK : CT_SDC2; /* SDv2+ */
}
}
} else { /* SDv1 or MMCv3 */
if (SD1_Tx_cmd(ACMD41, 0) <= 1) {
ty = CT_SDC2; cmd = ACMD41; /* SDv1 */
} else {
ty = CT_MMC3; cmd = CMD1; /* MMCv3 */
}
for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */
if (SD1_Tx_cmd(cmd, 0) == 0) break;
dly_us(1000);
}
if (!tmr || SD1_Tx_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
ty = 0;
}
}
SD1_CTRL = SD1_CTRL & ~SDx_SLOW; // Bring back the Fast Mode - 25Mhz
//printf("SD1_CardType: %x\r", ty);
SD1_CardType = ty;
s = ty ? 0 : STA_NOINIT;
SD1_Stat = s;
//printf("SD1_Status: %x\r", SD1_Stat);
SD1_deselect();
return s;
}
return RES_NOTRDY;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read ( BYTE drv, BYTE *buff, LBA_t sector, UINT count ) {
BYTE cmd;
DWORD sect = (DWORD)sector;
if ( drv == DEV_SD0) {
if (disk_status(drv) & STA_NOINIT)
return RES_NOTRDY;
if (!(SD0_CardType & CT_BLOCK))
sect *= 512; /* Convert LBA to byte address if needed */
cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
if (SD0_Tx_cmd(cmd, sect) == 0) {
do {
if (!SD0_Rx_datablock(buff, 512))
break;
buff += 512;
} while (--count);
if (cmd == CMD18)
SD0_Tx_cmd(CMD12, 0); /* STOP_TRANSMISSION */
}
SD0_deselect();
}
if ( drv == DEV_SD1) {
if (disk_status(drv) & STA_NOINIT)
return RES_NOTRDY;
if (!(SD1_CardType & CT_BLOCK))
sect *= 512; /* Convert LBA to byte address if needed */
cmd = count > 1 ? CMD18 : CMD17; /* READ_MULTIPLE_BLOCK : READ_SINGLE_BLOCK */
if (SD1_Tx_cmd(cmd, sect) == 0) {
do {
if (!SD1_Rx_datablock(buff, 512))
break;
buff += 512;
} while (--count);
if (cmd == CMD18)
SD1_Tx_cmd(CMD12, 0); /* STOP_TRANSMISSION */
}
SD1_deselect();
}
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
//DRESULT disk_write (
// BYTE drv, /* Physical drive nmuber (0) */
// const BYTE *buff, /* Pointer to the data to be written */
// LBA_t sector, /* Start sector number (LBA) */
// UINT count /* Sector count (1..128) */
//)
DRESULT disk_write ( BYTE drv, const BYTE *buff, LBA_t sector, UINT count ) {
DWORD sect = (DWORD)sector;
if ( drv == DEV_SD0) {
if (disk_status(drv) & STA_NOINIT)
return RES_NOTRDY;
if (!(SD0_CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */
if (count == 1) { /* Single block write */
if ((SD0_Tx_cmd(CMD24, sect) == 0) && SD0_Tx_datablock(buff, 0xFE))
count = 0;
}
else { /* Multiple block write */
if (SD0_CardType & CT_SDC)
SD0_Tx_cmd(ACMD23, count);
if (SD0_Tx_cmd(CMD25, sect) == 0) { /* WRITE_MULTIPLE_BLOCK */
do {
if (!SD0_Tx_datablock(buff, 0xFC))
break;
buff += 512;
} while (--count);
if (!SD0_Tx_datablock(0, 0xFD)) /* STOP_TRAN token */
count = 1;
}
}
SD0_deselect();
}
if ( drv == DEV_SD1) {
if (disk_status(drv) & STA_NOINIT)
return RES_NOTRDY;
if (!(SD1_CardType & CT_BLOCK)) sect *= 512; /* Convert LBA to byte address if needed */
if (count == 1) { /* Single block write */
if ((SD1_Tx_cmd(CMD24, sect) == 0) && SD1_Tx_datablock(buff, 0xFE))
count = 0;
}
else { /* Multiple block write */
if (SD1_CardType & CT_SDC)
SD1_Tx_cmd(ACMD23, count);
if (SD1_Tx_cmd(CMD25, sect) == 0) { /* WRITE_MULTIPLE_BLOCK */
do {
if (!SD1_Tx_datablock(buff, 0xFC))
break;
buff += 512;
} while (--count);
if (!SD1_Tx_datablock(0, 0xFD)) /* STOP_TRAN token */
count = 1;
}
}
SD1_deselect();
}
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
//DRESULT disk_ioctl (
// BYTE drv, /* Physical drive nmuber (0) */
// BYTE ctrl, /* Control code */
// void *buff /* Buffer to send/receive control data */
//)
DRESULT disk_ioctl ( BYTE drv, BYTE ctrl, void *buff ) {
DRESULT res;
BYTE n, csd[16];
DWORD cs;
if ( drv == DEV_SD0) {
if (disk_status(drv) & STA_NOINIT)
return RES_NOTRDY; /* Check if card is in the socket */
res = RES_ERROR;
switch (ctrl) {
case CTRL_SYNC : /* Make sure that no pending write process */
if (SD0_select())
res = RES_OK;
break;
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
if ((SD0_Tx_cmd(CMD9, 0) == 0) && SD0_Rx_datablock(csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
*(LBA_t*)buff = cs << 10;
}
else { /* SDC ver 1.XX or MMC */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(LBA_t*)buff = cs << (n - 9);
}
res = RES_OK;
}
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
*(DWORD*)buff = 128;
res = RES_OK;
break;
default:
res = RES_PARERR;
}
SD0_deselect();
}
if ( drv == DEV_SD1) {
if (disk_status(drv) & STA_NOINIT)
return RES_NOTRDY; /* Check if card is in the socket */
res = RES_ERROR;
switch (ctrl) {
case CTRL_SYNC : /* Make sure that no pending write process */
if (SD1_select())
res = RES_OK;
break;
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
if ((SD1_Tx_cmd(CMD9, 0) == 0) && SD1_Rx_datablock(csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
cs = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
*(LBA_t*)buff = cs << 10;
}
else { /* SDC ver 1.XX or MMC */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
cs = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(LBA_t*)buff = cs << (n - 9);
}
res = RES_OK;
}
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
*(DWORD*)buff = 128;
res = RES_OK;
break;
default:
res = RES_PARERR;
}
SD1_deselect();
}
return res;
}
DWORD get_fattime (void)
{
t_time time;
rtc_get_time(&time);
return (DWORD)(time.year - 80) << 25 |
(DWORD)(time.month + 1) << 21 |
(DWORD)time.day << 16 |
(DWORD)time.hour << 11 |
(DWORD)time.minute << 5 |
(DWORD)time.second >> 1;
}

View file

@ -0,0 +1,548 @@
/**
******************************************************************************
* @file user_diskio_spi.c
* @brief This file contains the implementation of the user_diskio_spi FatFs
* driver.
******************************************************************************
* Portions copyright (C) 2014, ChaN, all rights reserved.
* Portions copyright (C) 2017, kiwih, all rights reserved.
*
* This software is a free software and there is NO WARRANTY.
* No restriction on use. You can use, modify and redistribute it for
* personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
* Redistributions of source code must retain the above copyright notice.
*
******************************************************************************
*/
//This code was ported by kiwih from a copywrited (C) library written by ChaN
//available at http://elm-chan.org/fsw/ff/ffsample.zip
//(text at http://elm-chan.org/fsw/ff/00index_e.html)
//This file provides the FatFs driver functions and SPI code required to manage
//an SPI-connected MMC or compatible SD card with FAT
//It is designed to be wrapped by a cubemx generated user_diskio.c file.
#include "stm32f3xx_hal.h" /* Provide the low-level HAL functions */
#include "user_diskio_spi.h"
//Make sure you set #define SD_SPI_HANDLE as some hspix in main.h
//Make sure you set #define SD_CS_GPIO_Port as some GPIO port in main.h
//Make sure you set #define SD_CS_Pin as some GPIO pin in main.h
extern SPI_HandleTypeDef SD_SPI_HANDLE;
/* Function prototypes */
//(Note that the _256 is used as a mask to clear the prescalar bits as it provides binary 111 in the correct position)
#define FCLK_SLOW() { MODIFY_REG(SD_SPI_HANDLE.Instance->CR1, SPI_BAUDRATEPRESCALER_256, SPI_BAUDRATEPRESCALER_128); } /* Set SCLK = slow, approx 280 KBits/s*/
#define FCLK_FAST() { MODIFY_REG(SD_SPI_HANDLE.Instance->CR1, SPI_BAUDRATEPRESCALER_256, SPI_BAUDRATEPRESCALER_8); } /* Set SCLK = fast, approx 4.5 MBits/s */
#define CS_HIGH() {HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_SET);}
#define CS_LOW() {HAL_GPIO_WritePin(SD_CS_GPIO_Port, SD_CS_Pin, GPIO_PIN_RESET);}
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
/* MMC/SD command */
#define CMD0 (0) /* GO_IDLE_STATE */
#define CMD1 (1) /* SEND_OP_COND (MMC) */
#define ACMD41 (0x80+41) /* SEND_OP_COND (SDC) */
#define CMD8 (8) /* SEND_IF_COND */
#define CMD9 (9) /* SEND_CSD */
#define CMD10 (10) /* SEND_CID */
#define CMD12 (12) /* STOP_TRANSMISSION */
#define ACMD13 (0x80+13) /* SD_STATUS (SDC) */
#define CMD16 (16) /* SET_BLOCKLEN */
#define CMD17 (17) /* READ_SINGLE_BLOCK */
#define CMD18 (18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (23) /* SET_BLOCK_COUNT (MMC) */
#define ACMD23 (0x80+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (24) /* WRITE_BLOCK */
#define CMD25 (25) /* WRITE_MULTIPLE_BLOCK */
#define CMD32 (32) /* ERASE_ER_BLK_START */
#define CMD33 (33) /* ERASE_ER_BLK_END */
#define CMD38 (38) /* ERASE */
#define CMD55 (55) /* APP_CMD */
#define CMD58 (58) /* READ_OCR */
/* MMC card type flags (MMC_GET_TYPE) */
#define CT_MMC 0x01 /* MMC ver 3 */
#define CT_SD1 0x02 /* SD ver 1 */
#define CT_SD2 0x04 /* SD ver 2 */
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
#define CT_BLOCK 0x08 /* Block addressing */
static volatile
DSTATUS Stat = STA_NOINIT; /* Physical drive status */
static
BYTE CardType; /* Card type flags */
uint32_t spiTimerTickStart;
uint32_t spiTimerTickDelay;
void SPI_Timer_On(uint32_t waitTicks) {
spiTimerTickStart = HAL_GetTick();
spiTimerTickDelay = waitTicks;
}
uint8_t SPI_Timer_Status() {
return ((HAL_GetTick() - spiTimerTickStart) < spiTimerTickDelay);
}
/*-----------------------------------------------------------------------*/
/* SPI controls (Platform dependent) */
/*-----------------------------------------------------------------------*/
/* Exchange a byte */
static
BYTE xchg_spi (
BYTE dat /* Data to send */
)
{
BYTE rxDat;
HAL_SPI_TransmitReceive(&SD_SPI_HANDLE, &dat, &rxDat, 1, 50);
return rxDat;
}
/* Receive multiple byte */
static
void rcvr_spi_multi (
BYTE *buff, /* Pointer to data buffer */
UINT btr /* Number of bytes to receive (even number) */
)
{
for(UINT i=0; i<btr; i++) {
*(buff+i) = xchg_spi(0xFF);
}
}
#if _USE_WRITE
/* Send multiple byte */
static
void xmit_spi_multi (
const BYTE *buff, /* Pointer to the data */
UINT btx /* Number of bytes to send (even number) */
)
{
HAL_SPI_Transmit(&SD_SPI_HANDLE, buff, btx, HAL_MAX_DELAY);
}
#endif
/*-----------------------------------------------------------------------*/
/* Wait for card ready */
/*-----------------------------------------------------------------------*/
static
int wait_ready ( /* 1:Ready, 0:Timeout */
UINT wt /* Timeout [ms] */
)
{
BYTE d;
//wait_ready needs its own timer, unfortunately, so it can't use the
//spi_timer functions
uint32_t waitSpiTimerTickStart;
uint32_t waitSpiTimerTickDelay;
waitSpiTimerTickStart = HAL_GetTick();
waitSpiTimerTickDelay = (uint32_t)wt;
do {
d = xchg_spi(0xFF);
/* This loop takes a time. Insert rot_rdq() here for multitask envilonment. */
} while (d != 0xFF && ((HAL_GetTick() - waitSpiTimerTickStart) < waitSpiTimerTickDelay)); /* Wait for card goes ready or timeout */
return (d == 0xFF) ? 1 : 0;
}
/*-----------------------------------------------------------------------*/
/* Despiselect card and release SPI */
/*-----------------------------------------------------------------------*/
static
void despiselect (void)
{
CS_HIGH(); /* Set CS# high */
xchg_spi(0xFF); /* Dummy clock (force DO hi-z for multiple slave SPI) */
}
/*-----------------------------------------------------------------------*/
/* Select card and wait for ready */
/*-----------------------------------------------------------------------*/
static
int spiselect (void) /* 1:OK, 0:Timeout */
{
CS_LOW(); /* Set CS# low */
xchg_spi(0xFF); /* Dummy clock (force DO enabled) */
if (wait_ready(500)) return 1; /* Wait for card ready */
despiselect();
return 0; /* Timeout */
}
/*-----------------------------------------------------------------------*/
/* Receive a data packet from the MMC */
/*-----------------------------------------------------------------------*/
static
int rcvr_datablock ( /* 1:OK, 0:Error */
BYTE *buff, /* Data buffer */
UINT btr /* Data block length (byte) */
)
{
BYTE token;
SPI_Timer_On(200);
do { /* Wait for DataStart token in timeout of 200ms */
token = xchg_spi(0xFF);
/* This loop will take a time. Insert rot_rdq() here for multitask envilonment. */
} while ((token == 0xFF) && SPI_Timer_Status());
if(token != 0xFE) return 0; /* Function fails if invalid DataStart token or timeout */
rcvr_spi_multi(buff, btr); /* Store trailing data to the buffer */
xchg_spi(0xFF); xchg_spi(0xFF); /* Discard CRC */
return 1; /* Function succeeded */
}
/*-----------------------------------------------------------------------*/
/* Send a data packet to the MMC */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
static
int xmit_datablock ( /* 1:OK, 0:Failed */
const BYTE *buff, /* Ponter to 512 byte data to be sent */
BYTE token /* Token */
)
{
BYTE resp;
if (!wait_ready(500)) return 0; /* Wait for card ready */
xchg_spi(token); /* Send token */
if (token != 0xFD) { /* Send data if token is other than StopTran */
xmit_spi_multi(buff, 512); /* Data */
xchg_spi(0xFF); xchg_spi(0xFF); /* Dummy CRC */
resp = xchg_spi(0xFF); /* Receive data resp */
if ((resp & 0x1F) != 0x05) return 0; /* Function fails if the data packet was not accepted */
}
return 1;
}
#endif
/*-----------------------------------------------------------------------*/
/* Send a command packet to the MMC */
/*-----------------------------------------------------------------------*/
static
BYTE send_cmd ( /* Return value: R1 resp (bit7==1:Failed to send) */
BYTE cmd, /* Command index */
DWORD arg /* Argument */
)
{
BYTE n, res;
if (cmd & 0x80) { /* Send a CMD55 prior to ACMD<n> */
cmd &= 0x7F;
res = send_cmd(CMD55, 0);
if (res > 1) return res;
}
/* Select the card and wait for ready except to stop multiple block read */
if (cmd != CMD12) {
despiselect();
if (!spiselect()) return 0xFF;
}
/* Send command packet */
xchg_spi(0x40 | cmd); /* Start + command index */
xchg_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
xchg_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
xchg_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
xchg_spi((BYTE)arg); /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
xchg_spi(n);
/* Receive command resp */
if (cmd == CMD12) xchg_spi(0xFF); /* Diacard following one byte when CMD12 */
n = 10; /* Wait for response (10 bytes max) */
do {
res = xchg_spi(0xFF);
} while ((res & 0x80) && --n);
return res; /* Return received response */
}
/*--------------------------------------------------------------------------
Public FatFs Functions (wrapped in user_diskio.c)
---------------------------------------------------------------------------*/
//The following functions are defined as inline because they aren't the functions that
//are passed to FatFs - they are wrapped by autogenerated (non-inline) cubemx template
//code.
//If you do not wish to use cubemx, remove the "inline" from these functions here
//and in the associated .h
/*-----------------------------------------------------------------------*/
/* Initialize disk drive */
/*-----------------------------------------------------------------------*/
inline DSTATUS USER_SPI_initialize (
BYTE drv /* Physical drive number (0) */
)
{
BYTE n, cmd, ty, ocr[4];
if (drv != 0) return STA_NOINIT; /* Supports only drive 0 */
//assume SPI already init init_spi(); /* Initialize SPI */
if (Stat & STA_NODISK) return Stat; /* Is card existing in the soket? */
FCLK_SLOW();
for (n = 10; n; n--) xchg_spi(0xFF); /* Send 80 dummy clocks */
ty = 0;
if (send_cmd(CMD0, 0) == 1) { /* Put the card SPI/Idle state */
SPI_Timer_On(1000); /* Initialization timeout = 1 sec */
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDv2? */
for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF); /* Get 32 bit return value of R7 resp */
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* Is the card supports vcc of 2.7-3.6V? */
while (SPI_Timer_Status() && send_cmd(ACMD41, 1UL << 30)) ; /* Wait for end of initialization with ACMD41(HCS) */
if (SPI_Timer_Status() && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* Card id SDv2 */
}
}
} else { /* Not SDv2 card */
if (send_cmd(ACMD41, 0) <= 1) { /* SDv1 or MMC? */
ty = CT_SD1; cmd = ACMD41; /* SDv1 (ACMD41(0)) */
} else {
ty = CT_MMC; cmd = CMD1; /* MMCv3 (CMD1(0)) */
}
while (SPI_Timer_Status() && send_cmd(cmd, 0)) ; /* Wait for end of initialization */
if (!SPI_Timer_Status() || send_cmd(CMD16, 512) != 0) /* Set block length: 512 */
ty = 0;
}
}
CardType = ty; /* Card type */
despiselect();
if (ty) { /* OK */
FCLK_FAST(); /* Set fast clock */
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT flag */
} else { /* Failed */
Stat = STA_NOINIT;
}
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Get disk status */
/*-----------------------------------------------------------------------*/
inline DSTATUS USER_SPI_status (
BYTE drv /* Physical drive number (0) */
)
{
if (drv) return STA_NOINIT; /* Supports only drive 0 */
return Stat; /* Return disk status */
}
/*-----------------------------------------------------------------------*/
/* Read sector(s) */
/*-----------------------------------------------------------------------*/
inline DRESULT USER_SPI_read (
BYTE drv, /* Physical drive number (0) */
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
UINT count /* Number of sectors to read (1..128) */
)
{
if (drv || !count) return RES_PARERR; /* Check parameter */
if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ot BA conversion (byte addressing cards) */
if (count == 1) { /* Single sector read */
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
&& rcvr_datablock(buff, 512)) {
count = 0;
}
}
else { /* Multiple sector read */
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
do {
if (!rcvr_datablock(buff, 512)) break;
buff += 512;
} while (--count);
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
}
}
despiselect();
return count ? RES_ERROR : RES_OK; /* Return result */
}
/*-----------------------------------------------------------------------*/
/* Write sector(s) */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
inline DRESULT USER_SPI_write (
BYTE drv, /* Physical drive number (0) */
const BYTE *buff, /* Ponter to the data to write */
DWORD sector, /* Start sector number (LBA) */
UINT count /* Number of sectors to write (1..128) */
)
{
if (drv || !count) return RES_PARERR; /* Check parameter */
if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check drive status */
if (Stat & STA_PROTECT) return RES_WRPRT; /* Check write protect */
if (!(CardType & CT_BLOCK)) sector *= 512; /* LBA ==> BA conversion (byte addressing cards) */
if (count == 1) { /* Single sector write */
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
&& xmit_datablock(buff, 0xFE)) {
count = 0;
}
}
else { /* Multiple sector write */
if (CardType & CT_SDC) send_cmd(ACMD23, count); /* Predefine number of sectors */
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
do {
if (!xmit_datablock(buff, 0xFC)) break;
buff += 512;
} while (--count);
if (!xmit_datablock(0, 0xFD)) count = 1; /* STOP_TRAN token */
}
}
despiselect();
return count ? RES_ERROR : RES_OK; /* Return result */
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous drive controls other than data read/write */
/*-----------------------------------------------------------------------*/
#if _USE_IOCTL
inline DRESULT USER_SPI_ioctl (
BYTE drv, /* Physical drive number (0) */
BYTE cmd, /* Control command code */
void *buff /* Pointer to the conrtol data */
)
{
DRESULT res;
BYTE n, csd[16];
DWORD *dp, st, ed, csize;
if (drv) return RES_PARERR; /* Check parameter */
if (Stat & STA_NOINIT) return RES_NOTRDY; /* Check if drive is ready */
res = RES_ERROR;
switch (cmd) {
case CTRL_SYNC : /* Wait for end of internal write process of the drive */
if (spiselect()) res = RES_OK;
break;
case GET_SECTOR_COUNT : /* Get drive capacity in unit of sector (DWORD) */
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
csize = csd[9] + ((WORD)csd[8] << 8) + ((DWORD)(csd[7] & 63) << 16) + 1;
*(DWORD*)buff = csize << 10;
} else { /* SDC ver 1.XX or MMC ver 3 */
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(DWORD*)buff = csize << (n - 9);
}
res = RES_OK;
}
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
if (CardType & CT_SD2) { /* SDC ver 2.00 */
if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
xchg_spi(0xFF);
if (rcvr_datablock(csd, 16)) { /* Read partial block */
for (n = 64 - 16; n; n--) xchg_spi(0xFF); /* Purge trailing data */
*(DWORD*)buff = 16UL << (csd[10] >> 4);
res = RES_OK;
}
}
} else { /* SDC ver 1.XX or MMC */
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
if (CardType & CT_SD1) { /* SDC ver 1.XX */
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
} else { /* MMC */
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
}
res = RES_OK;
}
}
break;
case CTRL_TRIM : /* Erase a block of sectors (used when _USE_ERASE == 1) */
if (!(CardType & CT_SDC)) break; /* Check if the card is SDC */
if (USER_SPI_ioctl(drv, MMC_GET_CSD, csd)) break; /* Get CSD */
if (!(csd[0] >> 6) && !(csd[10] & 0x40)) break; /* Check if sector erase can be applied to the card */
dp = buff; st = dp[0]; ed = dp[1]; /* Load sector block */
if (!(CardType & CT_BLOCK)) {
st *= 512; ed *= 512;
}
if (send_cmd(CMD32, st) == 0 && send_cmd(CMD33, ed) == 0 && send_cmd(CMD38, 0) == 0 && wait_ready(30000)) { /* Erase sector block */
res = RES_OK; /* FatFs does not check result of this command */
}
break;
default:
res = RES_PARERR;
}
despiselect();
return res;
}
#endif

View file

@ -0,0 +1,38 @@
/**
******************************************************************************
* @file user_diskio_spi.h
* @brief This file contains the common defines and functions prototypes for
* the user_diskio_spi driver implementation
******************************************************************************
* Portions copyright (C) 2014, ChaN, all rights reserved.
* Portions copyright (C) 2017, kiwih, all rights reserved.
*
* This software is a free software and there is NO WARRANTY.
* No restriction on use. You can use, modify and redistribute it for
* personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
* Redistributions of source code must retain the above copyright notice.
*
******************************************************************************
*/
#ifndef _USER_DISKIO_SPI_H
#define _USER_DISKIO_SPI_H
#include "integer.h" //from FatFs middleware library
#include "diskio.h" //from FatFs middleware library
#include "ff_gen_drv.h" //from FatFs middleware library
//we define these as inline because we don't want them to be actual function calls (they get "called" from the cubemx autogenerated user_diskio file)
//we define them as extern because they are defined in a separate .c file to user_diskio.c (which #includes this .h file)
extern DSTATUS USER_SPI_initialize (BYTE pdrv);
extern DSTATUS USER_SPI_status (BYTE pdrv);
extern DRESULT USER_SPI_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
#if _USE_WRITE == 1
extern DRESULT USER_SPI_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
#endif /* _USE_WRITE == 1 */
#if _USE_IOCTL == 1
extern DRESULT USER_SPI_ioctl (BYTE pdrv, BYTE cmd, void *buff);
#endif /* _USE_IOCTL == 1 */
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.14b / / FatFs - Generic FAT Filesystem module R0.15 /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ /
/ Copyright (C) 2021, ChaN, all right reserved. / Copyright (C) 2022, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -20,7 +20,7 @@
#ifndef FF_DEFINED #ifndef FF_DEFINED
#define FF_DEFINED 86631 /* Revision ID */ #define FF_DEFINED 80286 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -131,10 +131,11 @@ extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
typedef struct { typedef struct {
BYTE fs_type; /* Filesystem type (0:not mounted) */ BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */ BYTE pdrv; /* Volume hosting physical drive */
BYTE ldrv; /* Logical drive number (used only when FF_FS_REENTRANT) */
BYTE n_fats; /* Number of FATs (1 or 2) */ BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */ BYTE wflag; /* win[] status (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */ BYTE fsi_flag; /* FSINFO status (b7:disabled, b0:dirty) */
WORD id; /* Volume mount ID */ WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */ WORD csize; /* Cluster size [sectors] */
@ -147,9 +148,6 @@ typedef struct {
#if FF_FS_EXFAT #if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */ BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif #endif
#if FF_FS_REENTRANT
FF_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !FF_FS_READONLY #if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */ DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */ DWORD free_clst; /* Number of free clusters */
@ -163,10 +161,10 @@ typedef struct {
#endif #endif
#endif #endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */ DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */ DWORD fsize; /* Number of sectors per FAT */
LBA_t volbase; /* Volume base sector */ LBA_t volbase; /* Volume base sector */
LBA_t fatbase; /* FAT base sector */ LBA_t fatbase; /* FAT base sector */
LBA_t dirbase; /* Root directory base sector/cluster */ LBA_t dirbase; /* Root directory base sector (FAT12/16) or cluster (FAT32/exFAT) */
LBA_t database; /* Data base sector */ LBA_t database; /* Data base sector */
#if FF_FS_EXFAT #if FF_FS_EXFAT
LBA_t bitbase; /* Allocation bitmap base sector */ LBA_t bitbase; /* Allocation bitmap base sector */
@ -181,7 +179,7 @@ typedef struct {
typedef struct { typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */ FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */ WORD id; /* Hosting volume's mount ID */
BYTE attr; /* Object attribute */ BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */ BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */ DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
@ -250,7 +248,7 @@ typedef struct {
WORD ftime; /* Modified time */ WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */ BYTE fattrib; /* File attribute */
#if FF_USE_LFN #if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */ TCHAR altname[FF_SFN_BUF + 1];/* Alternative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */ TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else #else
TCHAR fname[12 + 1]; /* File name */ TCHAR fname[12 + 1]; /* File name */
@ -298,8 +296,10 @@ typedef enum {
/*--------------------------------------------------------------*/
/* FatFs Module Application Interface */
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */ FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */ FRESULT f_close (FIL* fp); /* Close an open file object */
@ -336,6 +336,8 @@ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
/* Some API fucntions are implemented as macro */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err) #define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr) #define f_tell(fp) ((fp)->fptr)
@ -349,38 +351,43 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Additional user defined functions */ /* Additional Functions */
/*--------------------------------------------------------------*/
/* RTC function */ /* RTC function (provided by user) */
#if !FF_FS_READONLY && !FF_FS_NORTC #if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void); DWORD get_fattime (void); /* Get current time */
#endif #endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */ /* LFN support functions (defined in ffunicode.c) */
#if FF_USE_LFN >= 1
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */ WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */ WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */ DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif #endif
/* O/S dependent functions (samples available in ffsystem.c) */
#if FF_USE_LFN == 3 /* Dynamic memory allocation */ #if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */ void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */ void ff_memfree (void* mblock); /* Free memory block */
#endif #endif
#if FF_FS_REENTRANT /* Sync functions */
/* Sync functions */ int ff_mutex_create (int vol); /* Create a sync object */
#if FF_FS_REENTRANT void ff_mutex_delete (int vol); /* Delete a sync object */
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */ int ff_mutex_take (int vol); /* Lock sync object */
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */ void ff_mutex_give (int vol); /* Unlock sync object */
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
#endif #endif
/*--------------------------------------------------------------*/ /*--------------------------------------------------------------*/
/* Flags and offset address */ /* Flags and Offset Address */
/*--------------------------------------------------------------*/
/* File access mode and open method flags (3rd argument of f_open) */ /* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01 #define FA_READ 0x01

View file

@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs Functional Configurations / Configurations of FatFs Module
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define FFCONF_DEF 86631 /* Revision ID */ #define FFCONF_DEF 80286 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Function Configurations / Function Configurations
@ -25,7 +25,7 @@
/ 3: f_lseek() function is removed in addition to 2. */ / 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_FIND 2 #define FF_USE_FIND 1
/* This option switches filtered directory read functions, f_findfirst() and /* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */ / f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
@ -57,9 +57,9 @@
#define FF_USE_STRFUNC 1 #define FF_USE_STRFUNC 1
#define FF_PRINT_LLI 0 #define FF_PRINT_LLI 1
#define FF_PRINT_FLOAT 0 #define FF_PRINT_FLOAT 1
#define FF_STRF_ENCODE 0 #define FF_STRF_ENCODE 3
/* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and /* FF_USE_STRFUNC switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf(). / f_printf().
/ /
@ -68,7 +68,7 @@
/ 2: Enable with LF-CRLF conversion. / 2: Enable with LF-CRLF conversion.
/ /
/ FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2 / FF_PRINT_LLI = 1 makes f_printf() support long long argument and FF_PRINT_FLOAT = 1/2
makes f_printf() support floating point argument. These features want C99 or later. / makes f_printf() support floating point argument. These features want C99 or later.
/ When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character / When FF_LFN_UNICODE >= 1 with LFN enabled, string functions convert the character
/ encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE / encoding in it. FF_STRF_ENCODE selects assumption of character encoding ON THE FILE
/ to be read/written via those functions. / to be read/written via those functions.
@ -113,8 +113,8 @@
*/ */
#define FF_USE_LFN 1 #define FF_USE_LFN 0
#define FF_MAX_LFN 255 #define FF_MAX_LFN 127
/* The FF_USE_LFN switches the support for LFN (long file name). /* The FF_USE_LFN switches the support for LFN (long file name).
/ /
/ 0: Disable LFN. FF_MAX_LFN has no effect. / 0: Disable LFN. FF_MAX_LFN has no effect.
@ -170,26 +170,27 @@
/* Number of volumes (logical drives) to be used. (1-10) */ /* Number of volumes (logical drives) to be used. (1-10) */
#define FF_STR_VOLUME_ID 2 #define FF_STR_VOLUME_ID 1
// #define FF_VOLUME_STRS "S,F,H" // #define FF_VOLUME_STRS "SD","SD2"
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid / logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are / characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is / compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as: / not defined, a user defined volume string table is needed as:
/ /
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",... / const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/ */
#define FF_MULTI_PARTITION 0 #define FF_MULTI_PARTITION 0
/* This option switches support for multiple volumes on the physical drive. /* This option switches support for multiple volumes on the physical drive.
/ By default (0), each logical drive number is bound to the same physical drive / By default (0), each logical drive number is bound to the same physical drive
/ number and only an FAT volume found on the physical drive will be mounted. / number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to / When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk() / arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */ / function will be available. */
#define FF_MIN_SS 512 #define FF_MIN_SS 512
@ -237,12 +238,12 @@
#define FF_FS_NORTC 1 #define FF_FS_NORTC 1
#define FF_NORTC_MON 1 #define FF_NORTC_MON 2
#define FF_NORTC_MDAY 1 #define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2020 #define FF_NORTC_YEAR 2024
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have /* The option FF_FS_NORTC switches timestamp feature. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable / an RTC or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable the
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp / timestamp feature. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time. / defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be / To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON, / added to the project to read current time form real-time clock. FF_NORTC_MON,
@ -252,7 +253,7 @@
#define FF_FS_NOFSINFO 0 #define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this /* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force / option, and f_getfree() function at the first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number. / a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/ /
/ bit0=0: Use free cluster count in the FSINFO if available. / bit0=0: Use free cluster count in the FSINFO if available.
@ -274,26 +275,21 @@
/ lock control is independent of re-entrancy. */ / lock control is independent of re-entrancy. */
/* #include <somertos.h> // O/S definitions */
#define FF_FS_REENTRANT 0 #define FF_FS_REENTRANT 0
#define FF_FS_TIMEOUT 1000 #define FF_FS_TIMEOUT 1000
#define FF_SYNC_t HANDLE
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs /* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different / module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs() / volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access / and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function. / to the same volume is under control of this featuer.
/ /
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect. / 0: Disable re-entrancy. FF_FS_TIMEOUT have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers, / 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj() / ff_mutex_create(), ff_mutex_delete(), ff_mutex_take() and ff_mutex_give()
/ function, must be added to the project. Samples are available in / function, must be added to the project. Samples are available in ffsystem.c.
/ option/syscall.c.
/ /
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick. / The FF_FS_TIMEOUT defines timeout period in unit of O/S time tick.
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*, */
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */

275
src/fatfs/ffconf_new.h Normal file
View file

@ -0,0 +1,275 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
#ifndef _FFCONF
#define _FFCONF 32020 /* Revision ID */
/*-----------------------------------------------------------------------------/
/ Additional user header to be used
/-----------------------------------------------------------------------------*/
#include "main.h"
#include "stm32f3xx_hal.h"
/*-----------------------------------------------------------------------------/
/ Functions and Buffer Configurations
/-----------------------------------------------------------------------------*/
#define _FS_TINY 0 /* 0:Normal or 1:Tiny */
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
/ bytes. Instead of private sector buffer eliminated from the file object,
/ common sector buffer in the file system object (FATFS) is used for the file
/ data transfer. */
#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define _FS_MINIMIZE 0 /* 0 to 3 */
/* This option defines minimization level to remove some basic API functions.
/
/ 0: All basic functions are enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
/ f_truncate() and f_rename() function are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define _USE_STRFUNC 2 /* 0:Disable or 1-2:Enable */
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 0
/* This option switches filtered directory read feature and related functions,
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
#define _USE_MKFS 1
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 1
/* This option switches fast seek feature. (0:Disable or 1:Enable) */
#define _USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable)
/ To enable it, also _FS_TINY need to be set to 1. */
/*-----------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/-----------------------------------------------------------------------------*/
#define _CODE_PAGE 850
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 932 - Japanese Shift_JIS (DBCS, OEM, Windows)
/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
/ 949 - Korean (DBCS, OEM, Windows)
/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
/ 1250 - Central Europe (Windows)
/ 1251 - Cyrillic (Windows)
/ 1252 - Latin 1 (Windows)
/ 1253 - Greek (Windows)
/ 1254 - Turkish (Windows)
/ 1255 - Hebrew (Windows)
/ 1256 - Arabic (Windows)
/ 1257 - Baltic (Windows)
/ 1258 - Vietnam (OEM, Windows)
/ 437 - U.S. (OEM)
/ 720 - Arabic (OEM)
/ 737 - Greek (OEM)
/ 775 - Baltic (OEM)
/ 850 - Multilingual Latin 1 (OEM)
/ 858 - Multilingual Latin 1 + Euro (OEM)
/ 852 - Latin 2 (OEM)
/ 855 - Cyrillic (OEM)
/ 866 - Russian (OEM)
/ 857 - Turkish (OEM)
/ 862 - Hebrew (OEM)
/ 874 - Thai (OEM, Windows)
/ 1 - ASCII (No extended character. Valid for only non-LFN configuration.) */
#define _USE_LFN 0 /* 0 to 3 */
#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
/* The _USE_LFN option switches the LFN feature.
/
/ 0: Disable LFN feature. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
/ to 1. This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 3
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/
/ 0: ANSI/OEM
/ 1: UTF-16LE
/ 2: UTF-16BE
/ 3: UTF-8
/
/ When _LFN_UNICODE is 0, this option has no effect. */
#define _FS_RPATH 0 /* 0 to 2 */
/* This option configures relative path feature.
/
/ 0: Disable relative path feature and remove related functions.
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
/
/ Note that directory items read via f_readdir() are affected by this option. */
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/----------------------------------------------------------------------------*/
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */
/* USER CODE BEGIN Volumes */
#define _STR_VOLUME_ID 0 /* 0:Use only 0-9 for drive ID, 1:Use strings for drive ID */
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
/* _STR_VOLUME_ID option switches string volume ID feature.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
/* USER CODE END Volumes */
#define _MULTI_PARTITION 0 /* 0:Single partition, 1:Multiple partition */
/* This option switches multi-partition feature. By default (0), each logical drive
/ number is bound to the same physical drive number and only an FAT volume found on
/ the physical drive will be mounted. When multi-partition feature is enabled (1),
/ each logical drive number is bound to arbitrary physical drive and partition
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
#define _MIN_SS 512 /* 512, 1024, 2048 or 4096 */
#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
/* These options configure the range of sector size to be supported. (512, 1024,
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _USE_TRIM 0
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define _FS_NOFSINFO 0 /* 0,1,2 or 3 */
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/----------------------------------------------------------------------------*/
#define _FS_NORTC 0
#define _NORTC_MON 6
#define _NORTC_MDAY 4
#define _NORTC_YEAR 2015
/* The _FS_NORTC option switches timestamp feature. If the system does not have
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
/ to be added to the project to read current time form RTC. _NORTC_MON,
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
#define _FS_LOCK 2 /* 0:Disable or >=1:Enable */
/* The _FS_LOCK option switches file lock feature to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
/ is 1.
/
/ 0: Disable file lock feature. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock feature. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock feature is independent of re-entrancy. */
#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */
#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
#define _SYNC_t NULL
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this feature.
/
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc.. */
#define _WORD_ACCESS 0 /* 0 or 1 */
/* The _WORD_ACCESS option is an only platform dependent option. It defines
/ which access method is used to the word data on the FAT volume.
/
/ 0: Byte-by-byte access. Always compatible with all platforms.
/ 1: Word access. Do not choose this unless under both the following conditions.
/
/ * Address misaligned memory access is always allowed to ALL instructions.
/ * Byte order on the memory is little-endian.
/
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
/ Following table shows allowable settings of some processor types.
/
/ ARM7TDMI 0 ColdFire 0 V850E 0
/ Cortex-M3 0 Z80 0/1 V850ES 0/1
/ Cortex-M0 0 x86 0/1 TLCS-870 0/1
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
/ AVR32 0 RL78 0 R32C 0
/ PIC18 0/1 SH-2 0 M16C 0/1
/ PIC24 0 H8S 0 MSP430 0
/ PIC32 0 H8/300H 0 8051 0/1
*/
#endif /* _FFCONF */

View file

@ -1,170 +1,208 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */ /* A Sample Code of User Provided OS Dependent Functions for FatFs */
/* (C)ChaN, 2018 */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include "ff.h" #include "ff.h"
#if FF_USE_LFN == 3 /* Dynamic memory allocation */ #if FF_USE_LFN == 3 /* Use dynamic memory allocation */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Allocate a memory block */ /* Allocate/Free a Memory Block */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#include <stdlib.h> /* with POSIX API */
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */ void* ff_memalloc ( /* Returns pointer to the allocated memory block (null if not enough core) */
UINT msize /* Number of bytes to allocate */ UINT msize /* Number of bytes to allocate */
) )
{ {
return malloc(msize); /* Allocate a new memory block with POSIX API */ return malloc((size_t)msize); /* Allocate a new memory block */
} }
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree ( void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do if null) */ void* mblock /* Pointer to the memory block to free (no effect if null) */
) )
{ {
free(mblock); /* Free the memory block with POSIX API */ free(mblock); /* Free the memory block */
} }
#endif #endif
#if FF_FS_REENTRANT /* Mutal exclusion */ #if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Create a Synchronization Object */ /* Definitions of Mutex */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object for the volume, such as semaphore and mutex.
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
//const osMutexDef_t Mutex[FF_VOLUMES]; /* Table of CMSIS-RTOS mutex */ #define OS_TYPE 0 /* 0:Win32, 1:uITRON4.0, 2:uC/OS-II, 3:FreeRTOS, 4:CMSIS-RTOS */
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */ #if OS_TYPE == 0 /* Win32 */
BYTE vol, /* Corresponding volume (logical drive number) */ #include <windows.h>
FF_SYNC_t* sobj /* Pointer to return the created sync object */ static HANDLE Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
)
{
/* Win32 */
*sobj = CreateMutex(NULL, FALSE, NULL);
return (int)(*sobj != INVALID_HANDLE_VALUE);
/* uITRON */ #elif OS_TYPE == 1 /* uITRON */
// T_CSEM csem = {TA_TPRI,1,1}; #include "itron.h"
// *sobj = acre_sem(&csem); #include "kernel.h"
// return (int)(*sobj > 0); static mtxid Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
/* uC/OS-II */ #elif OS_TYPE == 2 /* uc/OS-II */
// OS_ERR err; #include "includes.h"
// *sobj = OSMutexCreate(0, &err); static OS_EVENT *Mutex[FF_VOLUMES + 1]; /* Table of mutex pinter */
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */ #elif OS_TYPE == 3 /* FreeRTOS */
// *sobj = xSemaphoreCreateMutex(); #include "FreeRTOS.h"
// return (int)(*sobj != NULL); #include "semphr.h"
static SemaphoreHandle_t Mutex[FF_VOLUMES + 1]; /* Table of mutex handle */
/* CMSIS-RTOS */ #elif OS_TYPE == 4 /* CMSIS-RTOS */
// *sobj = osMutexCreate(&Mutex[vol]); #include "cmsis_os.h"
// return (int)(*sobj != NULL); static osMutexId Mutex[FF_VOLUMES + 1]; /* Table of mutex ID */
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
/* Win32 */
return (int)CloseHandle(sobj);
/* uITRON */
// return (int)(del_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err);
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// vSemaphoreDelete(sobj);
// return 1;
/* CMSIS-RTOS */
// return (int)(osMutexDelete(sobj) == osOK);
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
FF_SYNC_t sobj /* Sync object to wait */
)
{
/* Win32 */
return (int)(WaitForSingleObject(sobj, FF_FS_TIMEOUT) == WAIT_OBJECT_0);
/* uITRON */
// return (int)(wai_sem(sobj) == E_OK);
/* uC/OS-II */
// OS_ERR err;
// OSMutexPend(sobj, FF_FS_TIMEOUT, &err));
// return (int)(err == OS_NO_ERR);
/* FreeRTOS */
// return (int)(xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE);
/* CMSIS-RTOS */
// return (int)(osMutexWait(sobj, FF_FS_TIMEOUT) == osOK);
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
FF_SYNC_t sobj /* Sync object to be signaled */
)
{
/* Win32 */
ReleaseMutex(sobj);
/* uITRON */
// sig_sem(sobj);
/* uC/OS-II */
// OSMutexPost(sobj);
/* FreeRTOS */
// xSemaphoreGive(sobj);
/* CMSIS-RTOS */
// osMutexRelease(sobj);
}
#endif #endif
/*------------------------------------------------------------------------*/
/* Create a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to create a new mutex
/ or semaphore for the volume. When a 0 is returned, the f_mount function
/ fails with FR_INT_ERR.
*/
int ff_mutex_create ( /* Returns 1:Function succeeded or 0:Could not create the mutex */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
Mutex[vol] = CreateMutex(NULL, FALSE, NULL);
return (int)(Mutex[vol] != INVALID_HANDLE_VALUE);
#elif OS_TYPE == 1 /* uITRON */
T_CMTX cmtx = {TA_TPRI,1};
Mutex[vol] = acre_mtx(&cmtx);
return (int)(Mutex[vol] > 0);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
Mutex[vol] = OSMutexCreate(0, &err);
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
Mutex[vol] = xSemaphoreCreateMutex();
return (int)(Mutex[vol] != NULL);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDef(cmsis_os_mutex);
Mutex[vol] = osMutexCreate(osMutex(cmsis_os_mutex));
return (int)(Mutex[vol] != NULL);
#endif
}
/*------------------------------------------------------------------------*/
/* Delete a Mutex */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount function to delete a mutex or
/ semaphore of the volume created with ff_mutex_create function.
*/
void ff_mutex_delete ( /* Returns 1:Function succeeded or 0:Could not delete due to an error */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
CloseHandle(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
del_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexDel(Mutex[vol], OS_DEL_ALWAYS, &err);
#elif OS_TYPE == 3 /* FreeRTOS */
vSemaphoreDelete(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexDelete(Mutex[vol]);
#endif
}
/*------------------------------------------------------------------------*/
/* Request a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on enter file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_mutex_take ( /* Returns 1:Succeeded or 0:Timeout */
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
return (int)(WaitForSingleObject(Mutex[vol], FF_FS_TIMEOUT) == WAIT_OBJECT_0);
#elif OS_TYPE == 1 /* uITRON */
return (int)(tloc_mtx(Mutex[vol], FF_FS_TIMEOUT) == E_OK);
#elif OS_TYPE == 2 /* uC/OS-II */
OS_ERR err;
OSMutexPend(Mutex[vol], FF_FS_TIMEOUT, &err));
return (int)(err == OS_NO_ERR);
#elif OS_TYPE == 3 /* FreeRTOS */
return (int)(xSemaphoreTake(Mutex[vol], FF_FS_TIMEOUT) == pdTRUE);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
return (int)(osMutexWait(Mutex[vol], FF_FS_TIMEOUT) == osOK);
#endif
}
/*------------------------------------------------------------------------*/
/* Release a Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leave file functions to unlock the volume.
*/
void ff_mutex_give (
int vol /* Mutex ID: Volume mutex (0 to FF_VOLUMES - 1) or system mutex (FF_VOLUMES) */
)
{
#if OS_TYPE == 0 /* Win32 */
ReleaseMutex(Mutex[vol]);
#elif OS_TYPE == 1 /* uITRON */
unl_mtx(Mutex[vol]);
#elif OS_TYPE == 2 /* uC/OS-II */
OSMutexPost(Mutex[vol]);
#elif OS_TYPE == 3 /* FreeRTOS */
xSemaphoreGive(Mutex[vol]);
#elif OS_TYPE == 4 /* CMSIS-RTOS */
osMutexRelease(Mutex[vol]);
#endif
}
#endif /* FF_FS_REENTRANT */

View file

@ -1,13 +1,13 @@
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode handling functions for FatFs R0.13+ */ /* Unicode Handling Functions for FatFs R0.13 and Later */
/*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .rodata section when the */
/* FatFs is configured for LFN with DBCS. If the system has a Unicode */
/* library for the code conversion, this module should be modified to use */
/* it to avoid silly memory consumption. */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* This module will occupy a huge memory in the .const section when the /
/ FatFs is configured for LFN with DBCS. If the system has any Unicode /
/ utilitiy for the code conversion, this module should be modified to use /
/ that function to avoid silly memory consumption. /
/-------------------------------------------------------------------------*/
/* /*
/ Copyright (C) 2014, ChaN, all right reserved. / Copyright (C) 2022, ChaN, all right reserved.
/ /
/ FatFs module is an open source software. Redistribution and use of FatFs in / FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided / source and binary forms, with or without modification, are permitted provided
@ -25,7 +25,7 @@
#include "ff.h" #include "ff.h"
#if FF_USE_LFN /* This module will be blanked if non-LFN configuration */ #if FF_USE_LFN != 0 /* This module will be blanked if in non-LFN configuration */
#define MERGE2(a, b) a ## b #define MERGE2(a, b) a ## b
#define CVTBL(tbl, cp) MERGE2(tbl, cp) #define CVTBL(tbl, cp) MERGE2(tbl, cp)
@ -15214,8 +15214,8 @@ static const WCHAR uc869[] = { /* CP869(Greek 2) to Unicode conversion table */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */ /* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* SBCS fixed code page */ /* SBCS Fixed Code Page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900 #if FF_CODE_PAGE != 0 && FF_CODE_PAGE < 900
@ -15225,7 +15225,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
) )
{ {
WCHAR c = 0; WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR* p = CVTBL(uc, FF_CODE_PAGE);
if (uni < 0x80) { /* ASCII? */ if (uni < 0x80) { /* ASCII? */
@ -15247,7 +15247,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
) )
{ {
WCHAR c = 0; WCHAR c = 0;
const WCHAR *p = CVTBL(uc, FF_CODE_PAGE); const WCHAR* p = CVTBL(uc, FF_CODE_PAGE);
if (oem < 0x80) { /* ASCII? */ if (oem < 0x80) { /* ASCII? */
@ -15267,8 +15267,8 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for static code page configuration */ /* OEM <==> Unicode Conversions for Static Code Page Configuration with */
/* DBCS fixed code page */ /* DBCS Fixed Code Page */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE >= 900 #if FF_CODE_PAGE >= 900
@ -15277,7 +15277,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0, uc; WCHAR c = 0, uc;
UINT i = 0, n, li, hi; UINT i = 0, n, li, hi;
@ -15313,7 +15313,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0; WCHAR c = 0;
UINT i = 0, n, li, hi; UINT i = 0, n, li, hi;
@ -15346,7 +15346,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* OEM <==> Unicode conversions for dynamic code page configuration */ /* OEM <==> Unicode Conversions for Dynamic Code Page Configuration */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
#if FF_CODE_PAGE == 0 #if FF_CODE_PAGE == 0
@ -15360,7 +15360,7 @@ WCHAR ff_uni2oem ( /* Returns OEM code character, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0, uc; WCHAR c = 0, uc;
UINT i, n, li, hi; UINT i, n, li, hi;
@ -15412,7 +15412,7 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
WORD cp /* Code page for the conversion */ WORD cp /* Code page for the conversion */
) )
{ {
const WCHAR *p; const WCHAR* p;
WCHAR c = 0; WCHAR c = 0;
UINT i, n, li, hi; UINT i, n, li, hi;
@ -15458,14 +15458,14 @@ WCHAR ff_oem2uni ( /* Returns Unicode character in UTF-16, zero on error */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
/* Unicode up-case conversion */ /* Unicode Up-case Conversion */
/*------------------------------------------------------------------------*/ /*------------------------------------------------------------------------*/
DWORD ff_wtoupper ( /* Returns up-converted code point */ DWORD ff_wtoupper ( /* Returns up-converted code point */
DWORD uni /* Unicode code point to be up-converted */ DWORD uni /* Unicode code point to be up-converted */
) )
{ {
const WORD *p; const WORD* p;
WORD uc, bc, nc, cmd; WORD uc, bc, nc, cmd;
static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */ static const WORD cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
/* Basic Latin */ /* Basic Latin */
@ -15590,4 +15590,4 @@ DWORD ff_wtoupper ( /* Returns up-converted code point */
} }
#endif /* #if FF_USE_LFN */ #endif /* #if FF_USE_LFN != 0 */

95
src/fatfs/toolbox_bdev.c Normal file
View file

@ -0,0 +1,95 @@
/**
* @file toolbox_bdev.h
* @author your name (you@domain.com)
* @brief Connector module to allow FatFS to use Foenix Toolkit block devices
* @version 0.1
* @date 2024-07-06
*
* @copyright Copyright (c) 2024
*
*/
#include "log_level.h"
#define DEFAULT_LOG_LEVEL LOG_ERROR
#include <stdio.h>
#include <ctype.h>
#include "log.h"
#include "toolbox_bdev.h"
#include "constants.h"
#include "errors.h"
#include "dev/block.h"
/**
* @brief Convert Toolkit Block Device result codes to FatFS result codes
*
* @param result Toolkit result code
* @return DRESULT a corresponding result code
*/
static DRESULT bdev_to_fatfs(short result) {
if (result < 0) {
switch(result) {
case DEV_WRITEPROT:
return RES_WRPRT;
case ERR_NOT_READY:
return RES_NOTRDY;
case ERR_BAD_ARGUMENT:
return RES_PARERR;
default:
return RES_ERROR;
}
}
return RES_OK;
}
DSTATUS disk_initialize(BYTE pdrv) {
return (DSTATUS)bdev_init(pdrv);
}
DSTATUS disk_status(BYTE pdrv) {
DSTATUS result = (DSTATUS)bdev_status(pdrv);
INFO1("disk_status: %02X", result);
return result;
}
static void sector_dump(uint8_t * buffer, int count) {
char char_buffer[17];
printf("Sector:\n");
short index = 0;
for (int i = 0; i < count; i++) {
char c = buffer[i];
if ((i & 0xf) == 0) {
printf("\n");
}
printf("%02X ", c);
}
}
DRESULT disk_read(BYTE pdrv, BYTE* buff, LBA_t sector, UINT count) {
short result = bdev_read(pdrv, sector, buff, 512 * count);
INFO2("disk_read: sector #%u result %d", sector, result);
// sector_dump(buff, 512);
return bdev_to_fatfs(result);
}
DRESULT disk_write(BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count) {
short result = bdev_write(pdrv, sector, buff, 512 * count);
INFO2("disk_write: sector #%u result %d", sector, result);
return bdev_to_fatfs(result);
}
DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void* buff) {
short result = bdev_ioctrl(pdrv, cmd, buff, 0);
INFO1("disk_ioctl: %d", result);
return bdev_to_fatfs(result);
}

86
src/fatfs/toolbox_bdev.h Normal file
View file

@ -0,0 +1,86 @@
/**
* @file toolbox_bdev.h
* @author your name (you@domain.com)
* @brief Connector module to allow FatFS to use Foenix Toolkit block devices
* @version 0.1
* @date 2024-07-06
*
* @copyright Copyright (c) 2024
*
*/
#ifndef __toolbox_bdev_h__
#define __toolbox_bdev_h__
#include "ff.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -1,14 +0,0 @@
/*
* Definitions for access to the SDC controller
*/
#ifndef __SDC_C256_H
#define __SDC_C256_H
#include <stdint.h>
#define SDC_BASE ((volatile uint8_t *)0xf01d00)
// TODO: fill out with the actual registers
#endif

View file

@ -0,0 +1,30 @@
/*
* Definitions for access to the SDC controller using the SPI interface
*/
#ifndef __SDC_SPI_H
#define __SDC_SPI_H
#include <stdint.h>
/**
* @brief Structure to manage the SPI driven SDC ports
*
*/
typedef struct s_sdc_spi {
uint8_t ctrl;
uint8_t data;
} t_sdc_spi, *p_sdc_spi;
#define SDx_CS 0x01 // 1 = Enable
#define SDx_SLOW 0x02 // 1 = Slow 400Khz, 0 = 25Mhz
#define SDx_BUSY 0x80 // 1 = Busy
#define SD0_REG ((volatile __attribute__((far)) p_sdc_spi)0xf016a0)
#define SD1_REG ((volatile __attribute__((far)) p_sdc_spi)0xf01d80)
#define SD0_STAT (*(volatile __far uint8_t *)0xf016a0)
#define SD0_STAT_CD 0x40 // When 1 = No Card, 0 = Card is Present
#define SD0_STAT_WP 0x80 // When 0 = Writeable, 1 = Card is Protected
#endif

View file

@ -47,9 +47,10 @@
* Block devices * Block devices
*/ */
#define BDEV_SDC 0 #define BDEV_SD0 0
#define BDEV_FDC 1 #define BDEV_SD1 1
#define BDEV_HDC 2 #define BDEV_FDC 2
#define BDEV_HDC 3
/* /*
* Channel devices * Channel devices
@ -63,4 +64,13 @@
#define CDEV_MIDI 5 #define CDEV_MIDI 5
#define CDEV_FILE 6 #define CDEV_FILE 6
/*
* Block Device IOCRTRL commands
*/
#define IOCTRL_CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define IOCTRL_GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define IOCTRL_GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define IOCTRL_GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#endif #endif

View file

@ -49,5 +49,6 @@
#define ERR_NOT_SUPPORTED -37 /* Device does not support the file or operation */ #define ERR_NOT_SUPPORTED -37 /* Device does not support the file or operation */
#define ERR_BAD_ARGUMENT -38 /* An invalid argument was provided */ #define ERR_BAD_ARGUMENT -38 /* An invalid argument was provided */
#define ERR_MEDIA_CHANGE -39 /* Removable media has changed */ #define ERR_MEDIA_CHANGE -39 /* Removable media has changed */
#define ERR_NOT_READY -40 /* Media device is not ready */
#endif #endif

View file

@ -112,12 +112,13 @@ typedef struct s_sys_info {
typedef struct s_dev_block { typedef struct s_dev_block {
short number; // The number of the device (assigned by registration) short number; // The number of the device (assigned by registration)
char * name; // The name of the device char * name; // The name of the device
FUNC_V_2_S init; // short init() -- Initialize the device void * data; // Device-specific data block
FUNC_LBS_2_S read; // short read(long lba, byte * buffer, short size) -- Read a block from the device short (*init)(struct s_dev_block *); // Initialize the device
FUNC_LcBS_2_S write; // short write(long lba, byte * buffer, short size) -- Write a block to the device short (*read)(struct s_dev_block *, long lba, uint8_t * buffer, short size); // Read a block from the device
FUNC_V_2_S status; // short status() -- Get the status of the device short (*write)(struct s_dev_block *, long lba, const uint8_t * buffer, short size); // Write a block to the device
FUNC_V_2_S flush; // short flush() -- Ensure that any pending writes to teh device have been completed short (*status)(struct s_dev_block *); // Get the status of the device
FUNC_SBS_2_S ioctrl; // short ioctrl(short command, byte * buffer, short size)) -- Issue a control command to the device short (*flush)(struct s_dev_block *); // Ensure that any pending writes to the device have been completed
short (*ioctrl)(struct s_dev_block *, short command, unsigned char * buffer, short size); // Issue a control command to the device
} t_dev_block, *p_dev_block; } t_dev_block, *p_dev_block;
/* /*

View file

@ -6,6 +6,7 @@
#define DEFAULT_LOG_LEVEL LOG_INFO #define DEFAULT_LOG_LEVEL LOG_INFO
#define LOG_CHANNEL LOG_CHANNEL_UART0 #define LOG_CHANNEL LOG_CHANNEL_UART0
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -35,6 +36,7 @@
#elif MODEL == MODEL_FOENIX_F256 || MODEL == MODEL_FOENIX_F256K || MODEL == MODEL_FOENIX_F256K2 #elif MODEL == MODEL_FOENIX_F256 || MODEL == MODEL_FOENIX_F256K || MODEL == MODEL_FOENIX_F256K2
#include "dev/txt_f256.h" #include "dev/txt_f256.h"
#include "dev/kbd_f256k.h" #include "dev/kbd_f256k.h"
#include "dev/sdc_f256.h"
#endif #endif
#include "syscalls.h" #include "syscalls.h"
@ -214,11 +216,11 @@ void initialize() {
} }
#endif #endif
// if ((res = sdc_install())) { if ((res = sdc_install())) {
// ERROR1("FAILED: SDC driver installation %d", res); ERROR1("FAILED: SDC driver installation %d", res);
// } else { } else {
// INFO("SDC driver installed."); INFO("SDC driver installed.");
// } }
#if HAS_FLOPPY #if HAS_FLOPPY
if ((res = fdc_install())) { if ((res = fdc_install())) {
@ -266,17 +268,41 @@ void initialize() {
// log(LOG_INFO, "Serial ports initialized."); // log(LOG_INFO, "Serial ports initialized.");
// } // }
// if ((res = fsys_init())) { if ((res = fsys_init())) {
// log_num(LOG_ERROR, "FAILED: file system initialization", res); log_num(LOG_ERROR, "FAILED: file system initialization", res);
// } else { } else {
// INFO("File system initialized."); INFO("File system initialized.");
// } }
} }
char dec2hex(uint8_t x) { t_file_info dir;
char * hex_digits = "0123456789ABCDEF"; uint8_t buffer[512];
return hex_digits[x & 0x0f];
void dump(uint8_t * buffer, int count) {
char char_buffer[17];
printf("\n");
short index = 0;
for (int i = 0; i < count; i++) {
if ((i > 0) && (i % 16 == 0)) {
index = 0;
char_buffer[16] = 0;
printf(" %s\n", char_buffer);
} else if (i > 0) {
char c = buffer[i];
printf("%02X ", c);
if (isalpha(c) || isdigit(c)) {
char_buffer[index++] = c;
} else {
char_buffer[index++] = '.';
}
}
}
printf(" %s\n", char_buffer);
} }
int main(int argc, char * argv[]) { int main(int argc, char * argv[]) {
@ -286,17 +312,52 @@ int main(int argc, char * argv[]) {
initialize(); initialize();
kbd_init(); short fd = fsys_opendir("0:/");
printf("\n> "); if (fd > -1) {
chan_ioctrl(0, CON_IOCTRL_ECHO_OFF, 0, 0); INFO("fsys_opendir");
while (!kbd_break()) {
char c = chan_read_b(0); short result = fsys_readdir(fd, &dir);
if (c != 0) { while (result == 0) {
chan_write_b(0, c); if (dir.name[0] != 0) {
} printf("%s\n", dir.name);
} else {
break;
} }
printf("\nDone.\n"); result = fsys_readdir(fd, &dir);
}
fsys_closedir(fd);
INFO("fsys_closedir");
} else {
ERROR1("Could not open directory %d", fd);
}
// kbd_init();
// printf("\n> ");
// chan_ioctrl(0, CON_IOCTRL_ECHO_OFF, 0, 0);
// while (!kbd_break()) {
// char c = chan_read_b(0);
// if (c != 0) {
// chan_write_b(0, c);
// }
// }
// INFO("bdev_init");
// short status = bdev_init(BDEV_SD0);
// if (status) {
// ERROR1("bdev_init returned %d", status);
// }
// INFO("bdev_read");
// status = bdev_read(BDEV_SD0, 97, buffer, 512);
// if (status < 512) {
// ERROR1("bdev_read returned %d", status);
// }
// INFO("Read.");
// dump(buffer, 512);
// printf("\nDone.\n");
// Attempt to start up the user code // Attempt to start up the user code
// log(LOG_INFO, "Looking for user startup code:"); // log(LOG_INFO, "Looking for user startup code:");