16bit resolution PWM wave player with SD card, super lite version.
Dependencies: mbed DirectSPI FastPWM
Supported boards (confirmed):
Nucleo-F030R8
Nucleo-L152RE
Nucleo-F401RE
Nucleo-F411RE
Only compilation is OK (unchecked, but may work):
Nucleo-L073RZ
Nucleo-F334R8
Nucleo-F303RE
Nucleo-F429ZI
Nucleo-F446RE
Nucleo-F446ZE
Nucleo-L476RG
Supported SD card:
SDSC/SDHC card,
FAT16 and FAT32.
(1) At first, format SD card using SD Card Formatter
https://www.sdcard.org/downloads/formatter_4/index.html
(2) Copy PCM wav files to the SD card.
Supported file:
PCM wave file that have file extension ".wav" on root directory.
16bit/8bit, fs(sampling rate)=32kHz,44.1kHz,48kHz.
Stereo/Mono.
Hardware setting:
Refer to the file port_setting.txt
PWM output port:
Left upper(Hi) PWM 8bit out: PB_5 (TM3_CH2)
Right upper(Hi) PWM 8bit out: PB4 (TM3_CH1)
Left lower(Low) PWM 8bit out: PC_9 (TM3_CH4)
Right lower(Low) PWM 8bit out: PC_8 (TM3_CH3)
USER_BUTTON: PC_13(default button)
Next song: One click in Play mode.
Pause : Push long time .
Play : One click from Pause.
sd_card.cpp
- Committer:
- mimi3
- Date:
- 2020-10-09
- Revision:
- 21:dc161a192ba7
- Parent:
- 4:8c1772c05eaf
File content as of revision 21:dc161a192ba7:
/* -- Title: Library for communicating with SD memory cards -- Author: Matthew Schinkel - borntechi.com, copyright (c) 2009, all rights reserved. -- Adapted-by: -- Compiler: >=2.4q2 -- Revision: $Revision: 3534 $ -- -- This file is part of jallib (http://jallib.googlecode.com) -- Released under the ZLIB license (http://www.opensource.org/licenses/zlib-license.html) -- -- Description: this library provides functions for SD memory cards. -- -- Notes: SD card SPI mode is 1,1 -- -- This version works with standard capacity sd cards up to 4gb and -- high capacity up to 32 gb. Extended Capacity up to 2TB -- may be supported later on. -- -- Sources: -- SanDisk Secure Digital Card - http://www.cs.ucr.edu/~amitra/sdcard/ProdManualSDCardv1.9.pdf -- How to use MMC/SDC - http://forums.parallax.com/forums/attach.aspx?a=32012 -- */ #include "sys.h" #include "sd_card.h" #if HAVE_DIRECT_SPI # include "DirectSPI.h" DirectSPI spi(SPI_MOSI,SPI_MISO,SPI_SCK); # define spi_write(m) spi.directWrite8(m) #else SPI spi(SPI_MOSI,SPI_MISO,SPI_SCK); # define spi_write(m) spi.write(m) #endif DigitalOut sd_chip_select(SPI_CS); #define _usec_delay(m) wait_us(m) #define SD_BYTE_PER_SECTOR 512 void sd_ready(); //-- counters word sd_byte_count = 0; word sd_sector_count = 0; dword sd_sector_select; //-- Basic Commands #define SD_GO_IDLE_STATE 0 #define SD_SEND_OP_COND 1 #define SD_SEND_IF_COND 8 //-- for SDHC only #define SD_SEND_CSD 9 //-- sd sends "Card Specific Data" standard or high capacity #define SD_SEND_CID 10 #define SD_STOP_TRANSMISSION 12 #define SD_SEND_STATUS 13 //-- Read Commands #define SD_SET_BLOCKLEN 16 #define SD_READ_SINGLE_BLOCK 17 #define SD_READ_MULTIPLE_BLOCK 18 //-- Write Commands #define SD_WRITE_BLOCK 24 #define SD_WRITE_MULTIPLE_BLOCK 25 #define SD_PROGRAM_CSD 27 //-- Write Protection Commands #define SD_SET_WRITE_PROT 28 #define SD_CLR_WRITE_PROT 29 #define SD_SEND_WRITE_PROT 30 //-- Erase Commands #define SD_ERASE_WR_BLK_START 32 #define SD_ERASE_WR_BLK_END 33 #define SD_ERASE 38 //-- Application Specific Commands #define SD_APP_CMD 55 //-- indicate that the next command is a application specific command #define SD_GEN_CMD 56 //-- Other Commands #define SD_READ_OCR 58 #define SD_CRC_ON_OFF 59 //-- default is off //-- application specific command, must write command 55 first #define SD_SD_STATUS 13 #define SD_SEND_NUM_WR_BLOCKS 22 #define SD_SET_WR_BLK_ERASE_COUNT 23 #define SD_SD_APP_OP_COND 41 #define SD_SET_CLR_CARD_DETECT 42 #define SD_SEND_SCR 51 //-- R1 RESPONCE boolS #define SD_IN_IDLE_STATE 0 #define SD_ERASE_RESET 1 #define SD_ILLEGAL_COMMAND 2 #define SD_COM_CRC_ERROR 3 #define SD_ERASE_SEQUENCE_ERROR 4 #define SD_ADDRESS_ERROR 5 #define SD_PARAMETER_ERROR 6 bool sd_error = false; bool sd_card_type = 0; #define SD_HIGH_CAPACITY 0 #define SD_STANDARD_CAPACITY 1 //-- carrier used to access SD-Card (pseudo-var dealing with SPI) //-- number of sectors variable //dword sd_number_of_sectors; //-- number of sectors * 512 = sd card size void sd_get_number_of_sectors(){} //-------------------------------------------------------------------------------- //-- send a command to the sd card (commands with 1 response only) //-------------------------------------------------------------------------------- void send_command(byte command,dword _data, byte *response){ byte x; uint16_t i; //-- send a valid CRC byte only for set idle command //-- right bool must always be 1 (stop bool) if( command == SD_GO_IDLE_STATE){ x = 0x95; }else if( command == SD_SEND_IF_COND){ x = 0x87; }else{ x = 0xFF; } command = command + 64;// -- left bools must be 01 (start bools) spi_write(0xFF); //-- send 8 clock pulses spi_write(command); //-- send the command spi_write((byte)(_data>>24) ); //-- send command parameters spi_write((byte)(_data>>16) ); //-- send command parameters spi_write((byte)(_data>>8 ) ); //-- send command parameters spi_write((byte)(_data ) ); //-- send command parameters //-- CRC data byte, crc disabled in this lib, but required for SD_GO_IDLE_STATE & SD_SEND_IF_COND commands. spi_write( x ); //-- Get a responce from the card after each command #define RETRY 10 for(i=0;i<RETRY;i++){ *response = spi_read(); //printf("\ncmd resp = %02X ",*response); //if( *response != 0xFF){ if( !(*response & 0x80 ) ){ break; } } #if DEBUG_SD_CARD if(i>=RETRY){ printf("\n Fail Command [0x%02X]",command);} #endif } //-------------------------------------------------------------------------------- //-- check if the sd card is ready after last command. //-------------------------------------------------------------------------------- void sd_ready(){ byte response = 1; while (response != 0) {// -- wait till last command has been completed //;start sdcard initialize send_command(SD_SEND_OP_COND,1, &response); // CMD1 } } //-------------------------------------------------------------------------------- //-- initalize the sd card in SPI data transfer mode. //-------------------------------------------------------------------------------- void sd_init(){ byte response = 0;// -- shows if sd card init is ok byte i; uint16_t count1 = 0; spi.frequency(500*1000);//500khz spi.format(8,0); //bool illegal_command at response : SD_ILLEGAL_COMMAND; #define illegal_command ( response & (1<<SD_ILLEGAL_COMMAND) ) //-- steps to set sd card to use SPI _usec_delay(1000);// -- delay sd_chip_select = 1;// -- chip select high for(i=0;i<10;i++){ spi_write(0xFF);// -- send clock pulses (0xFF 10 times) } //;-- try to contact the sd card while ( response == 0 ) { // -- try 100 times _usec_delay(1000); // -- delay 1ms sd_chip_select = 0; // -- enable the sd card _usec_delay(255); //-- delay 255us // -- command 0, Resets card to idle state, get a response send_command(SD_GO_IDLE_STATE,0,&response); // CMD0 sd_chip_select = 1; // -- disable the sd card count1 = count1 + 1; // -- increment count if( count1 == 100) { sd_error = true; #if DEBUG_SD_CARD printf("\n Error SD card initialize !"); #endif return; } //printf("\n response = 0x%02X",response); } //-- send SD_SEND_IF_COND command sd_chip_select = 0; // -- enable the sd card send_command(SD_SEND_IF_COND, 0x1AA, &response) ; //CMD8 //printf("\n sd_init"); if ( illegal_command ) { //-- SD CARD SPEC 1 #if DEBUG_SD_CARD printf("\n SDv1"); #endif #define print_string(sd,str) //printf(str) sd_card_type = SD_STANDARD_CAPACITY; sd_chip_select = 0;// -- enable the sd card //;start sdcard initialize //sd_ready();// -- CMD1 wait till sd card is ready sd_chip_select = 1;// -- disable the sd card sd_get_number_of_sectors(); return; }else{ //-- SD CARD SPEC 2 #if DEBUG_SD_CARD printf("\n SDv2"); #endif //; read OCR 4 byte response = spi_read(); response = spi_read(); response = spi_read();// ;0x01 response = spi_read();// ;0xAA sd_chip_select = 1;// -- disable the sd card if (response == 0xAA) { sd_chip_select = 0;// -- enable the sd card //-- check if it has completed init while(1){ //; send ACMD41 send_command(SD_APP_CMD, 0, &response); send_command(SD_SD_APP_OP_COND,0x40000000, &response); if( response == 0) { break; } } #if DEBUG_SD_CARD printf("\n ACMD41 OK"); #endif //-- read OCR here send_command(SD_READ_OCR,0, &response);// CMD58 if ((spi_read() & 0x40) > 0) {// ; ocr[0] sd_card_type = SD_HIGH_CAPACITY; //and BLOCK mode #if DEBUG_SD_CARD printf("\nSDHC block mode"); #endif }else{// -- sd card spec 2 standard capacity?? sd_card_type = SD_STANDARD_CAPACITY; //and none BLOCK mode #if DEBUG_SD_CARD printf("\n SDSC none block mode"); #endif } response = spi_read(); response = spi_read(); response = spi_read(); //-- set block size to 512 send_command(SD_SET_BLOCKLEN,512, &response); //sd_ready(); sd_chip_select = 1;// -- disable the sd card #if DEBUG_SD_CARD printf("\n Finished sd card initialize."); #endif }else{ sd_error = true; sd_chip_select = 1;// -- disable the sd card sd_get_number_of_sectors(); return; } } sd_get_number_of_sectors(); spi.frequency(16*1000000);// } //-------------------------------------------------------------------------------- //-- set the sd card to idle state //-------------------------------------------------------------------------------- void sd_set_idle(){ byte response = 0; sd_chip_select = 0;// -- enable the sd card send_command(SD_STOP_TRANSMISSION,0,&response);// -- stop current transmission send_command(SD_STOP_TRANSMISSION,0,&response);//-- stop current transmission send_command(SD_STOP_TRANSMISSION,0,&response);// -- stop current transmission send_command(SD_STOP_TRANSMISSION,0,&response);// -- stop current transmission sd_chip_select = 1;// -- disable the sd card } //-------------------------------------------------------------------------------- //-- tell sd card you will be reading data from a specified sector //-- do not interupt read process by switching to another spi component //-------------------------------------------------------------------------------- void sd_start_read(dword address){ byte response; sd_sector_select = address; //-- put spi into mode sd_chip_select = 0;// -- enable the sd card if( sd_card_type == SD_STANDARD_CAPACITY) { address = address * SD_BYTE_PER_SECTOR;// -- make sd card sector addressable, sd cards are normally byte addressable. } // -- send read multi block command, ignore response. send_command(SD_READ_MULTIPLE_BLOCK,address,&response); //CMD18 sd_byte_count = 0; sd_sector_count = 0;// -- reset count //wait_idle(); } //-------------------------------------------------------------------------------- //-- read 1 bytes from the sd card (pseudo ) //-------------------------------------------------------------------------------- byte sd_data_byte() { byte data_byte; if( sd_byte_count == 0) { // -- beginning of sector read while( spi_read() != 0xFE){} // -- wait till data is ready to read } data_byte = spi_read();// -- get data byte sd_byte_count = sd_byte_count + 1;// -- increment byte_count if( sd_byte_count == SD_BYTE_PER_SECTOR) {// -- end of sector read sd_byte_count = 0; sd_sector_count = sd_sector_count + 1;// -- increment sector number spi_read();// -- get junk crc data, crc is disabled spi_read();// -- get junk crc data, crc is disabled } return data_byte; } //-------------------------------------------------------------------------------- //-- tell sd card you are finished reading //-- needed to be the same as other mass media libs //-------------------------------------------------------------------------------- void sd_stop_read(){ sd_set_idle(); sd_chip_select = 1;// -- disable the sd card } //-------------------------------------------------------------------------------- //-- send a read pulse to the sd card, go 1 bytes forward in current sector. //-------------------------------------------------------------------------------- void sd_read_pulse_byte(word count1){ uint16_t i; for(i=0;i<count1;i++){// -- loop specified number of times sd_data_byte();// -- do a data read and ignore the incomming data } }