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

Buleste
Tue Jan 24, 2017 4:34 pm
I am trying to convert some Arduino Nano projects of mine over to the Maple Leaf Mini with the hope of combining them into one project but adapting the code is proving problematic to say the least.

The simplest project, ArduiTape, is a simple WAV file player that uses the TMRpcm library and whilst that has been converted to STM32 it stubbornly refuses to verify and comes back with a the following error.

error: ‘TMRpcm’ does not name a type

TMRpcm tmrpcm; //Initialise tmrpcm

You can download the Arduino code here.
https://mega.nz/#!qNty1JCY!jnHxeC-qtmhP … PWMjXD4O0Y

The other two have the same problem which is converting TimerOne library calls to using HardwareTimer instead.
There are several TimerOne functions that are not so easily translated and I was wondering if you can help?

You can download the Arduino codes for TZXDuino one of the projects from here. https://mega.nz/#!yRVkhITZ!geW4k0jrY4BG … HeMSz6N7Gs

I’m a total noob to the STM32 so any and all help would be appreciated.


victor_pv
Tue Jan 24, 2017 4:53 pm
Buleste wrote:I am trying to convert some Arduino Nano projects of mine over to the Maple Leaf Mini with the hope of combining them into one project but adapting the code is proving problematic to say the least.

The simplest project, ArduiTape, is a simple WAV file player that uses the TMRpcm library and whilst that has been converted to STM32 it stubbornly refuses to verify and comes back with a the following error.

error: ‘TMRpcm’ does not name a type

TMRpcm tmrpcm; //Initialise tmrpcm

You can download the Arduino code here.
https://mega.nz/#!qNty1JCY!jnHxeC-qtmhP … PWMjXD4O0Y

The other two have the same problem which is converting TimerOne library calls to using HardwareTimer instead.
There are several TimerOne functions that are not so easily translated and I was wondering if you can help?

You can download the Arduino codes for TZXDuino one of the projects from here. https://mega.nz/#!yRVkhITZ!geW4k0jrY4BG … HeMSz6N7Gs

I’m a total noob to the STM32 so any and all help would be appreciated.


Buleste
Tue Jan 24, 2017 5:42 pm
Thanks Victor.

I am using your version. I’ve only just found your wav player example though and figured out where I was going wrong and what needed changing.

I’ve made change so that it now at least verifies and can be uploaded to my Maple Leaf Mini however it looks like I need to do a lot more code to alter including my LCD and SD card code (LCD is on I2C1 and SD is on SPI1 btw).

https://mega.nz/#!GYdHDI7a!YOxbKmn3D7Cm … IG4LnGFYlI

// ---------------------------------------------------------------------------------
// 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 <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; //SD card file

#define filenameLength 100

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

const int chipSelect = 7; //Sd card chip select pin

// ---------------------------------------------------------------------------------
// set cardType to 'oldCard' if using an old SD card (more than a few years old) or
// to 'newCard' if using a newly-purchase Class-4 card.
int cardType = SPI_FULL_SPEED;
// ---------------------------------------------------------------------------------

#define btnPlay 20 //Play Button
#define btnStop 19 //Stop Button
#define btnUp 18 //Menu Up button
#define btnDown 17 //Menu Down button
#define btnMotor 10 //Motor Sense (connect pin to gnd to play, NC for pause)
#define btnMselect 11 //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(chipSelect, OUTPUT); //Setup SD card chipselect pin
if (!sd.begin(chipSelect,cardType)) { //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 = 9; //Set speaker pin

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("ArduiTape v1.4");
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 && wasPlaying == 1) {
stopFile();
//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);
}


victor_pv
Tue Jan 24, 2017 6:31 pm
Buleste wrote:Thanks Victor.

I am using your version. I’ve only just found your wav player example though and figured out where I was going wrong and what needed changing.

I’ve made change so that it now at least verifies and can be uploaded to my Maple Leaf Mini however it looks like I need to do a lot more code to alter including my LCD and SD card code (LCD is on I2C1 and SD is on SPI1 btw).

https://mega.nz/#!GYdHDI7a!YOxbKmn3D7Cm … IG4LnGFYlI

