Friday, December 25, 2009

Software

The software (SW) was entirely written in C. I used the CCS compiler PCM, which is in my opinion very affordable and amazingly good, together with the MPLAB IDE development platform (free). For this project, the SW should be able to handle following requirements:
  • Support serial communication (RX and TX) @ 115,200 baud (bluetooth module)
  • Generate audible tones (440, 2300 and 2700 Hz)
  • Detect and debounce the hook switch and the rotary dial contacts
  • Count the dialed pulses and store the digits
  • Provide real time timers with fine resolution (typically msecs)
  • Able to handle multiple tasks
  • State-Event driven (using a state machine)
I won't get into much detail, since the code is well documented and self explanatory. I will only explain the highlights of its operation.

Structure
The SW is based on a multitask, state-event-driven structure. Each task has its own timer assigned and its value can range from 1 to 65534 msecs. A master interrupt driven by PIC Timer0 (RTCC) checks every 1 msec all task timers and decrements their values if the timers are active (value 1 to 65534). If a timer is disabled (value 0xFFFF) or has expired (value 0) the master interrupt won't decrement its value.

#define     TICK        213                 //interrupt reload value 1 mSec
#INT_RTCC                               
void clock_isr()
{
    int     i;                              //local index
    set_rtcc(TICK);                         //reload timer to TICK every 1 mS
    for (i = 0; i < T_END; ++i)             //for each active task timer, decrement it
    {
        if (task_delay[i] != T_DISABLE)     //if task timer is enabled..
            if (task_delay[i] != 0)         //..and running..
                task_delay[i]--;            //..then decrement it
    }
}

The main loop checks if any task timer has expired, which in such case will run the task. Multiple tasks can have their timer expired, in which case the main loop will first execute the task with the highest priority. In case no task requires to run, the main loop also check if any serial received message is ready for processing and if any serial transmission is pending. Regular 'get strings' and 'print strings' (such as printf() functions) are not allowed, because they will hog the processor and will affect time critical tasks. The main loop is:

while(true)
{
    task_index = 0;  //start scanning from first task
    flag.run_task = false;  //test flag
    while (!flag.run_task && (task_index < T_END)) //check if a task needs to run
    {
        if (task_delay[task_index] == 0) //if task timer expired, run task
            flag.run_task = true;
        else                             //if not, search for next task until done
            task_index++;
    }
          
    if (flag.run_task)                   //if task needs to run, then run it
    {
        task_delay[task_index] = T_DISABLE; //disable further calls of same task
        switch (task_index)                 //run highest task that is ready
        {
            case T_ANALIZE_CONTACTS:    ANALIZE_CONTACTS(); break;
            case T_END_OF_ROTARY:       END_OF_ROTARY();    break;
            case T_END_OF_DIAL:         END_OF_DIAL();      break;
            case T_HOOK_FLASH:          HOOK_FLASH();       break;
            case T_BUSY_TONE:           BUSY_TONE();        break;
            case T_RING:                RING();             break;
            default: break;
        }
    }
    else                            //no task pending, work on serial messages
    {
        TX_MESSAGE(); //check if a TX message ready and send it
        RX_MESSAGE(); //check if a RXd message ready and process it
    }
}//end while loop

Serial Communication
PIC interrupt RDA is triggered every time the USART receives a character. The interrupt routine stores the received character in a receive buffer. Only the first sizeof(buffer)-1 characters are stored and the rest are discarded. A new line (\n) character determines the end of reception and the interrupt routine inserts a null (\0) character for further string analysis. The interrupt sets a flag to indicate that a message is ready to be analyzed by RX_MESSAGE().

#INT_RDA
void rs232_isr(void)
{
    int character;
    character = getc();        // Get new character
    if (character=='\n')       // If \n then line is completed
    {
        disable_interrupts(INT_RDA);   //freeze serial input while analyzes data
        buffer.rx[index.rx] = '\0';    //replace \n for \0 to the last position
        flag.rx_msg_ready = true;      //message ready to process
    }
    else
    {
        if (index.rx < sizeof(buffer.rx)-1)  //store char if buffer not full yet, otherwise ignore it
        {
            buffer.rx[index.rx] = character; //save character in buffer
            index.rx++;                      //increment index
        }
    }
}


