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/
Memos From the Cube » Excitement and exhaustion // Apr 26, 2010 at 9:31 am
[...] 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 [...]
works a treat on my at90usb1287 first go… although your make file is corrupt…
whats the licensing on your code?
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.
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?
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
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.
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?
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
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
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.
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.
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.
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.
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
Can you also use a teensy 2.0++ without a SD card?
The teensy 2.0++ has proper storage.
Thanks for any response
Paul
Hi Paul,
It depends on your application requirements.
The Teensy++ 2.0 uses an AT90USB1286 microcontroller with 128KB of Flash memory.
If your storage needs are within this capacity, it is indeed easier to store your data as const arrays in your flash memory (small pictures, LCD fonts…). But as soon as you want to use audio media in your application or big data files (1MB, 10MB…), an external SD card is much more practical. For a WAV audio playback application, you could store more than 3 hours of CD-quality audio (44.1kHz stereo 16 bits) on a 2GB SD card…
Another solution is to use an external serial Flash memory device integrated in your design, but it will lack the removable media practicality for your user.
Mathieu
So this gave me the great idea of activating the “flashdrive” (SD Card adaptor) – copy the files to the PC via CMD and then disable the SD card adaptor.
Hi Gabriel,
Do you mean driving cmd.exe from a USB keyboard profile in the Teensy2 ? Yes it could be done with a composite USB profile.
But I think the malicious potential (like in Teensy AVRs used in penetration testing) could limit the usefulness of the idea.
BR
Mathieu
Thanks for the reply,
The idea bascially is:
- Make the teensy a composite USB = Flashdrive + Keyboard
- Connect this to the host
- Make the “Keyboard” copy the files in the “Flashdrive” to the computer
- Dissmount the “Flashdrive”
- Execute the files
Keep up the good work !
Hi,
I tried running this application using the at90usb162 but it doesn’t work as the memory card, I reduced the buffer size that’s used to access the memory card, then it shows the device connected as a USB MassStorage device but the device is not mounted.
My question is will the buffer of 256 bytes is ok to access the data from MMC, is there any way that I could use at90usb162(with 512 bytes SRAM) as a card reader.
Thanks in advance.
Hi Prashanth,
By default, the sd-reader library caches the last read or written SD card sector in memory and thus can not work with the AT90USB162 as a sector is 512 bytes.
You can use less memory by setting SD_RAW_SAVE_RAM to 1 in sd_raw_config.h. You must also set SD_RAW_WRITE_SUPPORT to 0, because buffering is mandatory for write operations.
With this configuration, you should be able to use the AT90USB162 as a read-only card reader.
Because the Mass Storage profile is block oriented, you could implement block writing without buffering. It would require modifying the sd_raw_write_interval function to send a CMD_WRITE_SINGLE_BLOCK command to the SD card and then get the data from a callback that would read directly 16-byte packets from the USB endpoint, like it is done in SDCardManager_WriteBlockHandler.
I had not the courage to implement this for the Teensy1 and switched to the Teensy2 instead when I built my demo code
BR,
Mathieu
Hi Chief,
Thanks for the previous reply for at90usb162 I tried SD_RAW_SAVE_RAM to 1 and SD_RAW_WRITE_SUPPORT to 0, I had the write functions undefined removed the SDCardManager_WriteBlocks function call and compiled the same code, the card is detected by the controller but the MMC device doesnot mount on ubuntu never tried with a different OS, so should I change something on the OS side, and my at90usb162 runs at 8Mhz not 16 MHz
the messages that I get on minicom (serial port is as follows) when the MMC card is connected, for single restart.
Connect
Connect
Connect
Connect
Connect
Ready
Connect
Connect
Ready
Connect
Connect
Ready
Connect
Connect
Ready
Connect
Connect
Ready
and when the MMC card is not connected I get this message continuously on my serial port
MMC/SD initialization failed
Any further help greatly appreciated thanks in advance,
Prashanth. G
Hi Chief,
My at90usb162 works as a read only MMC card reader with the changes you suggested and in addition to that, I changed the configuration of endpoints which were double bank to single bank, it doesn’t work with ejecting the card,
Prashanth. G
Hi Prashanth,
The USB communication does not seem to work correctly. You should only see one Connect followed by one Ready.
You are not reaching the moment where the PC tries to read or write from the SD card.
Have you changed the values for your target in the project Makefile ?
MCU = at90usb162
F_CPU = 8000000
F_CLOCK = 8000000
BR,
Mathieu
Hi Cheif I changed the MCU, F_CPU, F_CLOCK parameters in the make file now I can read the files from the MMC but I get more number of connect and ready the sequence is as follows.
USB Disconnect
Connect
Connect
USB Disconnect
Connect
Connect
Connect
Ready
SD blocks: 0
Invalid Command
Invalid Command
more than 12 Invalid commands
then
R 0 8
6 Invalid Commands then it displays the usual text, it works as a read only card reader but eject section is an error
I still have to edit the sd_raw_write_interval function
Regards,
Prashanth. G