// ---------------------------------------------------------------------------------
// 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 <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; //SD card file

#define filenameLength 100

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

const int chipSelect = 7; //Sd card chip select pin

// ---------------------------------------------------------------------------------
// set cardType to 'oldCard' if using an old SD card (more than a few years old) or
// to 'newCard' if using a newly-purchase Class-4 card.
int cardType = SPI_FULL_SPEED;
// ---------------------------------------------------------------------------------

#define btnPlay 20 //Play Button
#define btnStop 19 //Stop Button
#define btnUp 18 //Menu Up button
#define btnDown 17 //Menu Down button
#define btnMotor 10 //Motor Sense (connect pin to gnd to play, NC for pause)
#define btnMselect 11 //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(chipSelect, OUTPUT); //Setup SD card chipselect pin
if (!sd.begin(chipSelect,cardType)) { //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 = 9; //Set speaker pin

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("ArduiTape v1.4");
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 && wasPlaying == 1) {
stopFile();
//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
Wed Jan 25, 2017 7:05 pm
That sounds great. It would be nice to get TMRpcm fully functional.

EDIT: Managed to get everything verifying but can’t get it to recognise the SD Card at the moment. I know it’s connected correctly as a SD.h example can find and read it. I probably need to use a different library.


Buleste
Thu Jan 26, 2017 3:15 pm
Nope. Not a problem with SDFat so it must be an issue with the buttons or rather the code for the buttons.

EDIT
Altered some of the code and the pins and some of the buttons work properly now. I can at least scroll up and down the files.
Can’t get anything to play though yet.

// ---------------------------------------------------------------------------------
// 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 <SPI.h>
#include <SdFat.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; //SD card file

#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 3 //Play Button
#define btnStop 2 //Stop Button
#define btnUp 1 //Menu Up button
#define btnDown 0 //Menu Down button
#define btnMotor 10 //Motor Sense (connect pin to gnd to play, NC for pause)
#define btnMselect 11 //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
if (!SD.begin(SD_ChipSelectPin,SPI_CLOCK_DIV4)) { //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 = 9; //Set speaker pin

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,LOW);
//pinMode(btnMselect, INPUT_PULLUP);
//digitalWrite(btnMselect, LOW);//Setup buttons with internal pullup
lcd.clear();
lcd.print("ArduiTape v1.4");
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 && wasPlaying == 1) {
stopFile();
//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);
}


victor_pv
Thu Jan 26, 2017 5:22 pm
Buleste wrote:Nope. Not a problem with SDFat so it must be an issue with the buttons or rather the code for the buttons.

EDIT
Altered some of the code and the pins and some of the buttons work properly now. I can at least scroll up and down the files.
Can’t get anything to play though yet.

// ---------------------------------------------------------------------------------
// 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 <SPI.h>
#include <SdFat.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; //SD card file

