Elastic Sheep

Because elasticdog was already taken

Elastic Sheep header image 2

Teensy2 USB Mass Storage with an SD card

April 12th, 2010 · 14 Comments · Uncategorized

Iterating on my precedent post, the next logical step is to use the USB interface to access the SD card connected to the Teensy2/ATMEGA32U4 with a Mass Storage profile.

LUFA Mass Storage demo

The LUFA library offers a mass storage demo. It is based on the AT90USBKEY demonstration board that provides two onchip serial flash memories accessed via the SPI bus. With the LUFA demo, the flash memories can ve viewed as an USB flash drive from a host PC.

To read/write data in the flash storage, the host uses the SCSI Primary Command (SPC) Set and SCSI Block Command (SBC) Set. Those SCSI commands are wrapped in Command Block Wrapper (CBW) and Command Status Wrapper (CSW) structures.

Here is a bloc diagram of the demo code:

The CBW are received from the host and decoded in MassStorage.c. The extracted SCSI commands are handled by SCSI.c. Then DataFlashManager.c provides an interface to read/write data blocks using the DataFlash driver.

In the SCSI_Command_Read_Capacity_10 handler, the block size VIRTUAL_MEMORY_BLOCK_SIZE is set to 512 bytes. The flash capacity is returned as a number of 512-bytes blocks. This is the same block size used in SD card with capacity smaller than 2GB.

The DataFlashManager directly reads small data blocks from the OUT endpoint and write them to the data flash. Doing like that you don’t need to store full data blocks in the MCU RAM. Incoming data are only stored in the endpoint buffer before being written to the data flash. The same principle is used to read data blocks from the data flash to the IN endpoint.

Integration of a SD driver

To access a SD card instead of a dataflash, I simply need a driver able to read/write raw blocks through the SPI bus. I will re-use the sd_raw driver from the sd-reader library introduced in the previous post.

Between the SCSI decoder and the sd_raw driver, I developped a SdCardManager adapted from the DataFlashManager of the original LUFA demo.

Here is the bloc diagram with my modifications:

The SDCardManager layer implements read/write operations directly from/to the USB endpoints.

Because data blocks are not stored in RAM, I can not directly use the functions sd_raw_read and sd_raw_write. Instead I will use the functions sd_raw_read_interval and sd_raw_write_interval that allows to do data transfers using callbacks.

The hardware

The hardware used to test my application is a Teensy2/ATMEGA32U4 with a SD card adapter connected on the SPI bus. The serial port is used to output debug traces.

Compiling the project

See at the end of the post how to download my source code.

The application code is located in the LowLevelMassStorage+SD directory. Just type make to compile it.

The resulting MassStorage.hex binary can be downloaded to a Teensy2 with the Teensy loader.

Connecting to the host

I insert a 2GB SD in my adapter and connect the Teensy2 to OS X. Using the serial port and printf, I can see read and write commands being issued to the application:

$ cu -s 9600 -l /dev/tty.usbserial
MMC/SD initialization failed
USB Connect
USB_Device_SetConfiguration
USB Ready
R 0 1
W 0 1
R 0 48
R 0 1
R 0 1
R 0 1
R 1 1
R 63 8
R 550 1
R 551 1
R 552 1
R 553 1
R 63 8
R 64 1
R 63 8
R 543 8
R 551 8
R 559 8
R 567 8
R 575 8
R 583 8
R 63 8
R 64 243
W 64 8
W 307 8
R 550 32
R 582 64
W 2694 8
W 64 8
W 307 8
W 550 32
W 2630 64
R 646 8
R 902 64
W 64 8
W 307 8
W 582 64

When the activity stops, I can see my SD card successfully mounted in the Finder:

I can copy files on the SD card and then read them again without problem.
It is just that the transfer speed is suddenly very slow compared to a real SD card reader ;) .

Source code

As an experiment, the source code for this project can be downloaded from my BitBucket Mercurial repository: http://bitbucket.org/elasticsheep/lufa-sdcard-mass-storage-demo/get/V1.zip. A binary is also available.

The repository root address is http://bitbucket.org/elasticsheep/lufa-sdcard-mass-storage-demo/

Tags: ·····

