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:
Fri Oct 09 07:47:36 2020 +0900
Revision:
21:dc161a192ba7
Parent:
10:1108261dabe8
trivial change

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