#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 3 //Play Button
#define btnStop 2 //Stop Button
#define btnUp 1 //Menu Up button
#define btnDown 0 //Menu Down button
#define btnMotor 10 //Motor Sense (connect pin to gnd to play, NC for pause)
#define btnMselect 11 //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
if (!SD.begin(SD_ChipSelectPin,SPI_CLOCK_DIV4)) { //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 = 9; //Set speaker pin

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,LOW);
//pinMode(btnMselect, INPUT_PULLUP);
//digitalWrite(btnMselect, LOW);//Setup buttons with internal pullup
lcd.clear();
lcd.print("ArduiTape v1.4");
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 && wasPlaying == 1) {
stopFile();
//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
Thu Jan 26, 2017 5:37 pm
I tried to just verify as I don’t have the screen and just seem to get the following error.

exit status 1
‘swap’ was not declared in this scope

I do have a ILI9341 though so I could try that. Just need to figure out what to wire to where.


victor_pv
Thu Jan 26, 2017 8:52 pm
Buleste wrote:I tried to just verify as I don’t have the screen and just seem to get the following error.

exit status 1
‘swap’ was not declared in this scope

I do have a ILI9341 though so I could try that. Just need to figure out what to wire to where.


Buleste
Fri Jan 27, 2017 3:13 pm
Thanks for that. Added the buffer and it’s trying to play files now.

The sound is terrible for all the various wavs I’ve tried but it’s a start. Making progress and that’s what counts.


victor_pv
Fri Jan 27, 2017 4:27 pm
Buleste wrote:Thanks for that. Added the buffer and it’s trying to play files now.

The sound is terrible for all the various wavs I’ve tried but it’s a start. Making progress and that’s what counts.


Buleste
Fri Jan 27, 2017 7:40 pm
Essentially it’s just sounding as clicks. I’m using a LM386 to amplify the sound. I’ve tried 16-bit, 8-bit, Stereo and mono all of varying frequencies.

I’m just seeing if I can get your player working on the ILI9341. Got the graphics working but no sound as of yet although it may be my SD card at the moment.


victor_pv
Fri Jan 27, 2017 8:55 pm
Buleste wrote:Essentially it’s just sounding as clicks. I’m using a LM386 to amplify the sound. I’ve tried 16-bit, 8-bit, Stereo and mono all of varying frequencies.

I’m just seeing if I can get your player working on the ILI9341. Got the graphics working but no sound as of yet although it may be my SD card at the moment.


victor_pv
Sat Jan 28, 2017 1:38 am
BTW, is this your project?
https://hackaday.io/project/2876-arduitape

If so, I was reading you rather take a square wave out.
For that it would be better if you skip all the PWM out stuff, and just set a pin high or low depending on whether the sample value is bigger or smaller than a number. That would be much easier to implement at all levels, and would give you a perfectly square wave.


Buleste
Sat Jan 28, 2017 11:29 am
That’s an old version of the project but yes.
The latest version of all the projects I’m trying to convert can be found here. http://arduitapemarkii.blogspot.co.uk/

victor_pv
Sat Jan 28, 2017 1:46 pm
Buleste wrote:That’s an old version of the project but yes.
The latest version of all the projects I’m trying to convert can be found here. http://arduitapemarkii.blogspot.co.uk/

Buleste
Sat Jan 28, 2017 5:49 pm
I’m one of the original authors.

At the moment I’m having issues anyway.
I uploaded my Maple Mini to Bootloader 2 and SDFat has stopped working and isn’t detecting the SD card.
I’ve just made sure I have your latest SDFat library and that’s throwing an error.


victor_pv
Sat Jan 28, 2017 11:45 pm
Buleste wrote:I’m one of the original authors.

At the moment I’m having issues anyway.
I uploaded my Maple Mini to Bootloader 2 and SDFat has stopped working and isn’t detecting the SD card.
I’ve just made sure I have your latest SDFat library and that’s throwing an error.


Buleste
Sun Jan 29, 2017 11:08 am
victor_pv wrote:
The bootloader should not affect in anyway the SD card. The bootloader handles full control to the code uploaded. Did you update anything else?

victor_pv
Sun Jan 29, 2017 5:08 pm
Buleste wrote:victor_pv wrote:
The bootloader should not affect in anyway the SD card. The bootloader handles full control to the code uploaded. Did you update anything else?

Buleste
Sun Jan 29, 2017 7:03 pm
Okay. For some reason SDFat fails at SD.begin();

I used the example SDInfo in SDFat and got the following.
SdFat version: 20150321

Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Assuming the SD chip select pin is: 8
Edit SD_CHIP_SELECT to change the SD chip select pin.

type any character to start

cardBegin failed
SD errorCode: 0X1
SD errorData: 0X0

type any character to start


victor_pv
Sun Jan 29, 2017 7:33 pm
Buleste wrote:Okay. For some reason SDFat fails at SD.begin();

I used the example SDInfo in SDFat and got the following.
SdFat version: 20150321

Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Assuming the SD chip select pin is: 8
Edit SD_CHIP_SELECT to change the SD chip select pin.

type any character to start

cardBegin failed
SD errorCode: 0X1
SD errorData: 0X0

type any character to start


stevestrong
Mon Jan 30, 2017 7:25 am
If the same card in the same adapter works in one case and doesn’t work in the other case, then it seems to be a software problem in the second case.
Double-check the initialization part, make a diff between those two cases.

Buleste
Mon Jan 30, 2017 5:18 pm
victor_pv wrote:Make sure the sdcard module you use does not have level converters. If you used it with arduino boards it most likely has level converters.

victor_pv
Mon Jan 30, 2017 6:08 pm
Buleste wrote:victor_pv wrote:Make sure the sdcard module you use does not have level converters. If you used it with arduino boards it most likely has level converters.

Buleste
Mon Jan 30, 2017 7:33 pm
I know the Maple Mini works at 3.3v but I have the SDCard readers on my Maple Mini powered by the VIN pin giving them 5v so they should be operating normally.

Okay. After a complete uninstall I get the following when using SDInfo example so SDFat is working with my SD card and reader. Now I just have to figure out why it hates me in the code.
SdFat version: 20150321

Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Assuming the SD chip select pin is: 8
Edit SD_CHIP_SELECT to change the SD chip select pin.

type any character to start

init time: 0 ms

Card type: SDHC

Manufacturer ID: 0X1B
OEM ID: SM
Product: 00000
Version: 1.0
Serial number: 0X3F359301
Manufacturing date: 3/2011

cardSize: 8064.60 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true
OCR: 0XC0FF8000

SD Partition Table
part,boot,type,start,length
1,0X0,0XC,8192,15742976
2,0X0,0X0,0,0
3,0X0,0X0,0,0
4,0X0,0X0,0,0

Volume is FAT32
blocksPerCluster: 64
clusterCount: 245856
freeClusters: 186105
freeSpace: 6098.29 MB (MB = 1,000,000 bytes)
fatStartBlock: 12542
fatCount: 2
blocksPerFat: 1921
rootDirStart: 2
dataStartBlock: 16384

type any character to start


RogerClark
Mon Jan 30, 2017 8:49 pm
If you power the SD adaptor from 5V and it had level conveters, you should check that it is not converting MISO from 3.3V back to 5V signal levels.

Some pins on the STM32 are 5V tollerent but I dont know if MISO is one of them.


zmemw16
Mon Jan 30, 2017 8:53 pm
the problem is that the data & control lines that are 0 or 3v3 from the stm32 to the card.
the level converter on the ‘interface’ pcb is expecting arduino levels of 0 -> 5v is converting a 3v3 signal down
by approx 1/2-2/3’s equals marginal or a maybe state;
particularly if its using resistors, not sure if that’s also true for a ‘real ic/tr/fet’ level converter

the 3v3 data returning from the card via the converter is quite happily becoming 0->5v ; those the stm32 inputs can handle.
as roger says needs checking (time crossed post)
hth
stephen


RogerClark
Mon Jan 30, 2017 10:28 pm
Stephen

Good point about the converter, possibly trying to convert the 3.3V logic signals from the STM32 as if they were 5V.

I guess it will depend on whether the level converter is active or passive.

Either way, using a SD adaptor with level converters is not the correct way to connect 3.3V logic to 3.3V logic and is likely to lead to problems.


Buleste
Tue Jan 31, 2017 12:01 pm
Does anyone have a recommendation for a usable SDcard reader?

stevestrong
Tue Jan 31, 2017 12:08 pm
Here it is: https://www.aliexpress.com/item/2PCS-TF … 31024.html

Buleste
Tue Jan 31, 2017 12:42 pm
stevestrong wrote:Here it is: https://www.aliexpress.com/item/2PCS-TF … 31024.html

zmemw16
Tue Jan 31, 2017 2:25 pm
i followed a recommendation link from the forum, this is from my order
http://www.ebay.co.uk/itm/191736124794? … EBIDX%3AIT

it is 3v3 ONLY, no regulator and has smt resistors, easy enough to lose them or just short circuit if required :)

