mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik PIC32MZ - SD Probleme


Autor: Malte S. (Firma: Student) (malte92)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Wolfgang (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: soso... (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Malte S. (Firma: Student) (malte92)
Datum:

Bewertung
0 lesenswert
nicht 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.
#include "ff.h"
#include "diskio.h"


/** CONFIGURATION *************************************************************/

// DEVCFG2
//Define SYSCLK = 200 MHz
#pragma config FPLLIDIV = DIV_3         // System PLL Input Divider (3x Divider)
#pragma config FPLLRNG = RANGE_5_10_MHZ // System PLL Input Range (5-10 MHz Input)
#pragma config FPLLICLK = PLL_POSC      // System PLL Input Clock Selection (POSC is input to the System PLL)
#pragma config FPLLMULT = MUL_50        // System PLL Multiplier (PLL Multiply by 50)
#pragma config FPLLODIV = DIV_2         // System PLL Output Clock Divider (2x Divider)
#pragma config UPLLFSEL = FREQ_24MHZ    // USB PLL Input Frequency Selection (USB PLL input is 24 MHz)

// DEVCFG1
#pragma config FNOSC = SPLL             // Oscillator Selection Bits (System PLL)
#pragma config POSCMOD = EC             // Primary Oscillator Configuration (External clock mode)
#pragma config DMTCNT = DMT31           // Deadman Timer Count Selection (2^31 (2147483648))
#pragma config FDMTEN = OFF             // Deadman Timer Enable (Deadman Timer is disabled)

// DEVCFG0
#pragma config ICESEL = ICS_PGx2        // ICE/ICD Comm Channel Select (Communicate on PGEC2/PGED2)

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <proc/p32mz2048efg100.h>

#define SYS_FREQ 200000000 // Running at 200MHz

void set_performance_mode()
{   
  unsigned int cp0;
  
    // Unlock Sequence
    asm volatile("di"); // Disable all interrupts
    SYSKEY = 0xAA996655;
    SYSKEY = 0x556699AA;  

    // PB1DIV
    // Peripheral Bus 1 cannot be turned off, so there's no need to turn it on
    PB1DIVbits.PBDIV = 1; // Peripheral Bus 1 Clock Divisor Control (PBCLK1 is SYSCLK divided by 2)

    // PB2DIV
    PB2DIVbits.ON = 1; // Peripheral Bus 2 Output Clock Enable (Output clock is enabled)
    PB2DIVbits.PBDIV = 1; // Peripheral Bus 2 Clock Divisor Control (PBCLK2 is SYSCLK divided by 2)

    // PB3DIV
    PB3DIVbits.ON = 1; // Peripheral Bus 2 Output Clock Enable (Output clock is enabled)
    PB3DIVbits.PBDIV = 1; // Peripheral Bus 3 Clock Divisor Control (PBCLK3 is SYSCLK divided by 2)

    // PB4DIV
    PB4DIVbits.ON = 1; // Peripheral Bus 4 Output Clock Enable (Output clock is enabled)
    while (!PB4DIVbits.PBDIVRDY); // Wait until it is ready to write to
    PB4DIVbits.PBDIV = 0; // Peripheral Bus 4 Clock Divisor Control (PBCLK4 is SYSCLK divided by 1)

    // PB5DIV
    PB5DIVbits.ON = 1; // Peripheral Bus 5 Output Clock Enable (Output clock is enabled)
    PB5DIVbits.PBDIV = 1; // Peripheral Bus 5 Clock Divisor Control (PBCLK5 is SYSCLK divided by 2)

    // PB7DIV
    PB7DIVbits.ON = 1; // Peripheral Bus 7 Output Clock Enable (Output clock is enabled)
    PB7DIVbits.PBDIV = 1; // Peripheral Bus 7 Clock Divisor Control (PBCLK7 is SYSCLK divided by 1)

    // PB8DIV
    PB8DIVbits.ON = 1; // Peripheral Bus 8 Output Clock Enable (Output clock is enabled)
    PB8DIVbits.PBDIV = 1; // Peripheral Bus 8 Clock Divisor Control (PBCLK8 is SYSCLK divided by 2)

    // PRECON - Set up prefetch
    PRECONbits.PFMSECEN = 0; // Flash SEC Interrupt Enable (Do not generate an interrupt when the PFMSEC bit is set)
    PRECONbits.PREFEN = 0b11; // Predictive Prefetch Enable (Enable predictive prefetch for any address)
    PRECONbits.PFMWS = 0b010; // PFM Access Time Defined in Terms of SYSCLK Wait States (Two wait states)

    // Set up caching
    cp0 = _mfc0(16, 0);
    cp0 &= ~0x07;
    cp0 |= 0b011; // K0 = Cacheable, non-coherent, write-back, write allocate
    _mtc0(16, 0, cp0);  

    // Lock Sequence
    SYSKEY = 0x33333333;
    asm volatile("ei"); // Enable all interrupts
}

// Global variables
FIL file; // File handle for the file we open
DIR dir; // Directory information for the current directory
FATFS fso; // File System Object for the file system we are reading from
FILINFO fileInfo; // Information for the file we have opened (not really necessary to have this)

void init_disk()
{
    // Wait for the disk to initialise
    while(disk_initialize(0));
    // Mount the disk
    f_mount(&fso, "", 0);
    // Change dir to the root directory
    f_chdir("/");
    // Open the directory
    f_opendir(&dir, ".");
}

void main()
{
  int bytes_read;
    unsigned char buffer[32768];
  
  // Set up all ports to be digital and not analog
    ANSELA = 0;
    ANSELB = 0;
    ANSELC = 0;
    ANSELD = 0;
    ANSELE = 0;
    ANSELF = 0;
    ANSELG = 0;
  
  
  // Set up PPS for SPI3 on RB10 and RC4
  SDI3R = 0b0110; // RB10 = SDI3
  RPC4R = 0b0111; // RC4 = SDO3
  TRISBbits.TRISB10 = 1; // Set RB10 as input because it's SDI3
  
  // Set max performance mode
//  set_performance_mode();
  
  // Initialise the SD card
  init_disk();
  
  // Open the file test.txt
  f_open(&file, "/test.txt", FA_WRITE);
      

  while (1);
}
/*------------------------------------------------------------------------/
/  MMCv3/SDv1/SDv2 (in SPI mode) control module
/-------------------------------------------------------------------------/
/
/  Copyright (C) 2010, 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.
/
/-------------------------------------------------------------------------*/
//Edited by A. Morrison to function on PIC32.

// Ported by Riccardo Leonardi to PIC32MX795F512L  (22/11/2011)
// Many thanks to Aiden Morrison's good work!
// changes: parametrization of SPI port number

// Modified by Bryn Thomas (11/09/2016) to use Enhanced Buffer SPI mode
// and boost read performance with 32-bit transfers

// Modified by Aidan Mocke (04/09/2018) to work with the PIC32MZ series

#define _DISABLE_OPENADC10_CONFIGPORT_WARNING
#define _SUPPRESS_PLIB_WARNING

#include <xc.h>
#include "diskio.h"

/* Definitions for MMC/SDC command */
#define CMD0   (0)      /* GO_IDLE_STATE */
#define CMD1   (1)      /* SEND_OP_COND */
#define ACMD41 (41|0x80)  /* 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 (13|0x80)  /* 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 (23|0x80)  /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24  (24)      /* WRITE_BLOCK */
#define CMD25  (25)      /* WRITE_MULTIPLE_BLOCK */
#define CMD41  (41)      /* SEND_OP_COND (ACMD) */
#define CMD55  (55)      /* APP_CMD */
#define CMD58  (58)      /* READ_OCR */


/* Port Controls  (Platform dependent) */
#define CS_SETOUT() TRISCbits.TRISC3 = 0 
#define CS_LOW()  LATCbits.LATC3 = 0  //MMC CS = L
#define CS_HIGH() LATCbits.LATC3 = 1  //MMC CS = H
//Change the SPI port number as needed on the following 5 lines
#define SPIBRG  SPI3BRG
#define SPIBUF  SPI3BUF
#define SPISTATbits SPI3STATbits
#define SPICONbits SPI3CONbits

#define  FCLK_SLOW()  SPIBRG = 128    /* Set slow clock (100k-400k) */
#define  FCLK_FAST()  SPIBRG = 16    /* Set fast clock (depends on the CSD) */


static volatile
DSTATUS Stat = STA_NOINIT;  /* Disk status */

static volatile
UINT Timer1, Timer2;    /* 1000Hz decrement timer */

static
UINT CardType;

typedef union 
{ 
    UINT int_data[128]; 
    BYTE byte_data[512];
} spi32_data;

unsigned char __attribute__((coherent)) rcvbuff[8192];

#define xmit_spi(dat)   xchg_spi(dat)
#define rcvr_spi()    xchg_spi(0xFF)
#define rcvr_spi_m(p)  SPIBUF = 0xFF; while (SPISTATbits.SPIRBE); *(p) = (BYTE)SPIBUF;

static
BYTE xchg_spi (BYTE dat)
{
  SPIBUF = dat;
  while (!SPISTATbits.SPIRBF);
  return (BYTE)SPIBUF;
}

/*-----------------------------------------------------------------------*/
/* Wait for card ready                                                   */
/*-----------------------------------------------------------------------*/

static
BYTE wait_ready (void)
{
  BYTE res;


  Timer2 = 500;  /* Wait for ready in timeout of 500ms */
  rcvr_spi();
  do
    res = rcvr_spi();
  while ((res != 0xFF) && Timer2);

  return res;
}



/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus                                 */
/*-----------------------------------------------------------------------*/

static
void deselect (void)
{
  CS_HIGH();
  rcvr_spi();
}



/*-----------------------------------------------------------------------*/
/* Select the card and wait ready                                        */
/*-----------------------------------------------------------------------*/

static
int select (void)  /* 1:Successful, 0:Timeout */
{
  CS_LOW();
  if (wait_ready() != 0xFF) {
    deselect();
    return 0;
  }
  return 1;
}




/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC                                          */
/*-----------------------------------------------------------------------*/

static
BYTE send_cmd (
  BYTE cmd,    /* Command byte */
  DWORD arg    /* Argument */
)
{
  BYTE n, res;


  if (cmd & 0x80) {  /* ACMD<n> is the command sequense of CMD55-CMD<n> */
    cmd &= 0x7F;
    res = send_cmd(CMD55, 0);
    if (res > 1) return res;
  }

  /* Select the card and wait for ready */
  deselect();
  if (!select()) return 0xFF;

  /* Send command packet */
  xmit_spi(0x40 | cmd);      /* Start + Command index */
  xmit_spi((BYTE)(arg >> 24));  /* Argument[31..24] */
  xmit_spi((BYTE)(arg >> 16));  /* Argument[23..16] */
  xmit_spi((BYTE)(arg >> 8));    /* Argument[15..8] */
  xmit_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) */
  xmit_spi(n);

  /* Receive command response */
  if (cmd == CMD12) rcvr_spi();  /* Skip a stuff byte when stop reading */
  n = 10;              /* Wait for a valid response in timeout of 10 attempts */
  do
    res = rcvr_spi();
  while ((res & 0x80) && --n);

  return res;      /* Return with the response value */
}

/*-----------------------------------------------------------------------*/
/* Send a data packet to MMC                                             */
/*-----------------------------------------------------------------------*/

#if _READONLY == 0
static
int xmit_datablock (  /* 1:OK, 0:Failed */
  const BYTE *buff,  /* 512 byte data block to be transmitted */
  BYTE token      /* Data token */
)
{
  BYTE resp;
  UINT bc = 512;


  if (wait_ready() != 0xFF) return 0;

  xmit_spi(token);    /* Xmit a token */
  if (token != 0xFD) {  /* Not StopTran token */
    do {            /* Xmit the 512 byte data block to the MMC */
      xmit_spi(*buff++);
      xmit_spi(*buff++);
    } while (bc -= 2);
    xmit_spi(0xFF);        /* CRC (Dummy) */
    xmit_spi(0xFF);
    resp = rcvr_spi();      /* Receive a data response */
    if ((resp & 0x1F) != 0x05)  /* If not accepted, return with error */
      return 0;
  }

  return 1;
}
#endif  /* _READONLY */


#if _READONLY == 0
DRESULT disk_write (
  BYTE pdrv,        /* Physical drive nmuber (0) */
  const BYTE *buff,    /* Pointer to the data to be written */
  DWORD sector,      /* Start sector number (LBA) */
  UINT count        /* Sector count (1..255) */
)
{
  if (pdrv || !count) return RES_PARERR;
  if (Stat & STA_NOINIT) return RES_NOTRDY;
  if (Stat & STA_PROTECT) return RES_WRPRT;

  if (!(CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */

  if (count == 1) {    /* Single block write */
    if ((send_cmd(CMD24, sector) == 0)  /* WRITE_BLOCK */
      && xmit_datablock(buff, 0xFE))
      count = 0;
  }
  else {        /* Multiple block write */
    if (CardType & CT_SDC) send_cmd(ACMD23, count);
    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))  /* STOP_TRAN token */
        count = 1;
    }
  }
  deselect();

  return count ? RES_ERROR : RES_OK;
}
#endif /* _READONLY */


