⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 yampp7_usb.c

📁 DIY自己的MP3的参考价值极高的代码。含有详细的解释
💻 C
📖 第 1 页 / 共 5 页
字号:
//
// return the next FAT in a chain
//

u32 next_fat(void)
{
	u32 fat_sector = fat_start + MyCluster / (SECTORSIZE / sizeof(CLUSTER));
	u16 fat_offset = MyCluster % (SECTORSIZE / sizeof(CLUSTER));
	while (CARD_Read(fat_sector))
	    	CARD_SW_Reset2();
	ClusterCount++;						// counter for F.Forward file sizing
	return ((CLUSTER*)SectorBuffer)[fat_offset];
}


void init_load_sectors(u32 cluster)
{
	MyCluster = cluster;
	MySector = sector_cluster_offset + YADL_SECTORS_PER_CLUSTER * MyCluster;
	while(CARD_Read(MySector))
	    	CARD_SW_Reset2();
	SectorsLd = 1;
}


//
// load a bufferfull of data
//
void load_sector(void)
{
	if (SectorsLd == YADL_SECTORS_PER_CLUSTER)
		init_load_sectors(next_fat());
	else
	{
		MySector++;
		while(CARD_Read(MySector))
	    		CARD_SW_Reset2();
		SectorsLd++;
	}
}

/****************************************************************************************/

void init_stuff(void)
{
	u08 i,update = 0;
	YADL_ROOT_SECTOR *pRoot;				// Boot Sector struct
	pRoot = (YADL_ROOT_SECTOR *) SectorBuffer;		// Allocate room from the temp buffer

	while (CARD_Read(YADL_SEC_ROOT))			// read root sector
		CARD_SW_Reset2();

	if ( *(u32*)pRoot->id != 0x4C444159)			// "YADL" signature not found
	{
		lcd_clrscr();
		_p_puts(Format_txt);
		static	u08 tones[]= {SINE_300,SINE_500,SINE_800,SINE_1000};
		for (i=0; i<4; i++)
		{		
			beep(tones[i],200);
			delayms(10);
		}
		do{
			get_key();
			i = check_event();
			wdt_reset();
		}while(i != EV_STOP);
		if(format_new_disk() == 0)			// format Card with YADL f.s.
		{
			_p_puts(FormOK_txt);
			beep(SINE_1500,100);
		}
		else
		{
			_p_puts(FormER_txt);
			beep(SINE_500,200);
		}
		wdt_enable(6);					// time for text displaying
		while(1);					// reset player by watchdog
	}

	if(pRoot->firmware_version_major != YAMPP_FIRMWARE_VERSION_MAJOR)
	{
		pRoot->firmware_version_major = YAMPP_FIRMWARE_VERSION_MAJOR;
		update = 1;
	}
	if(pRoot->firmware_version_minor != YAMPP_FIRMWARE_VERSION_MINOR)
	{
		pRoot->firmware_version_minor = YAMPP_FIRMWARE_VERSION_MINOR;
		update = 1;
	}
	if(strcmp_P(pRoot->build_timestamp, date_txt))
	{
		strcpy_P(pRoot->build_timestamp, date_txt);
		update = 1;
	}
	if (update)
	{
		while(CARD_Write(YADL_SEC_ROOT))
		    	CARD_SW_Reset2();
		lcd_clrscr();
		_p_puts(FirmUpd_txt);
		beep(SINE_1500,80);
		beep(SINE_2000,80);
		delayms(1000);
	}

	sector_cluster_offset = pRoot->sector_cluster_offset;
	songbase_start 	= pRoot->songbase_start;			// SECTOR !!
	songbase_qty	= pRoot->songbase_qty;
	playlist_start 	= sector_cluster_offset + YADL_SECTORS_PER_CLUSTER * pRoot->playlist_start;	// SECTOR !!!
	playlist_qty 	= pRoot->playlist_qty;		
	fat_start 	= pRoot->fat_start;

	//
	// VS1001 User Software Loader
	//

	u32 app_start = pRoot->wasteland_start;
	lcd_data_start = pRoot->wasteland_start + 10;
	vs1001_fw = 0;
	if (app_start != 0)
	{
		u16 *pData;
		pData = (u16*) SectorBuffer;
		CARD_Read(app_start);						// read first free sector
		if(*pData++ != 0x4679 || *pData++ != 0x776D)			// Firmware signature ('yFmw') not found
			return;							// exit
		u16 DataLen = *pData++;						// length of firmware in words (firmware only)
		vs1001_fw = *pData++;						// address to enter into VS1001 register A1ADDR
										// for application running.
		vs1001_write(7,vs1001_fw + 0x4000);				// write to VS1001 register WRAMADDR
		while(DataLen--)						// data length in words
		{
			if (pData == (u16*)(SectorBuffer+512))
			{
				app_start++;
				CARD_Read(app_start);				// read next sector with application datas
				pData = (u16*) SectorBuffer;			// new start address
			}
			vs1001_write(6,*pData++);				// write firmware word to vs1001
		}
	}
}