at £0.60 for 2, i got 2 lots

have it wired in, not tried as yet.

stephen


Buleste
Tue Jan 31, 2017 3:08 pm
In the mean time here’s my conversion of Victors original wavplayer but for the ILI9341. Sadly the build in SD card has the same issues so you cannot use it with this programme as far as I can tell.

coos_wav_player_setModule2_ILI9341.zip
(4.44 KiB) Downloaded 29 times

stevestrong
Tue Jan 31, 2017 3:18 pm
@Buleste,
let me conclude: your SD card and adapter are working fine using the SD info demo sketch but not working with your software, right?

Is your software the one you posted?
If yes, then it is a potential problem that there is no setModule() before initializing the SD card with SD.begin(…).
Also, you are using both SPI ports, but only one SPI port – for the display – is initialized in the setup() function. The one used by the SD card (SPI 1) seems to be initialized in another place, undefined time. I would suggest to init the card also in setup(). For testing, you could use the Sd card info example part which is working in the standalone version in setup(), too.

Alternatively, you could try to map the display to SPI 1 and the Sd card to SPI 2 without having to use the setModule() function. For this, use the latest SdFat beta from greiman, because it can be set to use SPI_2. I am using his version directly from github and it works:
SdFat sd(2); // use SPI 2 to access SD card


