Ticker

6/recent/ticker-posts

Arduino: Text-to-Speech talking clock



Today’s project is an Arduino talking clock. Whenever one moves its hand in front of the proximity sensor, the clock will talk the current time. As for the hardware, I will use one Arduino Mega with a MikroElektronika Arduino Mega click shield, and three click boards: Proximity, RTC2, and Text-To-Speech click. All three click boards were configured for 5V operation by placing the PWR_SEL jumper in the 5V position.

I chose Arduino Mega for several reasons: first is that I needed three mikroBUS sockets for the click boards, and the MEGA Click shield was a perfect choice. Second, the S1V30120 IC onboard the Text-to_Speech click needs a large chunk of data to be uploaded in the initialization phase. The Mega has 256kb or FLASH memory, so plenty of space to store that data.

Another reason for choosing the Arduino Mega is that both RTC2 and Proximity click boards use I2C communication. The VCNL4010 onboard the Proximity click is not fussy regarding I2C communication. As the datasheet specifies, “The stop condition between these write and read sequences is not mandatory. It works also with a repeated start condition”. On the other hand, the DS1307 serial real-time clock (RTC) is more strict regarding I2C communication, and it requires repeated start conditions to be sent over the I2C bus as part of its communication protocol.

Unfortunately, the I2C libraries for Arduino Due (and its cousin Flip & Click) are still flawed, and a repeated start condition cannot be issued on the SAM3X8E. Ironically, this problem is at least three years old. In that time there were a few updates of the Arduino IDE, including the major jump to 1.8.0 version just after the two Arduino teams came back together as one. Still, no one cares about fixing the I2C communication on the SAM boards.

So, three click boards, three problems to solve: getting the distance, setting and keeping the current time, and doing all the talking. Luckily, all three problems were already solved. Code libraries for VCNL4010 and DS1307 are already written, and I’ve covered the basics of S1V30120 text-to-speech in another blog post. Parsing the time into words is also solved, I’ve done it before in my PIC18F45K22 “word clock” with GLCD display.

As usual with MikroElektronika click boards, building the hardware is just like playing with Lego bricks. The Text-to-Speech click board is placed in the first socket of the Mega Click Shield, the Proximity click stays in the second socket, and the RTC2 click occupies the third mikroBUS socket. As both Proximity click and RTC2 click boards use I2C communication, their position can be swapped and the project will still work.

Arduino Mega talking clock with S1V30120, VCNL4010, and DS1307

As for the software, I used the libraries provided by Adafuit, as over the course of time I found their libraries are second to none. The link for the VCNL4010 library is https://github.com/adafruit/Adafruit_VCNL4010. You can get the code for DS1307 from https://github.com/adafruit/RTClib.

The Text-to-Speech click board uses SPI communication, plus three dedicated control lines. So, leave it in the first socket (or you will have to change the pin definitions yourself). The code is largely based on my previous tutorial.

Arduino: Talking clock code

As a prerequisite, running the code examples from the libraries is a good idea, so you’ll know everything works fine. Also, running the code example for VCNL4010 helps to find the right threshold. Mine is 2400, for a detection distance of about 6-7cm. This is what you should get on the serial monitor for the VCNL4010 example:

VCNL4010 testFound VCNL4010Ambient: 516Proximity: 2185

The DS1307 example produced the following output:

2003/2/10 (Monday) 17:37:34 since midnight 1/1/1970 = 1044898654s = 12093d now + 7d + 30s: 2003/2/18 6:7:40

Setting the time can be done by uncommenting the line:

// This line sets the RTC with an explicit date & time, for example to set// January 21, 2014 at 3am you would call:rtc.adjust(DateTime(2017, 2, 9, 15, 28, 1));

Much to my dismay, nothing happened at first. I found that the battery was dead, although this is a brand new RTC2 click board. OK, a new CR3032 battery, and things were back to normal:

2017/2/9 (Thursday) 3:33:48 since midnight 1/1/1970 = 1486611228s = 17206d now + 7d + 30s: 2017/2/16 16:3:54

Finally, the Text-To-Speech code example. Here I’ve changed some pin definitions to match the Arduino Mega pinout:

#define S1V30120_RST    49#define S1V30120_RDY    10#define S1V30120_CS     53#define S1V30120_MUTE   A0