To transmit a string another buffer is used. Different functions can store characters (commands) in the transmit buffer. Once the message is ready a flag is set and TX_MESSAGE() takes care of it. The function checks if the USART transmitter buffer is empty and then send the next character from the buffer. The operation is pretty simple using pointers and doesn't take so many memory and time resources as would a printf() command.

void    TX_MESSAGE()
{
    int  character;
    if (flag.tx_msg_ready && TRMT)  //check if needs to send message AND USART is ready
    { 
        character = *(buffer.tx + index.tx);    //read the next character to send
        TXREG = character;   //send it to UART output (triggers TX)
        if (character == '\n')                  //check if char was end of line
            flag.tx_msg_ready = false;          //transmission ends
        else
            index.tx++;                         //increment pointer to read next char
    }
}


To achieve a precise and stable communication speed of 115,200 bauds I used a 11.0592 MHz crystal. Unfortunately, the internal oscillator doesn't provide the precise rate and its accuracy is not that high.

Tone Generation
To generate tones I used the PIC Timer1. It is a 2-byte counter clocked by the master oscillator. Every time the counter rolls over it generates an interrupt. To generate the tone, I load the counter with a value that is half of the period of the tone. Every time the timer rolls over, the routine reloads the value and toggles the output port where I am producing the tone. To turn the tone on or off I enable or disable the interrupt, respectively. This allows me to generate virtually any tone with a very accurate frequency and without any noticeable jitter.

#INT_TIMER1 
void tone_isr()
{
    set_timer1(tone);                   //reload timer with tone value
    if (flag.dial0_ring1)               //if false, toggle dial port; if true, toggle ring port
        RING_TONE_O = ~RING_TONE_O;     //toggle ring tone port
    else
        DIAL_TONE_O = ~DIAL_TONE_O;     //toggle dial tone port
}

Debouncing
Debouncing and status of the contacts is accomplished by ANALYZE_CONTACTS() task. This task calls itself every 5 msecs and checks for three consecutive same-value readings from the external contacts before it declares a valid (steady-state) input. If the new steady-state value differs from a previous valid-state value, a function checks if the particular event requires any action based on the current state. Here the code how I debounce the rotary dial contact (similar for the hook contact):

flag.aux = ROTARY_IN;                 //read input port
if (flag.aux == rotary.sample_1 && flag.aux == rotary.sample_2 && flag.aux == rotary.sample_3)
{
    if (flag.aux != rotary.value)    //if all 3 samples are the same and is a change...
    {
        rotary.value = flag.aux;     //update status
        RTRY_CHANGE();               //analyze change based on phone state
    }
}
rotary.sample_3 = rotary.sample_2;   //update all samples (shift)
rotary.sample_2 = rotary.sample_1;
rotary.sample_1 = flag.aux;
task_delay[T_ANALIZE_CONTACTS] = 5;  //run this task every 5 msecs forever


States
The code is driven by a state machine. Depending on what state the phone is, the code takes different actions. Using state machines greatly simplify the code and makes it very robust. Here the states used in the code:

enum {
    IDLE,           //phone is idle (on-hook)
    DIAL_TONE,      //dial tone (before dialing 1st digit)
    DIALING,        //first digit dialed. dialing process
    TALKING,        //talking
    RINGING,        //ringing (incoming call)
    BLOCKED         //obtaining busy tone. only escape from here is to hang up
} state;

Code
I have combined multiple programming techniques and developed and fine-tuned processes over the years to make this multi-task, state-event driven concept very powerful and robust, nonetheless extremely simple. You can use the same concept with any micro-controller, including with Arduino platforms.

If you consider that you can get useful ideas and concepts from this code and project, that you can apply them in your current and future projects, or that you can help somebody else by teaching these concepts, then I'll appreciate a voluntary contribution of your convenience for keep improving the work and propagate it to others. Thank you!