/*-----------------------------------------------------------------------*/
/* Power Control  (Platform dependent)                                   */
/*-----------------------------------------------------------------------*/
/* When the target system does not support socket power control, there   */
/* is nothing to do in these functions and chk_power always returns 1.   */

static
void power_on (void)
{
    int cnt;
    
    /* Setup SPI */
  // Setup CS as output
  CS_SETOUT();
    SPICONbits.ON = 0;

    SPISTATbits.SPIROV = 0;

    SPICONbits.MSTEN = 1;
    SPICONbits.CKP = 1;
    SPICONbits.CKE = 0;
    SPICONbits.SMP = 1;
    SPICONbits.MODE16 = 0;
    SPICONbits.MODE32 = 0;
    SPICONbits.SRXISEL = 1;
    // Enables SPI port to run in Enhanced Buffer mode
    SPICONbits.ENHBUF = 0;
  SPICONbits.ON = 1;
}

static
void power_off (void)
{
  select();      /* Wait for card ready */
  deselect();

  SPICONbits.ON = 0;      /* Disable SPI */

  Stat |= STA_NOINIT;  /* Set STA_NOINIT */
}

/*-----------------------------------------------------------------------*/
/* Receive a data packet from MMC                                        */
/*-----------------------------------------------------------------------*/
static
int rcvr_datablock (  /* 1:OK, 0:Failed */
  BYTE *buff,      /* Data buffer to store received data */
  UINT btr      /* Byte count (must be multiple of 4) */
)
{
  BYTE token;


  Timer1 = 100;
  do {              /* Wait for data packet in timeout of 100ms */
    token = rcvr_spi();
  } while ((token == 0xFF) && Timer1);

  if(token != 0xFE) return 0;    /* If not valid data token, retutn with error */

  do {              /* Receive the data block into buffer */
    rcvr_spi_m(buff++);
    rcvr_spi_m(buff++);
    rcvr_spi_m(buff++);
    rcvr_spi_m(buff++);
  } while (btr -= 4);
  rcvr_spi();            /* Discard CRC */
  rcvr_spi();

  return 1;            /* Return with success */
}
/*--------------------------------------------------------------------------

   Public Functions

---------------------------------------------------------------------------*/


/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive                                                 */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
  BYTE drv    /* Physical drive nmuber (0) */
)
{
  BYTE n, cmd, ty, ocr[4];

  power_on();              /* Force socket power on */
        FCLK_SLOW();
  for (n = 80; n; n--) rcvr_spi();  /* 80 dummy clocks */

  ty = 0;
  if (send_cmd(CMD0, 0) == 1) {      /* Enter Idle state */
    Timer1 = 100;            /* Initialization timeout of 1000 msec */
    if (send_cmd(CMD8, 0x1AA) == 1) {  /* SDv2? */
      for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();      /* Get trailing return value of R7 resp */
      if (ocr[2] == 0x01 && ocr[3] == 0xAA) {        /* The card can work at vdd range of 2.7-3.6V */
        while (Timer1 && send_cmd(ACMD41, 0x40000000));  /* Wait for leaving idle state (ACMD41 with HCS bit) */
        if (Timer1 && send_cmd(CMD58, 0) == 0) {      /* Check CCS bit in the OCR */
          for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
          ty = (ocr[0] & 0x40) ? CT_SD2|CT_BLOCK : CT_SD2;  /* SDv2 */
        }
      }
    } else {              /* SDv1 or MMCv3 */
      if (send_cmd(ACMD41, 0) <= 1)   {
        ty = CT_SD1; cmd = ACMD41;  /* SDv1 */
      } else {
        ty = CT_MMC; cmd = CMD1;  /* MMCv3 */
      }
      while (Timer1 && send_cmd(cmd, 0));    /* Wait for leaving idle state */
      if (!Timer1 || send_cmd(CMD16, 512) != 0)  /* Set read/write block length to 512 */
        ty = 0;
    }
  }
  CardType = ty;
  deselect();

  if (ty) {      /* Initialization succeded */
    Stat &= ~STA_NOINIT;  /* Clear STA_NOINIT */
    FCLK_FAST();
  } else {      /* Initialization failed */
    power_off();
  }

  return Stat;
}