I also moved the S1V30120 initialization data into FLASH memory, to work with the ATMEGA 2560. For this, in the file text_to_speech_img.h I have changed the variable definition

const char TTS_INIT_DATA[]  =

to

const char TTS_INIT_DATA[] PROGMEM =

and also I’ve updated the following function to work with the data stored in FLASH:

bool S1V30120_load_chunk(unsigned short chunk_len)
{
  // Load a chunk of data
  char len_msb = ((chunk_len + 4) & 0xFF00) >> 8;
  char len_lsb = (chunk_len + 4) & 0xFF;
  digitalWrite(S1V30120_CS,LOW);
  SPI.beginTransaction(SPISettings(750000, MSBFIRST, SPI_MODE3));
  SPI.transfer(0xAA);  // Start Message Command
  SPI.transfer(len_lsb);  // Message length is 2048 bytes = 0x0800
  SPI.transfer(len_msb);  // LSB first
  SPI.transfer(0x00);  // Send SC_BOOT_LOAD_REQ (0x1000)
  SPI.transfer(0x10);
  for (int chunk_idx = 0; chunk_idx < chunk_len; chunk_idx++)
  {
    //SPI.transfer(TTS_INIT_DATA[TTS_DATA_IDX]);
    SPI.transfer(pgm_read_byte_near(TTS_INIT_DATA + TTS_DATA_IDX));
    TTS_DATA_IDX++;
  }
  SPI.endTransaction();
  digitalWrite(S1V30120_CS,HIGH);
  return S1V30120_parse_response(ISC_BOOT_LOAD_RESP, 0x0001, 16);
}

Notice how I use the pgm_read_byte_near macro instead of just reading from the array.

With all those changes, the code example should run fine on the Mega, and you should hear some words from the text-to-speech click.

And now it’s time to put all together and write the final code. Just double click on the code to expand it. Or, just download it from this link.

#include 
#include 
#include 
#include 
#include 
#include "S1V30120_defines.h"
#include "text_to_speech_img.h"
#include "Adafruit_VCNL4010.h"
#include "RTClib.h"

#define S1V30120_RST    49
#define S1V30120_RDY    10
#define S1V30120_CS     53
#define S1V30120_MUTE   A0

Adafruit_VCNL4010 vcnl;

RTC_DS1307 rtc;

String mytext = "I'm a talking clock! Put your hand in front of me and I will tell you the time!";

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

char its = "It's ";

// one empty position for 0 makes easier to convert the time into words
char HoursofDay [12][8] = {"twelfe ", "one ", "two ", "three ", "four ", "five ", "six ", "seven ", "eight ", "nine ",
"ten ", "eleven "};

char Minutes [11][18]= {"five past ", "ten past ", "quarter past ", "twenty past", "twenty five past ", "half past ",
"thirty five past ", "twenty to ", "quarter to ", "ten to ", "five to "};

uint16_t dist;
uint16_t myhour;
uint16_t myminutes;

// Variables
// Most received messages are 6 bytes
char rcvd_msg[20] = {0};

static volatile char send_msg[200] = {0};
static volatile unsigned short msg_len;
static volatile unsigned short txt_len;

unsigned short tmp;
long idx;
bool success;

// Used to download image data. This is changed by the
// This is why is declares as static volatile.
// Note: unsigned short is max 32767, while our image data is 31208 in length
// one must change this to unsigned long if future image data becomes larger
static volatile unsigned short TTS_DATA_IDX;