Next blog: Putting all things together

    Thursday, December 24, 2009

    Preparing the Ericofon

    The phone is working!! Today I made my first call using the rotary dial and also using the voice recognition feature. I also received a phone call and the phone rang as expected (as the Ericotone ringer). Everything is working great!! I took a break debugging the software and stared preparing the Ericofon to put all the pieces together inside the phone.

    In order to fit the PCB and the battery, I have to remove some components and cables. The first component is the big capacitor on top of the rotary dial mechanism. To remove it, unscrew the screw circled in the picture. This releases the bracket holding the capacitor. To remove the capacitor, disconnect the cables connected to the screw terminals. The red cable is soldered to one of the contacts. To make a clean job I suggest to carefully unsolder the cable. If it gets too messy, just cut it.

    The next step is to remove the metal plate holding the capacitor. Remove the flat head and the phillips head screws. After removing the plate you should reinstall the flat head screw to secure the mechanism to the chassis.

    Next, unsolder (or cut) the blue, white, yellow and red cables from the transformer. Since I don't need it any more I simply slide the white sleeve over the cables and tuck it underneath the transformer. Next, cut the jumper on the contact assembly. This jumper short-circuits the rotary dial contact and won't let the dial correctly interrupt the circuit while dialing.

    To wire the telephone to the PCB I used colored stranded cable #28. I got the cable from a 3-ft DB-25 to DB-25 cable. I twisted all cables to make it easier to bundle and to handle them, and to reduce noise to the microphone.

    Since an ON/OFF switch is required, I tried to keep the shell as original as possible and avoided drilling holes. I placed a very small switch in the back of the chassis where originally the phone line cable is secured. The mini-switch protrudes out barely peeking out of the original hole, just enough to move the lever with the finger nail.

    I soldered the hook (yellow), rotary dial (orange) and common (gray) cables to the contact assembly. The two prongs on the picture are the original contacts that connect to the receiver (ear piece). Since I will use the same prongs, I connected the green cables to the contacts. This will allow at any moment to remove the shell without having to unsolder the receiver.

    The LiPo battery can be placed either on top of the dialing mechanism, or on top of the PCB. I put it on top of the mechanism. The battery sort of locks in place when moving it a little bit around. Just make sure that the battery won't interfere with the gear axis below (see picture). Secure the battery with double-sided foam strips (1/8" thick). You can get it at any crafts store (e.g. Michaels).

    Using the same type of foam, secure the PCB to the battery. Just make sure that the PCB is centered on top of the battery and doesn't interfere with any other component. (The blue cable coming out from the center of the PCB is temporary, since I am using it to debug the software).

    To avoid drilling holes I decide to put the ON/OFF switch and the battery charge connector in the rear of the telephone, where the original line cable is attached. I used a micro-switch (C&K) and a mini power adapter connector. To make some space I had to cut the metal piece on the shell and attach it with glue, so it doesn't fall off when you open the shell. I attached the electret microphone to the existing microphone copper contact. First, I covered it with a shrinking tube and then I secured the tiny microphone to it using hot glue.

    Here the final pictures (notice the tiny scale).




    Tuesday, December 22, 2009

    PCBs and Testing

    Few days ago I received the PCBs. Right after, I soldered all the SMD components in place and started testing the device. It took me around an hour to put all components in place, considering that I was very careful analyzing what component to solder first. You don't want to go into a grid-lock situation where one component it severely obstructing another. Here the board (top and bottom). Notice the dimensions.



    The hardware is working great. No bugs in the PCB :) However, I found more bugs than I expected in my code. You never realize how easy is to forget basic stuff when you write the code. Debugging the code on PICs with small pin-count is hard if you don't have the appropriate tools. In order to run breakpoints for the 16F688 you need a special header, which of course I don't have. Fortunately, I added a debug LED (DBG white dot component, right above the black JP6 connector, to the left). The LED shares a pin with one of the programming signals, however, it works great when you need to find out what's going on.

    After some hours of debugging I could temporarily connect to my cellphone and managed to dial a number. However, the Bluetooth (BT) connection constantly dropped 5-10 secs after establishing a BT connection. I monitored the 115,200 baud messages going in and out of the PIC (blue and yellow cables in the picture) but couldn't see anything abnormal. After checking that everything was setup correctly and contacting BlueGiga's tech support, I found the culprit. My cellphone doesn't support the full HFP profile. It is a three years 'old' (!) Samsung SCH-A870 phone and has an outdated HFP profile (v.1.0). The current HFP profile is v1.5 and apparently don't work together.

    I tried another phone (LG enV2) and voila! It works flawlessly! I get dial tone when BT is connected (busy tone when not), can make phone calls, rings when receiving them, even dial a phone number using voice recognition (flash feature I added). It works great!

    Next stop: get another cellphone and do some more testings before packing in into the Ericofon.

    Wednesday, December 2, 2009

    BlueTooth Ericofon

    Wouldn't be cool sitting at your favorite coffee shop with this phone on the table, and while chatting with your friends the Ericofon rings and it is a call for you? Or picking it up, hearing a dial tone, cranking up the rotary dial and dialing home to say that you will be soon in your way? Well, this is what this is about. This is an open source project on how to retrofit an extraordinary phone to make it a special, functional piece of conversation. Literally.

    The idea started when several months ago when I read about the Port-o-Rotary phone. The cool guys from SparkFun converted an ordinary rotary dial telephone into a telephone that can make cellular phone calls. My plan is to come up with a retrofit kit (open source) for a cool phone that is easy to carry, and adding some nice features to the original idea. And what better to show off the project than an Ericofon.

    After doing some research on the internet about where to get an Ericofon, I found this amazing site www.Ericofon.com. I contacted the owner, Richard Rose and told him about what I was planning to do. He promptly sent me a very nice email explaining how tight it is in there and how quickly I will run into space problems. He also said: "You're not the first to think of this, although I've never heard of anyone actually going through with the idea. I've been inside these phones for a while and I don't see being able to maintain rotary dialing with the design you have in mind." I emailed him back: "You just dared my inner engineer and geek! Game on!"

    Getting an Ericofon
    Certainly, there are many places where you can get Ericofons, specially eBay. However, if you really want to get an excellent phone, probably NOS (new old stock), try first Richard's website. His website has an amazing collection of these and other sort of classic telephones. He has been a phone collector since 1990. What impressed me most is his knowledge about these phones. His website has tons of great, detailed information about how to fix and maintain the phones and other useful and interesting information. If you really appreciate this classic phone and want to get one, I seriously recommend to contact him first.

    Inside the Ericofon
    The color of the phone I got to work on the prototype is called "Candle Glow", which is an ivory color. The model I have is a K7 without a ringer.

    Richard was right. These phones are very dense and don't have room for much inside. They don't even have a ring bell. The Swedish phones use an internal buzzer (here its sound) and the American phones use an electronic wobbler called Ericotone. The Ericotone is placed inside the neck of the shell and the ring noise is produced modulating the earphone (here its sound).

    If you ever wondered how the designers crammed all the circuitry and a rotary dial inside the little shell, you can see what is inside mine (click on the pics to see the details).


    Here are the original schematic diagrams (posted on www.ericofon.com) of the phone without ringer, with ringer (Ericotone) and seeing from the Ericotone perspective (click to enlarge).


    Conversion
    I decided to use the BlueGiga Bluetooth module WT32. This module packs a lot of features in a very small package. It supports the required HFP protocol to interface via Bluetooth to cell phones and some of its neat features include analog input and output (for voice), programmable current and voltage source for an electret microphone, Bluetooth antenna and a battery charger/management for Lithium Polymer (LiPo) batteries. The WT32 interfaces include USB, SPI and serial asynchronous (UART) protocols.

    The goal of this retrofit was to keep the phone as original as possible with minimum modifications. I am very familiar with Microchip PICs, so I decided to build the retrofit circuit around the 16F688 micro-controller and programming in C using the CCS compiler.

    The design (HW and SW) in its initial version should:
    • Generate (fake) dial tone: 440 Hz
    • Generate (fake) busy tone: 440 Hz @ 1.5 Hz rate
    • Mimic Ericotone ring: 2,300 Hz and 2,700 Hz, 10 Hz (wobble) rate
    • Support dial speed: 10 pps to 20 pps
    • Support voice recognition dialing (through 'flashing' the hook)
    • Use and recharge a Lithium-Polymer (LiPo) battery
    • Use original earphone
    Other features may be added later, such as user programmable volume levels and other features using the rotary dial. Suggestions are welcome! Post your wish list!

    In order to mimic the Ericotone, first I needed to determine the wobble frequencies. I used the original .wav recording on Richard's page and an Agilent 33120A frequency generator applying the tones to the original earphone. I checked the amplitude and waveform of the applied signal with an oscilloscope and played with an RC circuit to smooth the signal and get an acceptable, similar tone effect.

    Although I could have used a differential OP amplifier adder to provide the tones and voice to the earphone, I decided to isolate the unbalanced ring signal from the balanced output signal from the WT32.

    I designed the schematic and the PCBs using Eagle software. Note that I really didn't have too much space to cram all inside the Ericofon, so the final printed circuit board (PCB) is only 2"x1.5" (5x3.8 cms)!!. Here are the printed circuit board designs. I will post the schematic, PCB and software Eagle files for download soon.

                               Both Layers                                        Top Layer                                           Bottom Layer

    Next stop: PCB