WT588D-16P Sound Module Working Code

EUREKA! Okay, finally got to program this module. For those brave enough to do it, I have attached the code. It uses a processing sketch to communicate with the firmware loaded on the arduino. Code is not optimized, no error checking, hence USE AT YOUR OWN RISK. Feel free to modify.

My setup is a deek-robot Arduino pro Nano 3.3V. You can use an Arduino with 5 V but you need level shifting with the WTD588D. Standard hardware SPI pins used. 11, 12, 13, 10.

Video of the uploading in progress

Arduino Firmware:


// Winbond serial flash loader.  Runs on normal Arduino (e.g. Uno,
// NOT Trinket), works with 'AudioXfer' Processing code on host PC.
// Modified by purgedsoul for uploading bin file to WTD588-16P sound module.
// Use at your own risk!

#include <Adafruit_TinyFlash.h>
#include <SPI.h>

//#define LED A0

// Blink LED (not pin 13) to indicate flash error
/*void error(uint32_t d) {
  for(;;) {
    digitalWrite(LED, HIGH);
    delay(d);
    digitalWrite(LED, LOW);
    delay(d);
  }
}
*/

void setup() {
  Adafruit_TinyFlash flash;
  
  uint8_t            buffer[256];
  
  int                c, index      = 0, 
                     rmdr          = 0,
                     numpages      = 0,
                     page          = 0;
                     
  uint32_t           capacity,
                     address       = 0,
                     bytesExpected = 0x7FFFFFFF,
                     bytesReceived = 0,
                     filesize=0;

//  pinMode(LED, OUTPUT);
//  digitalWrite(LED, LOW);

  Serial.begin(57600);
  Serial.println("HELLO");      // ACK to host

  capacity = flash.begin();
  Serial.println(capacity);     // Chip size to host
//  if(!capacity) error(250);     // Fast blink

  

  while(!Serial.find("ERASE")); // Wait for ERASE command from host
  if(!flash.eraseChip()) {
    Serial.println("ERROR");
//    error(500);                 // Slow blink
  }
  
//while(Serial.available() == 0) {}
   while(!Serial.find("CAPACITY")); 
    filesize = Serial.parseInt();
  
    numpages = filesize / 256;
    rmdr = filesize % 256;
    
    if(rmdr != 0) numpages = numpages + 1;
    
  Serial.println("READY");      // ACK to host

  for(;;) {
    // Buffer data until a full page is ready or last packet arrives.
    if((c = Serial.read()) >= 0) {
      buffer[index] = c;
      index=index+1;
      if((index >= sizeof(buffer))) {
        if(flash.writePage(address, buffer)) {
          
//          digitalWrite(LED, HIGH);
          Serial.print('.');
        } else {
          Serial.print('X');
        }
        
//        digitalWrite(LED, LOW);
        if(page >= numpages) break; //(address >= capacity) || 
        index = 0;
        page = page + 1;
        address = address + sizeof(buffer);
      }//if ((index >= sizeof(buffer)))
    } //if ((c = Serial.read()) >= 0)
  } //for(;;)
  //if filesize > 0
} // void setup()

void loop() { }

Processing Sketch


/ WT588D .bin file transfer.  Runs in conjunction with
// AudioLoader_WT588D.ino sketch on Arduino 
// Processing sketch based off AdaFruit AudioXfer sketch
// Use at your own risk

import processing.serial.*;
Serial  port = null;

int     capacity;
boolean done = false;

// Wait for line from serial port, with timeout
String readLine() {
  String s;
  int    start = millis();
  do {
    s = port.readStringUntil('\n');
  } while((s == null) && ((millis() - start) < 3000));
  return s;
}