Buleste
Tue Jan 31, 2017 4:00 pm
stevestrong wrote:@Buleste,
let me conclude: your SD card and adapter are working fine using the SD info demo sketch but not working with your software, right?

Is your software the one you posted?
If yes, then it is a potential problem that there is no setModule() before initializing the SD card with SD.begin(…).
Also, you are using both SPI ports, but only one SPI port – for the display – is initialized in the setup() function. The one used by the SD card (SPI 1) seems to be initialized in another place, undefined time. I would suggest to init the card also in setup(). For testing, you could use the Sd card info example part which is working in the standalone version in setup(), too.

Alternatively, you could try to map the display to SPI 1 and the Sd card to SPI 2 without having to use the setModule() function. For this, use the latest SdFat beta from greiman, because it can be set to use SPI_2. I am using his version directly from github and it works:
SdFat sd(2); // use SPI 2 to access SD card


victor_pv
Tue Jan 31, 2017 4:31 pm
Sorry I totally forgot about that example using 2 SPI ports.

The way the example is set, should be using SPI1 for the card and SPI2 for the screen:
...
SPI.setModule(2);
tft.begin();
...


victor_pv
Tue Jan 31, 2017 4:36 pm
stevestrong wrote:@Buleste,
let me conclude: your SD card and adapter are working fine using the SD info demo sketch but not working with your software, right?

Is your software the one you posted?
If yes, then it is a potential problem that there is no setModule() before initializing the SD card with SD.begin(…).
Also, you are using both SPI ports, but only one SPI port – for the display – is initialized in the setup() function. The one used by the SD card (SPI 1) seems to be initialized in another place, undefined time. I would suggest to init the card also in setup(). For testing, you could use the Sd card info example part which is working in the standalone version in setup(), too.

Alternatively, you could try to map the display to SPI 1 and the Sd card to SPI 2 without having to use the setModule() function. For this, use the latest SdFat beta from greiman, because it can be set to use SPI_2. I am using his version directly from github and it works:
SdFat sd(2); // use SPI 2 to access SD card


Buleste
Tue Jan 31, 2017 4:45 pm
As it happens I’ve just killed my Maple Mini so everythings on hold now anyway. Lol

However even though I don’t have a board to test on I will be carrying on with trying to convert the TimerOne library calls from TZXDuino/CASDuino to HardwareTimer to see if I can at least get them to verify.

EDIT:

For those interested the codes I’m trying to translate from Arduino programmes to SMT32 are the following
MapleTape which I have already started to alter so that is works on Maple Mini and is compiling but due to the SD and now the Mini issues isn’t working as of yet.
https://mega.nz/#!vVNlDTwT!ro5dbqHEGdfv … ew9tCo7SHo

CASMaple I haven’t altered yet and is still in it’s Arduino working form
https://mega.nz/#!bUkhBCzB!lvNOBlQaIp1a … Yk47Nxus2w

TZXMaple is the same story as CASMaple but because the code is so similar if I get one working then the other one should work too.
https://mega.nz/#!6Md1hTDI!5rk7c6fWwChG … dioJGyDB0E


