Sound for model railroading scale 1/32

Status
Not open for further replies.
In order to know when starting Python script (and when it's too late), I propose to put the LED solid during this time.
Code:
  ...............
 digitalWrite(13, HIGH);// Start Python script "Rawfile-uploader.py"
                  // xxxx .... DELAY FOR 10 SECONDS ADDED .................
                   // xxxx ... For more time to start up the Python script... Start command line to run the Python Script during this 10 second period
                    // xxxx ... when USB/serial commms is idle and waiting .......
  delay(10000);     // xxxx... Also this delay allows more time for a next sketch to be loaded into Teensy. If this CopyfromSerial sketch is already loaded in Teensy 
                   // xxxx... and gets past this stage, while compiling the next sketch, the files just copied will be erased from spiFlash if the flash is still connected.
                  // xxxx ... If the LEDs start double flashing ...then its too late.....you are about to start erasing the files that are already on the chip....xxxx
                 // xxxx.... You need to be prepared, compiling and uploading the next new sketch needs to be done quickly or with manual upload control.
  digitalWrite(13, LOW);// Too late to start Python "Rawfile-uploader.py"
  delay(1000);
.............
 
Yes, the CopyFomSerial you posted seems to be the same..... but I cannot get it to work with the #define CSPIN etc. The other programs for SerialFlash use.......
const int FlashChipSelect = 6; // digital pin for flash chip CS pin ..... so thats what I did no the sketch I modified and posted earlier......the one I put the 10 sec delay in.
The only other change I make is the pin numbers.....

I see you have posted again regards keeping the LED on solid warning........that fair enough, go with that........but the real problem is that the sketch runs automatically as soon as plugged in and if not aware of the erase....your files will be erased fully, OR maybe if unplugged as a panic abort if you see the LED on.....I wonder could the files be corrupt and still list the names but not play.....????

I had thought of adding a something like say.............
char CopyRun = Serial.read();
while(CopyRun <> 'c');
So that Copy prog will not run until you open the monitor and type in a 'c' and send it.

But I never got around to it.......

...............the CopyFromSerial, List files, ReadBenchmark,and PlayRawFlash work for me OKplaying out DAC, with python to send the actual files to spiflash and Audacity or SOX to convert them. The only problem I have is I cannot send large files with python on my XP machine.
 
Have you a mean to read the data (byte) which are in the SPI Flash ?......no not directly....except what can be de-ciphered from the examples.
The data sheet will give op-codes for each operation......eg reading and writing bytes/ blocks from/to different addresses etc...???

I thought from earlier post you had it working....what has changed....????
I would copy the files again on to spiflash..or copy different ones....and play some sound from memory you know is working to make sure DAC itself is still OK

I have attached a zip file containing a serial monitor controlled CopyFromSerial....you have to open Monitor and key in a "c" to start, guidence comes up on monitor, then run python script to copy files.....I had to put a serial.write("c") in the script so that it could start the teensy script
 

Attachments

  • CopyFromSerialMC.zip
    5.4 KB · Views: 105
The last post maybe indicates you need to open the monitor in all cases......but only if you want to see the sketch running from the Arduino IDE as test etc.
Normally if your Teensy has some sketch on it and you wanted to load CopyFromSerialMC to copy files to spiFlash........what you would do is open IDE upload the copy sketch to Teensy get the upload Boot OK message and Teensy would reboot but sit waiting on a "c" being typed.....there is no need to type "c" here......just let it wait and open python CMDline and run the rawfile-uploader-mc script.....It will send a "c" to start the teensy sketch copy the files to spiFlash. Then load Listfiles sketch or Player sketch as normal because when teensy is powered again with the CopyFromSerialMC sketch it will sit waiting for "c" and not erase the files when the delays time out as before.
 
Regards a means to read Byte by Byte Data from the chip to see whatdata is there in byte format.....below is "a first cog" of the Reader part if the "RawHardwareTest" example in the SerialFlash library.......There are a few options for the print out to the monitor screen......

Code:
// RawHardwareTest - Check if a SPI Flash chip is compatible
// with SerialFlash by performing many read and write tests
// to its memory.
//
//  *** THIS IS RUNNING THE READER PART ONLY TO SEE DATA ON THE CHIP  ***
//   ***  OUTPUT LOOKS SIMILAR TO READING A FILE IN A HEX EDITOR    ***
//    ***    OUTPUT IS PRINTED READABLE TEXT TO MONITOR SCREEN    ***
//     ***      IT IS IN HEX TEXT FORMAT NOT A BINARY FILE      ***
//
// The chip should be fully erased before running this test.
// Use the EraseEverything to do a (slow) full chip erase.
//
// Normally you should NOT access the flash memory directly,
// as this test program does.  You should create files and
// read and write the files.  File creation allocates space
// with program & erase boundaries within the chip, to allow
// reading from any other files while a file is busy writing
// or erasing (if created as erasable).
//
// If you discover an incompatible chip, please report it here:
// https://github.com/PaulStoffregen/SerialFlash/issues
// You MUST post the complete output of this program, and
// the exact part number and manufacturer of the chip.


#include <SerialFlash.h>
#include <SPI.h>

const int FlashChipSelect = 6; // digital pin for flash chip CS pin
//const int FlashChipSelect = 21; // Arduino 101 built-in SPI Flash

SerialFlashFile file;

const unsigned long testIncrement = 4096;

void setup() {

  //uncomment these if using Teensy audio shield
  SPI.setSCK(14);  // Audio shield has SCK on pin 14
  SPI.setMOSI(7);  // Audio shield has MOSI on pin 7

  //uncomment these if you have other SPI chips connected
  //to keep them disabled while using only SerialFlash
  //pinMode(4, INPUT_PULLUP);
  //pinMode(10, INPUT_PULLUP);

  Serial.begin(9600);

  while (!Serial) ;
  delay(100);

  Serial.println("Raw SerialFlash Hardware Test");
  SerialFlash.begin(FlashChipSelect); // proceed even if begin() fails

  if (test()) {
    Serial.println();
    Serial.println("All Tests Passed  :-)");
    Serial.println("This message only applies for full test not when running Reader only");
    Serial.println("Test data was written to your chip.  You must run");
    Serial.println("EraseEverything before using this chip for files.");
  } else {
    Serial.println();
    Serial.println("Tests Failed  :{");
    Serial.println("This message only applies for full test not when running Reader only");
    Serial.println("The flash chip may be left in an improper state.");
    Serial.println("You might need to power cycle to return to normal.");
  }
}


bool test() {
  unsigned char buf[256], sig[256], buf2[8];
  unsigned long address, count, chipsize, blocksize;
  unsigned long usec;
  bool first;

  // Read the chip identification
  Serial.println();
  Serial.println("Read Chip Identification:");
  SerialFlash.readID(buf);
  Serial.print("  JEDEC ID:     ");
  Serial.print(buf[0], HEX);
  Serial.print(" ");
  Serial.print(buf[1], HEX);
  Serial.print(" ");
  Serial.println(buf[2], HEX);
  Serial.print("  Part Nummber: ");
  Serial.println(id2chip(buf));
  Serial.print("  Memory Size:  ");
  chipsize = SerialFlash.capacity(buf);
  Serial.print(chipsize);
  Serial.println(" bytes");
  if (chipsize == 0) return false;
  Serial.print("  Block Size:   ");
  blocksize = SerialFlash.blockSize();
  Serial.print(blocksize);
  Serial.println(" bytes");


  // Read the entire chip.  Every test location must be
  // erased, or have a previously tested signature
  Serial.println();
  Serial.println("Reading Chip...");
  memset(buf, 0, sizeof(buf));
  memset(sig, 0, sizeof(sig));
  memset(buf2, 0, sizeof(buf2));
  address = 0;
  count = 0;
  first = true;
  while (address < chipsize) {
    SerialFlash.read(address, buf, 8);
    //Serial.print("  addr = ");
    Serial.print(address, HEX);
   // Serial.print(", data = ");
    printbuf(buf, 8);
    
   
    if (first) {
      address = address + (testIncrement - 8);
      first = false;
    } else {
      address = address + 8;
      first = true;
    }

  }

}


void loop() {
  // do nothing after the test
}

const char * id2chip(const unsigned char *id)
{
	if (id[0] == 0xEF) {
		// Winbond
		if (id[1] == 0x40) {
			if (id[2] == 0x14) return "W25Q80BV";
			if (id[2] == 0x15) return "W25Q16DV";
			if (id[2] == 0x17) return "W25Q64FV";
			if (id[2] == 0x18) return "W25Q128FV";
			if (id[2] == 0x19) return "W25Q256FV";
		}
	}
	if (id[0] == 0x01) {
		// Spansion
		if (id[1] == 0x02) {
			if (id[2] == 0x16) return "S25FL064A";
			if (id[2] == 0x19) return "S25FL256S";
			if (id[2] == 0x20) return "S25FL512S";
		}
		if (id[1] == 0x20) {
			if (id[2] == 0x18) return "S25FL127S";
		}
	}
	if (id[0] == 0xC2) {
		// Macronix
		if (id[1] == 0x20) {
			if (id[2] == 0x18) return "MX25L12805D";
		}
	}
	if (id[0] == 0x20) {
		// Micron
		if (id[1] == 0xBA) {
			if (id[2] == 0x20) return "N25Q512A";
			if (id[2] == 0x21) return "N25Q00AA";
		}
		if (id[1] == 0xBB) {
			if (id[2] == 0x22) return "MT25QL02GC";
		}
	}
	if (id[0] == 0xBF) {
		// SST
		if (id[1] == 0x25) {
			if (id[2] == 0x02) return "SST25WF010";
			if (id[2] == 0x03) return "SST25WF020";
			if (id[2] == 0x04) return "SST25WF040";
			if (id[2] == 0x41) return "SST25VF016B";
			if (id[2] == 0x4A) return "SST25VF032";
		}
		if (id[1] == 0x25) {
			if (id[2] == 0x01) return "SST26VF016";
			if (id[2] == 0x02) return "SST26VF032";
			if (id[2] == 0x43) return "SST26VF064";
		}
	}
	return "(unknown chip)";
}

void printbuf(const void *buf, uint32_t len)
{
  const uint8_t *p = (const uint8_t *)buf;
  do {
    unsigned char b = *p++;
    Serial.print(b >> 4, HEX);
    Serial.print(b & 15, HEX);
    //Serial.printf("%02X", *p++);
    Serial.print(" ");
  } while (--len > 0);
  Serial.println();
}
 
In last post....change the order of printbuf........

Put the line...... Serial.print(" "); ....as the first line......it makes more sense I think......gives a space between the offset and the actual data......:cool:....I couldn't find a smiley that smiles......?
 
I tried on with CopyFromSerialMC and rawfile-uploader-mc.py.
It works very well with "WHISTM1.TRW".
Now, I will try to manage and to mix some soundfiles.
Thank you very much.
:)
 
