Go Down

Topic: WT588D-16P Sound Module Working Code (Read 67100 times) previous topic - next topic


Can anyone tells me  why my stuff can't working  .i use three wire  serial interface mode to connect with arduino mega 2560 and my  buzzer did not have sound ,besides  i have  using Lm386 to be  power amplifier to make sound loud .   I  am  confuse ..   does the host code has wrong  or i use wt588d  wrong way


I found that the example code only works if you have the soundfiles in the first "playlist" 0.

If you connect the arduino as per the model of WT588D you are using. I found this document to be very helpful as the pins locations vary. http://www.waytronic.com/DownLoadCenter/2011825103320760.pdf

Using the pins as per the pdf and the code provided by SugarBombs I was able to get the audio working.

Just make sure you match arduino pins to WT588D pins as per the code.  You can change the the arduino pins by updating the pin in the #define statements

#define WT588D_SDA 8 //Module pin "P01" or pin # 9  (Pin 8 on the arduino and P01 on the WT588D)


Is the non-usb model only programmable by buying that external programmer?  Or can you program it using a USB-UART connection? 
I was actually wondering about the same as forsytjr, I already ordered the two modules wo/USB, I'm very hopeful that there is a way to bypass an external programmer.

Anyone out there maybe already have a working solution for this? :smiley-eek:
Hi Guys, I am in the same boat as forsytjr and Protonerd. I got this module, but alas I cannot get the programmer locally, since the local seller only carried the non USB model, and he has no programmer available.

that is very simple , all you need to do is use that application created the bin file.
and then write into the flash just same like how you write to the flash chip. :)


ps: pull reset to low before download the file.
Hi poiuycat, were you able to do it with the non USB module. The above instructables, seems to target winbond flash memory chips, I am not sure if it will be compatible with the flash chip on the wt588d module.


Oct 13, 2015, 05:47 pm Last Edit: Oct 13, 2015, 06:09 pm by purgedsoul
Well, i tried using poiuycat's instructables link. No response to the command get_jedec_id. I connected the SPI pins accordingly via CD4050 (except MISO, directly connected to the pro mini's pin12), also connected the RESET to GND. Sigh.

I'm using a 5V arduino by the way.


Just an update for those trying to program this module without the programmer. I was able to connect to the module's SPI Flash. It is Winbond compatible, mine was KH25L8006E (the datasheet I can find was of MX25L8006E). I ended up using AdaFruit's TinyFlash library for programming the trinket audio player, modified the code to just upload bin file to the flash.I was able to upload the .bin file, but somehow it will not play. Oh well, back to the drawing board.


Nov 06, 2015, 08:43 am Last Edit: Nov 06, 2015, 03:15 pm by purgedsoul
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:
Code: [Select]
// 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);
    digitalWrite(LED, LOW);

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,

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

  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()) {
//    error(500);                 // Slow blink
//while(Serial.available() == 0) {}
    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;
      if((index >= sizeof(buffer))) {
        if(flash.writePage(address, buffer)) {
//          digitalWrite(LED, HIGH);
        } else {
//        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
Code: [Select]
/ 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;
  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.
    print("Trying port " + portname + "... ");
    if(((s = readLine()) != null) && s.contains("HELLO")) {
    } else {
      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;
      while(((s = readLine()) == null) || (s.contains("READY") == false));
      print("\nFilesize: ");
      // 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;
        if((c = port.read()) >= 0) {print((char)c);}
   done = true;

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



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. 



Finally a library, thank you ecloud.


Dec 08, 2015, 05:24 am Last Edit: Dec 08, 2015, 05:32 am by raphax
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!



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:

Code: [Select]
return ((manID == 0xC2) && (devID == 0x13)) ? CHIP_BYTES : 0L;

Flash that is not recognized will always return a 0.



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.


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.

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

Code: [Select]
    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
    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/>   

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

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);
  *b1 = SPI.transfer(0); // manufacturer id
  *b2 = SPI.transfer(0); // memory type
  *b3 = SPI.transfer(0); // capacity
  digitalWrite(SS, HIGH);

 * 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);
  while (SPI.transfer(0) & 1) {};
  digitalWrite(SS, HIGH); 

void setup(void) {

 * 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) {



Dec 29, 2015, 07:15 pm Last Edit: Dec 29, 2015, 07:36 pm by smanettone
Try running this sketch and check the output of get_jedec_id in serial monitor:
Here you are the results:

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

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


Here you are the results:

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

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?

Go Up