victor_pv
Tue Jan 31, 2017 5:24 pm
Buleste wrote:As it happens I’ve just killed my Maple Mini so everythings on hold now anyway. Lol

However even though I don’t have a board to test on I will be carrying on with trying to convert the TimerOne library calls from TZXDuino/CASDuino to HardwareTimer to see if I can at least get them to verify.


Buleste
Tue Jan 31, 2017 5:33 pm
victor_pv wrote:What’s the TimerOne library for? I haven’t used it before.
A note of advice, when working on my port of the TMRPCM library I found HardwareTimer provides only the most basic features of the timers, but there are some core functions that can do more, and then all registers and bits are defined in the core, so for anything advanced other than generate PWM output and trigger an interrupt, you should go and have a good read on the stm32f1 reference manual and learn how the timer peripherals work, then you can go setting registers as you need.

BTW, there is a thread called something like “My maple mini just let go of the magic smoke” that shows some issues with the hardware, and some could be corrected. I started it when I thought I had burnt the MCU, and found out it was just the voltage regulator and a diode and was able to replace them.


victor_pv
Tue Jan 31, 2017 7:58 pm
Buleste wrote:
Timer one is similar to HardwareTimer for the Maple Mini.

Best example of what it does can be found here http://playground.arduino.cc/Code/Timer1 Although we use Paul Stoffregen’s modified TimerOne library which is faster and works on more boards.

We use it to help generate the sound pulses required to convert TZX/TAP/CAS files into noise that the computers can detect.


victor_pv
Wed Feb 01, 2017 3:57 am
This is an earlier version of the sketch, it doesn’t use set module, instead it uses SPI1 for the sdcard, and SPI2 is a new object of the spi class declared in the tft cpp file
SPIClass tftSPI(2);

BennehBoy
Wed Feb 01, 2017 7:45 am
victor_pv wrote:Buleste wrote:
We use it to help generate the sound pulses required to convert TZX/TAP/CAS files into noise that the computers can detect.

Buleste
Wed Feb 01, 2017 11:31 am
victor_pv wrote:Buleste wrote:
Timer one is similar to HardwareTimer for the Maple Mini.

Best example of what it does can be found here http://playground.arduino.cc/Code/Timer1 Although we use Paul Stoffregen’s modified TimerOne library which is faster and works on more boards.

We use it to help generate the sound pulses required to convert TZX/TAP/CAS files into noise that the computers can detect.


BennehBoy
Wed Feb 01, 2017 11:49 am
Buleste wrote:That’s actually for the Spectrum TAP file format which is surprisingly different to the C64 TAP file format. There are also several CAS file formats for different machines too. It’s a fun old world. Lol

Buleste
Thu Feb 02, 2017 6:21 pm
I’ve managed to get bot TZXMaple and CASMaple compiling. I had to // out some of the EEPROM lines for the moment whilst I figure them out but I can’t test anything just yet to see if it works as it should. Hurry up AliExpress.

victor_pv
Fri Feb 03, 2017 4:16 am
Buleste wrote:I’ve managed to get bot TZXMaple and CASMaple compiling. I had to // out some of the EEPROM lines for the moment whilst I figure them out but I can’t test anything just yet to see if it works as it should. Hurry up AliExpress.

Buleste
Fri Feb 03, 2017 11:21 am
victor_pv wrote:Buleste wrote:I’ve managed to get bot TZXMaple and CASMaple compiling. I had to // out some of the EEPROM lines for the moment whilst I figure them out but I can’t test anything just yet to see if it works as it should. Hurry up AliExpress.

BennehBoy
Fri Feb 03, 2017 11:25 am
Can’t you write to the SD? (not withstanding the level shifting issues on your existing reader, but I mean as an alternative to having to incorporate a physical eeprom)

Buleste
Sat Feb 04, 2017 10:42 am
BennehBoy wrote:Can’t you write to the SD? (not withstanding the level shifting issues on your existing reader, but I mean as an alternative to having to incorporate a physical eeprom)

