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)
http://mpu.up.seesaa.net/image/16bit-wave-player-output-schema.png
USER_BUTTON: PC_13(default button)
Next song: One click in Play mode.
Pause : Push long time .
Play : One click from Pause.

Committer:
mimi3
Date:
Tue Jan 15 12:45:24 2019 +0000
Revision:
0:9a5c2fb0d96f
Child:
10:1108261dabe8
first

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mimi3 0:9a5c2fb0d96f 1 #include "sys.h"
mimi3 0:9a5c2fb0d96f 2 #include "sd_card.h" // -- include the sd card ide hard disk library
mimi3 0:9a5c2fb0d96f 3 #include "fat_lib.h"
mimi3 0:9a5c2fb0d96f 4
mimi3 0:9a5c2fb0d96f 5 //;sd_init() // -- initialize startup settings
mimi3 0:9a5c2fb0d96f 6
mimi3 0:9a5c2fb0d96f 7 extern Serial pc;
mimi3 0:9a5c2fb0d96f 8
mimi3 0:9a5c2fb0d96f 9 /******************
mimi3 0:9a5c2fb0d96f 10 definition of global variables
mimi3 0:9a5c2fb0d96f 11 *******************/
mimi3 0:9a5c2fb0d96f 12 byte gDirEntryBuff[32];
mimi3 0:9a5c2fb0d96f 13 byte gbBPB_SecPerClus;
mimi3 0:9a5c2fb0d96f 14 dword gdwBPB_FileSize;
mimi3 0:9a5c2fb0d96f 15 word lgwBPB_BytesPerSec;
mimi3 0:9a5c2fb0d96f 16 word gwBPB_RootEntCnt;
mimi3 0:9a5c2fb0d96f 17 //--
mimi3 0:9a5c2fb0d96f 18 dword gdwRootdir_sector, gdwTargetFileSector;
mimi3 0:9a5c2fb0d96f 19 word gwSize_of_root;
mimi3 0:9a5c2fb0d96f 20 sbit gfFat32 ;
mimi3 0:9a5c2fb0d96f 21
mimi3 0:9a5c2fb0d96f 22 /******************
mimi3 0:9a5c2fb0d96f 23 FAT_init
mimi3 0:9a5c2fb0d96f 24 *******************/
mimi3 0:9a5c2fb0d96f 25 /*
mimi3 0:9a5c2fb0d96f 26 ; Refer to ChaN's FAT info page,
mimi3 0:9a5c2fb0d96f 27 ; http://elm-chan.org/docs/fat.html#bpb
mimi3 0:9a5c2fb0d96f 28 ; Thank you, ChaN san.
mimi3 0:9a5c2fb0d96f 29 */
mimi3 0:9a5c2fb0d96f 30 void FAT_init() {
mimi3 0:9a5c2fb0d96f 31 byte bi;
mimi3 0:9a5c2fb0d96f 32 #define bpbBuff gDirEntryBuff //; shares as temporaly data memory
mimi3 0:9a5c2fb0d96f 33 dword dwBPB_SecPerFats32;
mimi3 0:9a5c2fb0d96f 34 word wBPB_RsvdSecCnt;
mimi3 0:9a5c2fb0d96f 35 dword dwBPB_HiddSec;
mimi3 0:9a5c2fb0d96f 36 dword dwBPB_Sector;
mimi3 0:9a5c2fb0d96f 37 #if HAVE_FAT32
mimi3 0:9a5c2fb0d96f 38 byte bBPB_NumFATs;
mimi3 0:9a5c2fb0d96f 39 #else
mimi3 0:9a5c2fb0d96f 40 #define bBPB_NumFATs 2 //; to reduce Flash size
mimi3 0:9a5c2fb0d96f 41 #endif
mimi3 0:9a5c2fb0d96f 42
mimi3 0:9a5c2fb0d96f 43 sd_start_read(0); // -- read MBR sector
mimi3 0:9a5c2fb0d96f 44 #if 0
mimi3 0:9a5c2fb0d96f 45 printf("\n");
mimi3 0:9a5c2fb0d96f 46 for(i=0;i<512;i++){
mimi3 0:9a5c2fb0d96f 47 if((i%16)==0){ printf("\n %04X:",i);};
mimi3 0:9a5c2fb0d96f 48 printf("%02X ",sd_data_byte());
mimi3 0:9a5c2fb0d96f 49 }
mimi3 0:9a5c2fb0d96f 50 fflush(stdout);
mimi3 0:9a5c2fb0d96f 51 while(1);
mimi3 0:9a5c2fb0d96f 52 #endif
mimi3 0:9a5c2fb0d96f 53
mimi3 0:9a5c2fb0d96f 54 sd_read_pulse_byte(454); // -- go to partition info
mimi3 0:9a5c2fb0d96f 55 low(dwBPB_Sector)[0] = sd_data_byte(); //-- get BPB info sector number
mimi3 0:9a5c2fb0d96f 56 low(dwBPB_Sector)[1] = sd_data_byte();
mimi3 0:9a5c2fb0d96f 57 low(dwBPB_Sector)[2] = sd_data_byte();
mimi3 0:9a5c2fb0d96f 58 low(dwBPB_Sector)[3] = sd_data_byte();
mimi3 0:9a5c2fb0d96f 59 sd_stop_read();
mimi3 0:9a5c2fb0d96f 60
mimi3 0:9a5c2fb0d96f 61 sd_start_read(dwBPB_Sector);// -- go to BPB info sector
mimi3 0:9a5c2fb0d96f 62 // printf("\n%04X",dwBPB_Sector);
mimi3 0:9a5c2fb0d96f 63 // printf("\n ");
mimi3 0:9a5c2fb0d96f 64 for(bi=0;bi<32;bi++){
mimi3 0:9a5c2fb0d96f 65 bpbBuff[bi] = sd_data_byte();// -- read BPB info to bpbBuff[]
mimi3 0:9a5c2fb0d96f 66 // printf("%02X ",bpbBuff[bi]);
mimi3 0:9a5c2fb0d96f 67 }
mimi3 0:9a5c2fb0d96f 68
mimi3 0:9a5c2fb0d96f 69 //; register BPB info to each variable
mimi3 0:9a5c2fb0d96f 70 low(lgwBPB_BytesPerSec)[0] = bpbBuff[11];
mimi3 0:9a5c2fb0d96f 71 low(lgwBPB_BytesPerSec)[1] = bpbBuff[12];
mimi3 0:9a5c2fb0d96f 72
mimi3 0:9a5c2fb0d96f 73 gbBPB_SecPerClus = bpbBuff[13];
mimi3 0:9a5c2fb0d96f 74
mimi3 0:9a5c2fb0d96f 75 low(wBPB_RsvdSecCnt)[0] = bpbBuff[14];
mimi3 0:9a5c2fb0d96f 76 low(wBPB_RsvdSecCnt)[1] = bpbBuff[15];
mimi3 0:9a5c2fb0d96f 77 #if HAVE_FAT32
mimi3 0:9a5c2fb0d96f 78 bBPB_NumFATs = bpbBuff[16];
mimi3 0:9a5c2fb0d96f 79 #endif
mimi3 0:9a5c2fb0d96f 80
mimi3 0:9a5c2fb0d96f 81 low(gwBPB_RootEntCnt)[0] = bpbBuff[17];
mimi3 0:9a5c2fb0d96f 82 low(gwBPB_RootEntCnt)[1] = bpbBuff[18];
mimi3 0:9a5c2fb0d96f 83 //; BPB_FATSz16
mimi3 0:9a5c2fb0d96f 84 low(dwBPB_SecPerFats32)[0]= bpbBuff[22] ; //for FAT16
mimi3 0:9a5c2fb0d96f 85 low(dwBPB_SecPerFats32)[1]= bpbBuff[23] ; //for FAT16
mimi3 0:9a5c2fb0d96f 86 low(dwBPB_SecPerFats32)[2]= 0 ; //for FAT16
mimi3 0:9a5c2fb0d96f 87 low(dwBPB_SecPerFats32)[3]= 0 ; //for FAT16
mimi3 0:9a5c2fb0d96f 88
mimi3 0:9a5c2fb0d96f 89 low(dwBPB_HiddSec)[0] = bpbBuff[28];
mimi3 0:9a5c2fb0d96f 90 low(dwBPB_HiddSec)[1] = bpbBuff[29];
mimi3 0:9a5c2fb0d96f 91 low(dwBPB_HiddSec)[2] = bpbBuff[30];
mimi3 0:9a5c2fb0d96f 92 low(dwBPB_HiddSec)[3] = bpbBuff[31];
mimi3 0:9a5c2fb0d96f 93
mimi3 0:9a5c2fb0d96f 94 #if HAVE_FAT32
mimi3 0:9a5c2fb0d96f 95 if ((low(dwBPB_SecPerFats32)[0] == 0) && (low(dwBPB_SecPerFats32)[1]==0)){
mimi3 0:9a5c2fb0d96f 96 //----- enable FAT32 mode
mimi3 0:9a5c2fb0d96f 97 #if DEBUG_FAT_LIB
mimi3 0:9a5c2fb0d96f 98 pc.printf("\n FAT32");
mimi3 0:9a5c2fb0d96f 99 #endif
mimi3 0:9a5c2fb0d96f 100 gfFat32 = true;
mimi3 0:9a5c2fb0d96f 101 bi = sd_data_byte() ;// dummy read
mimi3 0:9a5c2fb0d96f 102 bi = sd_data_byte();
mimi3 0:9a5c2fb0d96f 103 bi = sd_data_byte();
mimi3 0:9a5c2fb0d96f 104 bi = sd_data_byte();
mimi3 0:9a5c2fb0d96f 105 //; BPB_FATSz32
mimi3 0:9a5c2fb0d96f 106 low(dwBPB_SecPerFats32)[0] = sd_data_byte();
mimi3 0:9a5c2fb0d96f 107 low(dwBPB_SecPerFats32)[1] = sd_data_byte();
mimi3 0:9a5c2fb0d96f 108 low(dwBPB_SecPerFats32)[2] = sd_data_byte();
mimi3 0:9a5c2fb0d96f 109 low(dwBPB_SecPerFats32)[3] = sd_data_byte();
mimi3 0:9a5c2fb0d96f 110 }
mimi3 0:9a5c2fb0d96f 111 #endif
mimi3 0:9a5c2fb0d96f 112
mimi3 0:9a5c2fb0d96f 113 //; /* Root DIR start sector : (absolute sector) */
mimi3 0:9a5c2fb0d96f 114 gdwRootdir_sector = ( dwBPB_SecPerFats32 * bBPB_NumFATs )
mimi3 0:9a5c2fb0d96f 115 + wBPB_RsvdSecCnt
mimi3 0:9a5c2fb0d96f 116 + dwBPB_HiddSec;
mimi3 0:9a5c2fb0d96f 117
mimi3 0:9a5c2fb0d96f 118 gwSize_of_root = gwBPB_RootEntCnt * 32;
mimi3 0:9a5c2fb0d96f 119
mimi3 0:9a5c2fb0d96f 120 //;include debug_info1
mimi3 0:9a5c2fb0d96f 121 sd_stop_read();
mimi3 0:9a5c2fb0d96f 122 }
mimi3 0:9a5c2fb0d96f 123
mimi3 0:9a5c2fb0d96f 124 /******************
mimi3 0:9a5c2fb0d96f 125 readDirEntry
mimi3 0:9a5c2fb0d96f 126 *******************/
mimi3 0:9a5c2fb0d96f 127 void readDirEntry(word wDestDirEntryIndex){
mimi3 0:9a5c2fb0d96f 128 byte i;
mimi3 0:9a5c2fb0d96f 129 word wCurrentDirEntryIndex = 0;
mimi3 0:9a5c2fb0d96f 130
mimi3 0:9a5c2fb0d96f 131 sd_start_read( gdwRootdir_sector );
mimi3 0:9a5c2fb0d96f 132 #if DEBUG_FAT_LIB
mimi3 0:9a5c2fb0d96f 133 pc.printf("\n");
mimi3 0:9a5c2fb0d96f 134 #endif
mimi3 0:9a5c2fb0d96f 135 while( true ){
mimi3 0:9a5c2fb0d96f 136 for(i=0;i<32;i++){ //; read one dir entry
mimi3 0:9a5c2fb0d96f 137 gDirEntryBuff[i] = sd_data_byte();
mimi3 0:9a5c2fb0d96f 138 #if DEBUG_FAT_LIB
mimi3 0:9a5c2fb0d96f 139 pc.printf("%02X ",gDirEntryBuff[i]);
mimi3 0:9a5c2fb0d96f 140 #endif
mimi3 0:9a5c2fb0d96f 141 }
mimi3 0:9a5c2fb0d96f 142 if( wCurrentDirEntryIndex == wDestDirEntryIndex) {
mimi3 0:9a5c2fb0d96f 143 break;
mimi3 0:9a5c2fb0d96f 144 }
mimi3 0:9a5c2fb0d96f 145 wCurrentDirEntryIndex = wCurrentDirEntryIndex + 32;
mimi3 0:9a5c2fb0d96f 146 if( !gfFat32 ){
mimi3 0:9a5c2fb0d96f 147 if (wCurrentDirEntryIndex >= gwSize_of_root){
mimi3 0:9a5c2fb0d96f 148 break;
mimi3 0:9a5c2fb0d96f 149 }
mimi3 0:9a5c2fb0d96f 150 }
mimi3 0:9a5c2fb0d96f 151 }
mimi3 0:9a5c2fb0d96f 152 sd_stop_read();
mimi3 0:9a5c2fb0d96f 153 }
mimi3 0:9a5c2fb0d96f 154
mimi3 0:9a5c2fb0d96f 155 /******************
mimi3 0:9a5c2fb0d96f 156 searchNexFile
mimi3 0:9a5c2fb0d96f 157 *******************/
mimi3 0:9a5c2fb0d96f 158 void searchNextFile(){
mimi3 0:9a5c2fb0d96f 159 byte i;
mimi3 0:9a5c2fb0d96f 160 byte topChar;
mimi3 0:9a5c2fb0d96f 161 dword dwTargetClusterNumber;
mimi3 0:9a5c2fb0d96f 162 dword ldwRootdir_sector_size;
mimi3 0:9a5c2fb0d96f 163 static word wNextDirEntryIndex = 0; // ; initialize
mimi3 0:9a5c2fb0d96f 164
mimi3 0:9a5c2fb0d96f 165 if( wNextDirEntryIndex != 0) {// ; if 0 , search first song
mimi3 0:9a5c2fb0d96f 166 wNextDirEntryIndex = wNextDirEntryIndex + 32 ; //search next song
mimi3 0:9a5c2fb0d96f 167 }
mimi3 0:9a5c2fb0d96f 168
mimi3 0:9a5c2fb0d96f 169 while (true) { //; start dir entry search
mimi3 0:9a5c2fb0d96f 170 //; skip deleted entry
mimi3 0:9a5c2fb0d96f 171 while (true) {
mimi3 0:9a5c2fb0d96f 172 readDirEntry(wNextDirEntryIndex);
mimi3 0:9a5c2fb0d96f 173 topChar = gDirEntryBuff[0];
mimi3 0:9a5c2fb0d96f 174 if( topChar == 0xE5) { //; skip deleted entry
mimi3 0:9a5c2fb0d96f 175 wNextDirEntryIndex = wNextDirEntryIndex + 32;
mimi3 0:9a5c2fb0d96f 176 }else if(topChar == 0){
mimi3 0:9a5c2fb0d96f 177 //; dir entry table is end, so return to the top entry
mimi3 0:9a5c2fb0d96f 178 wNextDirEntryIndex = 0;
mimi3 0:9a5c2fb0d96f 179 }else{
mimi3 0:9a5c2fb0d96f 180 break;
mimi3 0:9a5c2fb0d96f 181 }
mimi3 0:9a5c2fb0d96f 182 }
mimi3 0:9a5c2fb0d96f 183 //; check long file name
mimi3 0:9a5c2fb0d96f 184 if((topChar >= 0x42) && (topChar <= 0x54)) {
mimi3 0:9a5c2fb0d96f 185 if( ( gDirEntryBuff[11] & 0x0F ) == 0x0F) { //; long file name ID(=0x0F) or not
mimi3 0:9a5c2fb0d96f 186 //; this is long file name, so set index to short file name address
mimi3 0:9a5c2fb0d96f 187 wNextDirEntryIndex = wNextDirEntryIndex + ((word)((topChar - 0x40))<<5);
mimi3 0:9a5c2fb0d96f 188 readDirEntry(wNextDirEntryIndex);
mimi3 0:9a5c2fb0d96f 189 }
mimi3 0:9a5c2fb0d96f 190 }
mimi3 0:9a5c2fb0d96f 191
mimi3 0:9a5c2fb0d96f 192 //;get the file extention
mimi3 0:9a5c2fb0d96f 193 if( (gDirEntryBuff[8] =='W') && (gDirEntryBuff[9] =='A')
mimi3 0:9a5c2fb0d96f 194 && (gDirEntryBuff[10]=='V') && (gDirEntryBuff[11]==' ')) {
mimi3 0:9a5c2fb0d96f 195 // ; gDirEntryBuff[11]=" ": (space) is the mark of archive attribute
mimi3 0:9a5c2fb0d96f 196 // ; if the file extention matches 'WAV ', break
mimi3 0:9a5c2fb0d96f 197 // -----------
mimi3 0:9a5c2fb0d96f 198 break;
mimi3 0:9a5c2fb0d96f 199 //-----------
mimi3 0:9a5c2fb0d96f 200 }
mimi3 0:9a5c2fb0d96f 201 //; for read next entry
mimi3 0:9a5c2fb0d96f 202 wNextDirEntryIndex = wNextDirEntryIndex + 32;
mimi3 0:9a5c2fb0d96f 203 } //; end while: dir entry search
mimi3 0:9a5c2fb0d96f 204
mimi3 0:9a5c2fb0d96f 205 #if UART_INFO
mimi3 0:9a5c2fb0d96f 206 //-- print out music file name(short file name) to UART
mimi3 0:9a5c2fb0d96f 207 static int ix=0;
mimi3 0:9a5c2fb0d96f 208 byte fname[13];
mimi3 0:9a5c2fb0d96f 209 for(i=0;i<8;i++){ fname[i] = gDirEntryBuff[i]; }
mimi3 0:9a5c2fb0d96f 210 fname[8] = '.';
mimi3 0:9a5c2fb0d96f 211 fname[9] = gDirEntryBuff[8];
mimi3 0:9a5c2fb0d96f 212 fname[10] = gDirEntryBuff[9];
mimi3 0:9a5c2fb0d96f 213 fname[11] = gDirEntryBuff[10];
mimi3 0:9a5c2fb0d96f 214 fname[12] = 0;
mimi3 0:9a5c2fb0d96f 215 printf("\n[%3d]: %s",ix++,fname);
mimi3 0:9a5c2fb0d96f 216 #endif
mimi3 0:9a5c2fb0d96f 217
mimi3 0:9a5c2fb0d96f 218 if (gfFat32) {
mimi3 0:9a5c2fb0d96f 219 low(dwTargetClusterNumber)[2] = (gDirEntryBuff[20]);
mimi3 0:9a5c2fb0d96f 220 low(dwTargetClusterNumber)[3] = (gDirEntryBuff[21]);
mimi3 0:9a5c2fb0d96f 221 }else{
mimi3 0:9a5c2fb0d96f 222 low(dwTargetClusterNumber)[2] = 0;
mimi3 0:9a5c2fb0d96f 223 low(dwTargetClusterNumber)[3] = 0;
mimi3 0:9a5c2fb0d96f 224 }
mimi3 0:9a5c2fb0d96f 225 low(dwTargetClusterNumber)[0] = (gDirEntryBuff[26]);
mimi3 0:9a5c2fb0d96f 226 low(dwTargetClusterNumber)[1] = (gDirEntryBuff[27]);
mimi3 0:9a5c2fb0d96f 227
mimi3 0:9a5c2fb0d96f 228 low(gdwBPB_FileSize)[0] = (gDirEntryBuff[28]); // file size
mimi3 0:9a5c2fb0d96f 229 low(gdwBPB_FileSize)[1] = (gDirEntryBuff[29]);
mimi3 0:9a5c2fb0d96f 230 low(gdwBPB_FileSize)[2] = (gDirEntryBuff[30]);
mimi3 0:9a5c2fb0d96f 231 low(gdwBPB_FileSize)[3] = (gDirEntryBuff[31]);
mimi3 0:9a5c2fb0d96f 232
mimi3 0:9a5c2fb0d96f 233 ldwRootdir_sector_size = (32 * (dword)(gwBPB_RootEntCnt) + lgwBPB_BytesPerSec - 1 ) / lgwBPB_BytesPerSec;
mimi3 0:9a5c2fb0d96f 234
mimi3 0:9a5c2fb0d96f 235 //; calculate start sector of target song file
mimi3 0:9a5c2fb0d96f 236 gdwTargetFileSector = gdwRootdir_sector + ldwRootdir_sector_size
mimi3 0:9a5c2fb0d96f 237 + (dwTargetClusterNumber - 2) * gbBPB_SecPerClus;
mimi3 0:9a5c2fb0d96f 238
mimi3 0:9a5c2fb0d96f 239 //;include debug_info2
mimi3 0:9a5c2fb0d96f 240 }
mimi3 0:9a5c2fb0d96f 241