void setup() {
  String s;
  background(0);
  size(300, 150);                                 // Serial freaks out without a window :/

  // Locate Arduino running AudioLoader sketch.
  // Try each serial port, checking for ACK after opening.
  
  println("Scanning serial ports...");
   for(String portname : Serial.list()) {
    try {
      portname = "COM13";                        // bypass scan
      port = new Serial(this, portname, 57600);
    } catch (Exception e) {                      // Port in use, etc.
      continue;
    }
    print("Trying port " + portname + "... ");
    if(((s = readLine()) != null) && s.contains("HELLO")) {
      println("OK");
      break;
    } else {
      println();
      port.stop();
      port = null;
    }
  }

  if(port != null) {                              // Find one?
    if(((s        = readLine())                != null)
      && ((capacity = Integer.parseInt(s.trim())) > 0)) {
      println("Found Arduino w/" + capacity + " byte flash chip."); 
      selectInput("Select a file to process:", "fileSelected");
    } else {
      println("Arduino failed to initialize flash memory.");
      done = true;
    }
  } else {
    println("Could not find connected Arduino running WT588DAudioLoader sketch.");
    done = true;
  } 
}

void fileSelected(File f) {
  if(f == null) {
    println("Cancel selected or window closed.");
  } else {
    println("Selected file: " + f.getAbsolutePath());
    byte input[] = loadBytes(f.getAbsolutePath());

    int filesize = input.length;
    
    
      port.write("ERASE");                          // Issue erase command now, process audio while it works

      println("Processing file...\n");
                 
      print("Erasing flash...");                    // Really just waiting for the erase ACK
      
      String s, cap;
      int c;
      
      cap = "CAPACITY" + filesize;
      port.write(cap);
                  
      while(((s = readLine()) == null) || (s.contains("READY") == false));
      
      print("\nFilesize: ");
      println(cap);
      print("OK\nWriting...\n");
      // Instead of just write(output), it's done per-byte so we
      // can echo progress dots from the Arduino to the console.
      // Eventually may want to make it re-write error sectors.
     
      for(int i=0; i<filesize; i++) {
        //a = input[i]; //& 0xff;
        port.write(input[i]);
              
        if((c = port.read()) >= 0) {print((char)c);}
      }
      println("done!");
     
    } 
 
   done = true;
   
}

void draw() {
  if(done) exit();
}

AudioLoader_WT588D.zip (4.61 KB)

Hi,

for anyone interested I extend the code a little to a library and made a git repository. See https://github.com/ACDCLabs/WT588D.git

It's far from being a perfect well designed library, but rather a start for further contributions.

I spend some time flashing the chip with an Arduino and SPI directly, with mixed success. Flashing the chip produces several write errors during flashing, but worked occasionally.

N.

Finally a library, thank you ecloud.

Help, do you have a scheme to power and upload the songs on a wt588d-16p?

Hi PurgedSoul, thank you for your precious informations.

I tried your code on my Arduino Uno and connected the WT588D to the Arduino's SPI pin (with level shifter 5V to 3,3V), but i have "0" as "capacity" (println) all the time, can't get differente values.

Do you have some hint for me?

Thank you in advice!

@smanettone

can you query your WT588D flash chip's ID and capacity? In the Adafruit_Tiny library the flash's capacity is hardcoded and will only recognized chips whose ID and capacity is such:

return ((manID == 0xC2) && (devID == 0x13)) ? CHIP_BYTES : 0L;

Flash that is not recognized will always return a 0.

purgedsoul: @smanettone

can you query your WT588D flash chip's ID and capacity?

How can i do that?

I'm sorry, but i need to learn a lot of things about Arduino yet :p this is my first project.

smanettone:
How can i do that?

I’m sorry, but i need to learn a lot of things about Arduino yet :stuck_out_tongue: this is my first project.

Try running this sketch and check the output of get_jedec_id in serial monitor:

/*
    windbond_serial_debug.cpp 
    A simple program for the Arduino IDE to help familiarize you with
    using WinBond flash memory; can also be used to download the entire
    contents of a flash chip to a file via a serial port interface.
    
    Important bits of the code: the low-level flash functions (which 
    implement the timing diagrams in the datasheet), and a simple 
    serial-port command interface that allows you to talk to your 
    UNO with any generic terminal application (even the command line).
    
    Copyright 2014, Peter J. Torelli

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>   

Revisions:
    rev 2 - 21-SEP-2014.
    User 'fiaskow' pointed out that driving the WEL instruction after
    program and erase w/o waiting for the op to finish may be corrupting
    execution. Removed this code (also not needed b/c the WEL is already
    cleared after page write or chip erase).
*/
#include <Arduino.h>
#include <SPI.h>

// SS:   pin 10
// MOSI: pin 11
// MISO: pin 12
// SCK:  pin 13