void setup() {
  //Pin settings
  pinMode(S1V30120_RST, OUTPUT);
  pinMode(S1V30120_RDY, INPUT);
  pinMode(S1V30120_CS, OUTPUT);
  pinMode(S1V30120_MUTE, OUTPUT);

  // Unmute
  digitalWrite(S1V30120_MUTE,LOW);

  // for debugging
  Serial.begin(9600);

  SPI.begin();

  S1V30120_reset();
  tmp = S1V30120_get_version();
  if (tmp == 0x0402)
  {
    Serial.println("S1V30120 found. Downloading boot image!");
  }
  success = S1V30120_download();
  Serial.print("Boot image download: ");
  show_response(success);
  success = S1V30120_boot_run();
  Serial.print("Boot image run: ");
  show_response(success);
  delay(150); // Wait for the boot image to execute
  Serial.print("Registering: ");
  success = S1V30120_registration();
  show_response(success);
  // Once again print version information
  S1V30120_get_version();
  success = S1V30120_configure_audio();
  Serial.print("Configuring audio: ");
  show_response(success);
  success = S1V30120_set_volume();
  Serial.print("Setting volume: ");
  show_response(success);

  success = S1V30120_configure_tts();
  Serial.print("Configure TTS: ");
  show_response(success);

  success = S1V30120_speech(mytext,0);
  Serial.print("Speaking: ");
  show_response(success);
  Serial.println(" ");

  // Initialize VCNL4010
  Serial.println("VCNL4010 test");
  if (! vcnl.begin()){
    Serial.println("Sensor not found :(");
    while (1);
  }
  Serial.println("Found VCNL4010");

  // RTC2 init
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
  Serial.println("Clock mode");
}

void loop() {

  dist = vcnl.readProximity();
  // Serial.print("Distance: ");
  // Serial.println(dist);
  if (dist > 2400){
    // Speak the time
    //send_msg = {""};
    DateTime now = rtc.now();
    success = S1V30120_speech("It's ",0);
    myminutes = now.minute();
    myminutes = floor (myminutes / 5);
    Serial.println(myminutes);
    if (myminutes > 0){
      S1V30120_speech(Minutes[myminutes-1],0);
    }
    myhour = now.hour();
    if (myminutes > 7){
      myhour = myhour +1;
    }
    if (myhour > 12){
      myhour = myhour - 12;
    }
    success = S1V30120_speech(HoursofDay[myhour],0);
    success = S1V30120_speech(" o'clock.        Today is ",0);
    success = S1V30120_speech(daysOfTheWeek[now.dayOfTheWeek()],0);
    Serial.print("Speaking: ");
    show_response(success);
    delay(2000); // don't talk too much :)
  }
}

// This function resets the S1V30120 chip and loads the firmware code
void S1V30120_reset(void)
{
  digitalWrite(S1V30120_CS,HIGH); // S1V30120 not selected
  digitalWrite(S1V30120_RST,LOW);
  // send one dummy byte, this will leave the clock line high
  SPI.beginTransaction(SPISettings(750000, MSBFIRST, SPI_MODE3));
  SPI.transfer(0x00);
  SPI.endTransaction();
  delay(5);
  digitalWrite(S1V30120_RST,HIGH);
  delay(150);
}

unsigned short S1V30120_get_version(void)
{
    // Querry version
    unsigned short S1V30120_version = 0;
    unsigned short tmp_disp;
    // Sending ISC_VERSION_REQ = [0x00, 0x04, 0x00, 0x05];
    char msg_ver[] = {0x04, 0x00, 0x05, 0x00};
    S1V30120_send_message(msg_ver, 0x04);

    //wait for ready signal
    while(digitalRead(S1V30120_RDY) == 0);

    // receive 20 bytes
    digitalWrite(S1V30120_CS,LOW);
    SPI.beginTransaction(SPISettings(750000, MSBFIRST, SPI_MODE3));
    // wait for message start
    while(SPI.transfer(0x00) != 0xAA);
    for (int i = 0; i < 20; i++)
    {
      rcvd_msg[i]= SPI.transfer(0x00);
    }
    // Send 16 bytes padding
    S1V30120_send_padding(16);
    SPI.endTransaction();
    digitalWrite(S1V30120_CS,HIGH);
    S1V30120_version = rcvd_msg[4] << 8 | rcvd_msg[5];
    Serial.print("HW version ");
    Serial.print(rcvd_msg[4],HEX);
    Serial.print(".");
    Serial.println(rcvd_msg[5],HEX);
    Serial.print("Firmware version ");
    Serial.print(rcvd_msg[6],HEX);
    Serial.print(".");
    Serial.print(rcvd_msg[7],HEX);
    Serial.print(".");
    Serial.println(rcvd_msg[16],HEX);
    Serial.print("Firmware features ");
    Serial.println(((rcvd_msg[11] << 24) | (rcvd_msg[10] << 16) | (rcvd_msg[9] << 8) | rcvd_msg[8]),HEX);
    Serial.print("Firmware extended features ");
    Serial.println(((rcvd_msg[15] << 24) | (rcvd_msg[14] << 16) | (rcvd_msg[13] << 8) | rcvd_msg[12]),HEX);
    return S1V30120_version;
}

