Archive for November, 2008

Project rising from the dead

November 18, 2008

This will be a very short post.

I just got four new PCBs from a professional manufacturer (albeit without through-hole plating of “vias”) and I am about to start over rebuilding the circuit on at least one of them.

My building and testing plan is slightly different this time. I have already verified all I needed to verify about the interworking of the PIC and the 3210, so I ’d rather go for a cleaner build and easier hardware debugging. Thus, I ’ll first do the circuitry around the PIC, then test and verify all is OK with that; then I ’ll do the circuitry around the 3210, then test and verify all is OK with that too (which is the point where my project died last time); finally I ’ll do the circuitry around the 3201 (and yes, you guessed it right, then test and verify everything is OK). Don’t worry about my terse wording, I ’ll post all the gory details about the course of my build and tests as soon as I have them — after all, that’s exactly where the fun is, or not?

In the meantime, I have uploaded the firmware and the PC software source onto the project’s sourceforge site (actually, the site itself shows no code, you should look at the cvs tree) and I plan doing so soon for the Eagle sources as well.

I know every blog reader (supposing that anyone is reading this blog) is wishing the project a better luck this time. Thank you truly, right now that’s exactly what my Open USB FXS project really needs!

Update Nov 28 2008: I have now built the PIC part of my circuit onto one of my new PCBs. Initially the board remained dead, but now I am used to such bad surprises. So I checked and I noticed that I had forgotten CUSB. After adding that too, the green LED sprang to life, so good news here. There is one weird result though: when the PIC runs in bootloader mode and is being controlled by the PICDEM program (the PC controller for loading “userspace” firmware), the LED stops flashing. I ought to look at this some day, however since everything else seems OK (the bootloader works and uploads my userspace firmware fine), I ‘ll leave it for now. The uploaded firmware runs just fine as well (only, of course, since there is no 3210 on the board, the firmware fails when it tries to talk to it over SPI). So, good news up to now, and I am moving on with the 3210 part. An update or a new post ought to be up on this blog by some time next week. Stay in tune!

Some good results, but project goes R.I.P.

November 9, 2008

As you may guess from the title of this post, things went as good and as bad as they could. But let′s take things in order.

The first thing after finishing the solderwork was to do a few measurements to make sure I had no shorts. Everything OK there, so I went on. An accidental drop of my board on th floor resulted in the +5V line of the USB receptacle getting disconnected (I have already said that my home-made PCB was not first quality), so I  had to fix that. Done, then everything was looking OK, so I had to try the DC-DC converter.