/*-----------------------------------------------------------------------*/
/* Get Disk Status                                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
  BYTE drv    /* Physical drive nmuber (0) */
)
{
  if (drv) return STA_NOINIT;    /* Supports only single drive */
  return Stat;
}



/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
{
  if (pdrv || !count) return RES_PARERR;
  if (Stat & STA_NOINIT) return RES_NOTRDY;

  if (!(CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */

  if (count == 1) {    /* Single block read */
    if ((send_cmd(CMD17, sector) == 0)  /* READ_SINGLE_BLOCK */
      && rcvr_datablock(buff, 512))
      count = 0;
  }
  else {        /* Multiple block 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 */
    }
  }
  deselect();

  return count ? RES_ERROR : RES_OK;
}

/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if _READONLY == 0
DRESULT w (
  BYTE drv,        /* Physical drive nmuber (0) */
  const BYTE *buff,    /* Pointer to the data to be written */
  DWORD sector,      /* Start sector number (LBA) */
  BYTE count        /* Sector count (1..255) */
)
{
  if (drv || !count) return RES_PARERR;
  if (Stat & STA_NOINIT) return RES_NOTRDY;
  if (Stat & STA_PROTECT) return RES_WRPRT;

  if (!(CardType & CT_BLOCK)) sector *= 512;  /* Convert to byte address if needed */

  if (count == 1) {    /* Single block write */
    if ((send_cmd(CMD24, sector) == 0)  /* WRITE_BLOCK */
      && xmit_datablock(buff, 0xFE))
      count = 0;
  }
  else {        /* Multiple block write */
    if (CardType & CT_SDC) send_cmd(ACMD23, count);
    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))  /* STOP_TRAN token */
        count = 1;
    }
  }
  deselect();

  return count ? RES_ERROR : RES_OK;
}
#endif /* _READONLY */



/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

DRESULT disk_ioctl (
  BYTE drv,    /* Physical drive nmuber (0) */
  BYTE ctrl,    /* Control code */
  void *buff    /* Buffer to send/receive data block */
)
{
  DRESULT res;
  BYTE n, csd[16], *ptr = buff;
  DWORD csize;


  if (drv) return RES_PARERR;
  if (Stat & STA_NOINIT) return RES_NOTRDY;

  res = RES_ERROR;
  switch (ctrl) {
    case CTRL_SYNC :  /* Flush dirty buffer if present */
      if (select()) {
        deselect();
        res = RES_OK;
      }
      break;

    case GET_SECTOR_COUNT :  /* Get number of sectors on the disk (WORD) */
      if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
        if ((csd[0] >> 6) == 1) {  /* SDv2? */
          csize = csd[9] + ((WORD)csd[8] << 8) + 1;
          *(DWORD*)buff = (DWORD)csize << 10;
        } else {          /* SDv1 or MMCv2 */
          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 = (DWORD)csize << (n - 9);
        }
        res = RES_OK;
      }
      break;

    case GET_SECTOR_SIZE :  /* Get sectors on the disk (WORD) */
      *(WORD*)buff = 512;
      res = RES_OK;
      break;

    case GET_BLOCK_SIZE :  /* Get erase block size in unit of sectors (DWORD) */
      if (CardType & CT_SD2) {  /* SDv2? */
        if (send_cmd(ACMD13, 0) == 0) {    /* Read SD status */
          rcvr_spi();
          if (rcvr_datablock(csd, 16)) {        /* Read partial block */
            for (n = 64 - 16; n; n--) rcvr_spi();  /* Purge trailing data */
            *(DWORD*)buff = 16UL << (csd[10] >> 4);
            res = RES_OK;
          }
        }
      } else {          /* SDv1 or MMCv3 */
        if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {  /* Read CSD */
          if (CardType & CT_SD1) {  /* SDv1 */
            *(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
          } else {          /* MMCv3 */
            *(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
          }
          res = RES_OK;
        }
      }
      break;

    case MMC_GET_TYPE :    /* Get card type flags (1 byte) */
      *ptr = CardType;
      res = RES_OK;
      break;

    case MMC_GET_CSD :  /* Receive CSD as a data block (16 bytes) */
      if ((send_cmd(CMD9, 0) == 0)  /* READ_CSD */
        && rcvr_datablock(buff, 16))
        res = RES_OK;
      break;

    case MMC_GET_CID :  /* Receive CID as a data block (16 bytes) */
      if ((send_cmd(CMD10, 0) == 0)  /* READ_CID */
        && rcvr_datablock(buff, 16))
        res = RES_OK;
      break;

    case MMC_GET_OCR :  /* Receive OCR as an R3 resp (4 bytes) */
      if (send_cmd(CMD58, 0) == 0) {  /* READ_OCR */
        for (n = 0; n < 4; n++)
          *((BYTE*)buff+n) = rcvr_spi();
        res = RES_OK;
      }
      break;

    case MMC_GET_SDSTAT :  /* Receive SD statsu as a data block (64 bytes) */
      if (send_cmd(ACMD13, 0) == 0) {  /* SD_STATUS */
        rcvr_spi();
        if (rcvr_datablock(buff, 64))
          res = RES_OK;
      }
      break;

    default:
      res = RES_PARERR;
  }

  deselect();

  return res;
}



/*-----------------------------------------------------------------------*/
/* Device Timer Interrupt Procedure  (Platform dependent)                */
/*-----------------------------------------------------------------------*/
/* This function must be called in period of 1ms                         */


void disk_timerproc (void)
{
}

Beim Debuggen hänge ich in dem wait_ready block
static
BYTE wait_ready (void)
{
  BYTE res;


  Timer2 = 500;  /* Wait for ready in timeout of 500ms */
  rcvr_spi();
  do
    res = rcvr_spi();
  while ((res != 0xFF) && Timer2);

  return res;
}

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

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

Autor: soso... (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael E. (cuby)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: soso... (Gast)
Datum:

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

Ich vermute eher, das Problem ist die Abbruchbedingung der 
while-Schleife:
    res = rcvr_spi();
  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:
/*exception handlers*/
/*
 * Exception cause:
    0       0x00 Int Interrupt
   1-3      0x01 ? Reserved
   4        0x04 AdEL Address error exception (load or instruction fetch)
   5        0x05 AdES Address error exception (store)
   6        0x06 IBE Bus error exception (instruction fetch)
   7        0x07 DBE Bus error exception (data reference: load or store)
   8        0x08 Sys Syscall exception
   9        0x09 Bp Breakpoint exception
   10       0x0A RI Reserved instruction exception
   11       0x0B CPU Coprocessor Unusable exception
   12       0x0C Ov Arithmetic Overflow exception
   13       0x0D Tr Trap exception
   14-31    0x0E-0x1F ? Reserved
 */
static uint32_t excep_addr, excep_vaddr, excep_cause, exception;
void _simple_tlb_refill_exception_handler(void){
    uint32_t cause;
    asm volatile("mfc0 %0,$8" : "=r" (excep_vaddr)); 
    asm volatile("mfc0 %0,$13" : "=r" (cause)); 
    asm volatile("mfc0 %0,$14" : "=r" (excep_addr)); 
    excep_cause = (cause&0x000000FF) >> 2;
    exception = 1;
}
void _general_exception_handler (void){
    uint32_t cause;
    asm volatile("mfc0 %0,$8" : "=r" (excep_vaddr)); 
    asm volatile("mfc0 %0,$13" : "=r" (cause)); 
    asm volatile("mfc0 %0,$14" : "=r" (excep_addr)); 
    excep_cause = (cause&0x000000FF) >> 2;
    exception = 2;
}
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 ;-)

Autor: soso... (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.