mirror of
https://github.com/sweetlilmre/tapuino.git
synced 2026-07-27 19:55:41 +00:00
SPI Full speed fix and Timer rewrite (3rd time :()
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include <avr/io.h>
|
||||
#include <util/delay.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -9,194 +10,410 @@
|
||||
#include "pff.h"
|
||||
#include "diskio.h"
|
||||
#include "player.h"
|
||||
#include "serial.h"
|
||||
#include "delayMicroseconds.h"
|
||||
|
||||
#define FILE_TYPE_UNK 0
|
||||
#define FILE_TYPE_MP3 1
|
||||
#define FILE_TYPE_WAV 2
|
||||
#define FILE_TYPE_MID 3
|
||||
#define FILE_TYPE_WMA 4
|
||||
#define RECV_WAIT_START 1
|
||||
#define RECV_WAIT_CMD 2
|
||||
#define RECV_WAIT_DATA 3
|
||||
|
||||
#define COMMAND_IDLE 0
|
||||
#define COMMAND_PLAY 1
|
||||
#define COMMAND_NEXT 2
|
||||
|
||||
#define CMD_ARG_MAX 12
|
||||
#define FAT_BUF_SIZE 512
|
||||
#define FAT_BUF_SIZE 256
|
||||
#define DEFAULT_DIR "/"
|
||||
#define INVALID_FILE_ATTR ( AM_DIR | AM_LFN | AM_VOL )
|
||||
#define INVALID_FILE_ATTR (AM_DIR | AM_LFN | AM_VOL)
|
||||
|
||||
#define SENSE_PORT PORTD
|
||||
#define SENSE_DDR DDRD
|
||||
#define SENSE_PIN 5
|
||||
#define SENSE_ON() SENSE_PORT &= ~_BV(SENSE_PIN)
|
||||
#define SENSE_OFF() SENSE_PORT |= _BV(SENSE_PIN)
|
||||
|
||||
#define TAPE_READ_PORT PORTD
|
||||
#define TAPE_READ_DDR DDRD
|
||||
#define TAPE_READ_PIN 3
|
||||
#define TAPE_READ_PINS PIND
|
||||
#define TAPE_READ_LOW() TAPE_READ_PORT &= ~_BV(TAPE_READ_PIN)
|
||||
#define TAPE_READ_HIGH() TAPE_READ_PORT |= _BV(TAPE_READ_PIN)
|
||||
#define TAPE_READ_TOGGLE() TAPE_READ_PINS |= _BV(TAPE_READ_PIN)
|
||||
|
||||
#define MOTOR_PORT PORTD
|
||||
#define MOTOR_DDR DDRD
|
||||
#define MOTOR_PIN 4
|
||||
#define MOTOR_PINS PIND
|
||||
#define MOTOR_IS_ON() (MOTOR_PINS & _BV(MOTOR_PIN))
|
||||
|
||||
static FATFS g_fs;
|
||||
|
||||
static FATFS fs;
|
||||
static BYTE g_fatBuffer[ FAT_BUF_SIZE ];
|
||||
static DIR g_dir;
|
||||
|
||||
BYTE file_type_from_filename( char* filename )
|
||||
static BYTE g_recvState = RECV_WAIT_START;
|
||||
static BYTE g_pendingCommand = COMMAND_IDLE;
|
||||
static BYTE g_curCommand = COMMAND_IDLE;
|
||||
|
||||
static BYTE g_cmdArgPos = 0;
|
||||
char g_cmdArg[ CMD_ARG_MAX + 1 ];
|
||||
|
||||
static BYTE g_exitFlag = 0;
|
||||
|
||||
uint8_t g_fatBuffer[256];
|
||||
static volatile uint8_t g_readIdx;
|
||||
|
||||
static volatile uint8_t g_halfWave;
|
||||
static volatile uint8_t g_writeIdx;
|
||||
|
||||
BYTE player_handleInput(char ch);
|
||||
|
||||
void responseCallback(char* msg)
|
||||
{
|
||||
if( strstr( filename, ".MP3") != 0)
|
||||
serial_println(msg);
|
||||
}
|
||||
|
||||
unsigned char inputCallback()
|
||||
{
|
||||
if (serial_available() > 0)
|
||||
{
|
||||
return( FILE_TYPE_MP3 );
|
||||
char ch = serial_read();
|
||||
return(player_handleInput(ch));
|
||||
}
|
||||
else if( strstr( filename, ".WAV") != 0)
|
||||
return(0);
|
||||
}
|
||||
|
||||
BYTE player_handleInput(char ch)
|
||||
{
|
||||
if (ch >= 'a' && ch <= 'z')
|
||||
{
|
||||
return( FILE_TYPE_WAV );
|
||||
ch = (ch - 'a') + 'A';
|
||||
}
|
||||
else if( strstr( filename, ".MID") != 0)
|
||||
|
||||
switch(g_recvState)
|
||||
{
|
||||
return( FILE_TYPE_MID );
|
||||
case RECV_WAIT_START:
|
||||
{
|
||||
if (ch == ':')
|
||||
{
|
||||
g_recvState = RECV_WAIT_CMD;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RECV_WAIT_CMD:
|
||||
{
|
||||
switch(ch)
|
||||
{
|
||||
case 'P':
|
||||
{
|
||||
g_pendingCommand = COMMAND_PLAY;
|
||||
g_recvState = RECV_WAIT_DATA;
|
||||
break;
|
||||
}
|
||||
case 'N':
|
||||
{
|
||||
g_pendingCommand = COMMAND_NEXT;
|
||||
g_recvState = RECV_WAIT_DATA;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
g_recvState = RECV_WAIT_START;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case RECV_WAIT_DATA:
|
||||
{
|
||||
if (ch != '\n')
|
||||
{
|
||||
if (ch == '\r')
|
||||
{
|
||||
// ignore carrige return
|
||||
return(0);
|
||||
}
|
||||
if (g_cmdArgPos < CMD_ARG_MAX)
|
||||
{
|
||||
g_cmdArg[ g_cmdArgPos++ ] = ch;
|
||||
}
|
||||
else
|
||||
{
|
||||
// command is too long, ignore and reset for next command
|
||||
g_recvState = RECV_WAIT_START;
|
||||
g_cmdArgPos = 0;
|
||||
g_cmdArg[ 0 ] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// null terminate and reset state
|
||||
g_cmdArg[ g_cmdArgPos ] = 0;
|
||||
g_cmdArgPos = 0;
|
||||
g_recvState = RECV_WAIT_START;
|
||||
|
||||
switch(g_pendingCommand)
|
||||
{
|
||||
default:
|
||||
{
|
||||
g_curCommand = g_pendingCommand;
|
||||
g_exitFlag = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( strstr( filename, ".WMA") != 0)
|
||||
{
|
||||
return( FILE_TYPE_WMA );
|
||||
}
|
||||
return( FILE_TYPE_UNK );
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int find_first_file( char* pFile, FILINFO* pfile_info )
|
||||
int find_first_file(char* pFile, FILINFO* pfile_info)
|
||||
{
|
||||
FRESULT res;
|
||||
|
||||
if( !pfile_info )
|
||||
if (!pfile_info)
|
||||
{
|
||||
return( 0 );
|
||||
return(0);
|
||||
}
|
||||
// rewind directory to first file
|
||||
pf_readdir( &g_dir, 0 );
|
||||
pf_readdir(&g_dir, 0);
|
||||
|
||||
while( 1 )
|
||||
while(1)
|
||||
{
|
||||
pfile_info->fname[0] = 0;
|
||||
res = pf_readdir( &g_dir, pfile_info );
|
||||
if( res != FR_OK || !pfile_info->fname[0] )
|
||||
res = pf_readdir(&g_dir, pfile_info);
|
||||
if (res != FR_OK || !pfile_info->fname[0])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( !( pfile_info->fattrib & INVALID_FILE_ATTR ) )
|
||||
if (!(pfile_info->fattrib & INVALID_FILE_ATTR))
|
||||
{
|
||||
responseCallback( pfile_info->fname );
|
||||
if( file_type_from_filename( pfile_info->fname ) != FILE_TYPE_UNK )
|
||||
responseCallback(pfile_info->fname);
|
||||
if (strstr(pfile_info->fname, ".TAP") != 0)
|
||||
{
|
||||
if( !pFile || *pFile == 0 || !strncmp( pfile_info->fname, pFile, 12 ) )
|
||||
if (!pFile || *pFile == 0 || !strncmp(pfile_info->fname, pFile, 12))
|
||||
{
|
||||
// found the file we were looking for or a playable file
|
||||
return( 1 );
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return( 0 );
|
||||
return(0);
|
||||
}
|
||||
|
||||
int find_next_file( FILINFO* pfile_info )
|
||||
int find_next_file(FILINFO* pfile_info)
|
||||
{
|
||||
FRESULT res;
|
||||
BYTE count = 0;
|
||||
|
||||
if( !pfile_info )
|
||||
if (!pfile_info)
|
||||
{
|
||||
return( 0 );
|
||||
return(0);
|
||||
}
|
||||
|
||||
while( 1 )
|
||||
while(1)
|
||||
{
|
||||
pfile_info->fname[0] = 0;
|
||||
res = pf_readdir( &g_dir, pfile_info );
|
||||
if( res != FR_OK )
|
||||
res = pf_readdir(&g_dir, pfile_info);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( !pfile_info->fname[0] )
|
||||
if (!pfile_info->fname[0])
|
||||
{
|
||||
if( count++ < 1 )
|
||||
if (count++ < 1)
|
||||
{
|
||||
// rewind directory to first file and start from the top
|
||||
pf_readdir( &g_dir, 0 );
|
||||
pf_readdir(&g_dir, 0);
|
||||
continue;
|
||||
}
|
||||
return( 0 );
|
||||
return(0);
|
||||
}
|
||||
|
||||
if( !( pfile_info->fattrib & INVALID_FILE_ATTR ) )
|
||||
if (!(pfile_info->fattrib & INVALID_FILE_ATTR))
|
||||
{
|
||||
responseCallback( pfile_info->fname );
|
||||
if( file_type_from_filename( pfile_info->fname ) != FILE_TYPE_UNK )
|
||||
responseCallback(pfile_info->fname);
|
||||
if (strstr(pfile_info->fname, ".TAP") != 0)
|
||||
{
|
||||
return( 1 );
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return( 0 );
|
||||
return(0);
|
||||
}
|
||||
|
||||
FRESULT change_dir( char* path )
|
||||
{
|
||||
FRESULT res;
|
||||
ISR(TIMER1_COMPA_vect) {
|
||||
static unsigned long pulse_length = 0;
|
||||
static unsigned long pulse_length_save;
|
||||
unsigned long tap_data;
|
||||
|
||||
res = pf_chdir( path );
|
||||
if( res == FR_OK )
|
||||
{
|
||||
res = pf_opendir( &g_dir, "." );
|
||||
if (!MOTOR_IS_ON()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_halfWave) { // 2nd half of the signal
|
||||
if (pulse_length > 0xFFFF) { // check to see if its bigger than 16 bits
|
||||
pulse_length -= 0xFFFF;
|
||||
OCR1A = 0xFFFF;
|
||||
} else {
|
||||
OCR1A = (unsigned short) pulse_length;
|
||||
pulse_length = 0; // clear this!!!! for 1st half check so that the next data is loaded!
|
||||
g_halfWave = 0; // next time round switch to 1st half
|
||||
}
|
||||
TAPE_READ_HIGH(); // set the signal high
|
||||
} else { // 1st half of the signal
|
||||
if (pulse_length) { // do we have any pulse left?
|
||||
if (pulse_length > 0xFFFF) { // check to see if its bigger than 16 bits
|
||||
pulse_length -= 0xFFFF;
|
||||
OCR1A = 0xFFFF;
|
||||
} else {
|
||||
OCR1A = (unsigned short) pulse_length;
|
||||
pulse_length = pulse_length_save; // restore pulse length for the 2nd half of the signal
|
||||
g_halfWave = 1; // next time round switch to 2nd half
|
||||
}
|
||||
} else {
|
||||
tap_data = (unsigned long) g_fatBuffer[g_readIdx++];
|
||||
if (tap_data == 0) {
|
||||
pulse_length = (unsigned long) g_fatBuffer[g_readIdx++];
|
||||
pulse_length |= ((unsigned long) g_fatBuffer[g_readIdx++]) << 8;
|
||||
pulse_length |= ((unsigned long) g_fatBuffer[g_readIdx++]) << 16;
|
||||
pulse_length *= 1.015;
|
||||
} else {
|
||||
pulse_length = tap_data * 8.12;
|
||||
}
|
||||
pulse_length_save = pulse_length; // save this for the 2nd half of the wave
|
||||
if (pulse_length > 0xFFFF) { // check to see if its bigger than 16 bits
|
||||
pulse_length -= 0xFFFF;
|
||||
OCR1A = 0xFFFF;
|
||||
} else {
|
||||
OCR1A = (unsigned short) pulse_length;
|
||||
pulse_length = pulse_length_save; // restore pulse length for the 2nd half of the signal
|
||||
g_halfWave = 1; // next time round switch to 2nd half
|
||||
}
|
||||
TAPE_READ_LOW();
|
||||
}
|
||||
}
|
||||
return( res );
|
||||
}
|
||||
|
||||
void printcode(int code)
|
||||
{
|
||||
switch(code)
|
||||
{
|
||||
case FR_OK:
|
||||
responseCallback("FR_OK");
|
||||
break;
|
||||
case FR_DISK_ERR:
|
||||
responseCallback("FR_DISK_ERR");
|
||||
break;
|
||||
case FR_NOT_READY:
|
||||
responseCallback("FR_NOT_READY");
|
||||
break;
|
||||
case FR_NO_FILE:
|
||||
responseCallback("FR_NO_FILE");
|
||||
break;
|
||||
case FR_NO_PATH:
|
||||
responseCallback("FR_NO_PATH");
|
||||
break;
|
||||
case FR_NOT_OPENED:
|
||||
responseCallback("FR_NOT_OPENED");
|
||||
break;
|
||||
case FR_NOT_ENABLED:
|
||||
responseCallback("FR_NOT_ENABLED");
|
||||
break;
|
||||
case FR_NO_FILESYSTEM:
|
||||
responseCallback("FR_NO_FILESYSTEM");
|
||||
break;
|
||||
default:
|
||||
responseCallback("UNKNOWN ERROR");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int player_hardwareSetup( void )
|
||||
//purple green gray brown cyan green
|
||||
BYTE play_file(char* pFile)
|
||||
{
|
||||
FRESULT res;
|
||||
WORD br;
|
||||
g_exitFlag = 0;
|
||||
|
||||
res = pf_open(pFile);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
responseCallback("pf_open failed");
|
||||
return(1);
|
||||
}
|
||||
|
||||
// Initialize with very short pulses in case the TAP file
|
||||
// is smaller than the buffer
|
||||
memset(g_fatBuffer,1,256);
|
||||
|
||||
res = pf_read((void*) g_fatBuffer, FAT_BUF_SIZE, &br);
|
||||
if (res != FR_OK)
|
||||
{
|
||||
responseCallback("pf_read failed");
|
||||
return(1);
|
||||
}
|
||||
|
||||
if (strncmp((const char*) g_fatBuffer, "C64-TAPE-RAW", 12) != 0)
|
||||
{
|
||||
responseCallback("Invalid TAP file!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cli();
|
||||
|
||||
TCCR1A = 0x00; // clear timer registers
|
||||
TCCR1B = 0x00;
|
||||
TIMSK1 = 0x00;
|
||||
|
||||
//TCCR1A |= _BV(WGM12);
|
||||
TCCR1B |= _BV(CS11) | _BV(WGM12); //prescaller 8 = 2 MHZ
|
||||
|
||||
sei();
|
||||
serial_println("Loading...");
|
||||
if (MOTOR_IS_ON()) {
|
||||
serial_println("Motor on");
|
||||
}
|
||||
|
||||
// Start send-ISR
|
||||
TAPE_READ_LOW();
|
||||
SENSE_ON();
|
||||
|
||||
g_writeIdx = 0;
|
||||
g_readIdx = 20; // Skip header
|
||||
g_halfWave = 0;
|
||||
_delay_ms(100);
|
||||
|
||||
OCR1A = 0xFFFF;
|
||||
TCNT1 = 0;
|
||||
TIMSK1 |= _BV(OCIE1A);
|
||||
|
||||
while (br > 0) {
|
||||
// Wait until ISR is in the new half of the buffer
|
||||
while ((g_readIdx & 0x80) == (g_writeIdx & 0x80)) ;
|
||||
pf_read((void*) g_fatBuffer + g_writeIdx, 128, &br);
|
||||
g_writeIdx += 128;
|
||||
}
|
||||
|
||||
// Wait once more (last read tried to read new half of buffer,
|
||||
// but failed -> need to wait until ISR is in new half, but
|
||||
// g_writeIdx was incremented unconditionally -> wait until
|
||||
// ISR has left g_writeIdx-half of buffer)
|
||||
while ((g_readIdx & 0x80) == (g_writeIdx & 0x80)) ;
|
||||
|
||||
// pf_close();
|
||||
|
||||
TIMSK1 &= ~_BV(OCIE1A);
|
||||
|
||||
SENSE_OFF();
|
||||
TAPE_READ_LOW();
|
||||
serial_println("Loading complete!");
|
||||
|
||||
g_curCommand = COMMAND_IDLE;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int player_hardwareSetup(void)
|
||||
{
|
||||
FRESULT res;
|
||||
SENSE_DDR |= _BV(SENSE_PIN);
|
||||
SENSE_OFF();
|
||||
TAPE_READ_DDR |= _BV(TAPE_READ_PIN);
|
||||
TAPE_READ_HIGH();
|
||||
MOTOR_DDR &= ~_BV(MOTOR_PIN);
|
||||
MOTOR_PORT |= _BV(MOTOR_PIN);
|
||||
|
||||
SPI_Init();
|
||||
SPI_Speed_Slow();
|
||||
SPI_Send (0xFF);
|
||||
|
||||
//_delay_ms( 200 );
|
||||
|
||||
res = pf_mount( &fs );
|
||||
|
||||
|
||||
if( res == FR_OK )
|
||||
_delay_ms(200);
|
||||
SPI_Speed_Fast();
|
||||
serial_init();
|
||||
|
||||
res = pf_mount(&g_fs);
|
||||
if (res == FR_OK)
|
||||
{
|
||||
|
||||
res = pf_opendir( &g_dir, DEFAULT_DIR );
|
||||
res = pf_opendir(&g_dir, DEFAULT_DIR);
|
||||
}
|
||||
else
|
||||
{
|
||||
printcode(res);
|
||||
responseCallback(":risd mount failed");
|
||||
}
|
||||
|
||||
return( res == FR_OK );
|
||||
|
||||
return(res == FR_OK);
|
||||
}
|
||||
|
||||
|
||||
@@ -204,22 +421,39 @@ int player_hardwareSetup( void )
|
||||
void player_run()
|
||||
{
|
||||
FILINFO file_info;
|
||||
if (!player_hardwareSetup( ))
|
||||
return;
|
||||
|
||||
if( !find_first_file( NULL, &file_info ) )
|
||||
if (!player_hardwareSetup())
|
||||
{
|
||||
responseCallback( ":rpno file" );
|
||||
responseCallback("fail");
|
||||
return;
|
||||
}
|
||||
|
||||
while( 1 )
|
||||
if (!find_first_file(NULL, &file_info))
|
||||
{
|
||||
responseCallback(file_info.fname);
|
||||
if (!find_next_file( &file_info ))
|
||||
{
|
||||
find_first_file( NULL, &file_info );
|
||||
}
|
||||
_delay_ms(1000);
|
||||
responseCallback(":rpno file");
|
||||
return;
|
||||
}
|
||||
}
|
||||
responseCallback("run");
|
||||
|
||||
while(1)
|
||||
{
|
||||
switch(g_curCommand)
|
||||
{
|
||||
case COMMAND_PLAY:
|
||||
{
|
||||
responseCallback(file_info.fname);
|
||||
play_file(file_info.fname);
|
||||
//send_file();
|
||||
break;
|
||||
}
|
||||
case COMMAND_NEXT:
|
||||
{
|
||||
find_next_file(&file_info);
|
||||
g_curCommand = COMMAND_IDLE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
inputCallback();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-16
@@ -1,28 +1,13 @@
|
||||
#include <Wire.h>
|
||||
#include <LiquidCrystal_I2C.h>
|
||||
|
||||
LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 for a 16 chars and 2 line display
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "player.h"
|
||||
void responseCallback(char* msg)
|
||||
{
|
||||
lcd.home();
|
||||
lcd.print(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
lcd.init(); // initialize the lcd
|
||||
|
||||
// Print a message to the LCD.
|
||||
lcd.backlight();
|
||||
lcd.print("Init");
|
||||
player_run();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user