To do that, I had to write Direct Registers and one Indirect Register of the 3210 (namely, from the DC-DC converter Excel, I had to set DR#92 to 202, DR#93 to 12, DR#74 to 44 and IR#40 to 0). Plus, by doing some reading, I found that I had to set DR#14 to 0 in order to bring the DC-DC converter up.

I could write the required code in two places, either in PIC firmware, or in software. A quick look at the Zaptel driver informed me that the authors there provided four functions (read DR, write DR, read IR, write IR) that interface with a 32xx chip and then all work is done via these four functions in the kernel driver space. This convinced me to confine my newly-acquired firmware expertise into writing the equivalent of these functions only, and do the rest of the work in my .NET controller program (remember that I am targetting this project for Linux, but in the meantime I am doing the development work in my home PC which runs Windows).

Actually, the “read DR” function I had already written, so I only had to write three more functions. I decided to deviate a bit from the zaptel code, and write down a debug version of the “write DR”, which would check back the value just written to a register, by re-reading the register and doing a compare. Then, I copy-pasted these two functions into respective ones for indirect registers. It seems that copy-pasting introduced just about every bug typical to a beginner in programming in only twenty or so lines of code… After two days of fruitless debugging, during which the 3210 was driven into a non-responsive state, I erased all the code of the indirect register functions and re-wrote that from scratch. This time everything worked fine.

I thought that now it was easy to change my .NET program to display all registers. Well, yes, it was easy, but it required extensive copy-pasting in order to draw the GUI, so I let go after drawing up to DR#20. Here is what my controller program’s GUI looked like at the time:

controllerversionminus1

Then, I wrote a little sequence of register read/writes to bring up the DC-DC converter and then monitor its output via DR#82 (DR#82 monitors the DC-DC converter voltage, consult the 3210 datasheet for details). The picture above shows how close I (ever) got: the value of DR#82, appropriately translated into a voltage, is showing 63V, where the theoretical value should be 65V. Not bad at all! I shut down my computer and went to sleep late at night.

It turned out that this would be my project’s best result.

The next day, DR#82 started to show lower and lower measured output voltages, until a few days later it reached something as low as 2V and stayed there (of course I measured the same voltage using a meter; DR#82 was not lying, something was wrong indeed).

Soon this turned into my worse nightmare: my circuit was not working correctly, plus it was exhibiting variable behavior, and I could not tell why. It looked like an issue in the 5V power supply of the converter, but what exactly? After one week or so of nightly measurements I tracked down the issue to a finding that I did not like: my circuit had a low resistance from 5V to GND — only 200 Ohms. I did not know for sure, but this did not feel correct, since there was no path in my circuit that should have such a low resistance. I started unsoldering some components to isolate parts of the circuit. I even unsoldered the whole 3210 (which proved to be a fatal mistake), but the 200 Ohms resistance was still there.

I finally tracked down the issue into C31, which measured an ESR of 200 Ohms. Duh!… Either the capacitor was damaged (which I doubt, since I always measure components before soldering), or its low maximum voltage (6V) had let it burn. Who knows.

Thinking that I had solved my problems, I re-soldered a new 3210 in place (fortunately, I had — and I still have — a few of these in stock). However, this time I somehow managed to introduce a short between the pins VDDD and GNDD of the 3210 (pins 30 and 31, if I remember correctly). The cause of the short was invisible with my magnifying lenses. In spite of my many attempts to fix it, each time I cleaned the area and re-connected my circuit to the USB, the short was there again, causing a continuous spike which was overheating the area (it was even audible and produced a thin line of smoke) to the degree of melting the tin flux and re-reproducing itself. While trying to remove this short, I destroyed the pads around the 3210 on my one and only PCB.

At that time, I decided to declare the project R.I.P. After all, the project had been accumulating lots of bad Karma lately: my first blog had been erased without notice, my circuit had not worked as expected and the only PCB I had had been damaged Beyond Local Repair. This was enough for me to feel that this was The End for my project.

However, David, to whom I confessed my failure, offered to send me some hardware to help me go on, plus, even more important, he stressed to me that the hardware bugs are second order, because the essense of the work is the firmware and the drivers. I was convinced by the Voice of Reason speaking through these words, thus I accepted David’s generous offer and at the same time I ordered a quad of PCBs from trade, as I probably should have done from the very beginning. And, I am going to give it a second try. It’s worth it, don’t you think? And, if you have not been reading this blog from the very beginning, it’s also worth noting once more that this project owes its existence to David!

Interlude

November 8, 2008

You may have noticed that all my previous posts are written in the past tense. This is not by accident.

I started writing this blog when I had already gotten to the stage where I was somewhat sure that my Open USB FXS design would stand a chance of serving its purpose. I had many doubts when I first began with that project (especially given my not-so-relevant background), and I did not want to start posting on something that would prove to be a ”how-come-you-didn’t-see-it-right-away” kind of failure.

When I first started posting, I had the SPI already working and the two timing puzzles outlined in the “Delicate Timing Trickery” and “Time” posts already resolved (although the ISR code was not yet complete at that time). Now, after all that, it’ s time to switch to writing in the present tense. I have synched the blog with all my past work, and things are happening “now”.

This means that the blog will now be updated less frequently, as I ’ll be progressing through the next stages in my project (so I hope, at least!).

Right now, I am in the midst of soldering the rest of the components onto my PCB. This might seem like a few hours’ work, but it’s not. For one, to get here, I had to finalize the values of the resistors for the DC-DC circuit. I used the Excel spreadsheet of Silabs for this, so the final parts list is here.

Did you notice the table on the last page of the parts list? I decided to avoid ordering resistors with weird values from the Internet (which would cost me a little fortune). Instead, I decided to use a little Excel-based calculator and try to find the closest match for these weird values using two E12 resistors in parallel. Thanks to the law of Ohm (and the shape of SMD resistors), my worst match has an error of ~2%.

Although the 2% result is not bad, it turns out that soldering together couples of 1206 SMD resistors piled up in parallel is a bit of a slow process (it’s even more difficult than soldering SMDs on a PCB — try it for yourself if you don’t trust my word). Below you can see a close-up shot of this. The circled components are couples of 1206-sized E-12 series resistors piled up and soldered together in parallel.

img_0162-edited

You may ask why I went into the trouble of doing all this, since using E12 series resistors would give an error of at most 10% anyway. The reason is that I did not want to allow any reasons for poor performance or failure. The reference design specifies values such as 196k which are close to 10% off the nearest E12 value (180k for that case). It’s not impossible that if I deviated that much from the suggested value, something would work “not-quite-as-expected”. I thought I’d better avoid this…

So, what will happen next, when I finish up soldering components and plug the USB cable in? Will it all end in a big-and-loud-spike surrounded by a smelly cloud of smoke? Will it still work as it did so far, with all its components on? Will the DC-DC converter behave ok? Will the circuit eat well under 500mA (for USB) as promised by Silabs’ Excel?

As of this writing, I have not the slightest idea about all this. Truly, the contents of the next post are a big unknown. And this step is a critical one: if I manage to burn something now, the odds are that I won’t ever find the time to debug or to build a new PCB to find out what went wrong. Let’s be optimistic though. Let’s hope for the best, and maybe everything will go fine after all despites Murphy’s Law (I know that as you are reading these lines, you are doubting this as much as I am while typing them, but who knows…).

P.S. After finishing the soldering work, I thought it wouldn’t be a bad idea to add a photo of the board, fully assembled. Here it is:

img_0157

Time

November 7, 2008

Ticking away the moments that make up a dull day
You fritter and waste the hours in an off-hand way

I chose the lyrics from the excellent Pink Floyd’s Time song to show what my ISR was doing so far: just ticking the PCLK (and the FSYNC) away, without yet doing any useful work. There was plenty to do besides

Kicking around on a piece of ground in your home town

– namely, do PCM I/O, arrange data traffic between userland and the ISR, that was already enough to do. My ISR was waiting for me to write all the relevant code:

Waiting for someone or something to show you the way

So I plunged into firmware coding. Timed ISR code is one of the most demanding things (for me, at least), because one needs to take literally every instruction into account and struggle to optimize everything that can be optimized. To begin with, enough cycles were eaten for just invoking the ISR: the PIC needs 3 cycles to jump to a default address (0008h) and another 2 to execute the jump instruction usually found there. As things were, this jump was to an address inside the bootloader, which then jumped to a preconfigured address in “user space” (meaning the address space outside the bootloader), 0808h. From there, another jump, a test if this was a TMR1 interrupt, and still another jump to my ISR. All this summed up into wasting 9 or 10 clock cycles in order to just have the processor frogleap around its flash address space like mad. Not optimal, definitely.

I decided to dispose off the test for TMR1, since TMR1 interrupts were the only ones I would use. Then, I decided to tweak the firmware of the bootloader, so that it would jump directly to my ISR address. To do that, I had to fix an address in the EEPROM for my ISR, so I could use this as a constant in the bootloader. Doing all the relevant work brought the initial waste of time down to 5 cycles. This already felt better.

I soon discovered that the PIC assembly is not very powerful. In order to access a byte in RAM, one needs two clock cycles, one to load the “bank” (four topmost bits) of the RAM address, and another one to access the data. I made sure to ask the linker to place all my data in one “bank”, so all my ISR would have just a single “bank-load” instruction. Good. Just incrementing and testing my two counters, cnt16  (that was its initial name) and cnt4, required another 4 to 6 cycles. Re-loading TMR1 with the right value to fire within 23 or 24 cycles later required another 3; pulsing PCLK required another one; resetting the TMR1 interrupt flag still another one; and, returning from the interrupt, required another two cycles. All this summed up to 16 or so cycles. I was left with only seven cycles or even less (in some execution paths I had to also pulse FSYNC) to do all the useful work.

It was not doable.

There was nothing useful that could be done in seven cycles. For example, take PCM I/O: the ISR would have to test if it was the right moment to do PCM I/O (2-3 cycles), rotate left the output data byte (1 cycle), test for carry (1-2 cycles) and set accordingly the TXD signal — already seven or more cycles gone, and still nothing yet accomplished for the RXD signal…

At that point, I despaired. It seemed I had been caught in the exact situation that Pink Floyd describe by their lyrics:

 And you run and you run to catch up with the sun but it’s sinking
Racing around to come up behind you again

The song’s lyrics were clearly a metaphore for my PIC’s ISR day: I was running and running to catch up with the 23 machine cycles that my “day” (the ISR invocation) had, but I was running short of time and the sun was setting (I had to return from the ISR) without having done all that had to be done; then, time raced around and the ISR had to be called again.

…Every year is getting shorter, never seem to find the time…

(…yes, this was exactly what was happening in my ISR code…)

…Plans that either come to naught…

(…my plans for this project, quickly sinking…)

…Or half a page of scribbled lines…

(this blog)

…Hanging on in quiet desperation…

(this was me — all this struggling for nothing after all… Ahh!… Why hadn’t I thought about all this before starting to mess with PCBs and soldering irons?).

Until, after a couple of days in deep despair, I had another moment of enlightment: my ISR was wasting too much time to perform the bookkeeping of interrupt handling. If I could perhaps call the ISR less often, it would naturally waste less time in useless tasks!

The solution was looking simple: instead of invoking the ISR at every half-cycle of PCLK, I would call it at every full-cycle. Then, I would have 46 to 47 machine cycles available! I would do all there was to do within 20 or so cycles, plus another 10 cycles wasted in bookkeeping, and this would leave me with still some good 10 to 20 free cycles! How come I hadn’t thought of this before?!?

In my human day metaphore, this meant that, instead of waking up at 7:00 am, running like mad to do a nine-to-five daytime job  (plus the overhead of e.g., shaving, bathing, dressing, and driving to my workplace and back home), then getting a half-hour sleep and waking up again at 7:00 pm do quite the same stuff (plus the same overhead) for a nighttime job, I would work two daytime shifts in a row, seven-to-eleven  (as in Led Zeppelin’s Since I ’ve been loving you, to quote another song): thus I ’d have the overhead of driving etc. just once for both shifts, and at least I ’d have the opportunity to get a few hours’ worth of sleep!

I converted quickly the stub ISR I had coded so far into this form, and it turned out that I even had to insert NOP instructions in order to wait until the right time to pulse PCLK down to logical zero! There was plenty of time — or, as the song puts it:

…there is time to kill today…

Now, with enough time available, my next job was to spread the various ISR tasks around the four “periods” spanned by my outer counter, cnt4  (in the meantime, I had changed the inner counter to count only up to 8, so this was no longer called cnt16, but cnt8). I designed the following schedule:

 waveform31

If you enlarge the image (by clicking on it), you ‘ll see that the first cnt8  round (with cnt4 equal to 0) is devoted to doing PCM I/O on the 3210 PCM bus; along with the first PCLK pulse in each of the next two rounds (with cnt4 equal to 1 and 2, respectively), PCM I/O data are moved around. You may have noticed that there is a mention of an input and an output ring. I made this to serve as buffers between the ISR (which is an isochronous procedure), and USB I/O (which is by definition an asynchronous one). Each of the two rings had a capacity of 63 bytes (because of the simple algorithm that I use, I had to spare one byte out of the 64 available in each ring), or ~8 milliseconds of audio.

An interesting little detail is that in a certain situation I did  run out of time after all. In the case of “write byte to output ring” work, I had to code successive test-and-jump sequences for the value of my cnt4: is cnt4 equal to zero? No? Jump elsewhere, then test, is it equal to one? No? Jump and test again, and so on. Thus, the real work of writing the byte was starting late and I was running out of time again. So, just for that case, I figured that, instead of setting the timer and returning, I had to start with the next PCLK pulse from within the ISR without returning at all, and using a GOTO instruction instead. Expressed in my human working metaphore, once in a while my PIC would have to work three shifts in a row and start over right away with the first shift of the next day, but this was only one day out of sixteen, and my PIC would bravely cope with it!

Here is the full ISR code (beware: this is untested code and it will most certainly contain hundreds of bugs — I am just making this available here for scrutiny, without any guarantee that it is correct or even close to that). As you will see, I have painted the various sections of the code with different colors, so the reader’s eye can group together relevant pieces of code. Nevertheless, proof-reading this is a tough exercise, so if you attempt it, be prepared (for example have nearby enough cofee, aspirins, and the like).

So by now, I had gotten past two major obstacles, SPI and PCM I/O (or at least so it looked). My next step would be to complete my PCB with the DC-DC converter and the rest of the PCB components. And my next milestone had quite an ambitious description, to transfer audio from the PC to a handset using PCM I/O! Wow! But these I save for the next posts!

A delicate timing trickery

November 7, 2008

As it turned out from my first (failed) attempt to access the 3210 over SPI, before being able to use SPI, I had to clock the 3210 over its PCM clock input, PCLK. To this, I had to produce a 256kHz PCLK signal, which means that I had to write firmware to pulse the PCLK pin of my PIC at a frequency of 512 times per second.

In my board’s configuration (full-speed USB-2 device) the PIC runs internally at 48MHz, but the instruction cycle time Tcy is a quarter of that, that is, the PIC runs at 12 million instruction cycles per second. Thus, my first thought was to divide 12 MHz by something to get 512 kHz. However, this division yields a non-integer result. In other words, I would have to pulse my PCLK every 23.4375 PIC instructions. Now, honestly, does this look like something feasible to you? To me it did not – at least not at first glance.

So I turned to another idea (which I abandoned soon after, but it’s worth discussing a bit): what if I used an external 512kHz frequency source? The simplest idea for this would be to take advantage of the PIC’s second crystal oscillator input. I plunged into the datasheets, but my hopes faded quickly: the maximum frequency accepted by the second oscillator of the PIC is 32.768 kHZ, so the 512kHz crystal would not do (not to mention that 512-kHz crystals are hard to get by). Even so, I took a last-minute decision to keep this alternative open, so I provided for the second crystal and its capacitors in my design.

For the next couple of days, I kept asking myself how to achieve the division by 23.4375. There had to be a way to do it. When, suddenly — here was it: what if I did not require a 50% duty cycle for PCLK? Then I could allow the logical one PCLK half-cycles to be one PIC instruction longer than the logical zero ones. This would yield 23.5 PIC instructions per half-cycle, something close enough to what I needed. But still, this was not good enough: this was not  256kHz, and if I used a PCLK which wasn’t accurate, my clock would slowly drift against another party’s rate of PCM encoding or decoding. This in turn might create noise, clicks, audible artifacts or other unwanted effects.

But, wait a second — what if I  used a table of time invtervals? This would result in a waveform that would have a variable duty cycle, which would variate periodically to achieve exactly 256 kHz. This quickly led me into the following calculation: 9 half-cycles of 23 Tcy each, plus 7 half-cycles of 24 Tcy each yield a total of 16 half-cycles with a total duration of 207 + 168 = 375 Tcy. The average duration of each of these half-cycles is 375/16, which yields — guess what — the magic number 23.4375 Tcy!!

This is what a 16-half-cycle pulse train would look like:

waveform0

And there’s more: although the PCLK runs at 256 kHz, actually the 3210 performs PCM I/O at a rate of only 64 kbps: the chip devotes to PCM I/O only eight PCLK cycles out of every thirty two, and a FSYNC pulse is used to mark the start of a 32-cycle train, while some internal registers tell the chip how many cycles after FSYNC to wait before doing the PCM I/O. Here is the relevant timing diagram from the datasheet of the 3210:

3210pcm

I would need to pulse the FSYNC signal every 32 full PCLK cycles, or 64 PCLK half-cycles. So, there was it: I would create something like an inner loop of 16 half-cycles, and an outer loop of four iterations of the inner loop. In each inner loop I would arrange the time intervals between 23 and 24 machine cycles as explained above, during the first inner iteration of the first outer iteration I would raise FSYNC and I would lower it right after that. My invention of a 16-half-cycle 23/24-Tcy ISR proved to be immensely convenient!

Here’s what the whole thing would look like:

waveform2

One note here: maybe such tricks are common to all firmware clocking problems or to all similar projects. However, as I have already stated, my prior experience in such things was really limited, so the whole line of thought that led me to this solution was quite a revelation to me.

In order to test my assumptions, I decided to write some elementary firmware that would pusle PCLK and FSYNC and then re-try the SPI test. I decided to base this firmware on a Timer1 (TMR1) interrunt service routine (ISR). There is no real reason for choosing TMR1; in the future, I might change TMR1 into TMR0.

From the very first steps, after I studied the machine code produced by MCC18, I decided to write the ISR directly in PIC assembly. This would allow me to code accurately in time all the tasks I had to do in the ISR (see the next post – when posted). There was no easy way to do this using C.

It took me quite a while to get the ISR logic right. For one, I had to discover by trial-and-error that I was supposed to clear the TMR1 interrupt flag inside the ISR, or else the PIC would never again fire a TMR1 interrupt. By instructing the user LED to flicker inside the ISR (and observing that, instead of flickering, it stayed constantly lit), it was easy to spot this bug.

Then, I needed to set up the time intervals until the next TMR1 expiration. I did some experimentation there, checking to see what would happen if I asked the PIC to expire the timer immediately upon return from the ISR. Would this freeze the PIC? Nope, it would not, the PIC executes at least one instruction in “userland” before re-entering the ISR, so this felt safer: even if I screwed up times, I would not freeze entirely the PIC. At that point, I gave me some slack: I just wanted something rudimentary that would approach 256 kHz to test the SPI, I did not need full accuracy yet. Thus I wrote a small ISR that set TMR1 to fire in 23 instructions’ time, and then just returned to the “userland”.

After checking that the green LED kept flashing (somewhat less frequently, because its way of counting time is based on polling TMR0, and my ISR was eating some of its time), finally SPI’s turn came. I re-checked the reset sequence for the 3210: set up the TMR1 ISR, then lower \RESET, wait a little, raise \RESET and that should do it. Flashed this into the PIC, pressed the reset switch and — miraculous!! — my little .NET program immediately displayed the expected value for 3210’s direct register 0!!

Here are two screenshots for registers 0 and 11:

3210-reg0-5

3210-reg11-51

The value of Register 0 means “I am a 3210, Revision E” (3210 datasheet, p. 64), and that of Register 11 means “Pulse metering adjustment is 0 dB and audio hybrid adjustment is 0 dB” (same, p. 73).

I had just proved to myself that David Rowe (and Silabs’ FAQ) were right after all; the 3210 required PCLK in order to work… Even if I fooled it with something that wasn’t exactly 256kHz, it would not mind. How would it react however to my invention with the irregular PCLK duty cycle? And how would I write the actual ISR code for my PIC? Would there be enough time to do all the required tasks? All these are to be answered in my next post.

A stubborn Serial Peripheral Interface

November 7, 2008

After having soldered all three ICs on my PCB, I had to choose between two paths: either to solder all components, or to solder just one part of the circuit at the time, debugging incrementally as I would go on. I decided to go incrementally, starting from the PIC circuitry, then going into the interface between the PIC and the 3210, then into the DC-DC converter and the interface between the 3210 and the 3201.

So I soldered all the components around the PIC, removed a few short-circuits here and there (my PCB’s top and bottom sides weren’t very well aligned, something that caused some more of these) and used the ICSP with a modified version of FDART2003 (see picture below) to program the PIC with a version of the bootloader modified so that it would use my choice of PIC ports for the user switch and the user LED. Plugged the USB connector in and — nothing…

img_0149

A modified version of FDArt2003 for my board

But OK, I had seen this play before, so this time I did not panic. I double-checked the PIC ports in the bootloader source, fixed a bug there (some mask was not right), then re-tried. Still nothing… I re-checked my PCB for power — and there was it: the 5V pin of the USB connector was not soldered well and, altough it passed my first tests, it had been disconnected, and the PIC was not getting any power. Fixed this, and the green LED came into life with a reassuring flash.

Then, using the USB and the bootloader, I flashed the firmware for Microchip’s demo board, after removing lots of unneeded things and adapting the signals to those of my board. LED flashing again (this “user” firmware program instructs the LED to flash at a slower rate and one can see easily whether the bootloader or the user firmware is running). So the PIC-related part was looking OK now.

But so far it had been the easy part… Now it was time to move to the unknown territories of the 3210. I soldered just the decoupling capacitors and the little ferrite bead (the BLM something on the schematic), so as to give power to the chip, leaving all other external circuitry out. Adhering to my incremental testing plan, at this point I just wanted to test the SPI communication between the PIC and the 3210. A successful test result would also serve as a proof that I had not damaged the 3210 during soldering.

To test the SPI, I modified a little program written in .NET that Microchip provides, adding my own USB command between the PC and the PIC (the firmware uses one-byte commands for that) and displaying the result (and verified that part OK by passing successfully fake results from the firmware to the PC). The idea was that the program would query every second or so my board about the “current” 3210 register value, and my board would return the value of the same “current” register all the time, until the “user” switch was pressed, in which case the board would step on to the next register, and so on. After I verified that stepping the registers with the “user” switch was working OK, I went on into testing the SPI itself.

So, I studied a bit the SPI interface of both chips. This can be found in p.53 of the 3210 datasheet and on p.200 of the PIC 18F2550 datasheet. Mumble, mumble, the SPI interface has four “modes” depending on whether the clock signal is high or low during inactivity and on whether the data bit is asserted on the rising or on the falling clock edge in the middle of a clock cycle. And this, by a de facto standard from other vendors, is coded into four names, like “mode00″, “mode01″, “mode10″, and “mode11″. Good, nothing too difficult so far.

To complicate things, Microchip use the opposite logic level for one of the two bits controlling this setting (I think it is the CKP bit), so that e.g. “mode11″ corresponds to CKP=0. Duh!… Anyway, by placing both diagrams next to one another, I could tell that I needed CKE=1 (clock is high during inactivity) and CKP=0 (data asserted on rising edge), which oddly translates into “mode11″. Microchip have a library for SPI operations, so it sounded like my job would be as easy as this: OpenSPI (parameters), WriteSPI (command-to-read-a-register), then value=ReadSPI ( ).

Good, I flashed that into the PIC and – you guessed it right: It didn’t work… Not with any clock frequency I tried. Not with any SPI mode I tested. Not when I let go of the SPI routines and re-did the whole procedure manually, testing bits and writing bytes to the appropriate control registers of the PIC. Not with that, nor with any other trick I could imagine. The damn thing was always returning zeros or –

There was a reassuring sign though! Using some settings, I was receiving some bits set to one. This meant that there was some sort of activity between the 3210 and the PIC. The 3210 was sending logic ones sometimes, so it could not be entirely dead. It had to be something else I was not doing right. But what? As much as I scratched my head on this, the results I was getting did not make any sense to me.

It was again the time to express my despair to David Rowe and turn to him for help. David’s reply was very, very helpful. The 3210 does not reset properly unless the PCM clock is applied to the chip before resetting it. And, if the chip does not reset properly, the SPI bus does not work correctly. Actually, all this I had already read in an FAQ from Silabs (bottom of p.5), to which of course I had not payed any attention. David’s advice un-stuck me from a point at which I would have dropped the project altogether — this is just another reason why, as I said also before, this project owes a lot to him! Thanks, David!

So, I had to postpone my attempt to talk to the 3210 over SPI, and I had to go into one of the design quizzes that had been puzzling me for quite some time in parallel: how to generate the 256 kHz signal needed for the PCM clock and at the same time do PCM I/O between the 3210 and the PIC. But this is described in my next post.

Damn tiny thin copper stripes

November 4, 2008

By now, my schematic was ready. Now it was the turn of designing a PCB (a task that, for some undetermined reason, seemed terrifying to me — I really have to discuss this with a shrink, if I ever get to visit one). Supposedly this is an easy step: one gets CadSoft Eagle to create the board, places the components around, then clicks the autoroute button, then Eagle does all the flying there’s to do, and that’s it. Nope, you guessed right: in practice, seldom does it go like that.

To begin with, the SMD sizes in the reference design were not what I needed. In Greece, where I live, I could find no 603-series SMD components in retail stores, and I would have to order these in the order of hundreds from e-stores abroad. This would make my budget skyrocket. So I had to go back and change all components to 1206-series, available in my local retail store. This made my PCB quite larger; on the positive side, it also made it easier for me to solder components by hand. Then, I had to finally face the ugly truth: I had to turn this spaghetti mess (you can click on the image to see details):

fxsmod_brd_spaghetti

into a PCB. Aaaaargghghgh!!…. How is it ever possible that people do things like this?!? It goes without saying that Eagle’s autorouter failed because of several constraints. Eagle’s design rules do not allow sizes as small as the ones I had to deal with, and the PCB size allowed by the free version of Eagle did not allow me to spread components on a PCB sparsely enough to allow Eagle enough space to route all the signals. I would have to tweak its design rules, like how much space to leave between signals. This would be risky, since it would affect all the circuit’s signals. I decided to let go of the autorouter.

I turned again to David Rowe (to whom I must confess that this design owes a lot…); after all, David had also used the 3210 reference design. So I could “learn” from the PCB design of his IP04 FXS module, that is, I could use at least the component placement and routing guidelines from his board — or, put in less elegant words, copy shamelessly a part of his PCB design into mine. But after all, this is exactly what “Open Hardware” is all about: it’s letting other people re-use what one has accomplished, saving them time and effort, and letting them to the “diff” work instead of re-inventing the wheel. So, I “used” a lot of the IP04 FXS module design in mine. Thanks, David!

Just to complicate things further, either the snap grid of Eagle seems to be somehow not-exactly-tuned to millimeter dimensions, or its precision in small dimensions was not so great. Whatever the reason was, my octagon-like routing stripes with 45-degree angles were not exactly correct. I had to magnify several times the working area and drag-drop things around to achieve good-looking angles, just to find out that rescaling this to the normal PCB size would bring some stripes too close together, resulting in short-circuits. I had to print quite a number of transparencies and tweak routing by tenths of millimeters to avoid these.

After two weeks or so of sweat, I had a first version ready. Then, I had to go back-and-forth some times from the schematic to the board, correcting some things. Even in the last moment, I decided that soldering the miniature USB SMD connector was a toughy for me and switched into a normal type B connector. So, here is my final design (as of this writing, of course).

top-place

You could see quite a few signs of amateur design: I had not “smashed” components, so their names were not placed where they should be (for example, L1’s name is outside the board — this would make it impossible to print correctly in a mass-production scale); or, there were only three mounting holes, etc. etc. But it was a board that looked correct. Here are the top and bottom (mirrored) layers in PDF format in 200% magnification (the ugly stripes in the fill areas if you set the zoom to 50% are a bug of the PDF print driver in Eagle — these print OK in a normal printer, however you ’ll need the original Eagle .brd file to produce a usable printout; please drop me a mail in case you want this, WordPress won’t let me host Eaglle files here).

Now comes the funny part.

I decided to etch the two-layer PCB by myself, using my home “production facilities”: a laser printer to print the PCB; a good supply of projector transparency sheets; markers of different sizes to make fill areas darker (otherwise light still goes through these during exposure); a mercury-vapor lamp (placed in a gardening pot!); a generous supply of double-sided photosensitive boards; an equally generous supply of potassium hydroxide powder to develop exposed PCBs; and a less generous (most of the trial PCBs never made it through to this stage), but nevertheless still respectable supply of etching solution powder.

It turned out that I had better give the PCB production out to some professional service company. These damn tiny thin copper stripes made it almost impossible to produce and etch a correct PCB with my home facilities. Either the exposure was too much, so thin stripes tended to get totally eaten or corroded during the etching solution process, or it was to little. In some of my trial PCBs the stripes between the 3210 and the PIC simply did not exist. In still others, they were glued together by some ugly corroded copper areas. In still another trial PCB, the 3201 (on the right-hand) stripes and pads disappeared altogether… Duh… It took me about seven trials to get a PCB which still had some of the lines between the PIC and the 3210 eaten by the etching process, but in places where I could “patch” them by soldering hair-thin copper wires along their path.

After about 7 or 8 failed attemtps, I was finally able to proudly present my PCB (apologies, I didn’t shoot any pictures before soldering parts):

img_0144

To show a bit of the not-so-clean underwear, I am including a shot of the part with the wire patches soldered upon damaged stripes:

img_0152

As you can see in the underwear picture above, soldering the damn tiny pins of the 3210 onto the damn tiny thin (and very dense) copper pads proved to be less of a problem. If one uses an adequate soldering iron (my soldering iron for SMD is about 8W with a very thin tip) and lots of soldering paste, it is feasible to solder even a chip like this without burning it, short-circuiting pins together or destroying the PCB by overheating the pads. True, it required a bit of rehearsal on a throw-away PCB (and I had many of these from my failed etching attempts), but it proved to be doable.

A harder task was that of soldering “vias” (which would be through-hole plated in a normal production PCB): OK, I took care to avoid “vias” onto which non-SMD components must be soldered (otherwise there’s no access to the component-side part of the “via” and it’s very hard to solder it). OK, in most “vias” I just used a small piece of copper wire soldered on both the top and the bottom side. *But*, there were two “vias” under the 3201, and I had to make sure that the small wires that connected the top and the bottom side would not protrude over the top side of the PCB surface, otherwise the 3210 would not sit correctly on the PCB and it would be very hard to solder it. I solved this quizz by means of the following invention: I bent the top end of the small copper wire into a spiral, with a diameter of ~1mm (same as the diameter of the “via”’s hole). Then, this spiral, along with the neighboring copper pad of the “via” made a good surface onto which flux would spread, connecting the pad with the spiral, and without protruding a bit from the PCB’s surface. I practiced this on many other “vias” until I finally soldered the ones under the 3210. Phewww… The hard part of my PCB seemed to be done!

Also not yet placed into my Eagle PCB design is a hole that one needs to drill under the 3201 to have access to the thermal copper pad on the top-side of the PCB and underneath the chip. According to the datasheet, this thermal needs to be soldered  to the thermal pad on the bottom side of the chip, and this cannot be done otherwise without a reflow soldering oven (if you have such an oven at home, drilling this hole is not needed, but I did not).

To give a glimpse into what’s going to follow, this thing worked! Although this brought me face-to-face with my next big nightmare (it seems that I have a lot to confess to this shrink after all), that is, writing firmware code for the PIC. More on these in my next posts!

The USB FXS hardware design

November 4, 2008

By now, after all the woes I describe in my previous post, I had managed to tame the PIC 18F2550, Microchip’s IDE, MCC18, nuxie1’s board, and the PICDEM tool to be able to upload and run code on this board. The time had come to sit down and design the actual USB FXS circuitry.

The idea for this was to use the 3210 (FXS ProSLIC) and 3201 (line driver) chips from Silicon Labs. After half a week or so of studying the datasheets from Silabs, I thought I had a grip of the whole thing. Voltage levels between the PIC and the 3210 are compatible. Si3210 is controlled by a SPI port, and the PIC 18F2550 has a such built-in. Speeds and timing diagrams were looking OK to me. Even some worries I had about about the power consumption of the DC-DC converter circuit were proved unjustified after studying Silabs’ own calculator for the DC-DC converter Excel sheet (by setting NREN — the number of parallel telephone sets that can be connected in parallel — to 1, there exists a 5V configuration which needs close to 0,4 A, below the USB maximum of 500mA). The Gods of hardware seemed to be on my side. Good! Time to move on then!

My thought was to copy-paste the reference circuitry from the Si3201 datasheet, pp.17-20 (for the time, using the reference values provided therein — later I could adapt the values DC-DC converter components as per the spreadsheet). I cross-checked with David Rowe’s IP04 FXS module, which as I found uses the exact same reference design around the Si3210. OK, this was a Good Sign. With these in hand, I started entering my design into the CAD tool that I use, CadSoft Eagle.

Of course, I could not find CadSoft Eagle libraries for the Si3210 and the Si3201, so I had to make schematic and wirepad libraries for these myself. I am not a very good Eagle librarian, so I did some mistakes there (like picking the wrong layer for the device name, so I can’t make it disappear from my PCB like other device names). I am confident that these glitches can be corrected some day. On the other hand, the pad dimensions and the distances proved to be OK. If you are interested in these libraries, drop me a mail (the blogging software on this site won’t let me upload anything other than pictures, sorry…) or wait until I upload them to my sourceforge site.

Then I started designing my circuit. It took some more days until finally it looked like this (click on the image to see it full-size):

fxsmod_sch

Schematic of my USB FXS design (click to see it full-size)

Although my style in this post may look like I did things in a straight line (first the schematic, then the PCB), in practice it was not at all like that. Several times when designing the PCB had I to go back and make smaller or bigger changes and tweaks here and there. One example is the signals of the PCM bus between the Si3210 and the PIC: the PIC has many signal pins that I could use for this. So I tried to use those that would help me route the bus signals between the two chips on my PCB. When my initial guess proved, ehhm, not exactly optimal, I had to go back and change them.

Another issue is the 32kHz oscillator which appears in the schematic. This is not used at all in my current implementation. Supposedly its purpose would be to provide clocking for the PCM bus service routine, but it turned out that this was not a very good idea (I ‘ll explain in a future post why).

One final piece of advice about the design: as I am writing these lines, I have not tested anything more than the SPI communication between the PIC and the Si3210. So, please don’t take for granted that this design is correct. There may be serious errors, even copy-paste ones. The component values of the DC-DC converter are not the correct ones for 5V DC, and will most probably not work correctly.

So here’s a guided tour to the schematic:

  • There is really nothing to the left of (and including) the 3210 that differs from the Silabs reference design. One note: in order to get something like an FCC approval of an “FXS” device, one would need to include a surge protector between the RJ11 pins 3 and 4. I have omitted this, although it is easy to add it, since it is not really needed for intra-home use.
  • PIC’s RA5 is the “user LED”; it is still different from the one used both by Microchip’s demo board and nuxie1’s design.
  • PIC’s RB3 is the \CS line for the 3210; the SPI bus of the PIC does not include a special chip select signal for master mode.
  • The PCM bus (including the 3210’s \RESET signal) is made out of the first 5 usable PIC signals in order of increasing pin numbers. This is for reasons of PCB routing.
  • The CLR and USR switches do exactly what the respective switches of Microchip’s demo and nuxie1’s design boards do.
  • The JLVP jumper must be closed (soldered on the PCB) if LVP mode is to be used.
  • The ICSP bus is for programming the PIC after it has been soldered (which is always the case, since this is a SMD version of the PIC).

This is almost everything that I have to say about the schematic. It is very, very simple. Which, as I found out later on, makes firmware a not-so-simple story! But this I save for my next posts; for the time, I had to design and etch a PCB.

A board to be held tenderly

November 4, 2008

In my previous post I describe how I chose a board from an open design to use as my development environment. By now, I had assembled the board, I had searched in Microchip’s site, downloaded the USB drivers for Windows (unfortunately, I only have a single laptop on which I do all development plus my daily officework, so it had to be this), and everything seemed ready to kick off. So the big moment came, I plugged in a USB cable from my PC to the board.

And then nothing.

No smoke coming up from the board. No sign that my PC had seen a USB device. Had I burned my PC’s USB port? Naaah, the red power LED was on, plus I measured 5V DC on the PIC’s power supply line. Still, no signs of action at all. Time to re-read the instructions: to get the bootloader running, I had to hold down the USER switch of my board while pressing and releasing the RESET switch. Did that and still nothing. So, I repeated this step, trying several dozens of button combinations and holddown times, when suddenly… oops!! There was a glimpse of something on my PC!

I am saying “something”, because what happened was that a USB device appeared, then it disappeared again and an error message popped up about Windows not being able to recognize my USB device because the device had malfunctioned. So, there was a sign of life on my board after all! However, when I tried again, I could not even reproduce this “malfunction”. The board seemed dead again. Another several dozens of tries, and I managed to bluescreen my PC, with an error message appearing about the Microchip USB driver causing trouble. This had to be my board again, which was a good sign! My board was definitely not dead, but it was clear that I had to debug the situation further to see what was going on.

To cut a long story short, and after several hundreds of rounds of reset sequences, where I occasionally managed to make the “device malfunction” message appear and and/or to bluescreen my PC, I accidentally noticed that when I held the PCB with my left hand, pressing the buttons with the other hand, I could get the PC to see the board as a USB device for a few seconds, until it disappeared again.

By the next half hour, I had perfected myself in holding the board in a certain manner for long enough to get Windows to recognize the board as a USB device and to have the Microchip’s boot loader controller program talk to it. Holding the board “in a certain manner” means that I had to hold it with one hand, somehow making a “nest” for it, much like one would hold a wounded little bird or other small-size animal. It was clear: this board needed a lot of tenderness, or else it would refuse to work!

One other worrying sign was the green “user” LED of the board, which was not showing any activity. I had to look at the bootloader source files for this. It turned out that the bootloader source as modified for nuxie1’s board, was still using a different PIC port for the user LED — obviously, this was correct for Microchip’s own development board (which BTW has two user LEDs), but not for this one. So, I needed to recompile the and re-flash bootloader.

I installed Microchip’s MCC18 and MPLAB IDE, jumping into another day or two of steep learning curves, however at the end of the second day I had the modified-modified bootloader ready, and flashed it back into my PIC. Plugged back into the USB port of my PC, held the board tenderly and – voila! – the green user LED came to life! This was definitely a good sign!

Next I decided to demystify the “hold-me-tender” issue. I thought that it might have something to do with the LVP warning I had mentioned in my previous post. So, I read all about LVP, a configuration mode in modern PIC chips which allows In-Circuit-Serial-Programming (ICSP) without needing a high programming voltage (12V or higher). PICs come with this setting preconfigured on, and in in order to reset this to off, one needs to have 12V or higher available in the programmer — which FDART2003 does not.

Moreover, mumble, mumble, in LVP mode, PIC’s RB5 is used as a PGM (program) strobe, and in normal operation it has to be set to logic zero, otherwise the PIC will reset!  A quick look back to nuxie1’s board: RB5 was an open pin. This sounded much like what was happening: Windows was seeing the board for a while, then it lost it because the PIC was resetting. I tried connecting RB5 to the GND and then letting the board work without my own tender hold, and, yes! This was it!

So, how was then ever possible that the board worked at all before this? Well, when I was holding the board “tenderly”, I was accidentally connecting the open RB5 pin available at the one side of the board to the GND signal available at some other open pin at the opposite side of the board via my own hand! Mystery solved!

Now that I had a reliable environment to work on, I tried some of Microchip’s examples, changing the code and recompiling to get at least the user LED right. Microchip’s development board has several peripherals which are of course absent in nuxie1’s board, so I had to modify code here and there, but at the end of the day I managed to have the board communicate to the PC, accepting commands and returning back some values.

I deemed that this was enough for now, so I decided to pause and turned my attention to the actual project: design and build an FXS board. This is covered in my next post.

Setting up a PIC environment (but which one? how?)

November 3, 2008

After discussing with David Rowe, I set forth to design an open, low-cost USB FXS board. After David’s advice, I also found that a PIC microprocessor would be the best choice for this, both because PICs are very versatile devices with built-in USB functionality and because they are cheap enough.

Before going on, I must confess that I am not  an electronics professional. My field is totally different (I am a PhD-level computer and network engineer) and my only experience with electronics is this of an experienced enthusiast. Never before had I undertaken a task so difficult as this. However, I had confidence in my ability to understand and combine bits and pieces from other people’s designs and I found the idea interesting enough. So I said, what the heck, maybe I can do it after all.

That having been said, my first task was to decide the right PIC to use. Parameters: it must have USB functionality and it must be cheap. However, I needed to have a development environment to, ahem, develop (read: spend hours and hours of debugging) the required firmware for the PIC, right? How would I do this?

I started from the ATMega project that I had looked into before proposing it to David. I had proposed it because I thought it would be best to be able to use the USB as a bootloader. So I googled a while, and came up with this design by nuxie1 (BTW, the winner of a recent hackaday design challenge competition).

Nuxie1’s board was easy, I could produce it myself and I could learn a little PIC internals before going into my own design. And this board is based on a PIC2450/2550, which has USB! And, most important of all, Nuxie1 supplied a modified boot loader based on Microchip’s own boot loader for their development board, so I could well use the USB connection to upload and endless series of (my) firmware versions onto the PIC! Thanks Nuxie1, this is exactly what I was looking for!

Nuxie1’s PIC board, assembled

After etching the PCB and soldering everything as required, I needed to somehow get the bootloader loaded into the PIC. Even the programmer for that had to be open, so I used a design named  FD-ART2003 (again googled) by foxdelta, a PIC programmer that uses the parallel port of the PC to power the PIC, plus a little program called Winpic800v3.59. I would use these to program my board’s PIC with the initial USB boot loader firmware provided by nuxie1.

Foxdelta’s ART2003 PIC programmer board, assembled

When programming the PIC, I ignored an unimportant little error message generated by the Winpic program (a little something about the LVP configuration setting). As it turned out, I had better not overlook this message — but this is covered in my next post!