Playing whole song from hard disk

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@544 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Linus Nielsen Feltzing 2002-05-11 21:39:57 +00:00
parent 7958ea420f
commit bb69a59a97
2 changed files with 187 additions and 35 deletions

View file

@ -8,13 +8,13 @@ INCLUDES=-I../../common -I../.. -I../../drivers
TARGET = -DARCHOS_PLAYER_OLD=1
CFLAGS = -g -Wall -m1 -nostdlib -Wstrict-prototypes -fschedule-insns -fno-builtin $(INCLUDES) $(TARGET) -DDEBUG
CFLAGS = -g -Wall -m1 -save-temps -nostdlib -Wstrict-prototypes -fschedule-insns -fno-builtin $(INCLUDES) $(TARGET) -DDEBUG
AFLAGS += -small -relax
OBJS= ../../crt0.o main.o ../../drivers/i2c.o ../../drivers/mas.o \
../../debug.o ../../kernel.o thread.o ../../common/sprintf.o \
../../panic.o ../../system.o ../../drivers/led.o \
../../drivers/lcd.o ../../drivers/ata.o ../../drivers/fat.o \
../../drivers/lcd.o ata.o ../../drivers/fat.o \
../../common/disk.o ../../common/file.o ../../common/dir.o
%.o: %.S
@ -52,3 +52,9 @@ install:
thread.o: ../../thread.c
$(CC) -O $(CFLAGS) -c $<
ata.o: ../../drivers/ata.c
$(CC) -O $(CFLAGS) -c $<
main.o: main.c
$(CC) -O $(CFLAGS) -c $<

View file

@ -20,6 +20,7 @@
#include "i2c.h"
#include "mas.h"
#include "sh7034.h"
#include "system.h"
#include "debug.h"
#include "kernel.h"
#include "ata.h"
@ -27,6 +28,11 @@
#include "fat.h"
#include "file.h"
#include "dir.h"
#include "panic.h"
#ifndef MIN
#define MIN(a, b) (((a)<(b))?(a):(b))
#endif
unsigned char fliptable[] =
{
@ -66,13 +72,17 @@ unsigned char fliptable[] =
extern unsigned int stack[];
/* Place the MP3 data right after the stack */
unsigned char *mp3buf = (unsigned char *)stack;
int mp3datalen;
unsigned char *mp3dataptr;
int mp3_transmitted;
#define MP3BUF_LEN 0x100000 /* 1 Mbyte */
unsigned char *mp3buf = (unsigned char *)stack;
int mp3buf_write;
int mp3buf_read;
int last_dma_chunk_size;
bool dma_on;
static void mas_poll_start(unsigned int interval_in_ms);
void setup_sci0(void)
{
@ -124,11 +134,12 @@ int mas_tx_ready(void)
void init_dma(void)
{
SAR3 = (unsigned int) mp3buf;
SAR3 = (unsigned int) mp3buf + mp3buf_read;
DAR3 = 0x5FFFEC3;
CHCR3 &= ~0x0002; /* Clear interrupt */
CHCR3 = 0x1504; /* Single address destination, TXI0, IE=1 */
DTCR3 = 64000;
last_dma_chunk_size = MIN(65536, mp3buf_write - mp3buf_read);
DTCR3 = last_dma_chunk_size & 0xffff;
DMAOR = 0x0001; /* Enable DMA */
}
@ -156,6 +167,18 @@ void dma_tick(void)
}
}
void bitswap(unsigned char *data, int length)
{
unsigned int i;
for(i = 0;i < length;i++)
{
data[i] = fliptable[data[i]];
}
}
struct event_queue disk_queue;
int filling;
int main(void)
{
char buf[40];
@ -164,6 +187,11 @@ int main(void)
DIR *d;
struct dirent *dent;
int f;
int free_space_left;
int mp3_space_left;
int amount_to_read;
int play_song;
struct event *ev;
/* Clear it all! */
SSR1 &= ~(SCI_RDRF | SCI_ORER | SCI_PER | SCI_FER);
@ -173,12 +201,13 @@ int main(void)
SCR1 |= 0x40;
SCR1 &= ~0x80;
IPRE |= 0xf000; /* Highest priority */
i2c_init();
dma_on = TRUE;
kernel_init();
tick_add_task(dma_tick);
set_irq_level(0);
@ -247,27 +276,26 @@ int main(void)
debugf("Couldn't open file\n");
}
i = read(f, mp3buf, 1000000);
debugf("Read %d bytes\n", i);
mp3buf_read = mp3buf_write = 0;
mp3datalen = i;
/* First read in a few seconds worth of MP3 data */
i = read(f, mp3buf, 0x20000);
debugf("Read %d bytes\n", i);
ata_spindown(-1);
debugf("bit swapping...\n");
for(i = 0;i < mp3datalen;i++)
{
mp3buf[i] = fliptable[mp3buf[i]];
}
bitswap(mp3buf + mp3buf_write, i);
mp3buf_write = i;
queue_init(&disk_queue);
mas_poll_start(1);
while(1)
{
debugf("let's play...\n");
init_dma();
mp3dataptr = mp3buf;
mp3_transmitted = 0;
dma_on = TRUE;
/* Enable Tx & TXIE */
@ -275,9 +303,67 @@ int main(void)
CHCR3 |= 1;
debugf("sleeping...\n");
sleep(1000000);
#define MP3_LOW_WATER 0x30000
#define MP3_CHUNK_SIZE 0x20000
play_song = 1;
filling = 1;
while(play_song)
{
if(filling)
{
free_space_left = mp3buf_read - mp3buf_write;
if(free_space_left < 0)
free_space_left = MP3BUF_LEN + free_space_left;
if(free_space_left <= MP3_CHUNK_SIZE)
{
debugf("0\n");
ata_spindown(-1);
filling = 0;
continue;
}
amount_to_read = MIN(MP3_CHUNK_SIZE, free_space_left);
amount_to_read = MIN(MP3BUF_LEN - mp3buf_write, amount_to_read);
/* Read in a few seconds worth of MP3 data. We don't want to
read too large chunks because the bitswapping will take
too much time. We must keep the DMA happy and also give
the other threads a chance to run. */
debugf("R\n", i);
i = read(f, mp3buf+mp3buf_write, amount_to_read);
if(i)
{
debugf("B\n");
bitswap(mp3buf + mp3buf_write, i);
mp3buf_write += i;
if(mp3buf_write >= MP3BUF_LEN)
{
mp3buf_write = 0;
debugf("W\n");
}
}
else
{
play_song = 0;
ata_spindown(-1);
filling = 0;
}
}
else
{
debugf("S\n");
ev = queue_wait(&disk_queue);
debugf("Q\n");
debugf("1\n");
filling = 1;
}
}
debugf("Song is finished\n");
while(1);
}
#pragma interrupt
@ -289,14 +375,74 @@ void IRQ6(void)
#pragma interrupt
void DEI3(void)
{
mp3_transmitted += 64000;
if(mp3_transmitted < mp3datalen)
int unplayed_space_left;
int space_until_end_of_buffer;
mp3buf_read += last_dma_chunk_size;
if(mp3buf_read >= MP3BUF_LEN)
mp3buf_read = 0;
unplayed_space_left = mp3buf_write - mp3buf_read;
if(unplayed_space_left < 0)
unplayed_space_left = MP3BUF_LEN + unplayed_space_left;
space_until_end_of_buffer = MP3BUF_LEN - mp3buf_read;
if(!filling && unplayed_space_left < MP3_LOW_WATER)
{
DTCR3 = 64000;
queue_post(&disk_queue, 1, 0);
}
if(unplayed_space_left)
{
last_dma_chunk_size = MIN(65536, unplayed_space_left);
last_dma_chunk_size = MIN(last_dma_chunk_size, space_until_end_of_buffer);
DTCR3 = last_dma_chunk_size & 0xffff;
SAR3 = (unsigned int)mp3buf + mp3buf_read;
CHCR3 &= ~0x0002;
}
else
{
debugf("No more MP3 data. Stopping.\n");
CHCR3 = 0;
}
}
static void mas_poll_start(unsigned int interval_in_ms)
{
unsigned int count;
count = FREQ / 1000 / 8 * interval_in_ms;
if(count > 0xffff)
{
panicf("Error! The MAS poll interval is too long (%d ms)\n",
interval_in_ms);
return;
}
/* We are using timer 1 */
TSTR &= ~0x02; /* Stop the timer */
TSNC &= ~0x02; /* No synchronization */
TMDR &= ~0x02; /* Operate normally */
TCNT1 = 0; /* Start counting at 0 */
GRA1 = count;
TCR1 = 0x23; /* Clear at GRA match, sysclock/8 */
/* Enable interrupt on level 2 */
IPRC = (IPRC & ~0x000f) | 0x0002;
TSR1 &= ~0x02;
TIER1 = 0xf9; /* Enable GRA match interrupt */
TSTR |= 0x02; /* Start timer 2 */
}
#pragma interrupt
void IMIA1(void)
{
dma_tick();
TSR1 &= ~0x01;
}