I am trying to design a simple compact system that will record to SD when power is applied and stop when power is removed, with high quality audio but long recording times.
I am having problems recording ogg using a vs1053b to an SD card using a PIC24. Im using the FSFAT library. The VS1053b is mounted on a sparkfun VS10XX breakout board and I'm using encoder version 1.70c.
It appears that I have successfully loaded the plugin from SD into the VS1053b, however when I activate recording I SCI_HDAT1 contains the value 0x02bc (or there about depending on which plugin I use).
When I read data 256 Words(512 bytes) from SCI_HDAT1 all appears to be ok and I can see I receive an ogg header.
I check SCI_HDAT1:0x01bd AICTRL3:0x0000 and 0x180F:0x0002 which all appear to be correct.
Then try to read another 256 words from SCI_HDAT1 however after reading 240 words DREQ goes low and stays low.
Sequential reads of SCI_HDAT1 do not show any increase before or after reading from SCI_HDAT0.
I have tried messing with the VOX setting and using profiles that do not support VOX but all produce the same results? I cannot understand why the encoder always stops after producing a small amount of data.
Any help would be gratefully received.
Arran Holmes
Here is the output from the application code:
Code: Select all
OGG Recorder debug console
Init FSFAT
LFN Enabled, Code page: 437
SD CARD init OK
Mounting file system: OK
Init VS1053B....OK
Opening VS1053b ogg encoder plugin: OK
Uploading plugin to VS1053b
Type:1 Len:0x0020 Addr:0x1800
Type:0 Len:0x3edc Addr:0x0034
Type:0 Len:0x003c Addr:0x0010
Type:1 Len:0x0004 Addr:0x0000
Type:1 Len:0x2640 Addr:0x0100
Type:2 Len:0x158c Addr:0x0110
Type:1 Len:0x0028 Addr:0x0004
Type:1 Len:0x0020 Addr:0x0019
Type:2 Len:0x0434 Addr:0x0bd8
Type:1 Len:0x2000 Addr:0x3000
Type:2 Len:0x0880 Addr:0x1000
Type:3 Len:0x0000 Addr:0x0034
Plugin address:0x0034
Closing plugin file...OK
Opening output file "00000001.OGG" OK
Starting plugin...OK
wordsWaiting:0x02bc
................................................................................................................................................................................................................................................................
AICTRL3:0x0000wordsWaiting:0x01bc
................................................................................................................................................................................................................................................................
AICTRL3:0x3c06wordsWaiting:0x00bc
............................................................................................................................................................................................
AICTRL3:0x5506wordsWaiting:0x0000
AICTRL3:0x0002wordsWaiting:0x0000
AICTRL3:0x0002wordsWaiting:0x0000
AICTRL3:0x0002wordsWaiting:0x0000
Code: Select all
/*
* File: main.c
* Author: Arran Holmes
*
* Created on 10 September 2014, 23:10
*/
// must be at the top!
#define USE_AND_OR
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include <p24FJ64GA002.h>
#include "spi.h"
#include "PPS.h"
#include "ports.h"
#include "vs10xx_uc.h"
#include "pic24f.h"
#include "xprintf.h"
#include "uart_pic24f.h"
#include "ffconf.h"
#include "ff.h"
#include "diskio.h"
#include <libpic30.h> // __delay_ms() etc
// CONFIG2
#pragma config POSCMOD = NONE // Primary Oscillator Select (Primary oscillator disabled)
#pragma config I2C1SEL = PRI // I2C1 Pin Location Select (Use default SCL1/SDA1 pins)
#pragma config IOL1WAY = OFF // IOLOCK Protection (Once IOLOCK is set, cannot be changed)
#pragma config OSCIOFNC = ON // Primary Oscillator Output Function (OSC2/CLKO/RC15 functions as CLKO (FOSC/2))
#pragma config FCKSM = CSDCMD // Clock Switching and Monitor (Clock switching and Fail-Safe Clock Monitor are disabled)
#pragma config FNOSC = FRCPLL // Oscillator Select (Fast RC Oscillator with PLL module (FRCPLL))
#pragma config SOSCSEL = SOSC // Sec Oscillator Select (Default Secondary Oscillator (SOSC))
#pragma config WUTSEL = LEG // Wake-up timer Select (Legacy Wake-up Timer)
#pragma config IESO = ON // Internal External Switch Over Mode (IESO mode (Two-Speed Start-up) enabled)
// CONFIG1
#pragma config WDTPS = PS32768 // Watchdog Timer Postscaler (1:32,768)
#pragma config FWPSA = PR128 // WDT Prescaler (Prescaler ratio of 1:128)
#pragma config WINDIS = ON // Watchdog Timer Window (Standard Watchdog Timer enabled,(Windowed-mode is disabled))
#pragma config FWDTEN = ON // Watchdog Timer Enable (Watchdog Timer is enabled)
#pragma config ICS = PGx1 // Comm Channel Select (Emulator EMUC1/EMUD1 pins are shared with PGC1/PGD1)
#pragma config GWRP = OFF // General Code Segment Write Protect (Writes to program memory are allowed)
#pragma config GCP = OFF // General Code Segment Code Protect (Code protection is disabled)
#pragma config JTAGEN = OFF // JTAG Port Enable (JTAG port is enabled)
#define OUTPUT 0
#define INPUT 1
#define DREQ _RB14
#define DCS _LATA0
#define CS _LATB15
#define RESET _LATA1
#define noSectors 1
#define sectorSize 512
unsigned char buffer[noSectors][sectorSize];
// fsfat stuff
FILINFO Finfo;
#if _USE_LFN
TCHAR Lfname[256];
#endif
FATFS FatFs; // File system object
//BYTE Buff[4096]; // Working buffer
volatile UINT Timer; // 1kHz increment timer
volatile WORD rtcYear = 2014;
volatile BYTE rtcMon = 4, rtcMday = 6, rtcHour, rtcMin, rtcSec;
void __attribute__((interrupt, auto_psv)) _T1Interrupt (void)
{
static const BYTE samurai[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static UINT div1k;
BYTE n;
_T1IF = 0; // Clear irq flag
Timer++; // Performance counter for this module
disk_timerproc(); // Drive timer procedure of low level disk I/O module
// Real Time Clock
if (++div1k >= 1000) {
div1k = 0;
if (++rtcSec >= 60) {
rtcSec = 0;
if (++rtcMin >= 60) {
rtcMin = 0;
if (++rtcHour >= 24) {
rtcHour = 0;
n = samurai[rtcMon - 1];
if ((n == 28) && !(rtcYear & 3)) n++;
if (++rtcMday > n) {
rtcMday = 1;
if (++rtcMon > 12) {
rtcMon = 1;
rtcYear++;
}
}
}
}
}
}
}
void WaitForDreq(int timeOut){
int i =0;
while(DREQ == 0){
__delay_ms(10);
i++;
if (i == timeOut){
//xputs("DREQ - Timeout");
return;
}
};
// need to add timeout
}
u_int16 ReadSci(u_int8 addr) {
unsigned int i;
u_int16 res;
_DI();
WaitForDreq(10); // Wait until DREQ is high
CS = 0; // Activate xCS
WriteSPI2(3); // Read command code
while(SPI2_Tx_Buf_Full);
while(!DataRdySPI2());
ReadSPI2();
WriteSPI2(addr); // SCI register number
while(SPI2_Tx_Buf_Full);
while(!DataRdySPI2());
ReadSPI2();
WriteSPI2(0); //
while(SPI2_Tx_Buf_Full);
while(!DataRdySPI2());
res = ReadSPI2() << 8;
WriteSPI2(0);
while(SPI2_Tx_Buf_Full);
while(!DataRdySPI2());
res |= ReadSPI2();
CS = 1; // Deactivate xCS
_EI();
return res;
}
void WriteSci(u_int8 addr, u_int16 data) {
int i;
_DI();
WaitForDreq(10); // Wait until DREQ is high
CS = 0; // Activate xCS
WriteSPI2(2); // Write command code
while(SPI2_Tx_Buf_Full);
while(!DataRdySPI2());
ReadSPI2();
WriteSPI2(addr); // SCI register number
while(SPI2_Tx_Buf_Full);
while(!DataRdySPI2());
ReadSPI2();
WriteSPI2((u_int8)(data >> 8));
while(SPI2_Tx_Buf_Full);
while(!DataRdySPI2());
ReadSPI2();
WriteSPI2((u_int8)(data & 0xFF));
while(SPI2_Tx_Buf_Full);
while(!DataRdySPI2());
ReadSPI2();
CS = 1; // Deactivate xCS
_EI();
}
unsigned char f_getc(FIL * fp){
unsigned char buf;
unsigned int bytesRead;
FRESULT stat;
stat = f_read(fp,&buf,1,&bytesRead);
//xprintf("Read:%d",bytesRead);
return buf;
}
/*
SpiLoadImageInto1053() loads an image from a file into the memory
of VS1053(), then returns the start address to the caller. If it
fails, it will return 0xFFFFU.
The file format is as follows:
The file starts with three characters, "P&H".
The rest of the file are followed by records that are in the
following format:
Tp L1 L0 A1 A0 D0 D1 D2 ....
Tp: The type of the record. Values 0..3 are valid:
- 0 = Code (Instructions)
- 1 = X memory
- 2 = Y memory
- 3 = Execute (start address)
(L1<<8) + L0: Length of the record in bytes. Always an even number.
(A1<<8) + A0: Start address of the record. If the record is of type
Execute, then this is the execution start address. It is also the
end of the file.
Dx: Data. Read this two bytes at a time and send to VS1053 in a
big-endian fashion, as shown in the code below.
*/
u_int16 SpiLoadImageInto1053(FIL *fp) {
s_int16 type;
if (f_getc(fp) != 'P' || f_getc(fp) != '&' || f_getc(fp) != 'H') {
xputs("incorrect header\n");
return 0xFFFF;
}
while ((type = f_getc(fp)) >= 0) {
// offsets are: Code (I), X Mem, Y Mem when written through SCI_WRAM.
// See VS1053 datasheet's documentation for SCI register SCI_WRAMADDR for
// details.
static u_int16 offsets[3] = {0x8000U, 0x0U, 0x4000U};
u_int16 len, addr;
if (type >= 4) {
// Error condition
xputs("Error invalied type record\n");
return 0xFFFF;
}
len = (u_int16)f_getc(fp) << 8;
len |= f_getc(fp);// & ~1;
addr = (u_int16)f_getc(fp) << 8;
addr |= f_getc(fp);
xprintf("Type:%d Len:0x%04x Addr:0x%04x\n",type,len,addr);
if (type == 3) {
// Execute record: we can now return with the execute address
return addr;
}
// Set address
WriteSci(SCI_WRAMADDR, addr + offsets[type]);
// Write data
do {
u_int16 data;
data = (u_int16)f_getc(fp) << 8;
data |= f_getc(fp);
WriteSci(SCI_WRAM, data);
} while ((len -= 2));
}
xputs("Error invalied type record 0\n");
return 0xFFFF;
}
DWORD get_fattime (void)
{
DWORD tmr;
_DI();
// Pack date and time into a DWORD variable
tmr = (((DWORD)rtcYear - 1980) << 25)
| ((DWORD)rtcMon << 21)
| ((DWORD)rtcMday << 16)
| (WORD)(rtcHour << 11)
| (WORD)(rtcMin << 5)
| (WORD)(rtcSec >> 1);
_EI();
return tmr;
}
void put_rc (FRESULT rc)
{
const char *str =
"OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
"INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0" "WRITE_PROTECTED\0"
"INVALID_DRIVE\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0"
"LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0";
FRESULT i;
for (i = 0; i != rc && *str; i++) {
while (*str++) ;
}
xprintf("%s\n", str);
}
int main(int argc, char** argv) {
//configure clock
CLKDIV = 0x0100; //32Mhz
//configure IO ports
AD1PCFG = 0xFFFF; // all digital ports
CS = 1;
DCS = 1;
RESET = 0;
_RA3 = 1; // SD Card CS
_TRISA0 = OUTPUT; // #define DCS _LATB10
_TRISB15 = OUTPUT; // #define CS _LATB15
_TRISB14 = INPUT; // #define DREQ _RB14
_TRISA1 = OUTPUT; // RESET
_TRISA2 = INPUT; // SD_CD Card Detect
_TRISA3 = OUTPUT; // SD_CS Chip Select
_CN30PUE = 1; // SD_CD
//Configure PPS
//SPI2 - VS1053B
//PPSUnLock;
iPPSInput(IN_FN_PPS_SDI2,IN_PIN_PPS_RP11);
iPPSOutput(OUT_PIN_PPS_RP12,OUT_FN_PPS_SDO2);
iPPSOutput(OUT_PIN_PPS_RP13,OUT_FN_PPS_SCK2OUT);
//UART1 - Debug onsole
iPPSInput(IN_FN_PPS_U1RX,IN_PIN_PPS_RP3);
iPPSOutput(OUT_PIN_PPS_RP2,OUT_FN_PPS_U1TX);
//SPI1 - SDCARD
iPPSInput(IN_FN_PPS_SDI1,IN_PIN_PPS_RP6);
iPPSOutput(OUT_PIN_PPS_RP4,OUT_FN_PPS_SDO1);
iPPSOutput(OUT_PIN_PPS_RP7,OUT_FN_PPS_SCK1OUT);
//PPSLock;
// SPI2 Configuration VS1053B
unsigned int SPI2CON1Value, SPI2CON2Value,SPI2STATValue,test;
CloseSPI2();
SPI2CON1Value = ENABLE_SCK_PIN | SPI_MODE8_ON |SPI_CKE_OFF |SPI_SMP_OFF | MASTER_ENABLE_ON | PRI_PRESCAL_4_1 | SEC_PRESCAL_4_1;
SPI2CON2Value = FRAME_ENABLE_OFF;
SPI2STATValue = SPI_ENABLE;
OpenSPI2(SPI2CON1Value,SPI2CON2Value,SPI2STATValue );
// SPI1 Configuration SDCARD
unsigned int SPI1CON1Value,SPI1CON2Value,SPI1STATValue;
CloseSPI1();
SPI1CON1Value = 0x013B;//ENABLE_SCK_PIN | ENABLE_SDO_PIN | SPI_MODE8_ON | MASTER_ENABLE_ON | SPI_CKE_OFF |SPI_SMP_OFF | PRI_PRESCAL_1_1 | SEC_PRESCAL_2_1;
SPI1CON2Value = 0x0000;
SPI1STATValue = SPI_ENABLE;
OpenSPI1(SPI1CON1Value,SPI1CON2Value,SPI1STATValue);
// Start Timer1 in interval time of 1ms
PR1 = FCY / 8 / 1000;
_TCKPS0 = 1; // Select prescaler Fcy/8
_TON = 1; // Start Timer1
_T1IE = 1; // Enable Timer1 interrupt
_EI();
// UART Configuration
uart_init(19200);
xdev_in(uart_getc); // Join UART and console
xdev_out(uart_putc);
xputs("\nOGG Recorder debug console\n");
xputs("\nInit FSFAT\n");
xputs(_USE_LFN ? "LFN Enabled" : "LFN Disabled");
xprintf(", Code page: %u\n", _CODE_PAGE);
#if _USE_LFN // Initialize file info structure if in LFN cfg
Finfo.lfname = Lfname;
Finfo.lfsize = sizeof Lfname;
#endif
DSTATUS stat;
stat = disk_initialize(0);
if (stat != 0){
xprintf("SD Card Error: %u\n", stat);
while(1);
}
xputs("SD CARD init OK\n");
xputs("Mounting file system: ");
put_rc(f_mount(&FatFs, "", (BYTE)0));
xputs("Init VS1053B");
RESET = 1;
WaitForDreq(100);
// Set VS1053 clock to 4.5x = 55.3 MHz
WriteSci(SCI_CLOCKF, 0xC000);
WaitForDreq(10);
xputs(".");
// Clear SCI_BASS
WriteSci(SCI_BASS, 0);
xputs(".");
// Reset VS1053
WriteSci(SCI_MODE, SM_SDINEW | SM_RESET );
WaitForDreq(10); // Wait until DREQ is high or 100 ms
xputs(".");
// Disable all interrupts except SCI
WriteSci(SCI_WRAMADDR, 0xC01A);
WriteSci(SCI_WRAM, 0x2);
xputs(".OK");
//LoadPlugin();
u_int16 startAddress;
FIL file;
xputs("\nOpening VS1053b ogg encoder plugin: ");
put_rc(f_open(&file,"venc44k2q05.img",FA_READ));
xputs("Uploading plugin to VS1053b\n");
startAddress = SpiLoadImageInto1053(&file);
xprintf("\nPlugin address:0x%04x\n",startAddress);
xputs("Closing plugin file...");
put_rc(f_close(&file));
// Set VS1053 mode bits as instructed in the VS1053b Ogg Vorbis Encoder
// manual. Note: for microphone input, leave SMF_LINE1 unset!
WriteSci(SCI_MODE, SM_ADPCM | SM_SDINEW);
// Rec level: 1024 = 1. If 0, use AGC
WriteSci(SCI_AICTRL1, 1024);
// Maximum AGC level: 1024 = 1. Only used if SCI_AICTRL1 is set to 0.
WriteSci(SCI_AICTRL2, 0);
// Miscellaneous bits that also must be set before recording.
WriteSci(SCI_AICTRL3, 0);
// Activate recording from the address we got. (In the case of the Ogg
// Vorbis Encoder application, pluginStartAddr = 0x34.)
xputs("Opening output file \"00000001.OGG\" ");
put_rc(f_open(&file,"00000001.ogg",FA_CREATE_ALWAYS));
//WriteSci(SCI_WRAMADDR, 0x180F); // VOX off
//WriteSci(SCI_WRAM, 0x2);
xputs("Starting plugin...");
WriteSci(SCI_AIADDR, startAddress);
WaitForDreq(10);
xputs("OK\n");
u_int16 state = 0;
u_int16 wordsToRead;
u_int16 wordsWaiting;
#define EndRecording() 0
while (1) {
/* See how many 16-bit words there are waiting in the VS1053 buffer */
wordsWaiting = ReadSci(SCI_HDAT1);
xprintf("wordsWaiting:0x%04x\n",wordsWaiting);
u_int16 t;
u_int16 i;
if (wordsWaiting >= 256){
for (i=0; i!=512;) { // read 256 words or 512 bytes
t = ReadSci(SCI_HDAT0);
buffer[0][i++] = t >> 8;
buffer[0][i++]= t & 0xFF;
//f_putc((TCHAR)(t >> 8) , &file);
//f_putc((TCHAR)(t & 0xFF), &file);
xputs(".");
}
} else if (wordsWaiting >0) {
for (i=0; i!=(wordsWaiting *2);) {
t = ReadSci(SCI_HDAT0);
buffer[0][i++] = t >> 8;
buffer[0][i++]= t & 0xFF;
//f_putc((TCHAR)(t >> 8) , &file);
//f_putc((TCHAR)(t & 0xFF), &file);
xputs(".");
}
}
t = ReadSci(SCI_AICTRL3);
xprintf("\nAICTRL3:0x%04x ",t);
//put_rc(f_sync(&file));
}
return (EXIT_SUCCESS);
}