/****************************************************************************************/

YADL_PLAY_LIST_ENTRY *get_pl_entry(u16 index)
{
	u32 nCurSector;
	
	//
	// find (and load) correct playlist sector
	//
	nCurSector =  playlist_start + (index >> 3);	// 64 bytes per one playlist entry
	while(CARD_Read(nCurSector))
		CARD_SW_Reset2();
	return &((YADL_PLAY_LIST_ENTRY *)SectorBuffer)[index % 8];
}

YADL_SONG_BASE_ENTRY *get_song_entry(u16 index)
{
	u32 nCurSector;
	
	nCurSector = songbase_start + (index >> 2);
	while(CARD_Read(nCurSector))
		CARD_SW_Reset2();
	return &((YADL_SONG_BASE_ENTRY *)SectorBuffer)[index % 4];
}


// Nilrog: Rewrote this function since it couldn't properly handle
//         the fact that a playlist can begin in one sector and the
//         index pointed to a position which was located in the next
//         sector.

u16 get_offset_entry(u16 index)
{
 	YADL_PLAY_LIST_ENTRY *pListEntry = get_pl_entry(curPlaylist);
 	FOFFSET offset = pListEntry->offset;
	
	/* calculate absolute position from start of playlistfile */
	u16 pos = offset + index * sizeof(u16);

	/* calculate if the current playlist position wraps into another sector */
	u08 wraps = pos / SECTORSIZE;

	/* calculate which sector to read */
	u32 nCurSector = playlist_start + wraps;

	/* if playlist wraps we need to re-calculate index and offset */
	if (wraps)
	{
		index = (pos - wraps * SECTORSIZE) / sizeof(u16);
		offset = 0;
	}
	/* if no wrap ocurred 'index' and 'offset' are clear to use as is */

 	while(CARD_Read(nCurSector))
 		CARD_SW_Reset2();
 
 	u16 *pList = (u16*) ( (u08*)SectorBuffer + offset);
 	return pList[index];
 }


//********************************************************************************

char index_fmt[] __attribute__ ((progmem)) = "%3u/%u";

