//****************************************
// MP3¥Õ¥¡¥¤¥ë¤òºÆÀ¸
// fn: ¶ÊÈÖ¹æ
// clst: ±éÁÕ³«»Ï¥¯¥é¥¹¥¿¡£==0 ¤Î¾ì¹ç¤ÏºÇ½é¤«¤é
// remainsec: ºÆÀ¸¥Ç¡¼¥¿»Ä¤ê¥»¥¯¥¿¿ô
//****************************************
char play_music(uint fn, uint clst, long remainsec){
ulong sec;
uint remain;
uint cn;
uint i;
if (fn != search_MP3(fn)){
return -1;
}
MusicSize = (ulong)DataBuff[28] + ((ulong)DataBuff[29]<<8)
+ ((ulong)DataBuff[30]<<16) + ((ulong)DataBuff[31]<<24);
if (clst){
// ÅÓÃæ¤«¤éºÆÀ¸
Cluster = clst;
RemainSec = remainsec;
remain = MusicSize - (remainsec * 512);
} else {
// ºÇ½é¤«¤éºÆÀ¸
Cluster = (uint)DataBuff[26] + ((uint)DataBuff[27] << 8);
RemainSec = MusicSize / 512;
remain = MusicSize % 512;
}
if ((Cluster == 0xFFFF)||(Cluster < 2)){
return -2; // ¥¯¥é¥¹¥¿°Û¾ï
}
// ¼¡¤Î¥¯¥é¥¹¥¿¤òÄ´¤Ù¤Æ¤ª¤¯
NextCluster = next_cluster(Cluster, 0, 0);
StopSw = 0;
RewSw = 0;
FfSw = 0;
cn = SectorsPerCluster;
sec = (((ulong)Cluster - 2) * (ulong)SectorsPerCluster + DataStart) * 512;
MP3_init();
Timer = 100; // READY¥¿¥¤¥Þ¡¼¥»¥Ã¥È
while (RemainSec > 0){
uchar data;
char bit;
if (SPI_read_open(sec)) return -2;
cli(); // ³ä¹þ¤ß¶Ø»ß
SPI_out(0xFF); // 1byteÌܤΥ¯¥í¥Ã¥¯Á÷½Ð & WAIT
for (i = 0; i < 512; i++){
while (!(inp(PIND)&(1<<MP3_DREQ))){ // VS1001 BUSY¥Á¥§¥Ã¥¯
WDR; // ¥¦¥©¥Ã¥Á¥É¥Ã¥°¥¿¥¤¥Þ¡¼¥ê¥»¥Ã¥È
Timer = 100; // READY¥¿¥¤¥Þ¥»¥Ã¥È
if (NextCluster == 0){
// ¼¡¤Î¥¯¥é¥¹¥¿¤òÄ´¤Ù¤ë
NextCluster = next_cluster(Cluster, sec, i);
} else {
sei(); // ³ä¤ê¹þ¤ßµö²Ä
SLEEP;
cli(); // ³ä¹þ¤ß¶Ø»ß
}
}
data = inp(SPDR);
outp(0xFF, SPDR); // SD/MMC¥«¡¼¥É¤Ø¼¡¤Î¥Ç¡¼¥¿¥ê¥¯¥¨¥¹¥È
if (data & 0x80){
sbi(PORTD, MP3_SI);
} else {
cbi(PORTD, MP3_SI);
}
sbi(PORTD, MP3_BSYNC); // BSYNC = H
sbi(PORTD, MP3_DCLK);
data <<= 1;
cbi(PORTD, MP3_DCLK);
cbi(PORTD, MP3_BSYNC); // BSYNC = L
for (bit = 0; bit < 7; bit++){
if (data & 0x80){
sbi(PORTD, MP3_SI);
} else {
cbi(PORTD, MP3_SI);
}
sbi(PORTD, MP3_DCLK);
data <<= 1;
cbi(PORTD, MP3_DCLK);
}
}
sei(); // ³ä¤ê¹þ¤ßµö²Ä
SPI_read_close();
--RemainSec;
if (--cn > 0){
sec += 512; // ¼¡¤Î¥»¥¯¥¿
if (Debug && (cn == 1)){
uint n;
n = BattVolt;
WriteHex(n>>8);
WriteHex(n);
WriteCom(' ');
WriteHex(Cluster>>8);
WriteHex(Cluster);
WriteCom('\n');
}
} else {
// ¼¡¤Î¥¯¥é¥¹¥¿
if (NextCluster == 0){
Cluster = next_cluster(Cluster, 0, 0);
} else {
Cluster = NextCluster;
NextCluster = 0;
}
if ((Cluster == 0xFFFF)||(Cluster < 2)){
// °Û¾ï¥¯¥é¥¹¥¿¤¬¸¡½Ð¤µ¤ì¤¿¤Î¤Ç¶¯À©½ªÎ»
remain = 0;
break;
}
sec = (((ulong)Cluster - 2) * (ulong)SectorsPerCluster
+ DataStart) * 512;
cn = SectorsPerCluster;
}
check_batt(); // ¥Ð¥Ã¥Æ¥ê¡¼¥Á¥§¥Ã¥¯
if (Timer == 0){ // READY¥¿¥¤¥à¥¢¥¦¥È¤·¤¿¤é
if (NoBusyRetry > 0){ // ¥ê¥È¥é¥¤¤·¤Æ¤â¥À¥á¤Ê¤é
beep(1, BEEP_LOW); // Äã²»¥Ó¡¼¥×£±²ó
NoBusyRetry = 0;
FfSw = 0;
return 2; // FF°·¤¤¤Ç½ªÎ» ¢ª ¼¡¤Î¶Ê¤Ø
} else {
NoBusyRetry = 1;
RewSw = 0;
return 3; // REW°·¤¤¤Ç½ªÎ» ¢ª ¤½¤Î¶Ê¤ÎºÇ½é¤«¤é¥ê¥È¥é¥¤
}
}
// STOP, FF¥Ü¥¿¥ó¥Á¥§¥Ã¥¯
if (StopSw > 2){
beep(1, BEEP_HIGH);
NoBusyRetry = 0;
return 1;
} else if (FfSw > 2){
beep(1, BEEP_HIGH);
NoBusyRetry = 0;
return 2;
} else if (RewSw > 2){
beep(1, BEEP_HIGH);
NoBusyRetry = 0;
return 3;
}
}
NoBusyRetry = 0;
// £±¥»¥¯¥¿(512bytes)̤Ëþ¤Îʬ¤òºÆÀ¸
if ((remain > 0)&&(remain < 512)){
uchar data;
char bit;
if (SPI_read_open(sec)) return -2;
cli(); // ³ä¹þ¤ß¶Ø»ß
SPI_out(0xFF); // 1byteÌܤΥ¯¥í¥Ã¥¯Á÷½Ð¡õWAIT
for (i = 0; i < 512; i++){
data = inp(SPDR);
outp(0xFF, SPDR);
if (remain-- > 0){
while (!(inp(PIND)&(1<<MP3_DREQ))){
// VS1001 BUSY
WDR; // ¥¦¥©¥Ã¥Á¥É¥Ã¥°¥¿¥¤¥Þ¥¯¥ê¥¢
sei(); // ³ä¤ê¹þ¤ßµö²Ä
SLEEP;
cli(); // ³ä¹þ¤ß¶Ø»ß
}
sbi(PORTD, MP3_BSYNC); // BSYNC = H
for (bit=0; bit<8; bit++){
if (data & 0x80){
sbi(PORTD, MP3_SI);
} else {
cbi(PORTD, MP3_SI);
}
sbi(PORTD, MP3_DCLK);
data <<= 1;
cbi(PORTD, MP3_DCLK);
cbi(PORTD, MP3_BSYNC); // BSYNC = L
}
}
}
sei(); // ³ä¤ê¹þ¤ßµö²Ä
SPI_read_close();
}
return 0;
}
//****************************************
// ¼¡¤Î¥¯¥é¥¹¥¿¤òµá¤á¤ë
//****************************************
uint next_cluster(uint c, ulong sec, uint remain){
ulong addr;
uint data;
ulong fatadr;
uint i;
if (FATtype == 0){
// FAT12
addr = (ulong)FATstart * 512 + (ulong)c + (c >> 1);
if ((addr & 511) == 511){
if (sec != 0){
// ÆÉ¤ß¹þ¤ß¥ª¡¼¥×¥óÃæ¤Ê¤éÆÉ¤ß¼Î¤Æ
for (i = remain; i < 512; i++) SPI_in();
SPI_read_close();
data = read_word(addr) & 0x00FF;
data |= ((read_word(addr+1) & 0x00FF) << 8);
// ºÆÅÙ¥ª¡¼¥×¥ó¡¢°ÊÁ°¤Î°ÌÃÖ¤Þ¤ÇÆÉ¤ß¼Î¤Æ
if (SPI_read_open(sec)) return 0;
SPI_in();
for (i = 0; i < remain; i++) SPI_in();
} else {
// ¥»¥¯¥¿¤ò¤Þ¤¿¤°
data = read_word(addr) & 0x00FF;
data |= ((read_word(addr+1) & 0x00FF) << 8);
}
} else {
fatadr = addr & 0xFFFFFE00;
if ((sec != 0)&&(fatadr != FatCacheAddr)){
// ÆÉ¤ß¹þ¤ß¥ª¡¼¥×¥óÃæ¤Ç FAT¥Ð¥Ã¥Õ¥¡Ìµ¸ú¤Ê¤éÆÉ¤ß¼Î¤Æ
for (i = remain; i < 512; i++) SPI_in();
SPI_read_close();
data = read_word(addr);
// ºÆÅÙ¥ª¡¼¥×¥ó¡¢°ÊÁ°¤Î°ÌÃÖ¤Þ¤ÇÆÉ¤ß¼Î¤Æ
if (SPI_read_open(sec)) return 0xFFFF;
SPI_in();
for (i = 0; i < remain; i++) SPI_in();
} else {
data = read_word(addr);
}
}
if (c & 1){
c = data >> 4;
} else {
c = data & 0x0fff;
}
if (c >= 0x0ff8) c = 0xFFFF;
} else {
// FAT16
addr = (ulong)FATstart * 512 + (ulong)c * 2;
fatadr = addr & 0xFFFFFE00;
if ((sec != 0)&&(fatadr != FatCacheAddr)){
// ÆÉ¤ß¹þ¤ß¥ª¡¼¥×¥óÃæ¤Ç FAT¥Ð¥Ã¥Õ¥¡Ìµ¸ú¤Ê¤éÆÉ¤ß¼Î¤Æ
for (i = remain; i < 512; i++) SPI_in();
SPI_read_close();
c = read_word(addr);
// ºÆÅÙ¥ª¡¼¥×¥ó¡¢°ÊÁ°¤Î°ÌÃÖ¤Þ¤ÇÆÉ¤ß¼Î¤Æ
if (SPI_read_open(sec)) return 0;
SPI_in();
for (i = 0; i < remain; i++) SPI_in();
} else {
c = read_word(addr);
}
if (c >= 0xFFF8) c = 0xFFFF;
}
return c;
}
//****************************************
// MMC/SD¥«¡¼¥É¤«¤é 2byte¤òÆÉ¤à
// ¥»¥¯¥¿¶³¦¤Î¥¢¥¯¥»¥¹¤Ï¤Ç¤¤Ê¤¤¤Î¤Ç
// ¾å°Ì¹©Äø¤Ç¹Íθ¤¹¤ë¤³¤È
//****************************************
uint read_word(ulong addr){
uint w;
uint b;
uchar *p;
b = addr & 511;
addr &= 0xFFFFFE00;
if (addr != FatCacheAddr){
if (SPI_read_open(addr)) return 0;
for (p = FatCache; p < (FatCache + 512); ){
*p++ = SPI_in();
}
SPI_read_close();
FatCacheAddr = addr;
}
w = (uint)FatCache[b++];
w |= ((uint)FatCache << 8);
return w;
}
//*******************************************************
// ¥Ð¥Ã¥Æ¥ê¡¼Å۵¤òÄ´¤Ù¡¢Ä㤹¤®¤ì¤Ð¥·¥ã¥Ã¥È¥À¥¦¥ó¤¹¤ë
//*******************************************************
int check_batt(void){
if (BattVolt < BATT_SHUTDOWN){
sbi(PORTB, SPI_CS); // SPI CS=H
beep(4, BEEP_LOW);
cli(); // ³ä¹þ¤ß¶Ø»ß
if (RunningTimeH){
write_eeprom(EEPROM_RUNNING_TIME_OLD_M, RunningTimeM);
write_eeprom(EEPROM_RUNNING_TIME_OLD_H, RunningTimeH);
RunningTimeM = 0;
RunningTimeH = 0;
}
shutdown(0); // ¥·¥ã¥Ã¥È¥À¥¦¥ó
}
return BattVolt;
}
//*********************************************************
// ¥·¥ã¥Ã¥È¥À¥¦¥ó
// flag != 0 ¤Î¾ì¹ç¤Ï EEPROM½ñ¤¹þ¤ß¤ò¹Ô¤ï¤º¤ËÅŸ»¤òÀÚ¤ë
//*********************************************************
void shutdown(char flag){
cli(); // ³ä¹þ¤ß¶Ø»ß
sbi(PORTB, SPI_CS); // SPI CS=H
cbi(PORTB, MUTE); // ²»À¼¥ß¥å¡¼¥È
MP3_command(0, 0x0010); // VS1001k powerdown
if (!flag){
write_eeprom(EEPROM_VOLUME, Volume);
write_eeprom(EEPROM_MUSIC, PlayMusic);
write_eeprom(EEPROM_CLUSTER_L, Cluster);
write_eeprom(EEPROM_CLUSTER_H, Cluster>>8);
write_eeprom(EEPROM_REMAIN1, RemainSec);
write_eeprom(EEPROM_REMAIN2, RemainSec>>8);
write_eeprom(EEPROM_REMAIN3, RemainSec>>16);
write_eeprom(EEPROM_SIZE1, MusicSize);
write_eeprom(EEPROM_SIZE2, MusicSize>>8);
write_eeprom(EEPROM_SIZE3, MusicSize>>16);
write_eeprom(EEPROM_SIZE4, MusicSize>>24);
write_eeprom(EEPROM_RUNNING_TIME_M, RunningTimeM);
write_eeprom(EEPROM_RUNNING_TIME_H, RunningTimeH);
}
for(;;){ // ̵¸Â¥ë¡¼¥×
cbi(PORTC, POWER); // Power down
WDR;
SLEEP;
}
}
//*******************************************************
// EEPROM ½ñ¤¹þ¤ß
//*******************************************************
void write_eeprom(uchar adrs, uchar data){
// Ʊ¤¸ÆâÍÆ¤Ê¤é½ñ¤¹þ¤ßưºî¤ò¹Ô¤ï¤Ê¤¤
if (read_eeprom(adrs) != data){
while(inp(EECR) & (1<<EEWE));
outp(adrs >> 8, EEARH);
outp(adrs, EEARL);
outp(data, EEDR);
sbi(EECR, EEMWE);
sbi(EECR, EEWE);
}
}
//*******************************************************
// EEPROM ÆÉ¤ß¹þ¤ß
//*******************************************************
uchar read_eeprom(uchar adrs){
while(inp(EECR) & (1<<EEWE));
outp(adrs >> 8, EEARH);
outp(adrs, EEARL);
sbi(EECR, EERE);
return inp(EEDR);
}
//****************************************
// BEEP
// °ú¿ô¡§ n ÌÄÆ°²ó¿ô
// err != 0 ¤Ê¤é¥¨¥é¡¼²»(Ä㤤²»)
// ³ä¤ê¹þ¤ßµö²Ä¤Ë¤¹¤ë¤³¤È¤ËÃí°Õ
//****************************************
void beep(uchar n, char err){
char i;
cli(); // MP3_init()½èÍýÃæ¤Ë²»ÎÌÄ´Àᤵ¤ì¤¿¤éº¤¤ë¤Î¤Ç³ä¹þ¤ß¶Ø»ß
MP3_init();
sei(); // ³ä¤ê¹þ¤ßµö²Ä
for (; n > 0; --n){
if (err){
MP3_sin(ErrorBeep);
} else {
MP3_sin(BeepData);
}
// »þ´ÖÂÔ¤Á¡£¤³¤Î´Ö¤¬ BEEP¤Î²»¤ÎŤµ¤Ë¤Ê¤ë
for (i=0; i < 10*2; i++){ // Ìó100ms
SLEEP;
}
MP3_sin(BeepStop);
// BEEP¤Î²»´Ö
for (i=0; i < 3*2; i++){ // Ìó30ms
SLEEP;
}
}
MP3_sin(BeepStop); // »þ¡¹»ß¤Þ¤é¤Ê¤¤¤³¤È¤¬¤¢¤ë¤Î¤Ç¤â¤¦°ì²ó
}
//****************************************
// EasyMP3 ½é´ü²½
//****************************************
void MP3_init(void){
MP3_command(0, 0x0004); // Soft Reset
InitWait();
MP3_command(0, 0x0000);
while(!(inp(PIND)&(1<<MP3_DREQ)));
MP3_command(11, ((uint)Volume << 8)|((uint)Volume)); // ²»ÎÌÀßÄê
MP3_command(3, 0x8000 + (uint)((VS1001_CLOCK)/2000)); // Clock
InitWait();
}
//****************************************
// EasyMP3 ¥Æ¥¹¥ÈÍÑÀµ¸¹ÇȽÐÎÏ
//****************************************
void MP3_sin(PGM_VOID_P data){
uchar i;
uchar bit;
uchar c;
for (i=0; i < 8; i++){
c = (uchar)PRG_RDB(data++);
sbi(PORTD, MP3_BSYNC);
for (bit=0; bit<8; bit++){
if (c & 0x80){
sbi(PORTD, MP3_SI);
} else {
cbi(PORTD, MP3_SI);
}
sbi(PORTD, MP3_DCLK);
c <<= 1;
cbi(PORTD, MP3_DCLK);
cbi(PORTD, MP3_BSYNC);
}
sbi(PORTD, MP3_SI);
}
}
//****************************************
// EasyMP3 ¥³¥Þ¥ó¥É½ÐÎÏ
//****************************************
void MP3_command(uchar addr, uint arg){
cbi(PORTD, MP3_CS);
MP3_com_write(2);
MP3_com_write(addr);
MP3_com_write(arg >> 8);
MP3_com_write(arg);
sbi(PORTD, MP3_CS);
}
//****************************************
// EasyMP3 ¥³¥Þ¥ó¥ÉÆþÎÏ Ì¤»ÈÍÑ
//****************************************
/*
uint MP3_command_read(uchar addr){
char i;
uint r = 0;
cbi(PORTD, MP3_CS);
MP3_com_write(3);
MP3_com_write(addr);
for(i=0; i<16; i++){
sbi(PORTD, MP3_SCLK);
r <<= 1;
if (inp(PINB) & (1<<MP3_SO)){
r |= 1;
}
cbi(PORTD, MP3_SCLK);
}
sbi(PORTD, MP3_CS);
return r;
}
*/
//****************************************
// EasyMP3 ¥³¥Þ¥ó¥É 1byte½ÐÎÏ
//****************************************
void MP3_com_write(uchar data){
char i;
for (i=0; i<8; i++){
if (data & 0x80){
sbi(PORTD, MP3_SI);
} else {
cbi(PORTD, MP3_SI);
}
sbi(PORTD, MP3_SCLK);
data <<= 1;
cbi(PORTD, MP3_SCLK);
}
sbi(PORTD, MP3_SI);
}
//****************************************
// MMC/SD¥«¡¼¥É¤«¤é 32byte¤òÆÉ¤ó¤Ç DataBuff¤Ë³ÊǼ
//****************************************
void read_32(ulong addr){
uint i, b;
if (SPI_read_open(addr & 0xFFFFFE00)) return;
b = (uint)addr & 0x01FF;
for (i=0; i < 512; i++){
if (i == b){
int n;
for (n = 0; n < 32; n++){
DataBuff[n] = SPI_in();
i++;
}
} else {
SPI_in();
}
}
SPI_read_close();
}
//****************************************
// ½é´ü²½»þ¤Î¥¯¥í¥Ã¥¯¥¦¥¨¥¤¥È
//****************************************
void InitWait(void){
uchar i;
for(i=0; i< 255; i++){
NOP;
}
}
//****************************************
// MMC/SD¥«¡¼¥ÉÆÉ¤ß¹þ¤ß¥ª¡¼¥×¥ó
//****************************************
uchar SPI_read_open(ulong adrs){
uint i;
uchar r;
uchar retry;
// ¥«¡¼¥É¤Ë¤è¤Ã¤Æ¤Ï¥ê¥È¥é¥¤¤¬É¬ÍפΤ褦¤À
for (retry = 0; retry < 100; retry++){
cbi(PORTB, SPI_CS); // SPI CS=L
r = SPI_command(17, adrs);
if (r == 0){
for (i = 0; i < 2000; i++){ // ¤â¤Î¤¹¤´¤¯ÂԤľì¹ç¤¬¤¢¤ë
r = SPI_in();
if (r == 0xFE){
return 0; // žÁ÷³«»Ï¥Þ¡¼¥¯
}
}
} else if (r == 0xFE){
return 0; // Àµ¾ï¥ª¡¼¥×¥ó
}
sbi(PORTB, SPI_CS); // SPI CS=H
if (Debug){
WriteHex(r);
WriteCom(' ');
}
// InitWait();
}
return 1; // ¥ª¡¼¥×¥ó¤Ç¤¤Ê¤«¤Ã¤¿
}
//****************************************
// MMC/SD¥«¡¼¥ÉÆÉ¤ß¹þ¤ß¥¯¥í¡¼¥º
// 1byte¤Î¤º¤ì¤¬¤¢¤Ã¤Æ¤âµ¤¤Ë¤·¤Ê¤¤
//****************************************
void SPI_read_close(void){
uint i;
SPI_in(); // CRC
SPI_in(); // CRC
// BUSY¥Á¥§¥Ã¥¯
for (i = 0; i < 1000; i++){
if (SPI_in() == 0xFF) break;
}
sbi(PORTB, SPI_CS); // SPI CS=H
}
//****************************************
// MMC/SD SPI¥³¥Þ¥ó¥É½ÐÎÏ
//****************************************
uchar SPI_command(uchar com, ulong arg){
uint i;
uchar r;
// BUSY¥Á¥§¥Ã¥¯ Ë¿¼Ò¤Î¥«¡¼¥É¤Ç¤Ïɬ¿Ü¤ß¤¿¤¤
for (i = 0; i < 1000; i++){
r = SPI_in();
if (r == 0xFF) break;
}
if (r != 0xFF) return 1;
SPI_out(com|0x40);
SPI_out(arg >> 24);
SPI_out(arg >> 16);
SPI_out(arg >> 8);
SPI_out(arg);
SPI_out(0x95); // ½é´ü²½¥³¥Þ¥ó¥É¤ÎCRC
for(i = 0; i < 1000; i++){
r = SPI_in();
if (r == 0xFE) break;
if (!(r & 0x80)) break;
}
return r;
}
//****************************************
// MMC/SD SPI¥Ç¡¼¥¿½ÐÎÏ
//****************************************
void SPI_out(uchar data){
outp(data, SPDR);
while(!(inp(SPSR) & 0x80));
}
//****************************************
// MMC/SD SPI¥Ç¡¼¥¿ÆþÎÏ
//****************************************
uchar SPI_in(void){
outp(0xFF, SPDR);
while(!(inp(SPSR) & 0x80));
return inp(SPDR);
}
//****************************************
// MMC/SD SPI¥¯¥í¥Ã¥¯½ªÎ»ÂÔ¤Á
// SPDR¤ò¥¢¥¯¥»¥¹¤·¤Æ¤Ê¤¤¾ì¹ç¤Ï
// SPIF=0¤Ë¤Ê¤Ã¤ÆÌµ¸Â¥ë¡¼¥×¤¹¤ë¾ì¹ç¤¬¤¢¤ë¤³¤È¤ËÃí°Õ
//****************************************
void SPI_wait(void){
while(!(inp(SPSR) & 0x80));
}
//****************************************
// 1¥»¥¯¥¿¡¼ÆÉ¤ß¹þ¤ó¤Çɽ¼¨¤¹¤ë
//****************************************
void print_sector(ulong sec){
uchar r;
int i;
sec *= 512;
r = SPI_read_open(sec);
WriteHex(r);
WriteCom('\n');
for (i=0; i<512; i++){
r = SPI_in();
WriteHex(r);
if ((i & 31) == 31){
WriteCom('\n');
} else if (i & 1){
WriteCom(' ');
}
}
SPI_read_close();
}