Hi, folks:
When I am writing driver for my TTS module, I have some wired problem. The module has a status pin that will drop to low when it’s ready to take another batch of text. So I decided to put UART communication between MCU and TTS module in a thread. It usually takes seconds to minutes to finish TTS depending on the length of text. So it makes sense to suspend the TTS thread after it sends text to TTS module and resume it from the main thread upon InterruptEdgeLow. That what I planned and it largely worked.
Please have a look at my code attached below. The wired thing is, I have to add an extra
ttsThread.Suspend();
at the beginning of ttsThread, otherwise the first UART text would not be sent to TTS module/executed by TTS module. I am not sure what the problem is. The way it is works, I mean having an extra suspend() at the beginning is not too big a deal but I still want to figure this out.
Does it have anything to do with how interrupt is handled by NTMF? When TTS module first powers up, the status pin will remain high until the module is ready Will this low edge register into interrupt queue and then resumes the first suspend()?
Thanks in advance. The following is my code, all that matters is the ttsThread, interrupt event handler.
using System;
using System.Threading;
using System.IO.Ports;
using System.Text;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;
namespace TTS_Module
{
public class Program
{
private static byte[] ttsTalkback = new byte[10];
private static SerialPort tts;
private static OutputPort apSD = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di22, false);
private static OutputPort ttsReset = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di24, true);
private static InterruptPort ttsRdy = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di32, true, Port.ResistorMode.PullDown, Port.InterruptMode.InterruptEdgeLow);
private static Thread ttsThread = new Thread(ttsThreadMethod);
public static void Main()
{
tts = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
tts.Open();
tts.DataReceived += new SerialDataReceivedEventHandler(tts_DataReceived);
ttsRdy.OnInterrupt += new NativeEventHandler(ttsRdy_OnInterrupt);
//start the text to speech thread, while doing other staff in main thread.
ttsThread.Start();
/* do your staff here.
while (true)
{
// Sleep for 500 milliseconds
Thread.Sleep(500);
//
}
*/
Thread.Sleep(Timeout.Infinite);
}
private static void ttsThreadMethod()
{
apSD.Write(true); // turning on power amplifer actually has nothing to do with TTS IC but somehow the following thread.Suspend is necessary, otherwise the immediate following text/command will not be excuted.
ttsThread.Suspend();
Synthesis("[h2][g2]"); // configure for proper English TTS,[h?]: treatment of word, letter by letter or normal; [g?]: numbers to be read in Chinese or English
ttsThread.Suspend();
Synthesis("[m17]Hi, My name is John.[p200][m20]and my name is Catherine[m17]"); // profile selection, [m?] I prefer [m17] so I set it back to John at the end.
ttsThread.Suspend();
Synthesis("[f0]How do you do? [p200][f1]How do you do?"); // demo for use of tag "[f?]",word by word or normal
ttsThread.Suspend();
Synthesis("I can read words letter by letter like cat is spelled as[h1]cat[h2]"); // demo for use of tag "[h?]" :automatic, letter by letter or nornal
ttsThread.Suspend();
Synthesis("I can also say numbers digit by digit like [n1]123 or as a whole number[p200][n0]123[n2]"); // demo for use of tag "[n?]", treatment of numbers: value or number by number
ttsThread.Suspend();
Synthesis("I can talk [s0] very very slow [s5]Or [p50] normal. Or [p50][s7] faster,[s8][p50] faster,or[s10][p50]even faster![s5]"); // demo for use of tag "[s?]" speed of speech, 0-10
ttsThread.Suspend();
Synthesis("[v1]I can also whisper,[v4]or louder![v7]louder and [v10] even louder.[v5]"); // demo for use of tag "[v?]" volume of speech, 0-10
ttsThread.Suspend();
Synthesis("I can change my pitch too. like [t0]That's enough![t9]That's enough![[t10][s1]OK oK.[t5][s5]"); // demo for use of tag "[v?]" tone of speech
ttsThread.Suspend();
Synthesis("That's all about text control.[p200]Next we will listen to some recorded tones.First,[x0]sound101 through sound140[x1]"); // use of recorded message or not
ttsThread.Suspend();
Synthesis("sound101,sound102,sound103,sound104,sound105,sound106,sound107,sound108,sound109,sound110,sound111,sound112,sound113,sound114,sound115,sound116,sound117,sound118,sound119,sound120,sound121,sound122,sound123,sound124,sound125,sound126,sound127,sound128,sound129,sound130,sound131,sound132,sound133,sound134,sound135,sound136,sound137,sound138,sound139,sound140");
ttsThread.Suspend();
Synthesis("OK, more recorded tones. [x0]sound201 through sound240[x1]");
ttsThread.Suspend();
Synthesis("sound201,sound202,sound203,sound204,sound205,sound206,sound207,sound208,sound209,sound210,sound211,sound212,sound213,sound214,sound215,sound216,sound217,sound218,sound219,sound220,sound221,sound222,sound223,sound224,sound225,sound226,sound227,sound228,sound229,sound230,sound231,sound232,sound233,sound234,sound235,sound236,sound237,sound238,sound239,sound240");
ttsThread.Suspend();
Synthesis("Well, even more recorded tones. 90 alarm tones,sound301,sound302,sound303,sound304,sound305,sound306,sound307,sound308,sound309,sound310,sound311,sound312,sound313,sound314,sound315,sound316,sound317,sound318,sound319,sound320,sound321,sound322,sound323,sound324,sound325,sound326,sound327,sound328,sound329,sound330,sound331,sound332,sound333,sound334,sound335,sound336,sound337,sound338,sound339,sound340,sound341,sound342,sound343,sound344,sound345,sound346,sound347,sound348,sound349,sound350,sound351,sound352,sound353,sound354,sound355,sound356,sound357,sound358,sound359,sound360,sound361,sound362,sound363,sound364,sound365,sound366,sound367,sound368,sound369,sound370,sound371,sound372,sound373,sound374,sound375,sound376,sound377,sound378,sound379,sound380,sound381,sound382,sound383,sound384,sound385,sound386,sound387,sound388,sound389,sound390");
ttsThread.Suspend();
Synthesis("Hold on, 30 more tones: sound401,sound402,sound403,sound404,sound405,sound406,sound407,sound408,sound409,sound410,sound411,sound412,sound413,sound414,sound415,sound416,sound417,sound418,sound419,sound420,sound421,sound422,sound423,sound424,sound425,sound426,sound427,sound428,sound429,sound430");
ttsThread.Suspend();
Synthesis("ATT. Festival"); // two recorded messages stored in external SPI flash, read by ATT natural language and Festival reference engine, named as ATT and Festival respectively.
}
public static void Synthesis(String MSG)
{
byte[] Stream = new byte[MSG.Length + 5]; // if this function is frequently called, consider define Stream as static. The way it is involves frequent GC activation which can slow down system.
Stream[0] = 0xFD; // frame head
Stream[1] = (byte)((MSG.Length + 2) >> 8); // length, high byte
Stream[2] = (byte)((MSG.Length + 2) & 0xFF); // length, low byte
Stream[3] = 0x01; // tts synthesis command
Stream[4] = 0x01; // encoding
Array.Copy(Encoding.UTF8.GetBytes(MSG), 0, Stream, 5, MSG.Length); // Move payload MSG into data region of TTS frame
tts.Write(Stream, 0, Stream.Length);
}
public static void issueCMD(byte cmd)
{
byte[] Stream = new byte[4];
Stream[0] = 0xFD;
Stream[1] = 0x00;
Stream[2] = 0x01;
Stream[3] = cmd;
tts.Write(Stream, 0, 4);
}
private static void tts_DataReceived(object Sender, SerialDataReceivedEventArgs e)
{
tts.Read(ttsTalkback,0,tts.BytesToRead);
}
private static void ttsRdy_OnInterrupt(uint port, uint state, DateTime Time )
{
if (ttsThread.ThreadState == ThreadState.Suspended)
ttsThread.Resume();
}
}
}