1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
|
/*-----------------------------------------------------------------------*/
/* Dual-disk wrapper allowing operating of two different drives */
/* underneath the FatFs layer without modification of the existing */
/* single-unit drivers for those drives. */
/* */
/* This file was modified from a sample driver available from the FatFs */
/* web site. */
/*-----------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_types.h"
#include "fatfs/src/diskio.h"
#include "fatfs/src/ff.h"
/*-----------------------------------------------------------------------*/
/* Configuration */
/*-----------------------------------------------------------------------*/
/* This wrapper allows two independent, low level, single drive FatFs */
/* drivers to be used simultaneously to provide a FatFs implementation */
/* with two physical drives. Configuration is set using two #define */
/* labels, one each from the following two groups, to indicate which */
/* drivers to use for each of the logical drives supported. */
/* */
/* DISK0_EK_LM4F232H5QD - Logical disk 0 is an EK-LM4F232H5QD SD Card. */
/* DISK0_USB_MSC - Logical disk 0 is a USB Mass Storage Class */
/* device. */
/* */
/* DISK1_EK_LM4F232H5QD - Logical disk 1 is an EK-LM4F232H5QD SD Card. */
/* DISK1_USB_MSC - Logical disk 1 is a USB Mass Storage Class */
/* device. */
/* */
/* The same driver cannot be used to support both logical drives. */
/* */
/* Note that the USB MSC driver does not support a timer function so we */
/* need to undef DRIVEn_TIMERPROC whenever this driver is configured. */
/*-----------------------------------------------------------------------*/
#if defined(DISK0_EK_LM4F232H5QD)
#define DRIVE0_DRIVER "mmc-ek-lm4f232.c"
#define DRIVE0_TIMERPROC disk0_timerproc
#elif defined(DISK0_DK_TM4C123G)
#define DRIVE0_DRIVER "mmc-dk-tm4c123g.c"
#define DRIVE0_TIMERPROC disk0_timerproc
#elif defined(DISK0_DK_TM4C129XNCZAD)
#define DRIVE0_DRIVER "mmc-dk-tm4c129x.c"
#define DRIVE0_TIMERPROC disk0_timerproc
#elif defined(DISK0_USB_MSC)
#define DRIVE0_DRIVER "fat_usbmsc.c"
#undef DRIVE0_TIMERPROC
#else
#error "Unrecognized/undefined driver for DISK0!"
#endif
#if defined(DISK1_EK_LM4F232H5QD)
#define DRIVE1_DRIVER "mmc-ek-lm4f232.c"
#define DRIVE1_TIMERPROC disk1_timerproc
#elif defined(DISK1_DK_TM4C123G)
#define DRIVE1_DRIVER "mmc-dk-tm4c123g.c"
#define DRIVE1_TIMERPROC disk1_timerproc
#elif defined(DISK1_DK_TM4C129XNCZAD)
#define DRIVE1_DRIVER "mmc-dk-tm4c129x.c"
#define DRIVE1_TIMERPROC disk1_timerproc
#elif defined(DISK1_USB_MSC)
#define DRIVE1_DRIVER "fat_usbmsc.c"
#undef DRIVE0_TIMERPROC
#else
#error "Unrecognized/undefined driver for DISK1!"
#endif
/*-----------------------------------------------------------------------*/
/* The first low level driver */
/*-----------------------------------------------------------------------*/
#define disk_initialize disk0_initialize
#define disk_status disk0_status
#define disk_read disk0_read
#define disk_write disk0_write
#define disk_ioctl disk0_ioctl
#define disk_timerproc disk0_timerproc
#define get_fattime disk0_get_fattime
#include DRIVE0_DRIVER
#undef disk_initialize
#undef disk_status
#undef disk_read
#undef disk_write
#undef disk_ioctl
#undef disk_timerproc
#undef get_fattime
/*-----------------------------------------------------------------------*/
/* The second low level driver */
/*-----------------------------------------------------------------------*/
#define disk_initialize disk1_initialize
#define disk_status disk1_status
#define disk_read disk1_read
#define disk_write disk1_write
#define disk_ioctl disk1_ioctl
#define disk_timerproc disk1_timerproc
#define get_fattime disk1_get_fattime
#include DRIVE1_DRIVER
#undef disk_initialize
#undef disk_status
#undef disk_read
#undef disk_write
#undef disk_ioctl
#undef disk_timerproc
#undef get_fattime
/*-----------------------------------------------------------------------*/
/* Timer tick function. */
/*-----------------------------------------------------------------------*/
/* When using an SD card driver, this function must be called every 10mS */
/* by the application code. Note that this is not part of the device */
/* driver interface that is called directly by FatFs. */
/* */
void disk_timerproc (void)
{
#ifdef DRIVE0_TIMERPROC
disk0_timerproc();
#endif
#ifdef DRIVE1_TIMERPROC
disk1_timerproc();
#endif
}
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS
disk_initialize(
BYTE bValue) /* Physical drive number */
{
/* Depending upon the physical drive, call the relevant low level */
/* driver. Note that we call each with physical drive number 0 since the */
/* low level drivers typically expect this (they only support a single */
/* drive). */
if(bValue == 0)
{
return(disk0_initialize(0));
}
else
{
return(disk1_initialize(0));
}
}
/*-----------------------------------------------------------------------*/
/* Returns the current status of a drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE drv) /* Physical drive number */
{
/* Depending upon the physical drive, call the relevant low level */
/* driver. Note that we call each with physical drive number 0 since the */
/* low level drivers typically expect this (they only support a single */
/* drive). */
if(drv == 0)
{
return(disk0_status(0));
}
else
{
return(disk1_status(0));
}
}
/*-----------------------------------------------------------------------*/
/* This function reads sector(s) from the disk drive */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE drv, /* Physical drive number */
BYTE* buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Sector number */
BYTE count) /* Sector count (1..255) */
{
/* Depending upon the physical drive, call the relevant low level */
/* driver. Note that we call each with physical drive number 0 since the */
/* low level drivers typically expect this (they only support a single */
/* drive). */
if(drv == 0)
{
return(disk0_read(0, buff, sector, count));
}
else
{
return(disk1_read(0, buff, sector, count));
}
}
/*-----------------------------------------------------------------------*/
/* This function writes sector(s) to the disk drive */
/*-----------------------------------------------------------------------*/
#if _READONLY == 0
DRESULT disk_write (
BYTE ucDrive, /* Physical drive number (0) */
const BYTE* buff, /* Pointer to the data to be written */
DWORD sector, /* Sector number */
BYTE count) /* Sector count (1..255) */
{
/* Depending upon the physical drive, call the relevant low level */
/* driver. Note that we call each with physical drive number 0 since the */
/* low level drivers typically expect this (they only support a single */
/* drive). */
if(ucDrive == 0)
{
return(disk0_write(0, buff, sector, count));
}
else
{
return(disk1_write(0, buff, sector, count));
}
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE drv, /* Physical drive number (0) */
BYTE ctrl, /* Control code */
void *buff) /* Buffer to send/receive control data */
{
/* Depending upon the physical drive, call the relevant low level */
/* driver. Note that we call each with physical drive number 0 since the */
/* low level drivers typically expect this (they only support a single */
/* drive). */
if(drv == 0)
{
return(disk0_ioctl(0, ctrl, buff));
}
else
{
return(disk1_ioctl(0, ctrl, buff));
}
}
/*---------------------------------------------------------*/
/* User Provided Timer Function for FatFs module */
/*---------------------------------------------------------*/
/* This is a real time clock service to be called from */
/* FatFs module. Any valid time must be returned even if */
/* the system does not support a real time clock. */
/* */
/* Note that each driver implements the same function but, */
/* since the function doesn't take any parameter, we can't */
/* decide automatically which driver's get_fattime() to */
/* invoke. Instead, we control this with a #define */
/* which defaults to calling the first driver. */
/* */
DWORD get_fattime (void)
{
#ifndef DRIVE1_TIME_MASTER
return(disk0_get_fattime());
#else
return(disk1_get_fattime());
#endif
}
|