Lately, some of my fellow lab rat mates are slowly transitioning out of academia as if someone's spread deadly poison around the corner. As a result, a handful of hot and furious coffee-break chats arose, all on the efficiency of academia and the meaning of doctoral studies. In the end the debate didn't lead to any final conclusions, but I thought I'd put my thoughts into writing.
So, where did it all began? It is no secret that research in engineering (here referring from a semiconductors guy point of view, but I believe the situation in the rest of the engineering and applied physics world is not much different either) is mostly conducted in industrial entities. Nowadays academia has a hard time providing that manpower and financial resource needed to complete a few silicon iterations of a complex VLSI (or whatever) system. That immediately brought the assertions from some colleagues that academia is a "waste of time" and "super inefficient", while joining industry would bring you that quest for innovation and knowledge much faster. My answer, mostly as a spectator to this debate is: "it depends".
It depends on what you really want to do. If you are starting a PhD just because you think that someone (your supervisor) will be holding your hand, and expect that you will be coached on a daily basis (joining because of these extra courses) you are probably doing it wrong. If you prefer this model it may be easier to join an industrial group where you will be (as a fresh graduate) typically given specific orders, lots of teaching, lowered expectations as well as minimal freedom (here it also depends on the industrial group too). It is also wrong thinking that after completion that doctor's degree will immediately embark you on a senior position – nope, not necessarily. Please don't misunderstand me, there is nothing wrong with wanting to follow the taught model which will eventually lead you to being a professional, whatever that means. It's just that you risk running into a doctorate which will turn nightmare for you.
Anyhow, doing a PhD, as opposed to joining industry, brings young players the possibility to gain knowledge and shine very quickly just because there's virtually no obstacles (bar some academic idiotizms) to what you are allowed to do. In contrast, blue sky R&D in the corporate world is extremely rare and is typically reserved to seniors. A lot of the innovation occurring in companies is monetarily driven and follows certain goals which can sometimes squeeze the joy out of work. And again: it depends, it depends, depends! Surely access to fun technology is limited in academia, but unless you end up in a very shallow place I'm sure you'll find a way through to some good enough semiconductor process, or whatever it is that you need.
I think the most important bit to consider when starting a PhD is that to be successful you should be self-driven and self-motivated. When doing a doctorate one typically devotes its time almost entirely on his own project. You are your own boss and 3/4 of the success of your project depends entirely on you. On the plus side, the other 1/4 of your project is steered by your supervisor and, in contrast with doing research entirely on your own, you are at least taken care of project funding. That way you don't necessarily have to do the social part of science i.e. spreading the word, writing grant proposals, PR-engineering and taking care of work facilities, etc... Well, this doesn't mean that you shouldn't if there is a chance to do so. A doctorate as opposed to industry allows you to also develop other skills, which may not be entirely linked deeply with your scientific research, but these are perhaps sometimes even more useful than the new transistor sizing technique you've just discovered. Learning to deal with all sorts of characters is one of the most valuable skills I am beginning to acquire here in academia.
Being happy and feeling beneficial is of highest importance and you can only find out if the Third acaremic stage is for you by investigating more on the topic. So if you are hesitant of what you should do ask around, be inquisitive, talk with various current and former employees, alumni and students, compare - contrast. Don't be lazy, do your homework before it's even been assigned!
Every mixed-signal system needs some form of a digital sequencing which controls the internal blocks. Typically for test systems it is highly desirable that this sequencer is also flexible. While there are a number of ways of achieveing this, I am sharing a tool and perhaps a solution for generating control signals for testchips based on an external FPGA-based ROM memory block. This approach may not be the most efficient when it comes to silicon real estate or power. However, what I like in this methodology is that it is extremely flexible, and yet is relatively simple to work with. Fiddling with dedicated state machines is perhaps the most efficient methodology but it is a bit more time consuming for inexperienced people in digital design as myself.
To start with, here's an overview of an example system:
An FPGA contains a RAM/ROM block, together with some control circuitry. Pretty simple huh? And it truly is. The UART module clocks-in the memory content to the write and read address generator, which loads the data into the memory. After the memory is initialized, all the address generator does is to loop through the RAM's depth (addresses).
One can generate the RAM block using the IPcore generator in Xilinx's Vivado. If you use other vendors I am sure they would be offering similar tools. What you need to take care of is the memory's width, which is driven by the number of sequener signals you need, as well as its depth — depends on the sequencer resolution you are targeting, as well as its length. For most cases, if you use a large FPGA you shouldn't run out of dedicated memory block space. Here's an example screenshot oof Xilinx's IPcore generator:
There's plenty of ways to generate memories with various tools. If one has to write the memory content bit-by-bit it'll take him, perhaps not years, but hours. Fiddling with raw "1/0" text files, boxes, csv, or whatever else is a painful task.
To try and automate things a little bit, I created a tiny assembler instruction interpreter, which compiles memory machine code, which I can then directly load into the memory via the UART. This is currently a work in progress, however, I have put a plenty of code comments, and I've tried to keep things clean. Hehe, well, as much as perl code can be made clean.
The instruction list is currently embedded into the code and remains under the parse_line() subroutine, where you can swap bit posisions, instruction syntax and add new functionality. There are two global definitions in the main() subroutine needed to be taken care of. These are the: \$ram_width and \$ram_depth. The latter define the exact size of the memory file and must match with the ones used during the generation of the IP core, as well as the address length of the memory addresser module. Here's how the memory content file looks like:
memory_initialization_radix=2; memory_initialization_vector= 00000100111010011001111010100000, 00000100111010011001111010100000, 00000100111010011001111010100000, 00000000111110011001100011100000, 00000000111110011001100011100000, 00000000111010011111110011100000, 00000000111010011110110011100000, 00000000111010011110110011100000, 00000000111010011110110011100000, 00000000111010011111110011100000, ...
Each instruction, when called, alters a specific bit (also may be multiple bits) in the memory. Right now the tool has a set of 30ish instructions. Here's a complete list:
;|------------------------------------------------------------------| ;| Instruction List and Function | ;|------------------------------------------------------------------| ;| ROW 0x00 1/0 - set row_rs | ;| ROW 0x01 1/0 - set row_rst | ;| ROW 0x02 1/0 - set row_tx | ;| ROW 0x03 1/0 - set col_bias_sh | ;| ROW 0x04 1/0 - set row_next | ;| SHX 0x00 1/0 - set shr | ;| SHX 0x01 1/0 - set shs | ;| ADX 0x00 1/0 - set adr | ;| ADX 0x01 1/0 - set ads | ;| COM 0x00 1/0 - set comp_bias_sh | ;| COM 0x01 1/0 - set comp_dyn_pon | ;| CNT 0x00 1/0 - set count_en | ;| CNT 0x01 1/0 - set count_rst | ;| CNT 0x02 1/0 - set count_inv_clk | ;| CNT 0x03 1/0 - set count_hold | ;| CNT 0x04 1/0 - set count_updn | ;| CNT 0x05 1/0 - set count_inc_one | ;| CNT 0x06 1/0 - set count_jc_shift_en | ;| CNT 0x07 1/0 - set count_lsb_en | ;| CNT 0x08 1/0 - set count_lsb_clk | ;| MEM 0x00 1/0 - set count_mem_wr | ;| REF 0x00 1/0 - set ref_vref_ramp_rst | ;| REF 0x01 1/0 - set ref_vref_sh | ;| REF 0x02 1/0 - set ref_vref_clamp | ;| REF 0x03 1/0 - set ref_vref_ramp_ota_dyn_pon | ;| SER 0x00 1/0 - set digif_seraial_rst | ;| LOAD PAR - load follow-up instructions to buf register | ;| SET PAR - set the loaded in buf register to output | ;| START - initialize output register to 0x0000 | ;| NOP - NOP operation (stall) one cycle | ;| NOP n - NOP operation (stall) n cycles | ;| FVAL 0x00 1/0 - frame valid | ;| LVAL 0x00 1/0 - line valid | ;|------------------------------------------------------------------|
I tried to kind-of preserve the classic assembler language constructs as much as I could, e.g. comments use ";", to load a signal you start with MOV, then issue the command e.g. ROW followed by its specific bit e.g. 0x01 and finally the value to be written. The NOP instructions stall the system (copy the previous memory line for N cycles), LOAD PAR pushes the next instructions into the PAR register, afterwards SET PAR sets the modified instructions after LOAD PAR, in parallel. Here's a sample code:
START ;|----------------------------| ;| Initialize startup signals | ;|----------------------------| LOAD PAR MOV REF 0x03 1 ; ota_dyn_pon always @ '1' MOV CNT 0x04 1 ; count_updn '1' MOV CNT 0x01 1 ; count_rst '1' MOV CNT 0x05 1 ; count_inc_one '1' MOV CNT 0x08 1 ; count_lsb_clk '1' MOV MEM 0x00 1 ; count_mem_wr '1' MOV FVAL 0x00 1 ; FVAL '1' MOV COM 0x01 1 ; comp_dyn_pon always @ '1' ;|-----------------| ;| Sequencer start | ;|-----------------| ; references and shr sampling MOV ADX 0x00 1 ; adr MOV SHX 0x00 1 ; shr MOV REF 0x01 1 ; ref_vref_sh MOV REF 0x00 1 ; ref_vref_ramp_rst MOV COM 0x00 1 ; comp_bias_sh SET PAR NOP 22 ; halt 220 ns - phase 1 in vref_ramp LOAD PAR MOV REF 0x01 0 ; vref_sh SET PAR NOP 8 ; halt 80 ns MOV REF 0x02 0 ; cla off NOP 6 ; reset counter LOAD PAR MOV CNT 0x04 0 MOV CNT 0x01 0 MOV CNT 0x05 0 SET PAR NOP 2 LOAD PAR MOV CNT 0x04 1 MOV CNT 0x01 1 MOV CNT 0x05 1 SET PAR NOP NOP 52 ; halt 520 ns - wait for ramp buffer to settle MOV SER 0x00 1 ; stop data serialization out NOP 34 ; prehalt - wait SHA MOV SHX 0x00 0 ; complete shr sampling NOP 2 ; start count + ramp current LOAD PAR MOV REF 0x00 0 MOV CNT 0x00 1 SET PAR NOP 102 ; halt 1024 ns (ramp slew time) MOV CNT 0x00 0 ; stop counter MOV REF 0x00 1 ; stop ramp current ...
The execution of the script is rather simple:
asmitp.pl program.asm -o instr.coe
Future to do:
1. Put instruction table setting in an external file
2. Add a vec and vcd file generation switch, to allow integration with spectre/spice
3. Implement JUMP instruction (loop)
4. Implement conditional statements
5. Create pdf documentation
If you find this approach appealing, please feel free to fork my repo or write to me so that I can add you as a contributor and develop these tools further. Cheers ;)
I always feel heartfelt while reading great and sensuous short texts about the field of engineering. I am offering you a few beautiful, 1 to 3 minute reads on topics related to engineering science.
Where are today's engineering heroes? — By failing to celebrate its finest contributors, the profession risks far more than mere obscurity. This enriching article puts on the spotlight those engineering heroes who are often forgotten but have by far contributed equally much to our field.