This post is about making sense of the data copied into the chip rather than reading HEX numbers.......

I have 2 short sound files on the chip...... a whistle of about 0.5 seconds and an engine sound 4 puffs lasting about 1.5 seconds.....using the player I play the engine sound looped so it plays repeatedly and blow the whistle on the push of a button on demand.

To see the actual files on the chip, I run the RawHardwareReader and printed the data from the first 150000 adresses to the monitor screen, then selected and copied the data only and pasted into HxD hex editor and saved it as chipsnd1.raw......then imported this raw file into Audacity....16bit, Little Endian, 44100 ....and I cold see the waveform....it looks like the waveform of the orig 2 sound files that were copied.....then played the file in Audacity.....good quality of sound.
So the sound files are being copied and extracted to/from the chip without any distortion. You will see/hear 2 glitches near the start of the file.....this is the 2 file names and what ever other format info is saved when the files are being copied.....you can read the names in the binary chipsnd1.raw file.
Attached is Zip of the data extracted from the chip.........
 

Attachments

  • ChipSound1.zip
    158.6 KB · Views: 126
Hi Benoit92, I see you posted that the CopyFromSerialMC works.......So is your DAC sound out working again.....????
My last post will let you see the raw data bytes that are copied to the chip as you mentioned earlier...
 