bool S1V30120_download(void)
{
   // TTS_INIT_DATA is of unsigned char type (one byte)
   unsigned short len = sizeof (TTS_INIT_DATA);
   unsigned short fullchunks;
   unsigned short remaining;
   bool chunk_result;
   long data_index = 0;
   Serial.print("TTS_INIT_DATA length is ");
   Serial.println(len);
   // We are loading chunks of data
   // Each chunk, including header must be of maximum 2048 bytes
   // as the header is 4 bytes, this leaves 2044 bytes to load each time
   // Computing number of chunks
   fullchunks = len / 2044;
   remaining = len - fullchunks * 2044;
   Serial.print("Full chunks to load: ");
   Serial.println(fullchunks);
   Serial.print("Remaining bytes: ");
   Serial.println(remaining);
   // Load a chunk of data
   for (int num_chunks = 0; num_chunks < fullchunks; num_chunks++)
   {
     chunk_result = S1V30120_load_chunk (2044);
     if (chunk_result)
     {
       Serial.println("Success");
     }
     else
     {
       Serial.print("Failed at chunk ");
       Serial.println(num_chunks);
       return 0;
     }
   }
   // Now load the last chunk of data
   chunk_result = S1V30120_load_chunk (remaining);
   if (chunk_result)
   {
     Serial.println("Success");
   }
   else
   {
     Serial.print("Failed at last chunk ");
     return 0;
   }
// All was OK, returning 1
return 1;
}

bool S1V30120_load_chunk(unsigned short chunk_len)
{
  // Load a chunk of data
  char len_msb = ((chunk_len + 4) & 0xFF00) >> 8;
  char len_lsb = (chunk_len + 4) & 0xFF;
  digitalWrite(S1V30120_CS,LOW);
  SPI.beginTransaction(SPISettings(750000, MSBFIRST, SPI_MODE3));
  SPI.transfer(0xAA);  // Start Message Command
  SPI.transfer(len_lsb);  // Message length is 2048 bytes = 0x0800
  SPI.transfer(len_msb);  // LSB first
  SPI.transfer(0x00);  // Send SC_BOOT_LOAD_REQ (0x1000)
  SPI.transfer(0x10);
  for (int chunk_idx = 0; chunk_idx < chunk_len; chunk_idx++)
  {
    //SPI.transfer(TTS_INIT_DATA[TTS_DATA_IDX]);
    SPI.transfer(pgm_read_byte_near(TTS_INIT_DATA + TTS_DATA_IDX));
    TTS_DATA_IDX++;
  }
  SPI.endTransaction();
  digitalWrite(S1V30120_CS,HIGH);
  return S1V30120_parse_response(ISC_BOOT_LOAD_RESP, 0x0001, 16);
}

bool S1V30120_boot_run(void)
{
    char boot_run_msg[] = {0x04, 0x00, 0x02, 0x10};
    S1V30120_send_message(boot_run_msg, 0x04);
    return S1V30120_parse_response(ISC_BOOT_RUN_RESP, 0x0001, 8);
}

void show_response(bool response)
{
  if(response)
    Serial.println("OK!");
  else
  {
    Serial.println("Failed. System halted!");
    while(1);
  }
}

