greiman / SdFat

Arduino FAT16/FAT32 exFAT Library
MIT License
1.07k stars 502 forks source link

SD initialization error #321

Open prugit1 opened 3 years ago

prugit1 commented 3 years ago

Hi,

I am trying to run your AvrAdcLogger example code. But whenever I run the code I am getting the error "sd.begin failed", but when I uploaded the ReadWrite example code from Arduino IDE it worked. I am confused and didn't understand why it isn't working in the case of your code. Kindly help me to fix the issue. I have attached a screenshot for your reference. Screenshot (347)

greiman commented 3 years ago

AvrAdcLogger is designed for exFAT. If your card works with the old version of SdFat in the Arduino IDE it must be a FAT16/FAT32 card.

Try changing SD_FAT_TYPE from two to one here:

//------------------------------------------------------------------------------
// This example was designed for exFAT but will support FAT16/FAT32.
//
// If an exFAT SD is required, the ExFatFormatter example will format  <<--- this example has been removed.
// smaller cards with an exFAT file system.
//
// Note: Uno will not support SD_FAT_TYPE = 3.
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
#define SD_FAT_TYPE 2  <<---------------------Change 2 to 1

I removed the ExFatFormatter example since cards designed for FAT16/FAT32 should not be formatted exFAT. I will fix the above comment in a future version of SdFat.

prugit1 commented 3 years ago

Hi, Thank you for your reply.

I have changed the SD_FAT_TYPE to 1 as well as 0 but in both cases, it didn't work. When I uploaded the ReadWrite example code from Arduino IDE it worked. I have attached Screenshot (350) Screenshot (352) the screenshots for your reference. Kindly help me to resolve the issue.

greiman commented 3 years ago

Can't help since when I only make this change to AvrAdcLogger:

#define SD_FAT_TYPE 1

I get this with an Uno and an Adafruit data logging shield:

Type any character to begin.

Unused stack: 1080

type: b - open existing bin file c - convert file to csv l - list files p - print data to Serial r - record ADC data

I used an 8GB SanDisk card formatted FAT32 with SD Formatter.

The old version of SdFat in SD.h uses a very slow clock so it may be your hardware.

greiman commented 3 years ago

I now recall from the issue you closed about Due that you wanted to record 10 sensors at 25 kHz. You will need to use a high end ARM processor like STM32 and write a custom DMA ADC driver.

STM32 allows you to setup a sequence of up to 16 channels and the hardware will sequence through the channels.

I would also suggest you use a RTOS like ChibiOS and a high end STM32 with lots of SRAM. Arduino is just not up to 250K samples per second.

prugit1 commented 3 years ago

Can't help since when I only make this change to AvrAdcLogger:

#define SD_FAT_TYPE 1

I get this with an Uno and an Adafruit data logging shield:

Type any character to begin. Unused stack: 1080 type: b - open existing bin file c - convert file to csv l - list files p - print data to Serial r - record ADC data

I used an 8GB SanDisk card formatted FAT32 with SD Formatter.

The old version of SdFat in SD.h uses a very slow clock so it may be your hardware.

Thanks for your reply. The error which I got was resolved when I formatted the SD card using the SD Formatter, which you have specified. So I think the issue is with the error in formatting using default settings in Windows OS.

prugit1 commented 3 years ago

I now recall from the issue you closed about Due that you wanted to record 10 sensors at 25 kHz. You will need to use a high end ARM processor like STM32 and write a custom DMA ADC driver.

STM32 allows you to setup a sequence of up to 16 channels and the hardware will sequence through the channels.

I would also suggest you use a RTOS like ChibiOS and a high end STM32 with lots of SRAM. Arduino is just not up to 250K samples per second.

Since I don't have much knowledge on programming 32bit ARM processors, I thought of starting with Due as quite good resources are available when compared to Protenta H7. At this moment I trying to modify your code so that it works with Due.

But eventually, I will use the Protenta H7 board. It has got 3 ADC's thereby allowing simultaneous sampling up to 3.6 MS/s per channel per ADC.

greiman commented 3 years ago

Protenta H7 ADC with the Arduino IDE is a disaster the driver is slow. You will never get close to reading 10 channels at 25KHz with this driver. This leaves zero time to write to SD and the Arduino SD library on Protenta is slow.

I spent about a month working with a user who wanted to use a Protenta with SdFat to record ADC data. We gave up.

You will only get high speed if you write a custom driver.

greiman commented 3 years ago

The Protenta H7 Arduino IDE is a wrapper for the mbed OS.

analogRead() calls the mbed AnalogIn::read_16() function.

Here is an mbed program I used on a STM32H7 board to time the driver. Arduino's analogRead wrapper is slower.

#include "mbed.h"

// Initialize a pins to perform analog input
AnalogIn   ain(A0);

int main(void)
{
    Timer t;

    t.start();

    while (1) {
        uint16_t data[10];
        auto us = t.elapsed_time().count();
        for (int i = 0; i < 10; i++) {
            data[i] = ain.read_u16();
        }
        us = t.elapsed_time().count() - us;
        printf("\ntime us %lld\n\n", us);
        for (int i = 0; i < 10; i++) {
            printf("data[%d] %d\n", i, data[i]);
        }
        ThisThread::sleep_for(1000ms);
    }
}

Here is the output:

time us 580

data[0] 12670 data[1] 11734 data[2] 11100 data[3] 10430 data[4] 9961 data[5] 9575 data[6] 9244 data[7] 8966 data[8] 8811 data[9] 8646 So it took 580 usec for10 reads. or 58 usec per read. That's under 18,000 samples per second.

prugit1 commented 3 years ago

Protenta H7 ADC with the Arduino IDE is a disaster the driver is slow. You will never get close to reading 10 channels at 25KHz with this driver. This leaves zero time to write to SD and the Arduino SD library on Protenta is slow.

I spent about a month working with a user who wanted to use a Protenta with SdFat to record ADC data. We gave up.

You will only get high speed if you write a custom driver.

I wrote a bare-metal program to work with Protenta H7 ADC. The code was compiled but when I am running it, I found the code isn't working. I have attached the code and output. Kindly help me if you know how to resolve it.


#define ADC_ISR_EOC_Pos                   (2U)
#define ADC_ISR_EOC_Msk                   (0x1UL << ADC_ISR_EOC_Pos)           /*!< 0x00000004 */
#define ADC_ISR_EOC                       ADC_ISR_EOC_Msk                      /*!< ADC End of Regular Conversion flag */
uint16_t value;
uint32_t count=0;

void setup() {

Serial.begin(9600);

RCC-> AHB4ENR |= (1U<<2);  //Clock enable for GPIO pin

GPIOC->MODER |=(1U<<6) | (1U<<7);  //Set PC3 as analog pin

RCC-> AHB1ENR |=(1U<<5);  //Clock enable for ADC

ADC1->CFGR |= (1U<<13); //Set conversion to continuous

ADC1->SQR1 =0; //Set sequence length 

ADC1->SQR1 |=(1U<<9) | (1U<<8) | (1U<<6);  //set SQ1 to ADC1 channel 13

ADC1 ->CR |=(1U<<0);  //Enable ADC

ADC1->IER |=(1U<<2); //Set end of regular conversion interrupt enable

NVIC_EnableIRQ(ADC_IRQn); //Enable NVIC ADC interrupt

ADC1->CR |=(1U<<2);  //Start of regular conversion

}

void loop() {
  //Serial.println(value);
  if(millis()>1000){Serial.println(count);}
}

void ADC_IRQHandler(){
  if((ADC1->ISR & ADC_ISR_EOC) == ADC_ISR_EOC){  //Check for EOC bit enable
    ADC1->ISR &=~ADC_ISR_EOC;   //Disable EOC bit
    value=ADC1->DR;  //Read data from ADC1 Data Register
    count=count+1;
  }
}

Output:-

0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
greiman commented 3 years ago

You may never get good results on Portenta H7. I have finally been able to use ChibiOS to get good results on with a Nucleo H743ZI2.

I found that the Ethernet PHYS was causing huge noise interference with the ADC. The Protenta H7 has the same chip, a LAN8742AI. At power on this chip becomes active. I tried to stop the noise by opening a solder bridge that claimed to to disable Ethernet but no luck. I finally removed a ferrite bead which killed power to the Ethernet section.

I then customized the ChibiOS driver and got over a factor of 100 decrease in noise for 16-bit resolution.

The ChibiOS source is here:

https://osdn.net/projects/chibios/releases

the H7 ADC driver is here:

D:\ChibiOS\ChibiOS_21.6.0\os\hal\ports\STM32\LLD\ADCv4

I used these settings for continuous circular DMA buffers. My example uses 10 MHz ADC clock since H7 LQFP144 packages are limited to 12 MHz max for 16-bits. See:

https://www.st.com/resource/en/application_note/dm00628458-getting-started-with-the-stm32h7-series-mcu-16bit-adc-stmicroelectronics.pdf

const ADCConversionGroup portab_adcgrpcfg2 = {
  .circular     = true,
  .num_channels = ADC_GRP2_NUM_CHANNELS,
  .end_cb       = adccallback,
  .error_cb     = adcerrorcallback,
  .cfgr         = ADC_CFGR_CONT_ENABLED /*| ADC_CFGR_RES_12BITS | ADC_CFGR_EXTEN_RISING |
                      ADC_CFGR_EXTSEL_SRC(12)*/,  /* TIM4_TRGO */
  .cfgr2        = 0U,
  .ccr          = 0U,
  .pcsel        = ADC_SELMASK_IN0 | ADC_SELMASK_IN5,
  .ltr1         = 0x00000000U,
  .htr1         = 0x03FFFFFFU,
  .ltr2         = 0x00000000U,
  .htr2         = 0x03FFFFFFU,
  .ltr3         = 0x00000000U,
  .htr3         = 0x03FFFFFFU,
  .smpr         = { 
    ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_32P5) |
    ADC_SMPR1_SMP_AN5(ADC_SMPR_SMP_32P5),
    0U
  },
  .sqr          = {
    ADC_SQR1_SQ1_N(ADC_CHANNEL_IN5) | ADC_SQR1_SQ2_N(ADC_CHANNEL_IN5),
    0U,
    0U,
    0U
  }
}; 
greiman commented 3 years ago

You may need to declare value volatile.
volatile uint16_t value;

Also the H7 is quirky with RAM caches so if you use DMA, you may need to invalidate the CPU cache to access data. ChibiOS has calls to do that.