I think that the soundfiles was not correctly loaded in Flash memory.
But now, with your code modification, the sounfile is well loaded and the DAC works correctly?

I tried to upload to SPI Flash :
15 Ko ----------> Ok
250 Ko --------> Ok
1 Mo -----------> Ok
2 Mo -----------> Ok
4 Mo -----------> Ok

5 Mo ----------------> Not Ok
Windows Command :
C:\Python27>python -c "import serial, sys; print(sys.platform, serial.VERSION)"
('win32', '3.4')

C:\Python27>python -m serial.tools.list_ports
COM4
1 ports found

C:\Python27>Python "rawfile-uploader-mc.py" "COM4" "A6BR99.TRW"
Uploading 1 files...
1: A6BR99.TRWTraceback (most recent call last):
File "rawfile-uploader-mc.py", line 81, in <module>
ser.write("".join(encoded))
File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 323, in write
raise writeTimeoutError
serial.serialutil.SerialTimeoutException: Write timeout
 
Thats good all is working...........I dont know python except readit and guess.....
I have got errors like this before....basically I think it has timed out due to maybe connection interrupted or corruption.....did the lights flash and then go out or stay on.
It looks like it has seen the COM4 port and found the file and is actually writing or attempting to write and something is delaying either data in from Serial or data going to spiflash.
python displays on screen the message "uploading 1 files" and the filename before data has started....so if teensy didnt get the "c" the sketch would not start but COMMS would be made but teensy would not send data........You would know this if the LEDs did not flash...and then when data is complete LED goes out......Did you try it several times or with another copy of the file.
I see you are able to send quite large files.......good....
 
1) I tried to load some soundfiles together : 3758 Ko + 2441 Ko + 248 Ko ---> It works
But when I want to load just a soundfile over 4000 Ko ---> It doesn't work ?

2) When I try to load only a soundfile over 4000 Ko, the time-out message appears at the beginning (after unplug-plug-rawfileup-loader.py) when Led 13 goes like this :
Code:
// Double flash LED a few times to warn Erase is about to begin ..........
  for(uint8_t i = 0; i < 3; i++){
    delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
  	delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
    delay(1000);
  }
 