bool S1V30120_registration(void)
{
  SPI.beginTransaction(SPISettings(750000, MSBFIRST, SPI_MODE3));
  char reg_code[] = {0x0C, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  S1V30120_send_message(reg_code, 0x0C);
  return S1V30120_parse_response(ISC_TEST_RESP, 0x0000, 16);
}


// Message parser
// This function receives as parameter the expected response code and result
// And returns 1 if the expected result is received, 0 otherwise
// As an observation, most messages are 6 bytes in length
// (2 bytes length + 2 bytes response code + 2 bytes response)
bool S1V30120_parse_response(unsigned short expected_message, unsigned short expected_result, unsigned short padding_bytes)
{
    unsigned short rcvd_tmp;

    //wait for ready signal
    while(digitalRead(S1V30120_RDY) == 0);

    // receive 6 bytes
    digitalWrite(S1V30120_CS,LOW);
    SPI.beginTransaction(SPISettings(750000, MSBFIRST, SPI_MODE3));
    // wait for message start
    while(SPI.transfer(0x00) != 0xAA);
    for (int i = 0; i < 6; i++)
    {
      rcvd_msg[i]= SPI.transfer(0x00);
    }
    // padding bytes
    S1V30120_send_padding(padding_bytes);
    SPI.endTransaction();
    digitalWrite(S1V30120_CS,HIGH);
    // Are we successfull? We shall check
    rcvd_tmp = rcvd_msg[3] << 8 | rcvd_msg[2];
    if (rcvd_tmp == expected_message) // Have we received ISC_BOOT_RUN_RESP?
    {
       // We check the response
       rcvd_tmp = rcvd_msg[5] << 8 | rcvd_msg[4];
       if (rcvd_tmp == expected_result) // success, return 1
         return 1;
       else
         return 0;
    }
    else // We received something else
    return 0;
}

// Padding function
// Sends a num_padding_bytes over the SPI bus
void S1V30120_send_padding(unsigned short num_padding_bytes)
{
  for (int i = 0; i < num_padding_bytes; i++)
  {
     SPI.transfer(0x00);
  }
}

// Functions that run in normal mode

void S1V30120_send_message(volatile char message[], unsigned char message_length)
{
  // Check to see if there's an incoming response or indication
  while(digitalRead(S1V30120_RDY) == 1);  // blocking
  // OK, we can proceed
  digitalWrite(S1V30120_CS,LOW);
  SPI.beginTransaction(SPISettings(750000, MSBFIRST, SPI_MODE3));
  SPI.transfer(0xAA);  // Start Message Command
  for (int i = 0; i < message_length; i++)
  {
    SPI.transfer(message[i]);
  }
  SPI.endTransaction();
}

bool S1V30120_configure_audio(void)
{
  msg_len = 0x0C;
  send_msg[0] = msg_len & 0xFF;          // LSB of msg len
  send_msg[1] = (msg_len & 0xFF00) >> 8; // MSB of msg len
  send_msg[2] = ISC_AUDIO_CONFIG_REQ & 0xFF;
  send_msg[3] = (ISC_AUDIO_CONFIG_REQ & 0xFF00) >> 8;
  send_msg[4] = TTS_AUDIO_CONF_AS;
  send_msg[5] = TTS_AUDIO_CONF_AG;
  send_msg[6] = TTS_AUDIO_CONF_AMP;
  send_msg[7] = TTS_AUDIO_CONF_ASR;
  send_msg[8] = TTS_AUDIO_CONF_AR;
  send_msg[9] = TTS_AUDIO_CONF_ATC;
  send_msg[10] = TTS_AUDIO_CONF_ACS;
  send_msg[11] = TTS_AUDIO_CONF_DC;
  S1V30120_send_message(send_msg, msg_len);
  return S1V30120_parse_response(ISC_AUDIO_CONFIG_RESP, 0x0000, 16);
}

// set gain to 0 db
bool S1V30120_set_volume(void)
{
  char setvol_code[]={0x06, 0x00, 0x0A, 0x00, 0x00, 0x00};
  S1V30120_send_message(setvol_code, 0x06);
  return S1V30120_parse_response(ISC_AUDIO_VOLUME_RESP, 0x0000, 16);
}

bool S1V30120_configure_tts(void)
{
  msg_len = 0x0C;
  send_msg[0] = msg_len & 0xFF;          // LSB of msg len
  send_msg[1] = (msg_len & 0xFF00) >> 8; // MSB of msg len
  send_msg[2] = ISC_TTS_CONFIG_REQ & 0xFF;
  send_msg[3] = (ISC_TTS_CONFIG_REQ & 0xFF00) >> 8;
  send_msg[4] = ISC_TTS_SAMPLE_RATE;
  send_msg[5] = ISC_TTS_VOICE;
  send_msg[6] = ISC_TTS_EPSON_PARSE;
  send_msg[7] = ISC_TTS_LANGUAGE;
  send_msg[8] = ISC_TTS_SPEAK_RATE_LSB;
  send_msg[9] = ISC_TTS_SPEAK_RATE_MSB;
  send_msg[10] = ISC_TTS_DATASOURCE;
  send_msg[11] = 0x00;
  S1V30120_send_message(send_msg, msg_len);
  return S1V30120_parse_response(ISC_TTS_CONFIG_RESP, 0x0000, 16);
}

// bool S1V30120_speech(void)
bool S1V30120_speech(String text_to_speech, unsigned char flush_enable)
{
  bool response;
  txt_len = text_to_speech.length();
  msg_len = txt_len + 6;
  send_msg[0] = msg_len & 0xFF;          // LSB of msg len
  send_msg[1] = (msg_len & 0xFF00) >> 8; // MSB of msg len
  send_msg[2] = ISC_TTS_SPEAK_REQ & 0xFF;
  send_msg[3] = (ISC_TTS_SPEAK_REQ & 0xFF00) >> 8;
  send_msg[4] = flush_enable; // flush control
  for (int i = 0; i < txt_len; i++)
  {
     send_msg[i+5] = text_to_speech[i];
  }
  send_msg[msg_len-1] = '\0'; // null character
  S1V30120_send_message(send_msg, msg_len);
  response = S1V30120_parse_response(ISC_TTS_SPEAK_RESP, 0x0000, 16);
  while (!S1V30120_parse_response(ISC_TTS_FINISHED_IND, 0x0000, 16)); // blocking
  return response;
    }

// Defines parameters for S1V30120

// Commands
// Boot mode
#define ISC_VERSION_REQ			0x0005
#define ISC_BOOT_LOAD_REQ		0x1000
#define ISC_BOOT_RUN_REQ 		0x1002
#define ISC_TEST_REQ 			0x0003

// Normal (run) mode

#define ISC_AUDIO_CONFIG_REQ 	0x0008
#define ISC_AUDIO_VOLUME_REQ	0x000A
#define ISC_AUDIO_MUTE_REQ		0x000C

#define ISC_TTS_CONFIG_REQ		0x0012
//11 kHz
#define ISC_TTS_SAMPLE_RATE		0x01
#define ISC_TTS_VOICE			0x00
#define ISC_TTS_EPSON_PARSE  	0x01
#define ISC_TTS_LANGUAGE  		0x00
// 200 words/min
#define ISC_TTS_SPEAK_RATE_LSB	0xC8
#define ISC_TTS_SPEAK_RATE_MSB	0x00
#define ISC_TTS_DATASOURCE		0x00


#define ISC_TTS_SPEAK_REQ 		0x0014




// Response messages
// Boot mode
#define ISC_VERSION_RESP		0x0006
#define ISC_BOOT_LOAD_RESP		0x1001
#define ISC_BOOT_RUN_RESP 		0x1003
#define ISC_TEST_RESP 			0x0004

// Normal (run) mode

#define ISC_AUDIO_CONFIG_RESP   0x0009
#define ISC_AUDIO_VOLUME_RESP	0x000B
#define ISC_AUDIO_MUTE_RESP		0x000D

#define ISC_TTS_CONFIG_RESP		0x0013


#define ISC_TTS_SPEAK_RESP 		0x0015

// Fatal error indication
#define ISC_ERROR_IND			0x0000

// Request blocked
#define ISC_MSG_BLOCKED_RESP	0x0007

#define ISC_TTS_FINISHED_IND	0x0021



// Parameters

// Audio config
// See page 42 in S1V30120 Message Protocol Specification

// MONO = 0x00, all other values = reserved
#define TTS_AUDIO_CONF_AS 	0x00

// Audio gain = +18 db
#define TTS_AUDIO_CONF_AG 	0x43

// Audio amp not selected
#define TTS_AUDIO_CONF_AMP	0x00

// Sample rate 11kHz
#define TTS_AUDIO_CONF_ASR 	0x01

// Audio routing: application to DAC
#define TTS_AUDIO_CONF_AR 	0x00

// Audio tone control: depreciated, set to 0
#define TTS_AUDIO_CONF_ATC 	0x00

// Audio click source: internal, set to 0
#define TTS_AUDIO_CONF_ACS 	0x00

// DAC is on only while speech decoder
// or TTS synthesis is outputting audio
#define TTS_AUDIO_CONF_DC 	0x00

// TTS Config
    

Post a Comment

0 Comments