Forum: Mikrocontroller und Digitale Elektronik PIC32MZ - SD Probleme


von Malte S. (Firma: Student) (malte92)


Lesenswert?

Hallo allerseits,

würde gerne mit meinen ChipKIT WiFire (Rev C.) welches einen 
PIC32MZ2048EFG100 besitzt auf meine SD-Karte (onboard) zugreifen um 
Daten (txt) darauf zu speichern. Ich arbeite auf Mplab X IDE und habe 
mich an dem Beispiel von Aidan Mocke 
(http://www.aidanmocke.com/blog/2018/09/04/spi-fatfs/) orientiert, 
welcher die FatFS Bibliothek von elm-chan benutzt. Leider bleibt mein 
Microcontroller beim disk_initialize vorgang immer hängen. Ich hab alles 
ausprobiert was mir einfällt kriege es jedoch nicht hin das Problem zu 
lösen.

Hab es auch schon auf Mplab Harmony versucht, jedoch ohne erfolg, würde 
es deshalb gerne nicht mit Harmony machen, da es mir dann zu 
unübersichtlich/unverständlich wird.


Deswegen wende ich mich jetzt an euch, vlt hat einer erfahrung oder 
Beispiel-Programme mit dem Board/Controller und kann mir 
Tipps/Ratschläge geben :)


Gruß
Malte

von Wolfgang (Gast)


Lesenswert?

Malte S. schrieb:
> Leider bleibt mein Microcontroller beim disk_initialize vorgang
> immer hängen.

Dann schmeiß den Debugger an und gucke, womit er hängen bleibt.

von soso... (Gast)


Lesenswert?

Ich habe 3 Projekte, wo FATFS auf PIC32MX läuft. Es liegt also weder an 
MPLABX PIC32, noch an FATFS.

Worans liegen kann:
Den 1ms Timer  für FATFS hast du aufgesetzt, und ruft ihn auf?
Die SPI-Routine läuft? Scope dranhängen!

Sonst kann man nur empfehlen: Durchsteppen, und hier Code posten.

von Malte S. (Firma: Student) (malte92)


Lesenswert?

Hi,