Benoit92 wrote...............
2) When I try to load only a soundfile over 4000 Ko, the time-out message appears at the beginning (after unplug-plug-rawfileup-loader.py) when Led 13 goes like this
...................................................................
Are you using my -mc version.......you dont need to unplug it.............Load the CopyFromSerialMC into Teensy...watch that you get RebootOK or what ever it says for successful upload.....Teensy will the be re-booted and will sit waiting on a " c " being keyed in.....but dont do it.......open python CMDline and run the rawfile-uploader-mc.py......it will send a " c " and start the teensy sketch, find the files and transfer them........ I can do several at one time OK......my problem is I cannot do large ones 500k etc my WinXP PC crashes and restarts.....small files OK.......large files work OK when I use a new windows10 laptop.

I think the crash is caused by python talking to the serial port........I tried a mod to the python script...opened a file (g = open('sndbib.raw', 'wb') for writing the data to a file on PC instead of Serial out and sent the Large file 1.5MB to it.....it created the file and didnt crash PC.......dont know what to check why writing to serial crashes PD...???

Just thinking about you timeout problem....If its timing out when the double flash ....that is before erase so mustnt be due to a long erase time if say alot of files were on chip.....I think it erases the whole chip each time anyway.......
 
Last edited:
I use a windows10 + laptop (ASUS 550).
I followed your procedure and your codes (CopyFromSerialMC and rawfile-uploader-mc.py).
It works well except for files over 4000 Ko (???) (about 45 seconds sound).
I think I can do it with this limitation for my application.

C:\Python27>python -c "import serial, sys; print(sys.platform, serial.VERSION)"
('win32', '3.4')

C:\Python27>python -m serial.tools.list_ports
COM4
1 ports found

C:\Python27>Python "rawfile-uploader-mc.py" "COM4" "A3BR99.TRW" "A4BR99.TRW" "A5BR99.TRW" "A9BR99.TRW" "A1BR99.TRW" "A6BR99.TRW"
Uploading 6 files...
1: A3BR99.TRW (13.42 KB/s) ----> 248 Ko;)
2: A4BR99.TRW (198.41 KB/s)------>2441 Ko ;)
3: A5BR99.TRW (198.38 KB/s) ------> 3758 Ko ;)
4: A9BR99.TRW (649.18 KB/s) -------> 3937 Ko ;)
5: A1BR99.TRWTraceback (most recent call last): -------> 4135 Ko:confused:
File "rawfile-uploader-mc.py", line 81, in <module>
ser.write("".join(encoded))
File "C:\Python27\lib\site-packages\serial\serialwin32.py", line 323, in write
raise writeTimeoutError
serial.serialutil.SerialTimeoutException: Write timeout


--> Led13 stays solid.
Last soundfile "A6BR99.TRW" (5288 Ko) is lost.

Is it a probem linked with Windows configuration (USB serial port driver)?
 
I didnt get time out errors but maybe not doing as long a list or not as large files so it probably is a genuine time out due to the size of transfer.
I dont understand the size you list the files....is 3937Ko equal to 3937 Kbytes equal to 3.937 Mbytes.........I thought from previous posts you were using the W25Q64 flash
Is that not 64 Mbit equal to 8 Mbytes

There is an option ser.timeout() in setup for serial port in python.....I am not familiar with python so actually never used it......its in the pyserial docs.

I have now surfaced another problem......I have 4 files on Flash about 100 Kbytes each that all play no problem but now I cannot get the EraseEverything sketch OR EraseAll in CopyFromSerial to erase them and so CopyFromSerial wont copy on any more files. Neither will CopyFromSD, It finds the files already there and only copies to blank Flash.
All had been working but just stopped.....but still plays the files that are on........

The RawHardwareTest sketch now gives me this..............
JEDEC ID: EF 40 17
Part Nummber: W25Q64FV
Memory Size: 8388608 bytes
Block Size: 65536 bytes

Reading Chip...
Previous data found at address 0
You must fully erase the chip before this test
found this: 4C 55 96 FA 58 02 F6 18
correct: 00 00 00 00 15 F5 95 4B
And tells me all tests failed......Yet all was working yesterday.......... Except maybe this is another XP only problem.......I will have to check out..???....any ideas...???
 
I apologize because :
Ko = Kilo octets = Kilo bytes
So, W25Q64 = 64 Kilobits = 8 Kilobytes

I try :
Code:
ser = serial.Serial(sys.argv[1], 9600, timeout=0, writeTimeout=None)
But no effect !
This breaks the thermometer but not the fever !

any ideas...???
Check the wires and connections and Write protect pin : https://www.pjrc.com/store/w25q64fv.pdf
The Write Protect (/WP) pin can be used to prevent the Status Registersfrom being written.

There are also some bits (status register) in W25Q64FV which deals with "write protection".

3.12
Write Protect (/WP)