Naturally, you might then ask, What makes an engineering hero?, Stephen Harris has tried to shed some more light with a follow-up article, revealing some of our views on engineering achievements.
What would engineering be without its daily battles with complexity and trade-offs? Robert Lucky rubs salt into the wound with the headaches of Unsystematic engineering. But there should be a better handle to the control problem, how's that even happening?
Perhaps the problem lies in The ever-evolving field of electrical engineering. How exactly is electrical engineering defined nowadays? Is circuit design the only E-related early stage subject which all EEs take during their first year at university? Do you have any idea of what EEs actually do?
You think you do? But then, how about Engineers starting to think like field biologists?, Samuel Arbesman has some radical ideas for coping with complexity.
Finally, we all know that solving complexities is always accompanied by the birth of Great Thoughts, here Robert Lucky is stressing that great ideas accompany us in unusual times and places. So, always keep that pen and paper ready, you never know when would that bird land on your shoulder.
Hope these writings reach more people. Happy reading!
Awhile ago I wrote about the time I've been investing on designing an image sensor and its column-parallel ADCs in particular. If we know each other well chances are I've been moaning your years about that chip for a long time. Well, they ARE here! Alive! With practically no functional bugs such as inverted signals or wrong connections whatsoever! I might say that this device actually turned out pretty successful, especially considering that every single circuit inside was built all from scracth in a sharp tapeout deadline!
Of course there are a few glitches here and there, but thank goodness it's nothing critical. Besides I haven't seen a first time right image sensor yet, requiring no mask tweaking.
Let's not wait any longer. Here's a very quick and preliminary summary of my measurement adventures so far. And... sorry folks, the striptease will be next time, when I plan to reveal some of the circuits inside. Unfortunately due to some harsh journal pre-publication and disclosure rules I don't really want to get into trouble just yet.
To start with, here's a picture of the chip and the board itself:
It took quite awhile getting the board back with some iteraitons from the bonding vendor, despite the nice bonding diagrams sketched. Nevertheless, turns out bonding and ESD finally turned out to be successful. Hehe, well, I have some infant mortality in a few boards where the bonding operator has forgotten to weld a group of wires. Perhaps he thought the chips may miraculously work without a signal or two?
You may wonder what's with all these bond wires? Why so many (170)? Actually most of them are redundant power supply pads. The bottom side of the chip contains 16 LVDS output data pairs i.e. 32 pins, one pair LVDS clock in used for the serialization and SRAM readout. In-between the LVDS pairs there are power pads supplying the columns. Indivitual Analog (3.3V), Digital(1.5V), and IO (LVDS, 1.5V). The right side of the chip has another LVDS clock input used for the fast count clock 266 MHz, split power supply for the voltage references bias and control. The control signals for the sensor are on the right and top side, a few pins for the SPI and bias trim. Everything else is used for supplying the matrix with isolated from the ADC power and ground. To recap, here's a coarse high-level diagram:
The digital test system is based on a Xilix Spartan 6 LX150 FPGA, controlling a Cypress FX3 USB 3.0 chip for the high-speed ADC data transmission to the ADC. Even so, the bottleneck to reading out the chip at its highest rate is the USB 3.0 link and not the chip itself. Perhaps a PCI-Express protocol would have suited the applicaiton better.
The ADC board has AD8620 14-bit DACs which are used for providing test sweep voltages to the ADC. An ADC used for measuring the power drawn by the separate supplies, which are driven by a few fixed-voltage LDOs. There are also voltage translators to 1.5 V as the FPGA's banks operate on 1.8 V minimum.
It took me over three months to setup the FPGA and readout to the PC. The FPGA contains a few elemental blocks:
1. An UART Rx/Tx module which I use for preloading various settings and data to the FPGA. The module is bit-banged and re-used from a lab assignment during my MSc university days.
2. A bit-banged SPI module specifically tailored to the SPI register inside the testchip.
3. A bit-banged SPI module for the AD8620 DACs
4. A 4 kB block RAM with asynchronous write/read capability. The RAM contains the sequencer data and is preloaded via the UART module.
5. 16 hardware 1:6 deserializers (ISERDES), with automatic phase alignment of the strobation pulse and automatic bitslip module based on the received training pattern from the chip.
6. Two 12288 kbit frame line FIFO buffers which allow for fully pipelined ADC SRAM readout.
7. A transmission header combinarion module.
8. Control state machine for the FX3 GPIIF interface.
The FPGA without any readout software is useless. I use the in-house viewer at the company I was hosted for capturing images over the USB, while the register programming and sequener I had to design myself. To ease life with configuring the chip registers I created a tiny Java GUI calculator? which allows me to enable or disable the various on-chip registers. I also use it for controlling the DAC voltages and well as some of the FPGA internals. Its backend is written in bash and practically controls the corresponding UART device via the /dev folder.
Being able to easily change the chip's timing is one of the most important things in chip testing. My initial solution for a sequencer was to use hard-coded state machines on the FPGA. Such scheme however, is extremely hard to tune or tweak, making it impractical. To improve flexibility, I designed a tiny assembler, decoding my custom instructions controlling each individual (or combined) signals. Nothing extraordinary but a perl script parsing my assembler files, translating them to a binary stream, which is then fed via the same UART backend to the FPGA and ultimately the block RAM.
Here is a sample of the instruction set
;|------------------------------------------------------------------| ;| Instruction List and Function | ;|------------------------------------------------------------------| ;| ROW 0x00 1/0 - set row_rs | ;| ROW 0x01 1/0 - set row_rst | ;| ROW 0x02 1/0 - set row_tx | ;| ROW 0x03 1/0 - set col_bias_sh | ;| ROW 0x04 1/0 - set row_next | ;| SHX 0x00 1/0 - set shr | ;| SHX 0x01 1/0 - set shs | ;| ADX 0x00 1/0 - set adr | ;| ADX 0x01 1/0 - set ads | ;| COM 0x00 1/0 - set comp_bias_sh | ;| COM 0x01 1/0 - set comp_dyn_pon | ;| CNT 0x00 1/0 - set count_en | ;| CNT 0x01 1/0 - set count_rst | ;| CNT 0x02 1/0 - set count_inv_clk | ;| CNT 0x03 1/0 - set count_hold | ;| CNT 0x04 1/0 - set count_updn | ;| CNT 0x05 1/0 - set count_inc_one | ;| CNT 0x06 1/0 - set count_jc_shift_en | ;| CNT 0x07 1/0 - set count_lsb_en | ;| CNT 0x08 1/0 - set count_lsb_clk | ;| MEM 0x00 1/0 - set count_mem_wr | ;| REF 0x00 1/0 - set ref_vref_ramp_rst | ;| REF 0x01 1/0 - set ref_vref_sh | ;| REF 0x02 1/0 - set ref_vref_clamp | ;| REF 0x03 1/0 - set ref_vref_ramp_ota_dyn_pon | ;| SER 0x00 1/0 - set digif_seraial_rst | ;| LOAD PAR - load follow-up instructions to buf register | ;| SET PAR - set the loaded in buf register to output | ;| START - initialize output register to 0x0000 | ;| NOP - NOP operation (stall) one cycle | ;| NOP n - NOP operation (stall) n cycles | ;| FVAL 0x00 1/0 - frame valid | ;| LVAL 0x00 1/0 - line valid | ;|------------------------------------------------------------------|
Here comes the interesting part. The ADCs can be run at 1us ramp time, which is as designed, and achieve a noise variance of about 1.6 LSB at 1x gain. According to the preliminary histogram tests with a sinewave from the soundcard from my laptop and buffered via a, perhaps not so linear opamp, provides a monotonic response and DNL of less than 1 LSB. It would be desirable to be less than 0.5 LSB, however, I see tiny glitches popping up beyond 0.5 LSB. The root cause for this may likely be a poor duty cycle ratio of the count clock, as my architecture relies on a sharp clock with 50 % duty cycle. But for that I shall investigate further. The ADCs consume 35ish mW from the digital supply (1.5V) and about 100mW from the analog (3.3).
Here are some preliminary fancy pictures, starting with a noise histogram:
The noise may perhaps be dampened further, as the PCB itself can not boast with being the best low-noise design. The external DACs used for feeding in the input voltage use the power supply as a voltage reference (via a low-pass filter of course), which is horrendous circuit design practice.
Here is a posh 3D code distribution histogram for the columns in the first ADC group of 128. Shown is a bathtub distribution produced by feeding in an input sinewave to the columns.
You can see some stairs here:
To prove that the digital correlated double sampling works, here is the mean value of all columns under a uniform voltage input:
The pixel array also works and I can successfully acquire blank images. The pixel sequencer needs tuning so as to eliminate some strange column FPN artefacts. I also plan on attaching better lens, as the current ones are probably the worst possible choice for a sensor with a small size as the current.
Finally, just wanted to mention that this is work in progress, so stay tuned for more updates in the nearby months. But please lower your expectations for design details. I need to make sure this work is accepted in some of the major journals before publishing anything here. Sorry folks, it will come eventually.
I recently participated in a T-shirt design contest organized by the solid-state circuits society. I just got an e-mail rejecting my entry as apparently another participant has won the contest. His design, compared to mine looks neat and clean. Congrats!
Nevertheless, now that the contest is over, let me introduce you to my design, and perhaps make SSCS angry about not following their strict copyright ownership rules. Apparently, by submitting your design you are automatically giving out all of your copyright to SSCS. Yeah, sure! :)
Perhaps one of the most fascinating technologies empowered by solid-state devices is data communication and processing. I tried to express the peak of humanity, hehe "peak" (as well as IC design) with space technologies. My design entry contains an outline graphic of the Soyuz capsule, which is used for bringing in and out astronauts to the international space station (ISS) every 200 days. Keeping continents connected wouldn't have been possible without geostationary satellites. Similarly the ISS also relies on communication satellites, which is why my design also includes small satellite symbols surrounding the Soyuz capsule. All of that would not be possible without microchips, hence, the big chip with the SSCS logo at the center, linking the Earth and space.
Creating a hero of the IC designer is a rather hard and ambitious task, as solid-state technologies are so much embedded in today's life, that makes it hard for one to decide on the coolest application made possible by ICs.
Huge credit goes to my cousin (Queller 4) for giving a hand with the drawing.