BennehBoy
Sat Feb 04, 2017 11:15 am
Buleste wrote:
There’s no reason as to why I can’t.
Good idea.
That’s why I need other people to do the thinking for me. I get so stuck in my own ways I fail to see the other possibilities.

Buleste
Thu Feb 16, 2017 3:40 pm
Humbug. New Maple Mini arrived today and I’ve managed to upload Bootloader 2.0 to it but when I plug it into the USB I get no COM Port popping up in Device manager so I can’t programme it. Time to figure out whats wrong with it.

stevestrong
Thu Feb 16, 2017 4:02 pm
You don’t need the COM port to flash it. The uploader will detect the USB DFU port and will program the chip.
The COM port appears after the first program has been flashed, so that serial USB is active.

Buleste
Thu Feb 16, 2017 4:50 pm
stevestrong wrote:You don’t need the COM port to flash it. The uploader will detect the USB DFU port and will program the chip.
The COM port appears after the first program has been flashed, so that serial USB is active.

Buleste
Wed Mar 01, 2017 2:21 pm
Finally my new sd card readers are here and SD cards are being detected etc.

Sadly it looks like my alterations to my projects code haven’t worked and I haven’t been able to get the wav player to play wavs either yet but time to crack on.


BennehBoy
Wed Mar 01, 2017 4:44 pm
Is your code on github?

Buleste
Wed Mar 01, 2017 5:20 pm
Sadly not. MapleTape which uses the TMRpcm library by Victor plays garbled sound which is a start.

TZXMaple and CASMaple don’t play any sound and I think that’s due to the timer. The Arduino code used Timer1 Library and I’ve tried to change the functions to HardwareTimer library and they just aren’t the same.

MapleTape zip https://mega.nz/#!vVNlDTwT!ro5dbqHEGdfv … ew9tCo7SHo
CASMaple zip (Plays MSX .CAS files) https://mega.nz/#!bUkhBCzB!lvNOBlQaIp1a … Yk47Nxus2w
TZXMaple zip (plays ZX Spectrum TRZ/TAP files) https://mega.nz/#!6Md1hTDI!5rk7c6fWwChG … dioJGyDB0E

I also converted CoOS Wav Player setModule2 to work with an ILI9341 changing only the TFT code but it doesn’t seem to be able to search for .WAV files on the SD card as it did in the original even though I didn’t actually mess with that part of the coding.


victor_pv
Wed Mar 01, 2017 5:53 pm
Buleste wrote:Sadly not. MapleTape which uses the TMRpcm library by Victor plays garbled sound which is a start.

TZXMaple and CASMaple don’t play any sound and I think that’s due to the timer. The Arduino code used Timer1 Library and I’ve tried to change the functions to HardwareTimer library and they just aren’t the same.

MapleTape zip https://mega.nz/#!vVNlDTwT!ro5dbqHEGdfv … ew9tCo7SHo
CASMaple zip (Plays MSX .CAS files) https://mega.nz/#!bUkhBCzB!lvNOBlQaIp1a … Yk47Nxus2w
TZXMaple zip (plays ZX Spectrum TRZ/TAP files) https://mega.nz/#!6Md1hTDI!5rk7c6fWwChG … dioJGyDB0E

I also converted CoOS Wav Player setModule2 to work with an ILI9341 changing only the TFT code but it doesn’t seem to be able to search for .WAV files on the SD card as it did in the original even though I didn’t actually mess with that part of the coding.


Buleste
Wed Mar 01, 2017 7:02 pm
Thanks Victor
Okay changed to the following.
if(TMRpcm_sample_RATE > 48000 ){ TMRpcm_sample_RATE = 48000;
#if defined (debug)
Serial.print("TMRpcm_sample RATE TOO HIGH: ");
Serial.println(TMRpcm_sample_RATE);
#endif
}
if(TMRpcm_sample_RATE == 48000 ){
resolution = 260; //250
repetition = 5;
}
else if(TMRpcm_sample_RATE == 44100 ){
resolution = 285; //272
repetition = 5;
}
else if(TMRpcm_sample_RATE == 22050 ){
resolution = 285; //272
repetition = 11;
}
else if(TMRpcm_sample_RATE == 8000 ){
resolution = 260; //250
repetition = 35;
}
else {
resolution = 72000000/TMRpcm_sample_RATE;
repetition = resolution/256;
resolution = resolution/repetition;
repetition = repetition-1;
}

