I am trying to build an MP3 Player on a generic lpc1768 development board. I am trying to play an 8 bit 44.1 kHz .wav file using internal DAC. I am using elm chan FATfs and double buffering concept. I have written code that works and plays the first second of the music but after that it all goes haywire. Can somebody point out the mistake and correct it?
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include "lpc17xx.h"
#include "system_LPC17xx.h"
#include "lpc17xx_rtc.h"
#include "integer.h"
#include "diskio.h"
#include "ff.h"
#include "delay.h"
#include "uart.h"
static uint32_t ByteCounter;
volatile UINT Timer = 0; /* Performance timer (1kHz increment) */
bool initRead = false;
static int bufferPos = 0;
static int bufferPos1 = 0;
bool buffOneAck = true, buffTwoAck = false;
bool isBeingRead = true;
/* LED indicator */
#define LED1ON() do {LPC_GPIO0 -> FIOSET |= (1<<22);}while (0)
#define LED1OFF() do {LPC_GPIO0 -> FIOCLR |= (1<<22);}while (0)
static FIL WAVfile;
#define PRESCALE (17) //25000 PCLK clock cycles to increment TC by 1
void initTimer0();
bool shouldRead = 0;
/* SysTick Interrupt Handler (1ms) */
void SysTick_Handler (void)
{
static DWORD pres, flip, prescale_disk_io;
Timer++;
if ( pres++ >= 500 ) {
pres = 0;
if (flip) LED1ON();
else LED1OFF();
flip = !flip;
}
// Disk timer process to be called every 10 ms
if ( prescale_disk_io++ >=10 ) {
prescale_disk_io = 0;
// disk_timerproc(); // <- Disk timer process to be called every 10 ms
}
}
UINT bytes_read;
uint8_t buffer[512];
uint8_t buffer1[512];
typedef struct
{
uint8_t id[4]; /** should always contain "RIFF" */
uint32_t totallength; /** total file length minus 8 */
uint8_t wavefmt[8]; /** should be "WAVEfmt " */
uint32_t format; /** Sample format. 16 for PCM format. */
uint16_t pcm; /** 1 for PCM format */
uint16_t channels; /** Channels */
uint32_t frequency; /** sampling frequency */
uint32_t bytes_per_second; /** Bytes per second */
uint16_t bytes_per_capture; /** Bytes per capture */
uint16_t bits_per_sample; /** Bits per sample */
uint8_t data[4]; /** should always contain "data" */
uint32_t bytes_in_data; /** No. bytes in data */
} WAV_Header_TypeDef;
/** Wav header. Global as it is used in callbacks. */
static WAV_Header_TypeDef wavHeader;
void Vout(uint8_t v) {
LPC_DAC->DACR = v <<6;
}
void DACInit(){
LPC_PINCON->PINSEL1 |= 0x02<<20;
LPC_SC->PCLKSEL0 |= 1 <<24;
}
void initSysTick() {
SysTick->LOAD = 0x800;
SysTick->VAL = 800;
SysTick->CTRL = 7; //Enable SysTick, interrupts using sys clock
}
/*---------------------------------------------------------*/
/* User Provided RTC Function for FatFs module */
/*---------------------------------------------------------*/
/* This is a real time clock service to be called from */
/* FatFs module. Any valid time must be returned even if */
/* the system does not support an RTC. */
/* This function is not required in read-only cfg. */
DWORD get_fattime ()
{
RTCTime rtc;
// Get local time
rtc_gettime(&rtc);
// Pack date and time into a DWORD variable
return ((DWORD)(rtc.RTC_Year - 1980) << 25)
| ((DWORD)rtc.RTC_Mon << 21)
| ((DWORD)rtc.RTC_Mday << 16)
| ((DWORD)rtc.RTC_Hour << 11)
| ((DWORD)rtc.RTC_Min << 5)
| ((DWORD)rtc.RTC_Sec >> 1);
}
static void IoInit(void)
{
RTCTime current_time;
SystemInit();
SysTick_Config(SystemFrequency/1000 - 1); /* Generate interrupt each 1 ms */
LPC17xx_RTC_Init ();
current_time.RTC_Sec = 0;
current_time.RTC_Min = 0;
current_time.RTC_Hour = 0;
current_time.RTC_Mday = 1;
current_time.RTC_Wday = 0;
current_time.RTC_Yday = 0; /* current date 01/01/2010 */
current_time.RTC_Mon = 1;
current_time.RTC_Year = 2010;
LPC17xx_RTC_SetTime( ¤t_time ); /* Set local time */
LPC17xx_RTC_Start ();
LPC_GPIO1 -> FIODIR |= (1U<<28) | (1U<<29) | (1U<<31); /* P1.16..23 defined as Outputs */
LPC_GPIO0 -> FIODIR |= (1U<<22);
}
FRESULT result;
UINT s1, s2;
RTCTime rtc;
DSTATUS status;
FATFS Fatfs, drive; /* File system object for each logical drive */
FIL file; // File objects
void readBuffer(bool readNextBufferOne, bool readNextBufferTwo){
//FRESULT result;
//FIL file;
//UINT s1;
if(!initRead){
result = f_read(&file, buffer, sizeof buffer, &s1);
result = f_read(&file, buffer1, sizeof buffer1, &s1);
//UART_Printf("Init Read : %d\r\n",result);
//UART_TxString("in readBuffer\r\n");
initRead = true;
readNextBufferOne = false;
readNextBufferTwo = false;
//result = f_close(&file);
}
if(readNextBufferOne){
bufferPos = 0;
//memset(buffer, 0, sizeof buffer);
result = f_read(&file, buffer, sizeof buffer, &s1);
UART_Printf("Buffer One : %d\r\n",result);
readNextBufferOne = false;
isBeingRead = true;
//result = f_close(&file);
}
else if(readNextBufferTwo){
bufferPos1 = 0;
//memset(buffer, 0, sizeof buffer);
UART_Printf("Buffer two : %d\r\n",result);
result = f_read(&file, buffer1, sizeof buffer1, &s1);
readNextBufferTwo = false;
}
if(f_eof(&file))
{
f_close(&file);
}
}
long int counter = 0;
DWORD maxFileSize = 0;
bool already, readit;
int main (){
char c[1024], d[100];
char* l;
already = true;
readit = true;
IoInit();
DACInit();
initTimer0();
maxFileSize = file.fsize;
status = disk_initialize(0); //Prepare the card
result = f_mount(0,&drive); //Open card
result = f_open(&file,"sib.wav",FA_READ);
readBuffer(false, false);
while(1){
if(readit){
if(!already){
//Read chunk into buffer A
memset(buffer, 0, sizeof buffer);
result = f_read(&file, buffer, sizeof buffer, &s1);
} else {
//Read chunk into buffer B
//UART_Printf("buffer 1 reading");
memset(buffer1, 0, sizeof buffer1);
result = f_read(&file, buffer1, sizeof buffer1, &s1);
}
readit = false;
}
}
}
void initTimer0(void)
{
/*Assuming that PLL0 has been setup with CCLK = 100Mhz and PCLK = 25Mhz.*/
LPC_SC->PCONP |= (1<<1); //Power up TIM0. By default TIM0 and TIM1 are enabled.
LPC_SC->PCLKSEL0 &= ~(0x3<<3); //Set PCLK for timer = CCLK/4 = 100/4 (default)
LPC_TIM0->CTCR = 0x0;
LPC_TIM0->PR = PRESCALE; //Increment LPC_TIM0->TC at every 24999+1 clock cycles
//25000 clock cycles @25Mhz = 1 mS
LPC_TIM0->MR0 = 22; //Toggle Time in mS
LPC_TIM0->MCR |= (1<<0) | (1<<1); // Interrupt & Reset on MR0 match
LPC_TIM0->TCR |= (1<<1); //Reset Timer0
NVIC_EnableIRQ(TIMER0_IRQn); //Enable timer interrupt
LPC_TIM0->TCR = 0x01; //Enable timer
}
void TIMER0_IRQHandler(void) //Use extern "C" so C++ can link it properly, for C it is not required
{
//UART_Init(57600);
//UART_TxString("here");
LPC_TIM0->IR |= (1<<0); //Clear MR0 Interrupt flag
if(counter < 6000000){
if(already){
//UART_Printf("playing buffer 1");
Vout(buffer[bufferPos]);
}else{
Vout(buffer1[bufferPos]);
}
bufferPos++;
counter++;
if(bufferPos > 512){
if(!readit){
bufferPos = 0;
already = !already;
readit = true;
}else{
counter--;
bufferPos--;
}
}else{
//disable interrupt
//file ended.
}
}
}
An interrupt if fired matching 44 kHz sampling rate of song. The system frequency is 72 MHz.