0
\$\begingroup\$

I am trying to build an MP3 Player on a generic lpc1768 development board. I am trying to play 8bit 44.1Khz wav file using internal DAC. I am using elm chan FATfs and double buffering concept. I have written a 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. Thank You.

#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( &current_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 44kz sampling rate of song. The system frequency is 72Mhz

\$\endgroup\$
  • \$\begingroup\$ How do you check for buffer over-underflow? \$\endgroup\$ – Sunnyskyguy EE75 Apr 11 at 15:19
  • \$\begingroup\$ We aren't. How can can we check it? why would it be necessary though? \$\endgroup\$ – samosa Apr 11 at 15:30
  • \$\begingroup\$ step by step timing analysis. If OK then look for syntax or object or logic errors such as initialization. \$\endgroup\$ – Sunnyskyguy EE75 Apr 11 at 15:30
  • \$\begingroup\$ Could you point me out to a link stating the algorithm or logic? I'm really new to this and I could do with some guidance. Thank You \$\endgroup\$ – samosa Apr 11 at 15:34
  • \$\begingroup\$ Perhaps more experts on this other site can help you . stackoverflow.com/tags \$\endgroup\$ – Sunnyskyguy EE75 Apr 11 at 15:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.