14 Comments so far ↓

  • Memos From the Cube » Excitement and exhaustion

    [...] it a warmth I haven’t felt from a textbook before. Good stuff.A few days ago I came across a really neat post about the LUFA Mass Storage Device demo code, and how to modify it to support SD cards instead of [...]

  • Daniel

    works a treat on my at90usb1287 first go… although your make file is corrupt…

    whats the licensing on your code?

  • The Chief Sheep

    Hi Daniel,

    Thanks for your comment. Can you elaborate on the problem you run into with my Makefile ?

    To answer your question about code license:
    * the LUFA library is covered by the MIT license.
    * the sd-reader files (sd_raw.*) are covered by the LGPL 2.1 license.
    * my own code (SDCardManager.*) is covered by the MIT license.

  • Steven Meyer

    I’m assuming the file is at /Lufa/Demos/Device/LowLevel/ and when I try compiling it it says:

    ——– begin ——–
    avr-gcc (GCC) 4.3.2
    Copyright (C) 2008 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    make: *** No rule to make target `MassStorage.elf’, needed by `elf’. Stop.

    Any ideas on what the problem is?

  • Steven Meyer

    WOW, nvm I’m dumb. Now when I try compiling it I get this:

    steven@steven-laptop:/media/USB/lufa-sdcard-mass-storage-demo/LowLevelMassStorage+SD$ make

    ——– begin ——–
    avr-gcc (GCC) 4.3.2
    Copyright (C) 2008 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions. There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

    Compiling C: MassStorage.c
    avr-gcc -c -mmcu=atmega32u4 -I. -gdwarf-2 -DF_CPU=16000000UL -DF_CLOCK=16000000UL -DBOARD=BOARD_USER -D USB_DEVICE_ONLY -D FIXED_CONTROL_ENDPOINT_SIZE=8 -D FIXED_NUM_CONFIGURATIONS=1 -D USE_FLASH_DESCRIPTORS -D USE_STATIC_OPTIONS=”(USB_DEVICE_OPT_FULLSPEED | USB_OPT_REG_ENABLED | USB_OPT_AUTO_PLL)” -D INTERRUPT_CONTROL_ENDPOINT -Os -funsigned-char -funsigned-bitfields -ffunction-sections -fno-inline-small-functions -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wundef -Wa,-adhlns=./MassStorage.lst -I../LUFA_091223/ -std=gnu99 -Wundef -MMD -MP -MF .dep/MassStorage.o.d MassStorage.c -o MassStorage.o
    MassStorage.c: In function ‘SetupHardware’:
    MassStorage.c:74: warning: implicit declaration of function ‘clock_prescale_set’
    MassStorage.c:74: error: ‘clock_div_1’ undeclared (first use in this function)
    MassStorage.c:74: error: (Each undeclared identifier is reported only once
    MassStorage.c:74: error: for each function it appears in.)
    make: *** [MassStorage.o] Error 1

  • The Chief Sheep

    Hi Steven,

    It looks like your version of avr-libc does not support the ATMEGA32U4 microcontroller.

    I checked in the avr-libc history and it appears that the support of the clock_prescale_set macro for the ATMEGA32U4 has been added in the 1.6.3 version. I am currently using the avr-libc-1.6.7 from CrossPack-AVR-20100115.

  • JRSmile

    Hi there, you are the one with the most progress done so far i found on the internet, im looking for someone who could help me converting the teensy to a bootable USB CD-ROM Emulator.

    i want to develop a usb-stick like device which can be dip-switched to a cd-rom drive loading an iso file from the sd card.

    but at first i have the problem that if i change the SCSI_INQUIERY_RESPONSE to a cd-rom drive instead of a mass-storage device the attached pc freezes, any idea what that could be?

  • The Chief Sheep

    Hi Jan,

    This is an interesting project.

    From what I could gather about Mass Storage profile for CD drive, you can specify a CD/DVD Peripheral Device Type in the InquiryData structure returned in response to the SCSI_CMD_INQUIRY command in SCSI.c. But then in this case you have to implement the MMC-4 command set instead of the SBC-2 command set used for flash drive.

    I suppose your PC is freezing because it receives bad response to its requests.
    I would suggest enabling the printf in the SCSI_DecodeSCSICommand function to check the requests sent by the PC.

    The MMC-4 spec can be found at this address: http://www.13thmonkey.org/documentation/SCSI/mmc4r05a.pdf

  • Manolo

    Congratulations on your work.

    I’m working on your code, when I try load it with the hex file, works, but if I make a new project with the avrstudio, the sd card isn´t recognized automatically as with the hex file. The sd card is detected by the pc, but isn´t detected as a storage unit.

    Any idea where it might be the problem?

    thanks

  • The Chief Sheep

    Hi Manolo,

    What version of AvrStudio are you using ? How do you compile the project ?

    I tried to build the project with the latest AVRStudio 4.18SP2 and got an HEX file that is almost identical to the one provided. With this HEX file, when I connect the Teensy2 to Windows XP or 7, I am able to see the content of the SD card.

    I compared the LSS files from CrossPack vs AVRStudio and there is no significant difference in the generated assembly code.

  • Manolo

    thanks so much, I´ve got other problem, I need write, text and values of adc (the adc, run sucesfully ) in a file .txt in the sd card, . I´m testing with the functions of avr libs (fdevopen) and the functions in your file, sd_raw. I know that I need work in blocks of 512 bits (fat32), but it doesn´t run me.
    I saw the rest of your project with the atmega32u4, and they´re very good.

  • Vikas

    Can you elaborate on the speed of read/write you are getting for your implmentation.

    I did something similar on pic18f with USB and SD card.Im finding it very slow.

  • The Chief Sheep

    Hello Vikas,

    Same experience as you, reading the SD is slow and writing on it is very slow…

    I am done some tests with my WAV player application and the best case I observe is 300kBytes/s when reading raw blocks from the SD. It should be about the same with the Mass Storage application.

    The main bottleneck is the SPI clock limited to 8MHz with a 16MHz crystal. The SD card specifications state a maximum clock frequency of 25MHz, and the MMC specifications state a maximum clock frequency of 52MHz depending on the device.

  • JRSmile

    Hi there,
    after a lot of trial and error i stopped developing with the teensy for a while, and buyed myself an http://www.i-odd.com to get what i want.

    But i have plenty of spare time now and want to try the teensy (usb-stick) version of the bootable cd-rom emulator again.

    so id like to request if you could try to write an “howto” how to get an iso image of a fat32 partition mounted as cd-rom.

    best regards,
    JR

Leave a Comment