Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 2 of 2

Thread: speed up SD card transfer

  1. #1

    speed up SD card transfer

    I started a project with Arduino Mega2560. This project contains a library for audio output, SimpleSDAudio, see attachment. This library allows to output audio (speech in my application) by reading blocks of data from an SD card and generating the audio by PWM. Parallel to audio output the controller shall service lots of interrupts coming from a 433 MHz receiver. Both together prooved to be too much load for a Mega2560.

    So I decided to change to Teensy 3.2 which is much faster (16 MHz --> 96 MHz), installed Teensyduino IDE, and modified the library to SimpleSDAudio_Teensy, see attachment. This library contains many changes concerning my application, but the part to configure the SD card is the same, see the function SD_L0_init() in sd_l0.cpp respectively sd_l0_Te.cpp.

    In a first step I tested reading from the SD card and was disappointed because reading with Teensy 3.2 gets nearly the same speed as reading with Mega2560 inspite of 5 times faster clock. The transfer clock for SD card is defined by F_CPU/n (or f_OSC/n). n is defined by setting some bits in the SPCR register. This setting is the same for Mega2560 and for Teensy 3.2.

    Something in the background, I guess deep in some basic libraries, is changing the setting in SPCR for Teensy with the consequence that the 96 MHz are divided down to the same clock as the 16 MHz with Mega2560.

    For testing the speed of data transfer the code in is used, see attachment.
    The code in the function SD_L0_SpiSetHighSpeed(), see sd_l0_Te.cpp, is based on a posting from Paul Stoffregen:

    Agreed, the proper way is to use the SPI library. But there's still quite a lot of very old AVR code out there....

    I've added these missing AVR SPCR emulation features. Hopefully this makes everything work for you?

    Here's the complete sketch I used for testing.


    void setup() {
    pinMode(20, OUTPUT); // for comparison to Teensy++ 2.0
    pinMode(21, OUTPUT);
    pinMode(22, OUTPUT);
    digitalWrite(20, HIGH);
    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
    (1 << SPE) | /* SPI Enable */
    (0 << DORD) | /* Data Order: MSB first */
    (1 << MSTR) | /* Master mode */
    (0 << CPOL) | /* Clock Polarity: SCK low when idle */
    (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
    (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
    (1 << SPR0);
    SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */

    SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */;
    SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */

    void loop() {
    SPDR = 0x5A;
    while (!(SPSR & _BV(SPIF))) ; // wait


    The SD card shall contain a file with at least 512 consecutive blocks. In my code it is named ANSAGEK5.AHM. Any other name with 8.3 convention can be used. The file shall be located in the root directory.
    The SD card is conneted to Teensy 3.2:
    MISO 12
    MOSI 11
    SCK 13
    CS 4

    Now my question is, how can I increase the SD clock frequency?
    Attached Files Attached Files

  2. #2
    my initial post was rather complex. Now I have a more simple question.
    For setting the clock rate the SimpleSDAudio library contains two functions, SD_L0_init() and SD_L0_SpiSetHighSpeed().

    void SD_L0_Init(void)
    	/* Power up card */
    	// not for arduino
    	/* Setup ports */
       pinMode(SD_L0_CSPin, OUTPUT);
       pinMode(MISO, INPUT);
       pinMode(SCK, OUTPUT);
       pinMode(MOSI, OUTPUT);
       pinMode(SS, OUTPUT);
       digitalWrite(SCK, LOW);
       digitalWrite(MOSI, LOW);
       digitalWrite(SS, HIGH);
        /* Powering up takes at least 500us for capacitors to charge */
        // not for arduino
    //Serial.print(F("SIM_SCGC6=")); Serial.println(SIM_SCGC6,HEX);
    //Serial.print(F("SPI0_MCR=")); Serial.println(SPI0_MCR,HEX);
    //Serial.print(F("SPI0_CTAR0=")); Serial.println(SPI0_CTAR0,HEX);
        /* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */
        REGspcr = (0 << SPIE) | /* SPI Interrupt Enable */
               (1 << SPE)  | /* SPI Enable */
               (0 << DORD) | /* Data Order: MSB first */
               (1 << MSTR) | /* Master mode */
               (0 << CPOL) | /* Clock Polarity: SCK low when idle */
               (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
               (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */ 
               (1 << SPR0);
    	SPCR = REGspcr;
        SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */
     * Set SPI for full operation speed (up to 25 MHz).
     * Will be called after first part of card 
     * initialization was successful.
    void SD_L0_SpiSetHighSpeed(void)
    {	// fuer Teensy3.2 geht es nur ueber den backup-Wert (SPCR nur schreibbar)
        REGspcr &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */
    	SPCR = REGspcr;
    					//SPI0_CTAR0 &= 0xFFFCFFF0;
        SPSR |= (1 << SPI2X);         /* Doubled Clock Frequency: f_OSC / 2 */
    According to the comments in the code, SD_L0_SpiSetHighSpeed() should set the SPI clock to f_OSC/2. This is true for a Mega2560 with f_OSC=16 MHz but not for a Teensy3.2 with 96 MHz. Measurements with an oscilloscope show 8 MHz for both.

    The manual for Teensy3.2 describes registers for SPI configuration. With register SPI0_CTAR0 the SPI clock can be set. In a first step I just wanted to print the contents of some registers to verify that I have understood the manual.

    Uncommenting the three Serial.print lines within SD_L0_Init() results in a print out of SIM_SCGC6, but after the text "SPI0_MCR=" the program hangs. Serial Monitor output is
    Why is'nt it possible to print register contents of SPI0_MCR and why is the program hanging?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts