Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Buleste
Posts: 43
Joined: Sun Nov 06, 2016 12:19 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by Buleste » Mon Mar 06, 2017 8:25 pm

Anyone any good with SDFat.h?

I used to use the EEPROM on the arduino to store a setting but obviously not entirely practical on the Mini so instead of writing the setting to an EEPROM I want to write it to a file on the SDCard.
I can get the setting writing to a file but each time the setting is changed it adds another line to the file whereas I would prefer it to overwrite. Then I'm struggling to read the file and set that as an integer.

EG
There is a choice of BAUDRATE 1200, 2400, 3600. Once you choose that it will save 1200,2400,3600 to a file on the SD Card. When the board is switched on I want to read that file and for BAUDRATE to equal what it's just read.

Great work on the library Victor.

Another bug I think I've found is that when it reaches the end of the WAV file TMRpcm doesn't stop

victor_pv
Posts: 1650
Joined: Mon Apr 27, 2015 12:12 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by victor_pv » Tue Mar 07, 2017 2:47 am

Buleste wrote:
Another bug I think I've found is that when it reaches the end of the WAV file TMRpcm doesn't stop
What format of file? mono, stereo.8 bit, 16bit?

It seems to be stopping fine for me with all my test files, but perhaps I have made some other change in the last few days.

Buleste
Posts: 43
Joined: Sun Nov 06, 2016 12:19 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by Buleste » Tue Mar 07, 2017 9:30 am

victor_pv wrote:
Buleste wrote:
Another bug I think I've found is that when it reaches the end of the WAV file TMRpcm doesn't stop
What format of file? mono, stereo.8 bit, 16bit?

It seems to be stopping fine for me with all my test files, but perhaps I have made some other change in the last few days.
All files I've tried. 8-bit 16-bit mono and stereo. Just seems to play silence. It could very well be my code.

victor_pv
Posts: 1650
Joined: Mon Apr 27, 2015 12:12 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by victor_pv » Tue Mar 07, 2017 3:14 pm

Buleste wrote:All files I've tried. 8-bit 16-bit mono and stereo. Just seems to play silence. It could very well be my code.

Remember that in my library buffer_load function is not being called on interrupt, you need to call it in a loop as loon as the file is playing.
I'll try to add a setting to be attached to an interrupt when I clean up the library.

Buleste
Posts: 43
Joined: Sun Nov 06, 2016 12:19 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by Buleste » Tue Mar 07, 2017 5:05 pm

I have it running in a loop as it seems to be the only place it will actually work.

Code: Select all

// ---------------------------------------------------------------------------------
// DO NOT USE CLASS-10 CARDS on this project - they're too fast to operate using SPI
// ---------------------------------------------------------------------------------
// ArduiTape Arduino based 8-bit computer tape player. 
// Play WAV files from an SD card.  Based on the TMRpcm code.
//#include <SdFat.h>
#include <SPI.h>
#include <TMRpcm.h> 
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display

//TMRpcm tmrpcm;   //Initialise tmrpcm

SdFat SD;    //Initialise Sd card 

SdFile entry;

#define filenameLength    100

char fileName[filenameLength+1];  //Current filename
char sfileName[13];

const int SD_ChipSelectPin = 8;    //Sd card chip select pin

// ---------------------------------------------------------------------------------
//int cardType = SPI_CLOCK_DIV2;
// ---------------------------------------------------------------------------------

#define btnPlay       20    //Play Button
#define btnStop       19    //Stop Button
#define btnUp         18    //Menu Up button
#define btnDown       17    //Menu Down button
#define btnMotor      21    //Motor Sense (connect pin to gnd to play, NC for pause)
#define btnMselect    22    //Motor Control on/off button 

#define scrollSpeed   250   //text scroll delay
#define scrollWait    3000  //Delay before scrolling starts
byte scrollPos=0;
unsigned long scrollTime=millis()+scrollWait;

int mselectState = 1;//Motor control state 1=on 0=off
int wasPlaying = 0;  //Was there a file playing?
int motorState = 1;  //Current motor control state
int finished = 0;    //Has the file finished?
int start = 0;       //Currently playing flag
int pauseOn = 0;     //Pause state
int currentFile = 1; //Current position in directory
int maxFile = 0;     //Total number of files in directory
int isDir = 0;       //Is the current file a directory
unsigned long timeDiff = 0;  //button debounce

void setup() {
  
  lcd.init();  //Initialise LCD (16x2 type)
   lcd.backlight();
  pinMode(SD_ChipSelectPin, OUTPUT); //Setup SD card chipselect pin
  SPI.setModule(1);
  if (!SD.begin(SD_ChipSelectPin,SPI_CLOCK_DIV2)) {  //Start SD card and check it's working
    lcd_clearline(0);
    lcd.print("No SD Card");
    return;
  }
  SD.chdir();  //set SD to root directory

  speakerPin  = 27; //TMR1 CH1
  speakerPin2 = 26; //TMR1 CH2
  
  pinMode(btnPlay,INPUT_PULLUP);
  digitalWrite(btnPlay,HIGH);
  pinMode(btnStop,INPUT_PULLUP);
  digitalWrite(btnStop,HIGH);
  pinMode(btnUp,INPUT_PULLUP);
  digitalWrite(btnUp,HIGH);
  pinMode(btnDown,INPUT_PULLUP);
  digitalWrite(btnDown,HIGH);
  pinMode(btnMotor, INPUT_PULLUP);
  digitalWrite(btnMotor,HIGH);
  pinMode(btnMselect, INPUT_PULLUP);
  digitalWrite(btnMselect, HIGH);//Setup buttons with internal pullup 
  lcd.clear();
  lcd.print("MapleTape 0.2a");
  delay(1000);
  lcd.clear();
  getMaxFile();  //get the total number of files in the directory
  seekFile(currentFile);  //move to the first file in the directory
  lcd_clearline(0);
  lcd.print("Ready..");
}

void loop(void) {
  if (TMRpcm_playing) {
    TMRpcm_buffer_load();
  }
  
  if(!TMRpcm_playing && wasPlaying == 1) { 
    stopFile();
    //Serial.println("Stopped");
    //if the file has finished stop trying to play the file
  }
  
  if((millis()>=scrollTime) && start==0 && (strlen(fileName)>16)) {
    scrollTime = millis()+scrollSpeed;
    scrollText(fileName);
    scrollPos +=1;
    if(scrollPos>strlen(fileName)) {
      scrollPos=0;
      scrollTime=millis()+scrollWait;
      scrollText(fileName);
    }
  }
  
  motorState=digitalRead(btnMotor);
  if (millis() - timeDiff > 50) { // check switch every 100ms 
     timeDiff = millis(); // get current millisecond count
      
      if(digitalRead(btnPlay) == LOW) {
        if(start==0) {
          playFile();
          delay(200);
        } else {
        
          
          while(digitalRead(btnPlay)==LOW) {
            delay(50);
          }
            TMRpcm_pause();
            if (pauseOn == 0) {
              lcd_clearline(0);
              lcd.print("Paused");
              pauseOn = 1;
            } else {
              lcd_clearline(0);
              lcd.print("Playing");
              pauseOn = 0;
            }
       }
     }
     if(digitalRead(btnMselect)==LOW){
       if(mselectState==0) {
         lcd_clearline(0);
         lcd.print("Motor CTRL On");
         mselectState=1; 
       } else { 
         lcd_clearline(0);
         lcd.print("Motor CTRL Off");
         mselectState=0; 
       }
       while(digitalRead(btnMselect)==LOW) {
         delay(50);
       }
     }
     if(digitalRead(btnStop)==LOW && start==1) {
       stopFile();
       delay(200);
     } else {
      if (digitalRead(btnStop)==LOW && start==0){
      //Return to root of the SD card.
       SD.chdir(true);
       getMaxFile();
       currentFile=1;
       seekFile(currentFile);  
       while(digitalRead(btnStop)==LOW) {
         //prevent button repeats by waiting until the button is released.
         delay(50);
       }
     }
     }
     if(digitalRead(btnUp)==LOW && start==0) {
       upFile();
       while(digitalRead(btnUp)==LOW) {
         delay(50);  //wait until button is released
       }
     }
     if(digitalRead(btnDown)==LOW && start==0) {
       downFile();
       while(digitalRead(btnDown)==LOW) {
         delay(50);
       }
     }
     if(mselectState==1 && start==1) {  //if file is playing and motor control is on then handle current motor state
       if(motorState==1 && pauseOn==0) {
         TMRpcm_pause();
         lcd_clearline(0);
         lcd.print("Paused");
         pauseOn = 1;
       } 
       if(motorState==0 && pauseOn==1) {
         TMRpcm_pause();
         lcd_clearline(0);
         lcd.print("Playing");
         pauseOn = 0;
       }
     }
  }
}

void upFile() {    
  //move up a file in the directory
  
  currentFile--;
  if(currentFile<1) {
    getMaxFile();
    currentFile = maxFile;
  } 
  seekFile(currentFile);
}

void downFile() {    
  //move down a file in the directory
  
  currentFile++;
  if(currentFile>maxFile) { currentFile=1; }
  seekFile(currentFile);
}


void seekFile(int pos) {    
  //move to a set position in the directory, store the filename, and display the name on screen.
  
  entry.cwd()->rewind();
  for(int i=1;i<=currentFile;i++) {
    entry.openNext(entry.cwd(),O_READ);
    entry.getName(fileName,filenameLength);
    entry.getSFN(sfileName);
    if(entry.isDir() || !strcmp(sfileName, "ROOT")) { isDir=1; } else { isDir=0; }
    entry.close();
  }
  lcd_clearline(1);
  scrollPos=0;
  scrollText(fileName);
}

void stopFile() {
  TMRpcm_stopPlayback();
  if(start==1){
    lcd_clearline(0);
    lcd.print("Stopped");
    start=0;
  }
}

void playFile() {
  if(isDir==1) {
    changeDir();
  } else {
    if(entry.cwd()->exists(sfileName)) {
      lcd_clearline(0);
      lcd.print("Playing");
      lcd_clearline(1);
      scrollPos=0;
      scrollText(fileName);
      TMRpcm_play(sfileName);
      wasPlaying = 1;
      start=1; 
      TMRpcm_pause();
      lcd_clearline(0);
      lcd.print("Paused");
      pauseOn = 1;
      } else {
      lcd_clearline(1);
      lcd.print("No File Selected");
    }
  }
}

void getMaxFile() {    
  //gets the total files in the current directory and stores the number in maxFile
  
  entry.cwd()->rewind();
  maxFile=0;
  while(entry.openNext(entry.cwd(),O_READ)) {
    entry.getName(fileName,filenameLength);
    entry.close();
    maxFile++;
  }
  entry.cwd()->rewind();
}

void lcd_clearline(int l) {    
  //clear a single line on the LCD
  
  lcd.setCursor(0,l);
  lcd.print("                    ");
  lcd.setCursor(0,l);
}

void changeDir() {    
  //change directory, if fileName="ROOT" then return to the root directory
  //SDFat has no easy way to move up a directory, so returning to root is the easiest way. 
  //each directory (except the root) must have a file called ROOT (no extension)
                      
  if(!strcmp(fileName, "ROOT")) {
    SD.chdir(true);
  } else {
    SD.chdir(fileName, true);
  }
  getMaxFile();
  currentFile=1;
  seekFile(currentFile);
}

void scrollText(char* text)
{
  if(scrollPos<0) scrollPos=0;
  char outtext[16];
  for(int i=0;i<16;i++)
  {
    int p=i+scrollPos;
    if(p<strlen(text)) 
    {
      outtext[i]=text[p];
    } else {
      outtext[i]='\0';
    }
  }
  lcd_clearline(1);
  lcd.print(outtext);
}

Buleste
Posts: 43
Joined: Sun Nov 06, 2016 12:19 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by Buleste » Sat Mar 11, 2017 3:52 pm

New problem. Below are two pieces of code that do the same thing and both work on an Arduino Nano. The first won't compile on the Maple Mini due to the word word. The second will compile but doesn't do what the same piece of code does on the Arduino Nano.

It's a longshot that I'll be able to get help without showing the whole code for context or a lengthy explanation of what the code does but I thought I'd try.

Code: Select all

int ReadWord(unsigned long pos) {
  //Read 2 bytes from the file, and move file position on two if successful
  byte out[2];
  int i=0;
  if(entry.seekSet(pos)) {
    i = entry.read(out,2);
    if(i==2) bytesRead += 2;
  }
  outWord = word(out[1],out[0]);
  return i;
}

int ReadLong(unsigned long pos) {
  //Read 3 bytes from the file, and move file position on three if successful
  byte out[3];
  int i=0;
  if(entry.seekSet(pos)) {
    i = entry.read(out,3);
    if(i==3) bytesRead += 3;
  }
  outLong = (word(out[2],out[1]) << 8) | out[0];
  return i;
}

int ReadDword(unsigned long pos) {
  //Read 4 bytes from the file, and move file position on four if successful  
  byte out[4];
  int i=0;
  if(entry.seekSet(pos)) {
    i = entry.read(out,4);
    if(i==4) bytesRead += 4;
  }
  outLong = (word(out[3],out[2]) << 16) | word(out[1],out[0]);
  return i;
}

Code: Select all

int ReadWord(unsigned long pos) {
  //Read 2 bytes from the file, and move file position on two if successful
  byte out[2];
  int i=0;
  if(entry.seekSet(pos)) {
    i = entry.read(out,2);
    if(i==2) bytesRead += 2;
  }
  outWord = 0;
  outWord = out[1];
  outWord = outWord << 8;
  outWord += out[0];

  return i;
}

int ReadLong(unsigned long pos) {
  //Read 3 bytes from the file, and move file position on three if successful
  outLong = 0;
  byte out[3];
  int i=0;
  if(entry.seekSet(pos)) {
    i = entry.read(out,3);
    if(i==3) bytesRead += 3;
  }
  outLong = 0;
  outLong =  out[2];
  outLong = outLong << 8;
  outLong += out[1];
  outLong = outLong << 8;
  outLong += out[0];

  return i;
}

int ReadDword(unsigned long pos) {
  //Read 4 bytes from the file, and move file position on four if successful  
  outLong = 0;
  byte out[4];
  int i=0;
  if(entry.seekSet(pos)) {
    i = entry.read(out,4);
    if(i==4) bytesRead += 4;
  }
  outLong = 0;
  outLong = out[3];
  outLong = outLong << 8;
  outLong += out[2];
  outLong = outLong << 8;
  outLong += out[1];
  outLong = outLong << 8;
  outLong += out[0];
  return i;
}


Buleste
Posts: 43
Joined: Sun Nov 06, 2016 12:19 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by Buleste » Sat Mar 11, 2017 7:55 pm

Nevermind. The problem wasn't that code it's getting to grips with the timers.

Buleste
Posts: 43
Joined: Sun Nov 06, 2016 12:19 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by Buleste » Thu Mar 16, 2017 12:38 pm

New and frustrating problem.

The Maple Mini is processing microseconds too quickly.

It's supposed to produce an initial pulse of 619 microseconds and its producing one of just over 500.

Unfortunately with the TZXMaple code timing really is everything and it just seems to be running way too fast. Oddly though the length of file it plays is correct but the wavelength of the pulses is too short. The same processing works perfectly well now on the Nano.
TZXMaple_v0.1a.zip
(9.42 KiB) Downloaded 10 times

victor_pv
Posts: 1650
Joined: Mon Apr 27, 2015 12:12 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by victor_pv » Thu Mar 16, 2017 7:13 pm

Buleste wrote:New and frustrating problem.

The Maple Mini is processing microseconds too quickly.

It's supposed to produce an initial pulse of 619 microseconds and its producing one of just over 500.

Unfortunately with the TZXMaple code timing really is everything and it just seems to be running way too fast. Oddly though the length of file it plays is correct but the wavelength of the pulses is too short. The same processing works perfectly well now on the Nano.

TZXMaple_v0.1a.zip
Can you post which section of code is supposed to generate that pulse?

Buleste
Posts: 43
Joined: Sun Nov 06, 2016 12:19 pm

Re: Problems with converting Arduino Nano code over to Maple Mini. Help needed.

Post by Buleste » Fri Mar 17, 2017 10:22 am

victor_pv wrote:Can you post which section of code is supposed to generate that pulse?
I would but it's split between the TZXDuino.h and the TZXprocessing.

These are the .h #defines

Code: Select all

//Spectrum Standards
#define PILOTLENGTH           619
#define SYNCFIRST             191
#define SYNCSECOND            210
#define ZEROPULSE             244
#define ONEPULSE              489
#define PILOTNUMBERL          8063
#define PILOTNUMBERH          3223
#define PAUSELENGTH           1000  
And this is the main pulse generating section.

Code: Select all

void wave() {
  //ISR Output routine
  word workingPeriod = wbuffer[pos][workingBuffer];
  byte pauseFlipBit = false;
  unsigned long newTime=1;
  intError = false;
  if(isStopped==0 && workingPeriod >= 1)
  {
      if(bitRead(workingPeriod, 15))          
      {
        //If bit 15 of the current period is set we're about to run a pause
        //Pauses start with a 1.5ms where the output is untouched after which the output is set LOW
        //Pause block periods are stored in milliseconds not microseconds
        isPauseBlock = true;
        bitClear(workingPeriod,15);         //Clear pause block flag
        pinState = !pinState;
        pauseFlipBit = true;
        wasPauseBlock = true;
      } else {
        if(workingPeriod >= 1 && wasPauseBlock==false) {
          pinState = !pinState;
        } else if (wasPauseBlock==true && isPauseBlock==false) {
          wasPauseBlock=false;
        }
      }
      digitalWrite(outputPin, pinState);
      if(pauseFlipBit==true) {
        newTime = 1500;                     //Set 1.5ms initial pause block
        pinState = LOW;                     //Set next pinstate LOW
        wbuffer[pos][workingBuffer] = workingPeriod - 1;  //reduce pause by 1ms as we've already pause for 1.5ms
        pauseFlipBit=false;
      } else {
        if(isPauseBlock==true) {
          newTime = long(workingPeriod)*1000; //Set pause length in microseconds
          isPauseBlock = false;
        } else {
          newTime = workingPeriod;          //After all that, if it's not a pause block set the pulse period 
        }
        pos += 1;
        if(pos > buffsize)                  //Swap buffer pages if we've reached the end
        {
          pos = 0;
          workingBuffer^=1;
          morebuff = HIGH;                  //Request more data to fill inactive page
        } 
     }
  } else if(workingPeriod <= 1 && isStopped==0) {
    newTime = 1000;                         //Just in case we have a 0 in the buffer
    pos += 1;
    if(pos > buffsize) {
      pos = 0;
      workingBuffer ^= 1;
      morebuff = HIGH;
    }
  } else {
    newTime = 1000;                         //Just in case we have a 0 in the buffer
  }
 
  Timer.setPeriod(newTime);    //Finally set the next pulse length
  Timer.refresh();
}

Post Reply