danke für die Ratschläge habe jetzt meine Main und meine Diskio.c 
hochgeladen, die restlichen Dateien sind die von FATFS aus dem Patch 
R13b.
1
#include "ff.h"
2
#include "diskio.h"
3
4
5
/** CONFIGURATION *************************************************************/
6
7
// DEVCFG2
8
//Define SYSCLK = 200 MHz
9
#pragma config FPLLIDIV = DIV_3         // System PLL Input Divider (3x Divider)
10
#pragma config FPLLRNG = RANGE_5_10_MHZ // System PLL Input Range (5-10 MHz Input)
11
#pragma config FPLLICLK = PLL_POSC      // System PLL Input Clock Selection (POSC is input to the System PLL)
12
#pragma config FPLLMULT = MUL_50        // System PLL Multiplier (PLL Multiply by 50)
13
#pragma config FPLLODIV = DIV_2         // System PLL Output Clock Divider (2x Divider)
14
#pragma config UPLLFSEL = FREQ_24MHZ    // USB PLL Input Frequency Selection (USB PLL input is 24 MHz)
15
16
// DEVCFG1
17
#pragma config FNOSC = SPLL             // Oscillator Selection Bits (System PLL)
18
#pragma config POSCMOD = EC             // Primary Oscillator Configuration (External clock mode)
19
#pragma config DMTCNT = DMT31           // Deadman Timer Count Selection (2^31 (2147483648))
20
#pragma config FDMTEN = OFF             // Deadman Timer Enable (Deadman Timer is disabled)
21
22
// DEVCFG0
23
#pragma config ICESEL = ICS_PGx2        // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)
24
25
#include <xc.h>
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <stdbool.h>
29
#include <proc/p32mz2048efg100.h>
30
31
#define SYS_FREQ 200000000 // Running at 200MHz
32
33
void set_performance_mode()
34
{   
35
  unsigned int cp0;
36
  
37
    // Unlock Sequence
38
    asm volatile("di"); // Disable all interrupts
39
    SYSKEY = 0xAA996655;
40
    SYSKEY = 0x556699AA;  
41
42
    // PB1DIV
43
    // Peripheral Bus 1 cannot be turned off, so there's no need to turn it on
44
    PB1DIVbits.PBDIV = 1; // Peripheral Bus 1 Clock Divisor Control (PBCLK1 is SYSCLK divided by 2)
45
46
    // PB2DIV
47
    PB2DIVbits.ON = 1; // Peripheral Bus 2 Output Clock Enable (Output clock is enabled)
48
    PB2DIVbits.PBDIV = 1; // Peripheral Bus 2 Clock Divisor Control (PBCLK2 is SYSCLK divided by 2)
49
50
    // PB3DIV
51
    PB3DIVbits.ON = 1; // Peripheral Bus 2 Output Clock Enable (Output clock is enabled)
52
    PB3DIVbits.PBDIV = 1; // Peripheral Bus 3 Clock Divisor Control (PBCLK3 is SYSCLK divided by 2)
53
54
    // PB4DIV
55
    PB4DIVbits.ON = 1; // Peripheral Bus 4 Output Clock Enable (Output clock is enabled)
56
    while (!PB4DIVbits.PBDIVRDY); // Wait until it is ready to write to
57
    PB4DIVbits.PBDIV = 0; // Peripheral Bus 4 Clock Divisor Control (PBCLK4 is SYSCLK divided by 1)
58
59
    // PB5DIV
60
    PB5DIVbits.ON = 1; // Peripheral Bus 5 Output Clock Enable (Output clock is enabled)
61
    PB5DIVbits.PBDIV = 1; // Peripheral Bus 5 Clock Divisor Control (PBCLK5 is SYSCLK divided by 2)
62
63
    // PB7DIV
64
    PB7DIVbits.ON = 1; // Peripheral Bus 7 Output Clock Enable (Output clock is enabled)
65
    PB7DIVbits.PBDIV = 1; // Peripheral Bus 7 Clock Divisor Control (PBCLK7 is SYSCLK divided by 1)
66
67
    // PB8DIV
68
    PB8DIVbits.ON = 1; // Peripheral Bus 8 Output Clock Enable (Output clock is enabled)
69
    PB8DIVbits.PBDIV = 1; // Peripheral Bus 8 Clock Divisor Control (PBCLK8 is SYSCLK divided by 2)
70
71
    // PRECON - Set up prefetch
72
    PRECONbits.PFMSECEN = 0; // Flash SEC Interrupt Enable (Do not generate an interrupt when the PFMSEC bit is set)
73
    PRECONbits.PREFEN = 0b11; // Predictive Prefetch Enable (Enable predictive prefetch for any address)
74
    PRECONbits.PFMWS = 0b010; // PFM Access Time Defined in Terms of SYSCLK Wait States (Two wait states)
75
76
    // Set up caching
77
    cp0 = _mfc0(16, 0);
78
    cp0 &= ~0x07;
79
    cp0 |= 0b011; // K0 = Cacheable, non-coherent, write-back, write allocate
80
    _mtc0(16, 0, cp0);  
81
82
    // Lock Sequence
83
    SYSKEY = 0x33333333;
84
    asm volatile("ei"); // Enable all interrupts
85
}
86
87
// Global variables
88
FIL file; // File handle for the file we open
89
DIR dir; // Directory information for the current directory
90
FATFS fso; // File System Object for the file system we are reading from
91
FILINFO fileInfo; // Information for the file we have opened (not really necessary to have this)
92
93
void init_disk()
94
{
95
    // Wait for the disk to initialise
96
    while(disk_initialize(0));
97
    // Mount the disk
98
    f_mount(&fso, "", 0);
99
    // Change dir to the root directory
100
    f_chdir("/");
101
    // Open the directory
102
    f_opendir(&dir, ".");
103
}
104
105
void main()
106
{
107
  int bytes_read;
108
    unsigned char buffer[32768];
109
  
110
  // Set up all ports to be digital and not analog
111
    ANSELA = 0;
112
    ANSELB = 0;
113
    ANSELC = 0;
114
    ANSELD = 0;
115
    ANSELE = 0;
116
    ANSELF = 0;
117
    ANSELG = 0;
118
  
119
  
120
  // Set up PPS for SPI3 on RB10 and RC4
121
  SDI3R = 0b0110; // RB10 = SDI3
122
  RPC4R = 0b0111; // RC4 = SDO3
123
  TRISBbits.TRISB10 = 1; // Set RB10 as input because it's SDI3
124
  
125
  // Set max performance mode
126
//  set_performance_mode();
127
  
128
  // Initialise the SD card
129
  init_disk();
130
  
131
  // Open the file test.txt
132
  f_open(&file, "/test.txt", FA_WRITE);
133
      
134
135
  while (1);
136
}
1
/*------------------------------------------------------------------------/
2
/  MMCv3/SDv1/SDv2 (in SPI mode) control module
3
/-------------------------------------------------------------------------/
4
/
5
/  Copyright (C) 2010, ChaN, all right reserved.
6
/
7
/ * This software is a free software and there is NO WARRANTY.
8
/ * No restriction on use. You can use, modify and redistribute it for
9
/   personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
10
/ * Redistributions of source code must retain the above copyright notice.
11
/
12
/-------------------------------------------------------------------------*/
13
//Edited by A. Morrison to function on PIC32.
14
15
// Ported by Riccardo Leonardi to PIC32MX795F512L  (22/11/2011)
16
// Many thanks to Aiden Morrison's good work!
17
// changes: parametrization of SPI port number
18
19
// Modified by Bryn Thomas (11/09/2016) to use Enhanced Buffer SPI mode
20
// and boost read performance with 32-bit transfers
21
22
// Modified by Aidan Mocke (04/09/2018) to work with the PIC32MZ series
23
24
#define _DISABLE_OPENADC10_CONFIGPORT_WARNING
25
#define _SUPPRESS_PLIB_WARNING
26
27
#include <xc.h>
28
#include "diskio.h"
29
30
/* Definitions for MMC/SDC command */
31
#define CMD0   (0)      /* GO_IDLE_STATE */
32
#define CMD1   (1)      /* SEND_OP_COND */
33
#define ACMD41 (41|0x80)  /* SEND_OP_COND (SDC) */
34
#define CMD8   (8)      /* SEND_IF_COND */
35
#define CMD9   (9)      /* SEND_CSD */
36
#define CMD10  (10)      /* SEND_CID */
37
#define CMD12  (12)      /* STOP_TRANSMISSION */
38
#define ACMD13 (13|0x80)  /* SD_STATUS (SDC) */
39
#define CMD16  (16)      /* SET_BLOCKLEN */
40
#define CMD17  (17)      /* READ_SINGLE_BLOCK */
41
#define CMD18  (18)      /* READ_MULTIPLE_BLOCK */
42
#define CMD23  (23)      /* SET_BLOCK_COUNT */
43
#define ACMD23 (23|0x80)  /* SET_WR_BLK_ERASE_COUNT (SDC) */
44
#define CMD24  (24)      /* WRITE_BLOCK */
45
#define CMD25  (25)      /* WRITE_MULTIPLE_BLOCK */
46
#define CMD41  (41)      /* SEND_OP_COND (ACMD) */
47
#define CMD55  (55)      /* APP_CMD */
48
#define CMD58  (58)      /* READ_OCR */
49
50
51
/* Port Controls  (Platform dependent) */
52
#define CS_SETOUT() TRISCbits.TRISC3 = 0 
53
#define CS_LOW()  LATCbits.LATC3 = 0  //MMC CS = L
54
#define CS_HIGH() LATCbits.LATC3 = 1  //MMC CS = H
55
//Change the SPI port number as needed on the following 5 lines
56
#define SPIBRG  SPI3BRG
57
#define SPIBUF  SPI3BUF
58
#define SPISTATbits SPI3STATbits
59
#define SPICONbits SPI3CONbits
60
61
#define  FCLK_SLOW()  SPIBRG = 128    /* Set slow clock (100k-400k) */
62
#define  FCLK_FAST()  SPIBRG = 16    /* Set fast clock (depends on the CSD) */
63
64
65
static volatile
66
DSTATUS Stat = STA_NOINIT;  /* Disk status */
67
68
static volatile
69
UINT Timer1, Timer2;    /* 1000Hz decrement timer */
70
71
static
72
UINT CardType;
73
74
typedef union 
75
{ 
76
    UINT int_data[128]; 
77
    BYTE byte_data[512];
78
} spi32_data;
79
80
unsigned char __attribute__((coherent)) rcvbuff[8192];
81
82
#define xmit_spi(dat)   xchg_spi(dat)
83
#define rcvr_spi()    xchg_spi(0xFF)
84
#define rcvr_spi_m(p)  SPIBUF = 0xFF; while (SPISTATbits.SPIRBE); *(p) = (BYTE)SPIBUF;
85
86
static
87
BYTE xchg_spi (BYTE dat)
88
{
89
  SPIBUF = dat;
90
  while (!SPISTATbits.SPIRBF);
91
  return (BYTE)SPIBUF;
92
}
93
94
/*-----------------------------------------------------------------------*/
95
/* Wait for card ready                                                   */
96
/*-----------------------------------------------------------------------*/
97
98
static
99
BYTE wait_ready (void)
100
{
101
  BYTE res;
102
103
104
  Timer2 = 500;  /* Wait for ready in timeout of 500ms */
105
  rcvr_spi();
106
  do
107
    res = rcvr_spi();
108
  while ((res != 0xFF) && Timer2);
109
110
  return res;
111
}
112
113
114
115
/*-----------------------------------------------------------------------*/
116
/* Deselect the card and release SPI bus                                 */
117
/*-----------------------------------------------------------------------*/
118
119
static
120
void deselect (void)
121
{
122
  CS_HIGH();
123
  rcvr_spi();
124
}
125
126
127
128
/*-----------------------------------------------------------------------*/
129
/* Select the card and wait ready                                        */
130
/*-----------------------------------------------------------------------*/
131
132
static
133
int select (void)  /* 1:Successful, 0:Timeout */
134
{
135
  CS_LOW();
136
  if (wait_ready() != 0xFF) {
137
    deselect();
138
    return 0;
139
  }
140
  return 1;
141
}
142
143
144
145
146
/*-----------------------------------------------------------------------*/
147
/* Write Sector(s)                                                       */
148
/*-----------------------------------------------------------------------*/
149
/*-----------------------------------------------------------------------*/
150
/* Send a command packet to MMC                                          */
151
/*-----------------------------------------------------------------------*/
152
153
static
154
BYTE send_cmd (
155
  BYTE cmd,    /* Command byte */
156
  DWORD arg    /* Argument */
157
)
158
{
159
  BYTE n, res;
160
161
162
  if (cmd & 0x80) {  /* ACMD<n> is the command sequense of CMD55-CMD<n> */
163
    cmd &= 0x7F;
164
    res = send_cmd(CMD55, 0);
165
    if (res > 1) return res;
166
  }
167
168
  /* Select the card and wait for ready */
169
  deselect();
170
  if (!select()) return 0xFF;
171
172
  /* Send command packet */
173
  xmit_spi(0x40 | cmd);      /* Start + Command index */
174
  xmit_spi((BYTE)(arg >> 24));  /* Argument[31..24] */
175
  xmit_spi((BYTE)(arg >> 16));  /* Argument[23..16] */
176
  xmit_spi((BYTE)(arg >> 8));    /* Argument[15..8] */
177
  xmit_spi((BYTE)arg);      /* Argument[7..0] */
178
  n = 0x01;            /* Dummy CRC + Stop */
179
  if (cmd == CMD0) n = 0x95;    /* Valid CRC for CMD0(0) */
180
  if (cmd == CMD8) n = 0x87;    /* Valid CRC for CMD8(0x1AA) */
181
  xmit_spi(n);
182
183
  /* Receive command response */
184
  if (cmd == CMD12) rcvr_spi();  /* Skip a stuff byte when stop reading */
185
  n = 10;              /* Wait for a valid response in timeout of 10 attempts */
186
  do
187
    res = rcvr_spi();
188
  while ((res & 0x80) && --n);
189
190
  return res;      /* Return with the response value */
191
}
192
193
/*-----------------------------------------------------------------------*/
194
/* Send a data packet to MMC                                             */
195
/*-----------------------------------------------------------------------*/
196
197
#if _READONLY == 0
198
static
199
int xmit_datablock (  /* 1:OK, 0:Failed */
200
  const BYTE *buff,  /* 512 byte data block to be transmitted */
201
  BYTE token      /* Data token */
202
)
203
{
204
  BYTE resp;
205
  UINT bc = 512;
206
207
208
  if (wait_ready() != 0xFF) return 0;
209
210
  xmit_spi(token);    /* Xmit a token */
211
  if (token != 0xFD) {  /* Not StopTran token */
212
    do {            /* Xmit the 512 byte data block to the MMC */
213
      xmit_spi(*buff++);
214
      xmit_spi(*buff++);
215
    } while (bc -= 2);
216
    xmit_spi(0xFF);        /* CRC (Dummy) */
217
    xmit_spi(0xFF);
218
    resp = rcvr_spi();      /* Receive a data response */
219
    if ((resp & 0x1F) != 0x05)  /* If not accepted, return with error */
220
      return 0;
221
  }
222
223
  return 1;
224
}
225
#endif  /* _READONLY */
226
227
228
#if _READONLY == 0
229
DRESULT disk_write (
230
  BYTE pdrv,        /* Physical drive nmuber (0) */
231
  const BYTE *buff,    /* Pointer to the data to be written */
232
  DWORD sector,      /* Start sector number (LBA) */
233
  UINT count        /* Sector count (1..255) */
234
)
235
{
236
  if (pdrv || !count) return RES_PARERR;
237
  if (Stat & STA_NOINIT) return RES_NOTRDY;
238
  if (Stat & STA_PROTECT) return RES_WRPRT;
239
240
  if (!(CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */
241
242
  if (count == 1) {    /* Single block write */
243
    if ((send_cmd(CMD24, sector) == 0)  /* WRITE_BLOCK */
244
      && xmit_datablock(buff, 0xFE))
245
      count = 0;
246
  }
247
  else {        /* Multiple block write */
248
    if (CardType & CT_SDC) send_cmd(ACMD23, count);
249
    if (send_cmd(CMD25, sector) == 0) {  /* WRITE_MULTIPLE_BLOCK */
250
      do {
251
        if (!xmit_datablock(buff, 0xFC)) break;
252
        buff += 512;
253
      } while (--count);
254
      if (!xmit_datablock(0, 0xFD))  /* STOP_TRAN token */
255
        count = 1;
256
    }
257
  }
258
  deselect();
259
260
  return count ? RES_ERROR : RES_OK;
261
}
262
#endif /* _READONLY */
263
264
265
/*-----------------------------------------------------------------------*/
266
/* Power Control  (Platform dependent)                                   */
267
/*-----------------------------------------------------------------------*/
268
/* When the target system does not support socket power control, there   */
269
/* is nothing to do in these functions and chk_power always returns 1.   */
270
271
static
272
void power_on (void)
273
{
274
    int cnt;
275
    
276
    /* Setup SPI */
277
  // Setup CS as output
278
  CS_SETOUT();
279
    SPICONbits.ON = 0;
280
281
    SPISTATbits.SPIROV = 0;
282
283
    SPICONbits.MSTEN = 1;
284
    SPICONbits.CKP = 1;
285
    SPICONbits.CKE = 0;
286
    SPICONbits.SMP = 1;
287
    SPICONbits.MODE16 = 0;
288
    SPICONbits.MODE32 = 0;
289
    SPICONbits.SRXISEL = 1;
290
    // Enables SPI port to run in Enhanced Buffer mode
291
    SPICONbits.ENHBUF = 0;
292
  SPICONbits.ON = 1;
293
}
294
295
static
296
void power_off (void)
297
{
298
  select();      /* Wait for card ready */
299
  deselect();
300
301
  SPICONbits.ON = 0;      /* Disable SPI */
302
303
  Stat |= STA_NOINIT;  /* Set STA_NOINIT */
304
}
305
306
/*-----------------------------------------------------------------------*/
307
/* Receive a data packet from MMC                                        */
308
/*-----------------------------------------------------------------------*/
309
static
310
int rcvr_datablock (  /* 1:OK, 0:Failed */
311
  BYTE *buff,      /* Data buffer to store received data */
312
  UINT btr      /* Byte count (must be multiple of 4) */
313
)
314
{
315
  BYTE token;
316
317
318
  Timer1 = 100;
319
  do {              /* Wait for data packet in timeout of 100ms */
320
    token = rcvr_spi();
321
  } while ((token == 0xFF) && Timer1);
322
323
  if(token != 0xFE) return 0;    /* If not valid data token, retutn with error */
324
325
  do {              /* Receive the data block into buffer */
326
    rcvr_spi_m(buff++);
327
    rcvr_spi_m(buff++);
328
    rcvr_spi_m(buff++);
329
    rcvr_spi_m(buff++);
330
  } while (btr -= 4);
331
  rcvr_spi();            /* Discard CRC */
332
  rcvr_spi();
333
334
  return 1;            /* Return with success */
335
}
336
/*--------------------------------------------------------------------------
337
338
   Public Functions
339
340
---------------------------------------------------------------------------*/
341
342
343
/*-----------------------------------------------------------------------*/
344
/* Initialize Disk Drive                                                 */
345
/*-----------------------------------------------------------------------*/
346
347
DSTATUS disk_initialize (
348
  BYTE drv    /* Physical drive nmuber (0) */
349
)
350
{
351
  BYTE n, cmd, ty, ocr[4];
352
353
  power_on();              /* Force socket power on */
354
        FCLK_SLOW();
355
  for (n = 80; n; n--) rcvr_spi();  /* 80 dummy clocks */
356
357
  ty = 0;
358
  if (send_cmd(CMD0, 0) == 1) {      /* Enter Idle state */
359
    Timer1 = 100;            /* Initialization timeout of 1000 msec */
360
    if (send_cmd(CMD8, 0x1AA) == 1) {  /* SDv2? */
361
      for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();      /* Get trailing return value of R7 resp */
362
      if (ocr[2] == 0x01 && ocr[3] == 0xAA) {        /* The card can work at vdd range of 2.7-3.6V */
363
        while (Timer1 && send_cmd(ACMD41, 0x40000000));  /* Wait for leaving idle state (ACMD41 with HCS bit) */
364
        if (Timer1 && send_cmd(CMD58, 0) == 0) {      /* Check CCS bit in the OCR */
365
          for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
366
          ty = (ocr[0] & 0x40) ? CT_SD2|CT_BLOCK : CT_SD2;  /* SDv2 */
367
        }
368
      }
369
    } else {              /* SDv1 or MMCv3 */
370
      if (send_cmd(ACMD41, 0) <= 1)   {
371
        ty = CT_SD1; cmd = ACMD41;  /* SDv1 */
372
      } else {
373
        ty = CT_MMC; cmd = CMD1;  /* MMCv3 */
374
      }
375
      while (Timer1 && send_cmd(cmd, 0));    /* Wait for leaving idle state */
376
      if (!Timer1 || send_cmd(CMD16, 512) != 0)  /* Set read/write block length to 512 */
377
        ty = 0;
378
    }
379
  }
380
  CardType = ty;
381
  deselect();
382
383
  if (ty) {      /* Initialization succeded */
384
    Stat &= ~STA_NOINIT;  /* Clear STA_NOINIT */
385
    FCLK_FAST();
386
  } else {      /* Initialization failed */
387
    power_off();
388
  }
389
390
  return Stat;
391
}
392
393
394
395
/*-----------------------------------------------------------------------*/
396
/* Get Disk Status                                                       */
397
/*-----------------------------------------------------------------------*/
398
399
DSTATUS disk_status (
400
  BYTE drv    /* Physical drive nmuber (0) */
401
)
402
{
403
  if (drv) return STA_NOINIT;    /* Supports only single drive */
404
  return Stat;
405
}
406
407
408
409
/*-----------------------------------------------------------------------*/
410
/* Read Sector(s)                                                        */
411
/*-----------------------------------------------------------------------*/
412
413
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
414
{
415
  if (pdrv || !count) return RES_PARERR;
416
  if (Stat & STA_NOINIT) return RES_NOTRDY;
417
418
  if (!(CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */
419
420
  if (count == 1) {    /* Single block read */
421
    if ((send_cmd(CMD17, sector) == 0)  /* READ_SINGLE_BLOCK */
422
      && rcvr_datablock(buff, 512))
423
      count = 0;
424
  }
425
  else {        /* Multiple block read */
426
    if (send_cmd(CMD18, sector) == 0) {  /* READ_MULTIPLE_BLOCK */
427
      do {
428
        if (!rcvr_datablock(buff, 512)) break;
429
        buff += 512;
430
      } while (--count);
431
      send_cmd(CMD12, 0);        /* STOP_TRANSMISSION */
432
    }
433
  }
434
  deselect();
435
436
  return count ? RES_ERROR : RES_OK;
437
}
438
439
/*-----------------------------------------------------------------------*/
440
/* Write Sector(s)                                                       */
441
/*-----------------------------------------------------------------------*/
442
443
#if _READONLY == 0
444
DRESULT w (
445
  BYTE drv,        /* Physical drive nmuber (0) */
446
  const BYTE *buff,    /* Pointer to the data to be written */
447
  DWORD sector,      /* Start sector number (LBA) */
448
  BYTE count        /* Sector count (1..255) */
449
)
450
{
451
  if (drv || !count) return RES_PARERR;
452
  if (Stat & STA_NOINIT) return RES_NOTRDY;
453
  if (Stat & STA_PROTECT) return RES_WRPRT;
454
455
  if (!(CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */
456
457
  if (count == 1) {    /* Single block write */
458
    if ((send_cmd(CMD24, sector) == 0)  /* WRITE_BLOCK */
459
      && xmit_datablock(buff, 0xFE))
460
      count = 0;
461
  }
462
  else {        /* Multiple block write */
463
    if (CardType & CT_SDC) send_cmd(ACMD23, count);
464
    if (send_cmd(CMD25, sector) == 0) {  /* WRITE_MULTIPLE_BLOCK */
465
      do {
466
        if (!xmit_datablock(buff, 0xFC)) break;
467
        buff += 512;
468
      } while (--count);
469
      if (!xmit_datablock(0, 0xFD))  /* STOP_TRAN token */
470
        count = 1;
471
    }
472
  }
473
  deselect();
474
475
  return count ? RES_ERROR : RES_OK;
476
}
477
#endif /* _READONLY */
478
479
480
481
/*-----------------------------------------------------------------------*/
482
/* Miscellaneous Functions                                               */
483
/*-----------------------------------------------------------------------*/
484
485
DRESULT disk_ioctl (
486
  BYTE drv,    /* Physical drive nmuber (0) */
487
  BYTE ctrl,    /* Control code */
488
  void *buff    /* Buffer to send/receive data block */
489
)
490
{
491
  DRESULT res;
492
  BYTE n, csd[16], *ptr = buff;
493
  DWORD csize;
494
495
496
  if (drv) return RES_PARERR;
497
  if (Stat & STA_NOINIT) return RES_NOTRDY;
498
499
  res = RES_ERROR;
500
  switch (ctrl) {
501
    case CTRL_SYNC :  /* Flush dirty buffer if present */
502
      if (select()) {
503
        deselect();
504
        res = RES_OK;
505
      }
506
      break;
507
508
    case GET_SECTOR_COUNT :  /* Get number of sectors on the disk (WORD) */
509
      if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
510
        if ((csd[0] >> 6) == 1) {  /* SDv2? */
511
          csize = csd[9] + ((WORD)csd[8] << 8) + 1;
512
          *(DWORD*)buff = (DWORD)csize << 10;
513
        } else {          /* SDv1 or MMCv2 */
514
          n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
515
          csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
516
          *(DWORD*)buff = (DWORD)csize << (n - 9);
517
        }
518
        res = RES_OK;
519
      }
520
      break;
521
522
    case GET_SECTOR_SIZE :  /* Get sectors on the disk (WORD) */
523
      *(WORD*)buff = 512;
524
      res = RES_OK;
525
      break;
526
527
    case GET_BLOCK_SIZE :  /* Get erase block size in unit of sectors (DWORD) */
528
      if (CardType & CT_SD2) {  /* SDv2? */
529
        if (send_cmd(ACMD13, 0) == 0) {    /* Read SD status */
530
          rcvr_spi();
531
          if (rcvr_datablock(csd, 16)) {        /* Read partial block */
532
            for (n = 64 - 16; n; n--) rcvr_spi();  /* Purge trailing data */
533
            *(DWORD*)buff = 16UL << (csd[10] >> 4);
534
            res = RES_OK;
535
          }
536
        }
537
      } else {          /* SDv1 or MMCv3 */
538
        if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {  /* Read CSD */
539
          if (CardType & CT_SD1) {  /* SDv1 */
540
            *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
541
          } else {          /* MMCv3 */
542
            *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
543
          }
544
          res = RES_OK;
545
        }
546
      }
547
      break;
548
549
    case MMC_GET_TYPE :    /* Get card type flags (1 byte) */
550
      *ptr = CardType;
551
      res = RES_OK;
552
      break;
553
554
    case MMC_GET_CSD :  /* Receive CSD as a data block (16 bytes) */
555
      if ((send_cmd(CMD9, 0) == 0)  /* READ_CSD */
556
        && rcvr_datablock(buff, 16))
557
        res = RES_OK;
558
      break;
559
560
    case MMC_GET_CID :  /* Receive CID as a data block (16 bytes) */
561
      if ((send_cmd(CMD10, 0) == 0)  /* READ_CID */
562
        && rcvr_datablock(buff, 16))
563
        res = RES_OK;
564
      break;
565
566
    case MMC_GET_OCR :  /* Receive OCR as an R3 resp (4 bytes) */
567
      if (send_cmd(CMD58, 0) == 0) {  /* READ_OCR */
568
        for (n = 0; n < 4; n++)
569
          *((BYTE*)buff+n) = rcvr_spi();
570
        res = RES_OK;
571
      }
572
      break;
573
574
    case MMC_GET_SDSTAT :  /* Receive SD statsu as a data block (64 bytes) */
575
      if (send_cmd(ACMD13, 0) == 0) {  /* SD_STATUS */
576
        rcvr_spi();
577
        if (rcvr_datablock(buff, 64))
578
          res = RES_OK;
579
      }
580
      break;
581
582
    default:
583
      res = RES_PARERR;
584
  }
585
586
  deselect();
587
588
  return res;
589
}
590
591
592
593
/*-----------------------------------------------------------------------*/
594
/* Device Timer Interrupt Procedure  (Platform dependent)                */
595
/*-----------------------------------------------------------------------*/
596
/* This function must be called in period of 1ms                         */
597
598
599
void disk_timerproc (void)
600
{
601
}

Beim Debuggen hänge ich in dem wait_ready block
1
static
2
BYTE wait_ready (void)
3
{
4
  BYTE res;
5
6
7
  Timer2 = 500;  /* Wait for ready in timeout of 500ms */
8
  rcvr_spi();
9
  do
10
    res = rcvr_spi();
11
  while ((res != 0xFF) && Timer2);
12
13
  return res;
14
}

bei der do while schleife
1
while ((res != 0xFF) && Timer2);
hängt der Microcontroller sich auf, obwohl die Bedingung erfüllt ist.
res = 0x00 und Timer2 =500

An soso:
Was genau meinst du mit den 1ms Timer? Bin davon ausgegangen, das in dem 
Beispiel, das dementsprechend aufgerufen wird...
Wie kann ich das feststellen ob die SPI-Routine läuft?
Was meinst du mit Scope dranhängen?

LG
Malte

von soso... (Gast)


Lesenswert?

Wenn du in "wait_ready" hängst, heißt dass, dass du kein "ready" von der 
SD-Karte bekommst. Das kann eine defekte SPI-Routine sein. Dass er 
überhaupt hängenbleiben kann, hängt mit dem Timer zusammen.

Deine "disk_timerproc (void)" ist leer, das ist vermutlich schon mal 
falsch. Und außerdem musst du die jede ms aufrufen, sonst kann FATFs 
keine Zeit messen.

Was die SPI angeht:
Man muss auch mal schauen, ob die Versorgung da ist, ob bei SCK der Takt 
komt, MOSI, MISO Daten daherbringen und Chipselect betätigt wird. Sehr 
schnell hat man ein ANSEL-Bit vergessen oder ein obskures Bit in der 
SPI-Config und so weiter.
Darum ist es immer eine gute Idee sich zunächst anzusehen, ob das 
überhaupt generell funktionieren kann. Idealerweise mit dem Oszilloskop, 
dann sieht man elektrische Probleme auch gleich. Nicht dass du einen 
Hardwarefehler in Software suchst ;-)

Mein Rat wäre:
Schau dir die Seite von elm chan an, der hat eine brauchbare Doku:
http://elm-chan.org/fsw/ff/00index_e.html
Leg dein aktuelles Projekt zunächst zur Seite. Lade dir die "FatFs 
sample projects for various platforms October 14, 2018", nimm das PIC24 
example (das ist glaube ich mit Software-SPI) und bring das zum Laufen. 
PIC24 und PIC32 sind sich sehr ähnlich, das lässt sich ziemlich einfach 
portieren. Wenn das funktioniert, ist das Austauschen der SPI-Routinen 
gegen Hardware-SPI ist sehr viel einfacher.

Und nicht aufgeben. Es lohnt sich, sich da durchzubeißen.

von Michael E. (cuby)


Lesenswert?

Malte S. schrieb:
> bei der do while schleife
> while ((res != 0xFF) && Timer2);
> hängt der
> Microcontroller sich auf, obwohl die Bedingung erfüllt ist.
> res = 0x00 und Timer2 =500

Vielleicht die blöde Standard-Falle Compiler-Optimierung?

Hast du schon versucht, das "BYTE res" als volatile zu deklarieren?

-- Michael

von soso... (Gast)


Lesenswert?

Michael E. schrieb:
> Vielleicht die blöde Standard-Falle Compiler-Optimierung?

Ich vermute eher, das Problem ist die Abbruchbedingung der 
while-Schleife:
1
    res = rcvr_spi();
2
  while ((res != 0xFF) && Timer2);

Er bekommt VERMUTLICH (wissen tun wir es nicht!) weder etwas !=0xFF von 
der SPI zurück (res!=0xFF), noch kann der Timer2 auf 0 gehen.

Die Schleife bricht nie ab.

Dass die SPI keine Date ungleich 0xFF liefert, deutet auf ein Problem 
mit der SPI-Routine hin. Oder auf ein generelles Problem mit den 
Leitungen zur SD-Karte. Drum: Nachprüfen mit dem Oszilloskop.

Dass der Timer nicht abläuft liegt schlicht daran, dass die 
Tiemer-routine nicht behandelt wird.

Die Frage ist, was mit Aufhängen gemeint ist. Aber PIC32 haben 
Exceptions, wenn man die nutzt, kann man jeden "Aufhänge" abfangen. Ich 
verwende Exceptions oft für  Debugzwecke. Code:
1
/*exception handlers*/
2
/*
3
 * Exception cause:
4
    0       0x00 Int Interrupt
5
   1-3      0x01 ? Reserved
6
   4        0x04 AdEL Address error exception (load or instruction fetch)
7
   5        0x05 AdES Address error exception (store)
8
   6        0x06 IBE Bus error exception (instruction fetch)
9
   7        0x07 DBE Bus error exception (data reference: load or store)
10
   8        0x08 Sys Syscall exception
11
   9        0x09 Bp Breakpoint exception
12
   10       0x0A RI Reserved instruction exception
13
   11       0x0B CPU Coprocessor Unusable exception
14
   12       0x0C Ov Arithmetic Overflow exception
15
   13       0x0D Tr Trap exception
16
   14-31    0x0E-0x1F ? Reserved
17
 */
18
static uint32_t excep_addr, excep_vaddr, excep_cause, exception;
19
void _simple_tlb_refill_exception_handler(void){
20
    uint32_t cause;
21
    asm volatile("mfc0 %0,$8" : "=r" (excep_vaddr)); 
22
    asm volatile("mfc0 %0,$13" : "=r" (cause)); 
23
    asm volatile("mfc0 %0,$14" : "=r" (excep_addr)); 
24
    excep_cause = (cause&0x000000FF) >> 2;
25
    exception = 1;
26
}
27
void _general_exception_handler (void){
28
    uint32_t cause;
29
    asm volatile("mfc0 %0,$8" : "=r" (excep_vaddr)); 
30
    asm volatile("mfc0 %0,$13" : "=r" (cause)); 
31
    asm volatile("mfc0 %0,$14" : "=r" (excep_addr)); 
32
    excep_cause = (cause&0x000000FF) >> 2;
33
    exception = 2;
34
}
Da hab ich immer Breakpoints sitzen. Es ist manchmal nützlich zu wissen, 
was genau die Ursache des "Aufhängers" ist. Und wenn man beim 
Durchsteppen im Exceptionhandler landet (z.B. cause = 0x07) sollte man 
sich seine Pointer genau ansehen ;-)

von soso... (Gast)


Lesenswert?

Ich habe leider vergessen zu erwähnen: Die Exception-Handler sind für 
PIC32MX. Also bitte vorher überprüfen, ob das für PIC32MZ auch passt.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.