victor_pv
Wed Mar 01, 2017 7:37 pm
Buleste wrote:Thanks Victor
Okay changed to the following.
if(TMRpcm_sample_RATE > 48000 ){ TMRpcm_sample_RATE = 48000;
#if defined (debug)
Serial.print("TMRpcm_sample RATE TOO HIGH: ");
Serial.println(TMRpcm_sample_RATE);
#endif
}
if(TMRpcm_sample_RATE == 48000 ){
resolution = 260; //250
repetition = 5;
}
else if(TMRpcm_sample_RATE == 44100 ){
resolution = 285; //272
repetition = 5;
}
else if(TMRpcm_sample_RATE == 22050 ){
resolution = 285; //272
repetition = 11;
}
else if(TMRpcm_sample_RATE == 8000 ){
resolution = 260; //250
repetition = 35;
}
else {
resolution = 72000000/TMRpcm_sample_RATE;
repetition = resolution/256;
resolution = resolution/repetition;
repetition = repetition-1;
}

Buleste
Wed Mar 01, 2017 11:05 pm
I think I know where my problem is with MapleTape, I put the load buffer in a stupid place and it’s just playing the first half to full second of the WAV before going back to the start.

victor_pv
Thu Mar 02, 2017 12:32 am
Buleste wrote:I think I know where my problem is with MapleTape, I put the load buffer in a stupid place and it’s just playing the first half to full second of the WAV before going back to the start.

Buleste
Thu Mar 02, 2017 10:57 am
Thanks Victor.

That seems to have done the trick.

Still some bugs (doesn’t stop at the end of the file) but it plays .WAV files. Now to see if the computers will recognise them.


victor_pv
Thu Mar 02, 2017 2:47 pm
Buleste wrote:Thanks Victor.

That seems to have done the trick.

Still some bugs (doesn’t stop at the end of the file) but it plays .WAV files. Now to see if the computers will recognise them.


Buleste
Thu Mar 02, 2017 2:56 pm
victor_pv wrote:
:) I’ll have another look when I have some time, may have more bugs here and there. I didn’t use it other than testing it played some files, and didn’t intend to leave like that, but finish it, clean the code, etc. As I do corrections here and there I’ll let you know or anything relevant, and will upload it to github again when it’s more or less clean. I had planned to use DMA to load the timers, that would take CPU utilization way down, and remove all the interrupts that happen now to load the PWM cycles.

victor_pv
Thu Mar 02, 2017 6:24 pm
Buleste wrote:victor_pv wrote:
:) I’ll have another look when I have some time, may have more bugs here and there. I didn’t use it other than testing it played some files, and didn’t intend to leave like that, but finish it, clean the code, etc. As I do corrections here and there I’ll let you know or anything relevant, and will upload it to github again when it’s more or less clean. I had planned to use DMA to load the timers, that would take CPU utilization way down, and remove all the interrupts that happen now to load the PWM cycles.

Buleste
Sat Mar 04, 2017 4:16 pm
Oh my. I’ve gotten CASMaple to work now. Not entirely sure how I did it but I did. I shall have to try TZXMaple now.

victor_pv
Mon Mar 06, 2017 6:45 am
Buleste wrote:Oh my. I’ve gotten CASMaple to work now. Not entirely sure how I did it but I did. I shall have to try TZXMaple now.

RogerClark
Mon Mar 06, 2017 9:05 am
Thanks

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
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

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

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.

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.

// ---------------------------------------------------------------------------------
// 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
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.

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;
}


Buleste
Sat Mar 11, 2017 7:55 pm
Nevermind. The problem wasn’t that code it’s getting to grips with the timers.

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 16 times

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


Buleste
Fri Mar 17, 2017 10:22 am
victor_pv wrote:Can you post which section of code is supposed to generate that pulse?

Leave a Reply

Your email address will not be published. Required fields are marked *