// WinBond flash commands
#define WB_WRITE_ENABLE       0x06
#define WB_WRITE_DISABLE      0x04
#define WB_CHIP_ERASE         0xc7
#define WB_READ_STATUS_REG_1  0x05
#define WB_READ_DATA          0x03
#define WB_PAGE_PROGRAM       0x02
#define WB_JEDEC_ID           0x9f
#define WB_SECTOR_ERASE       0x20

/*
================================================================================
User Interface Routines
The functions below map to user commands. They wrap the low-level calls with 
print/debug statements for readability.
================================================================================
*/

/* 
 * The JEDEC ID is fairly generic, I use this function to verify the setup
 * is working properly.
 */
void get_jedec_id(void) {
  Serial.println("command: get_jedec_id");
  byte b1, b2, b3;
  _get_jedec_id(&b1, &b2, &b3);
  char buf[128];
  sprintf(buf, "Manufacturer ID: %02xh\nMemory Type: %02xh\nCapacity: %02xh",
    b1, b2, b3);
  Serial.println(buf);
  Serial.println("Ready");
} 

/*================================================================================
Low-Level Device Routines
The functions below perform the lowest-level interactions with the flash device.
They match the timing diagrams of the datahsheet. They are called by wrapper 
functions which provide a little more feedback to the user. I made them stand-
alone functions so they can be re-used. Each function corresponds to a flash
instruction opcode.
================================================================================
*/

/*
 * See the timing diagram in section 9.2.35 of the
 * data sheet, "Read JEDEC ID (9Fh)".
 */
void _get_jedec_id(byte *b1, byte *b2, byte *b3) {
  digitalWrite(SS, HIGH);
  digitalWrite(SS, LOW);
  SPI.transfer(WB_JEDEC_ID);
  *b1 = SPI.transfer(0); // manufacturer id
  *b2 = SPI.transfer(0); // memory type
  *b3 = SPI.transfer(0); // capacity
  digitalWrite(SS, HIGH);
  not_busy();
}  

/* 
 * not_busy() polls the status bit of the device until it
 * completes the current operation. Most operations finish
 * in a few hundred microseconds or less, but chip erase 
 * may take 500+ms. Finish all operations with this poll.
 *
 * See section 9.2.8 of the datasheet
 */
 
void not_busy(void) {
  digitalWrite(SS, HIGH);  
  digitalWrite(SS, LOW);
  SPI.transfer(WB_READ_STATUS_REG_1);       
  while (SPI.transfer(0) & 1) {}; 
  digitalWrite(SS, HIGH);  
}

void setup(void) {
  SPI.begin();
  SPI.setDataMode(0);
  SPI.setBitOrder(MSBFIRST);
  Serial.begin(9600);
  Serial.println("");
  Serial.println("Ready");
  get_jedec_id();
   
}

/*
 * loop() dispatches the commands compiled by the serialEvent
 * parser callback. Some commands take multiple arguments, so
 * I have to split up the strings with some messy manipulation.
 */
void loop(void) {

}

purgedsoul: Try running this sketch and check the output of get_jedec_id in serial monitor:

Here you are the results:

Ready command: get_jedec_id Manufacturer ID: c2h Memory Type: 20h Capacity: 16h Ready

I assume that i connected everything fine, but why i get "0" as capacity in the uploading sketch? :'(

smanettone: Here you are the results:

Ready command: get_jedec_id Manufacturer ID: c2h Memory Type: 20h Capacity: 16h Ready

I assume that i connected everything fine, but why i get "0" as capacity in the uploading sketch? :'(

By the way what type of WT588D module are you using. What is the flash memory capacity is it already the USB version or the 20 pins version?

purgedsoul: By the way what type of WT588D module are you using. What is the flash memory capacity is it already the USB version or the 20 pins version?

The version is the WT588D-20SS.

smanettone: The version is the WT588D-20SS.

If you are already using the USB version, you can just plug your WT to the computer and upload voice files using the WT Programmer application.

If your WT is non USB you can try this:

Modify the Adafruit_TinyFlash library by opening the Adafruit_TinyFlash.cpp file and then locate this line:

return ((manID == 0xC2) && (devID == 0x13)) ? CHIP_BYTES : 0L;