Used in conjunction with the Status Register’s Block Protect (CMP, SEC, TB,BP2, BP1 and BP0) bits and
Status Register Protect (SRP) bits, a portion as small as a
4KB sector or the entire memory array can be hardware protected.
The /WP pin is active low. However, when the QE bit of Status Register-2 is set for Quad I/O, the /WP
pin function is not available since this pin is used for IO2.
See figure 1a, 1b and 1c for the pin configuration of Quad I/O operation.

Try to erase :
1) with setting /WP low
2) then with /WP high
in order to defreeze the write protection !!!:confused:
-

Try with another PC
 
Thanks for reply.... I am still confused about the size of your files..... one of your files listed as 3937 Ko equals 3937 Kbytes equals 3.937 Mbytes ....... so adding up all your files transferred .....comes to over 14 MBytes........have you that much memory...?????.....maybe running out of memory...??
Are these long files playing continuously......maybe better of SD card....??

I dont know python well enough...but it looks a python error either due to setting or slow data

Are you making the changes to the ser line in the script.......I found this in the pyserial docs..

Possible values for the parameter timeout which controls the behavior of read():
•timeout = None: wait forever / until requested number of bytes are received
•timeout = 0: non-blocking mode, return immediately in any case, returning zero or more, up to
the requested number of bytes
•timeout = x: set timeout to x seconds (float allowed) returns immediately when the requested
number of bytes are available, otherwise wait until the timeout expires and return all bytes that were
received until then.
write() is blocking by default, unless write_timeout is set. For possible values refer to the list for
timeout above.

There is also a 3 second time out if no data detected in the teensy sketch......maybe if that was lengthened...say 6 seconds and see what happens.

Regards my copy and erase problem I put Arduino 185 and teensy 141 on the win10 laptop....no difference...still won't erase...No errors listed but says the usual "erase is Slow" but then says it does it in 0 , 1, or 2 seconds......but not actually done at all.

Thanks for the info on the chip, I had the datasheet.....but would now need to read it........????
 
Last edited:
I had previous problems with copyfromserial as per earlier posts and also copy large files on windows setup crashed my "old" XP PC.
So I setup an old laptop with Ubuntu 16.04 with Arduino 1.8.5 and Teensy 1.4.1 and all runs well very fast.
But a perculiar problem The CopyfromSerial that runs OK on windows PC with small files wouldnt copy at all on Linux setup, yet all compiled and ran no errors LEDs flashed but didn't go off at the end.
It turned out The serial.read waiting for a "c" to be sent was being detected from the serial.println on the line before it and that was upsetting things......but did not cause a problem on windows......

So maybe my statement for serial.read is wrong....?????...... but I took out all the serial.println statements and all works OK. I can now copy large files 2 MB plus on the Ubuntu laptop...no problem. Don't need to use monitor, just plug in teensy, upload copyfromserial sketch, then run python, then upload listfiles sketch to see files are there...no plugging and unplugging.

Code:
/*
 * This is free and unencumbered software released into the public domain.
 * 
 * ARDUINO / Teensy Modified CopyFromSerial direct using Python Script.....Apr2018....
 * ..
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 * 
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * 
 * For more information, please refer to <http://unlicense.org>
 * -------------------------------------------------------------------------
 * 
 * This is example code to 1) format an SPI Flash chip, and 2) copy raw 
 * audio files (mono channel, 16 bit signed, 44100Hz) to it using the 
 * SerialFlash library.  The audio can then be played back using the 
 * AudioPlaySerialflashRaw object in the Teensy Audio library.
 * 
 * To convert a .wav file to the proper .RAW format, use sox:
 * sox input.wav -r 44100 -b 16 --norm -e signed-integer -t raw OUTPUT.RAW remix 1,2
 * 
 * Note that the OUTPUT.RAW filename must be all caps and contain only the following
 * characters: A-Z, 0-9, comma, period, colon, dash, underscore.  (The SerialFlash
 * library converts filenames to caps, so to avoid confusion we just enforce it here).
 * 
 * It is a little difficult to see what is happening; aswe are using the Serial port
 * to upload files, we can't just throw out debug information.  Instead, we use the LED
 * (pin 13) to convey state.
 * 
 * While the chip is being formatted, the LED (pin 13) will toggle at 1Hz rate.  When 
 * the formatting is done, it flashes quickly (10Hz) for one second, then stays on 
 * solid.  When nothing has been received for 3 seconds, the upload is assumed to be 
 * completed, and the light goes off.
 * 
 * Use the 'rawfile-uploader.py' python script (included in the extras folder) to upload
 * the files.  You can start the script as soon as the Teensy is turned on, and the
 * USB serial upload will just buffer and wait until the flash is formatted.
 * 
 * This code was written by Wyatt Olson <wyatt@digitalcave.ca> (originally as part 
 * of Drum Master http://drummaster.digitalcave.ca and later modified into a 
 * standalone sample).
 * 
 * Enjoy!
 * 
 *     // xxxx ... MONITOR CONTROL ADDED ........Apr 2018.........
 * 
 */

#include <SerialFlash.h>
#include <SPI.h>

const int FlashChipSelect = 6; // digital pin for flash chip CS pin
//const int FlashChipSelect = 21; // Arduino 101 built-in SPI Flash
// I couldn't get #define CSPIN 6 to work so put in ... FlashChipSelect = 6  .....xxxxxxxxxxxxxx

//Buffer sizes
#define USB_BUFFER_SIZE      128   // was 128
#define FLASH_BUFFER_SIZE    4096  //was 4096

//Max filename length (8.3 plus a null char terminator)
#define FILENAME_STRING_SIZE      13

//State machine
#define STATE_START      0
#define STATE_SIZE      1
#define STATE_CONTENT    2

//Special bytes in the communication protocol
#define BYTE_START      0x7e
#define BYTE_ESCAPE      0x7d
#define BYTE_SEPARATOR    0x7c


//SPI Pins (these are the values on the Audio board; change them if you have different ones)
//#define MOSI               7
//#define MISO              12
//#define SCK               14
// #define CSPIN              6
//#define CSPIN           21  // Arduino 101 built-in SPI Flash


void setup(){
  
   pinMode(13, OUTPUT);    // Teensy LED pin
   
  Serial.begin(9600);  //Teensy serial is always at full USB speed and buffered... the baud rate here is required but ignored
      
   delay(1000);
   
  while(Serial.read() != 'c');  //wait on Python sending a c

  //Set up SPI
  SPI.setMOSI(7);  // uncomment these if using the alternate pins
  SPI.setMISO(12);  // these are the standard pins for the Teensy 3.2 & Audio Adaptor board conbination
  SPI.setSCK(14);
 

 if (!SerialFlash.begin(FlashChipSelect)) {
    while (1) {
      Serial.println("Unable to a access SPI Flash chip");
      delay(1000);
    }
  }
 
// Double flash LED a few times to warn Erase is about to begin ..........
  for(uint8_t i = 0; i < 3; i++){
    delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
  	delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
    delay(1000);
  }
                 
  //We start by formatting the flash...
  uint8_t id[5];
  SerialFlash.readID(id);
  SerialFlash.eraseAll();
  
  //Flash LED at 1Hz while formatting
  while (!SerialFlash.ready()) {
    delay(500);
    digitalWrite(13, HIGH);
    delay(500);
    digitalWrite(13, LOW);
  }

  //Quickly flash LED a few times when completed, then leave the light on solid 1 second
  for(uint8_t i = 0; i < 10; i++){
    delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
  }
  digitalWrite(13, HIGH);
  
  delay(1000);
 
  //We are now going to wait for the upload program
  while(!Serial.available());
  
  SerialFlashFile flashFile;
  //  Do some Flashing + 1 second off to indicate Copy is Starting
    delay(100);
    digitalWrite(13, LOW);
    delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
    delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
    delay(1000);
    digitalWrite(13, HIGH);
  
  uint8_t state = STATE_START;
  uint8_t escape = 0;
  uint8_t fileSizeIndex = 0;
  uint32_t fileSize = 0;
  char filename[FILENAME_STRING_SIZE];
  
  char usbBuffer[USB_BUFFER_SIZE];
  uint8_t flashBuffer[FLASH_BUFFER_SIZE];
  
  uint16_t flashBufferIndex = 0;
  uint8_t filenameIndex = 0;
  
  uint32_t lastReceiveTime = millis();
  
    // .... We assume the serial receive part is finished when we have not received something for 3 seconds
    // ..... parenthesis added around this bit on line below........... ((lastReceiveTime + 3000) > millis())....reads better...
  
  while(Serial.available() || ((lastReceiveTime + 3000) > millis())) {
    uint16_t available = Serial.readBytes(usbBuffer, USB_BUFFER_SIZE);
    if (available){
      lastReceiveTime = millis();
    }

    for (uint16_t usbBufferIndex = 0; usbBufferIndex < available; usbBufferIndex++){
      uint8_t b = usbBuffer[usbBufferIndex];
      
      if (state == STATE_START){
        //Start byte.  Repeat start is fine.
        if (b == BYTE_START){
          for (uint8_t i = 0; i < FILENAME_STRING_SIZE; i++){
            filename[i] = 0x00;
          }
          filenameIndex = 0;
        }
        //Valid characters are A-Z, 0-9, comma, period, colon, dash, underscore
        else if ((b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || b == '.' || b == ',' || b == ':' || b == '-' || b == '_'){
          filename[filenameIndex++] = b;
          if (filenameIndex >= FILENAME_STRING_SIZE){
            //Error name too long
            flushError();
            return;
          }
        }
        //Filename end character
        else if (b == BYTE_SEPARATOR){
          if (filenameIndex == 0){
            //Error empty filename
            flushError();
            return;
          }
          
          //Change state
          state = STATE_SIZE;
          fileSizeIndex = 0;
          fileSize = 0;
          
        }
        //Invalid character
        else {
          //Error bad filename
          flushError();
          return;
        }
      }
      //We read 4 bytes as a uint32_t for file size
      else if (state == STATE_SIZE){
        if (fileSizeIndex < 4){
          fileSize = (fileSize << 8) + b;
          fileSizeIndex++;
        }
        else if (b == BYTE_SEPARATOR){
          state = STATE_CONTENT;
          flashBufferIndex = 0;
          escape = 0;
          
          if (SerialFlash.exists(filename)){
            SerialFlash.remove(filename);  //It doesn't reclaim the space, but it does let you create a new file with the same name.
          }
          
          //Create a new file and open it for writing
          if (SerialFlash.create(filename, fileSize)) {
            flashFile = SerialFlash.open(filename);
            if (!flashFile) {
              //Error flash file open
              flushError();
              return;
            }
          }
          else {
            //Error flash create (no room left?)
            flushError();
            return;
          }
        }
        else {
          //Error invalid length requested
          flushError();
          return;
        }
      }
      else if (state == STATE_CONTENT){
        //Previous byte was escaped; unescape and add to buffer
        if (escape){
          escape = 0;
          flashBuffer[flashBufferIndex++] = b ^ 0x20;
        }
        //Escape the next byte
        else if (b == BYTE_ESCAPE){
          //Serial.println("esc");
          escape = 1;
        }
        //End of file
        else if (b == BYTE_START){
          //Serial.println("End of file");
          state = STATE_START;
          flashFile.write(flashBuffer, flashBufferIndex);
          flashFile.close();
          flashBufferIndex = 0;
        }
        //Normal byte; add to buffer
        else {
          flashBuffer[flashBufferIndex++] = b;
        }
        
        //The buffer is filled; write to SD card
        if (flashBufferIndex >= FLASH_BUFFER_SIZE){
          flashFile.write(flashBuffer, FLASH_BUFFER_SIZE);
          flashBufferIndex = 0;
        }
      }
    }
  }

  //Success!  Turn the light off.
  
   digitalWrite(13, LOW);
  
}

void loop(){
  //Do nothing.
}

void flushError(){
  uint32_t lastReceiveTime = millis();
  char usbBuffer[USB_BUFFER_SIZE];
  //We assume the serial receive part is finished when we have not received something for 3 seconds
  // ..... parenthesis added around this bit on line below........... (lastReceiveTime + 3000) > millis()....reads better...
  while(Serial.available() || ((lastReceiveTime + 3000) > millis())) {
    if (Serial.readBytes(usbBuffer, USB_BUFFER_SIZE)){
      lastReceiveTime = millis();
    }
  }
}
 
In short :
You cancelled the "println" and "Serial.read" in order to avoid percussion between flux coming from Python script and flux coming from serial monitor.

I tried to load 4,9 Mo, but it crashes.
It's not really very important because, I can do with several soundfiles under 4 Mo.
Perhaps a Windows limitation??!!:confused:
 
"It turned out The serial.read waiting for a "c" to be sent was being detected from the serial.println on the line before it and that was upsetting things......but did not cause a problem on windows......"

What I meant was....The serial.Println( Enter a " c " to start Copy") ......has a " c " in it.......and this was being detected some how by the if (serial.read() != 'c') .......

If I take the " c " out of the println sentence then all works OK...... OR if I change the serial.read to wait for " z " with a "c " in the println sentence all is OK...also change the python to send " z ".

Even in the Arduino IDE opening the monitor when the " c " was in the Println started the sketch without entering a " c ".

So I think the statement for getting serial.read() to detect a " c " or indeed any character is probably wrong....???.....but works in windows and not in Linux..?????
I use the same python script statement to ser.write('c') in both windows and Linux...??

Yes, the size of the files copied seems to be a different problem.......small files only work in windows....any size file works in Linux......??????....perculiar...??
 
I thought I would investigate your idea about "avoid percussion"....and I think that is actually the problem...
I commented out the printlm("Enter a c to start Copy") and left in the other print lines and copy was not reliable......would copy on the windows machine OK, but not on Linux. On Linux it ran CopyFromSerial and the Python script ran OK but LED did not go out and files were not copied.
Then commented out all the print lines, except the orig error prints which only print on error, and all works OK reliably. small files on windows and any size on Linux...

On the Linux I copied, a 6MByte + a 700KByte + 2 of 100KByte each, to the spiflash in one batch and all copied OK and all played OK on both Linux and windows.
I
 
Hi, my "simply" code goes well.
Now, I would like to mix two sounds together.
Here is my "simply"code but without using "mixer".

Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

    //'*' Type on Serial Monitor
    //A0A8B14.TRW = 'a' Engine start - Pantograph up
    //A1AB814.TRW = 'z' Compressor + Air release
    //A2AB814.TRW = 'e' Horn
    //A3AB814.TRW = 'r' Start driving
    //A4AB814.TRW = 't' Driving
    //A5AB814.TRW = 'y' Brake
    //A6AB814.TRW = 'u' Compressor - Air release + Engine start
    //A7AB814.TRW = 'i' Uncoupling
    //A8AB814.TRW = 'o' Stop driving
    //A9AB814.TRW = 'p' Stand-by engine

const int FLASH_CHIP_SELECT = 10;  
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioPlaySerialflashRaw  playFlashRaw1;  //xy=228,273
AudioOutputAnalog        dac1;           //xy=751,337
AudioConnection          patchCord1(playFlashRaw1, 0, dac1, 0);
// GUItool: end automatically generated code

int Data;     // Read serial data
int PrevData;  // Read previous serial data

void setup() {
    Serial.begin(9600); // Serial setup
    while (!Serial && millis()<500 );
    AudioMemory(50);//
    analogReference(EXTERNAL);// 3,3V Amplitude DAC

//************************************
//  Set up SPI Teensy without audio Card
  SPI.setMOSI(11); //7
  SPI.setMISO(12);
  SPI.setSCK(14);
//************************************
    delay(2000);
    if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
        while (1){
            Serial.println ("Cannot access SPI Flash chip");
            delay (10000);
        }
    }
}
    void playFile1(const char *filename)// Play audio file function
    {
      SerialFlashFile ff = SerialFlash.open(filename);
      Serial.print("Playing file1: ");
      Serial.println(ff);
      playFlashRaw1.play(filename);
     // Simply wait for the file to finish playing.
     while (playFlashRaw1.isPlaying()) {
     } 
    }
    
void loop() {
if ( Serial.available() ) {
    Data = Serial.read();
    Serial.println(Data);
  } 
  else {
    Serial.println("Nothing");
  }

switch (Data) {
   case 'a':{  // Play Soundfile in loop 
     PrevData = 'a';    
     playFile1("A0AB814.TRW");
     break;
   }
   case 'z':{  // Play Soundfile in loop   
      PrevData = 'z';
      playFile1("A1AB814.TRW");
      break;
   }    
           case 'e':{   // Play Soundfile only once   
           playFile1("A2AB814.TRW");
           Data=PrevData; // Continue with previous soundfile 
           Serial.println(Data);
           break;
           } 
    case 't':{  // Play Soundfile in loop   
     PrevData = 't'; 
     playFile1("A4A814.TRW");
     break;
    }    
    case 'y':{  // Play Soundfile in loop   
     PrevData = 'y'; 
     playFile1("A5AB814.TRW");
      break;
    }    
    case 'u':{  // Play Soundfile in loop   
      PrevData = 'u';  
      playFile1("A6AB814.TRW");
     break; 
    }        
    case 'i':{  // Play Soundfile in loop    
      PrevData = 'i'; 
      playFile1("A7AB814.TRW");
      break;
    }    
    case 'o':{  // Play Soundfile in loop   
      PrevData = 'o';  
      playFile1("A8AB814.TRW");
      break;
    }  
    case 'p':{  // Play Soundfile in loop   
      PrevData = 'p';  
      playFile1("A9A814.TRW");
      break;
   }      
  }
}
 
Depends on what sounds you want to mix...do you want to select 2 from the "case" list or is it a new sound played along with 1 of the select/case sounds
In any case you need another playflash object if the new sound is on flash......connect both to mixer1 and output to dac1
Depending on the logic of how you want them to play, copy the the playfile1 and call it playfile2 and change it to play the new object and call it as required.

Code:
AudioPlaySerialflashRaw  playFlashRaw1;  
AudioPlaySerialflashRaw  playFlashRaw2; 
AudioMixer4   mixer1;
AudioOutputAnalog        dac1;           
AudioConnection          patchCord1(playFlashRaw1, 0, mixer1, 0);
AudioConnection          patchCord2(playFlashRaw2, 0, mixer1, 1);
AudioConnection          patchCord3(mixer1, dac1);
 
Ok, Thanks.
I will define 2 functions : PlayFile1 and PlayFile2.
And I will use for instance this type of mechanism :

Setup
mixer1 (0, 0.5)
mixer1 (1, 0.5)​
void PlayFile1()
void PlayFile2()
Loop
1) Readserial
2) Switch ... Case 'a', 'z' ',e'
3) PlayFile1

4) Switch ... Case 'r', 't', 'y'
5) PlayFile2​

So, I can play 'a' with 'r' together ?
 
Status
Not open for further replies.
Back
Top