void Playlist_name(void)
{
	u08 *src;
	udiv_t divt;
	lcd_image(1);					// Playing background image
	pump_audio();
	YADL_PLAY_LIST_ENTRY *pListEntry = get_pl_entry(curPlaylist);
	u16 tmp = (pListEntry->entry_qty);
	lcd_color(colors[PLAYLIST_NAME], colors[PLAYLIST_NAME+16]);
#ifdef PLAYLIST_NAME_CENTERED
	u08 j = strlen(pListEntry->name);
	if(j<15)
		lcd_gotoxy((15-j)*4 + 4, PLAYLIST_NAME_YPOS);
	else
#endif
		lcd_gotoxy(4, PLAYLIST_NAME_YPOS);

	lcd_puts(pListEntry->name);			// playlist name

	YADL_SONG_BASE_ENTRY *pEntry = get_song_entry(get_offset_entry(curIndex));
	strcpy(titlename, pEntry->title);
	src = titlename + strlen(titlename);
	*src++ = ' ';
	*src++ = '(';
	songtime = pEntry->play_time;
	divt = udiv(songtime, 600);
	u08 s = (u08)divt.quot % 10;
	if (s)
		*src++ = '0' + s;			// song time up to 99 min
	divt = udiv(divt.rem, 60);
	*src++ = '0' + (u08)divt.quot;
	*src++ = ':';
	divt = udiv(divt.rem, 10);
	*src++ = '0' + (u08)divt.quot;
	*src++ = '0' + (u08)divt.rem;			
	*src++ = ')';

#ifndef ALTERNATE_SCROLL
	if (src-titlename > 14)
		*((u32*)src)++ = 0x203E3E20L;		// adding " >> " sign
#else
	scroll_dir = scroll_dir_2 = 0;
#endif
	*src = 0;
	scroll_length_2 = src-titlename;
	scroll_pos = scroll_pos_2 = 0;

	lcd_color(colors[ARTIST_NAME], colors[ARTIST_NAME+16]);
	lcd_gotoxy(4, ARTIST_NAME_YPOS);
	lcd_puts(pEntry->artist);			// artist name

	lcd_color(colors[SONG_NAME], colors[SONG_NAME+16]);
	lcd_gotoxy(4, SONG_NAME_YPOS);
	lcd_puts(titlename);				// title name

	lcd_color(colors[PL_SO_NUMBERS], colors[PL_SO_NUMBERS+16]);
	lcd_gotoxy(PLIST_NUMBER_XPOS, PLIST_NUMBER_YPOS);
	_p_printf(index_fmt, curPlaylist+1, playlist_qty);

	lcd_gotoxy(SONG_NUMBER_XPOS, SONG_NUMBER_YPOS);
	_p_printf(index_fmt, curIndex+1, tmp);

	pump_audio();
	status_display();
	time_flag = 5;
	scroll_flag = 2;
}

// ******************************************************************************

// this is in assembler procedure because c not propper handle 
// pointers array located in program memory (in this case)
u08* PRG_RDW(u08* addr)
{
	asm volatile ("movw r30,r24");
	asm volatile ("LPM  r24,Z+");
	asm volatile ("LPM  r25,Z");
	return addr;
}

#define SONGS_D	0
#define MENU_D	1

u16 browse_list(u16 index, u16 min, u16 max, u08 func)
{
	u08 i,j = 0;
	event_e event;
	while (1)
	{
		for (i=0; i < 3 + 3*func; i++)
		{
#if (CLKDIV > 0)
			set_cpu_speed(CLKDIV>>1);		// CPU clock * 2
#endif
			if (func)
			{
				lcd_clrline(14*i + MENUITEMS_YOFFSET);
				if (index+i < max)
				{
					lcd_putchar((i==j) ? 30 : ' ');
	 				lcd_progputs(PRG_RDW((u08*)&function_name[index+i]));	// menu print on LCD
				}
				if(isPlaying)
					feed_audio_data();
			}
			else
			{
				lcd_clrline(28*i + (MENUITEMS_YOFFSET+14));
				lcd_clrline(28*i + MENUITEMS_YOFFSET);
				if (index+i < max)
				{
					YADL_SONG_BASE_ENTRY *pEntry = get_song_entry(get_offset_entry(index+i));
					lcd_putchar((i==j) ? 30 : ' ');
					lcd_puts(pEntry->artist);		// print artist
					lcd_gotoxy(4, 28*i + (MENUITEMS_YOFFSET+14));
					lcd_putchar((i==j) ? 30 : ' ');
					lcd_puts(pEntry->title);		// print title
				}
				pump_audio();
			}
		}

		do 
		{
			time_flag = 0;
			sleepcount = 0;						// power off blocking
			event = get_event();
			switch (event)
			{
				case EV_NEXT:
				case EV_UP:
					if ( index+j > min )
					{
						if(j)
							 j--;
						else
							index--;
					}
					break;
				case EV_PREV:
				case EV_DOWN:
					if ( index+j+1 < max )
					{
						if(j < 3*func + 2)
							j++;
						else
							index++;
					}
					break;
				case EV_PLAY:
					return index+j;

				case EV_STOP:
					return -1;
			}
		}
		while (event == EV_IDLE);
	}
}