change devID to 0x20:

return ((manID == 0xC2) && (devID == 0x20)) ? CHIP_BYTES : 0L;

If I understand correctly i have to make a bin file with the software than I have to upload that to the WT588D-16P module. Could somebody make a schematic about arduino and the WT588D-16P module for the data upload?

I saw the page about the SPI Flash Memory INstructable link

And I saw the schematic |500x387

But the pins of the Flash memory aren't same like the pins of the WT588D-16P module.

The flash memori use 3.3V, But the module maybe 5V

Here is the datasheet of the WT588D-16P module: DAtasheet Here is the datasheet of the SPI flash memory: DAtasheet

There are two pins on the Flash.... Pin3 (WP) and Pin7 (HOLD) on the flash memory But what are thees on the WT588D-16P module?

Flash Memory-----------------WT588D-16P Pin1_CS________________Pin9_P15_CS Pin2_DO______________Pin6_P13_DO Pin3_WP______________? ? ? ? ? Pin4_GND_____________Pin8_GND Pin5_DI______________Pin5_P14_DI Pin6_CLK_____________Pin7_P16_CLK Pin7_HOLD____________? ? ? ? ? Pin8_VCC (3.3V)_________Pin14_VCC (5V)

So they are not same. I think the WT588D-16P module don't need the resistors too, until the flash memory need resistors in this schematic.

But i am beginner in that. So could somebody help me?

Thanx!

katonafull: If I understand correctly i have to make a bin file with the software than I have to upload that to the WT588D-16P module. Could somebody make a schematic about arduino and the WT588D-16P module for the data upload?

I saw the page about the SPI Flash Memory INstructable link

And I saw the schematic |500x387

But the pins of the Flash memory aren't same like the pins of the WT588D-16P module.

The flash memori use 3.3V, But the module maybe 5V

Here is the datasheet of the WT588D-16P module: DAtasheet Here is the datasheet of the SPI flash memory: DAtasheet

There are two pins on the Flash.... Pin3 (WP) and Pin7 (HOLD) on the flash memory But what are thees on the WT588D-16P module?

Flash Memory-----------------WT588D-16P Pin1_CS________________Pin9_P15_CS Pin2_DO______________Pin6_P13_DO Pin3_WP______________? ? ? ? ? Pin4_GND_____________Pin8_GND Pin5_DI______________Pin5_P14_DI Pin6_CLK_____________Pin7_P16_CLK Pin7_HOLD____________? ? ? ? ? Pin8_VCC (3.3V)_________Pin14_VCC (5V)

So they are not same. I think the WT588D-16P module don't need the resistors too, until the flash memory need resistors in this schematic.

But i am beginner in that. So could somebody help me?

Thanx!

Hi this is how I connect them:

Flash Memory-----------------WT588D-16P Pin1_CS________________Pin9_P15_CS Pin2_DO______________Pin6_P13_DO Pin3_WP______________NC Pin4_GND_____________Pin8_GND Pin5_DI_______________Pin5_P14_DI Pin6_CLK_____________Pin7_P16_CLK Pin7_HOLD____________NC Pin8_VCC (3.3V)_________Pin14_VCC (3.3V) connect it to 3.3 volts not 5

NC is no connection or not connected.

Thank you very much!

I have an arduino Uno
I made a schematic about the uploading.
Is it correct?
http://goo.gl/OGoMDh?gdriveurl

please see attached image for the modification. You need to supply 3.3V to your level shifter and WT. Connect the 3.3 V from the Uno to the LV pin of the level shifter and the VCC pin on the WT588D.

Thank you!

You are the King!

purgedsoul: please see attached image for the modification. You need to supply 3.3V to your level shifter and WT. Connect the 3.3 V from the Uno to the LV pin of the level shifter and the VCC pin on the WT588D.

Hey man, so... I've only got 3 SPI pins on my Pro Micro. I know my Pro Micro and wt588D are both 3.3v/5v compatible. How would I wire up between the two of them?

Hi Board, thanks for this info but im really a dumb a$$ and really lost trying to get my sound bin file onto my WT588D 16P using my Arduino Nano, can some that has managed to get it to work do an Instructable or step by step guide with full diagrams etc. Really sorry in advance for being suck a dumb A$$. TIA