// ***************************************************************************************

u16 browse_songs(void)
{
	lcd_image(3);
	status_display();
	lcd_color(colors[BROWSE_WINDOW], colors[BROWSE_WINDOW+16]);
	YADL_PLAY_LIST_ENTRY *pListEntry = get_pl_entry(curPlaylist);
	return (browse_list(curIndex, 0, pListEntry->entry_qty, SONGS_D));
}


/***********************************************************************************/

u16 browse_menu(void)
{
	lcd_image(2);
	status_display();
	lcd_color(colors[MENU_WINDOW], colors[MENU_WINDOW+16]);
	return (browse_list(menu_event ? menu_event-1 : 0, 0, 11, MENU_D));
}

/***********************************************************************************/
#ifdef PCB_REV_D

u08 IsCharging(void)
{
	u08 b = 0;
	u08 c = MCUCR;
	
	MCUCR = 0;				// disable external memory interface 

	cbi(CHARGE_DDR,CHARGE_PIN);		// set pin as input
	sbi(CHARGE_PORT,CHARGE_PIN);		// activate pullup
	delay10();
	if (bit_is_clear(CHARGE_INP,CHARGE_PIN))	// if charging 
		b = 1;

	MCUCR = c ;				// restore control register setting
	return b;
}

#else // PCB older than D

u08 IsCharging(void)
{
	return (bit_is_clear(CHARGE_INP,CHARGE_PIN));
}


#endif // PCB_REV_D


void BatteryMeasure(void)
{
	if (!IsCharging())					// no charging in progress
	{
		cbi(PORTB, PB3);				// PB3 as analog comparator input
		cbi(DDRB, PB3);					// for battery level measure
		delay100();
		if (bit_is_set(ACSR,ACO))			// low battery
		{
			if (!lobatt)
			{
				lobatt = 1;
				lobatt_time = 0;
			}
			else
				lobatt = 2;

		}
		sbi(PORTB, PB3);
		sbi(DDRB, PB3);
	}
}


void feed_audio_data(void)
{
	set_cpu_speed(CLKDIV);				// CPU clock = XTAL / M162CLKDIV
	wdt_reset();					// reset the watchdog
	u08 ContWrites = 0;				// counter for prevent infinite vs1001 writing
	// pump some data to the decoder
	while (bit_is_set(PIND, DREQ_PIN))		// while DREQ is hi 
	{
		vs1001_send32(outptr);			// send data on SPI bus
		outptr += 32;				// advance data pointer
		fileplayed++;

		// check for buffer wrap
		if ( outptr == (SectorBuffer+512) )	// buffer empty
		{
			outptr = SectorBuffer;		// data pointer at begin of sector buffer
			load_sector();			// will load into SectorBuffer on YAMPP7
		}
		
		// check if we're done

		if (fileplayed >= filesize)
		{
			isPlaying = 0;		// the end is near
			next_song(0);
			return;
		}

		if (--ContWrites == 0)			// if vs1001 needs to more data
		{
			wdt_reset();			// reset the watchdog
			cbi(PORTB, RESET_PIN);		// VS1001 hardware reset
			delayms(1);
			sbi(PORTB, RESET_PIN);		// VS1001 reset
			delayms(10);
			vs1001_reset();
			LoudSet();
			ContWrites = 0;
		}
	}
}


//********************************************************************************
//
// Run this as often as possible
// preferably every time around the main loop
//

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -