Saturday, May 12. 2018Power Op-amps Rock - Driving A YIG Oscillator
High on the list of things I need to write up is my radar-building saga; suffice for now to say that I’m (now) using a tiny yttrium iron garnet in a magnetic field as my viola to generate the signal for my frequency modulated continuous wave radar.
As fancy as it sounds, a Stellex YIG oscillator unit (mounted yttrium garnet, heater, tune and modulation coils) can be found on ebay for around $20. I got a Stellex 6755 job that does 8-10 ghz. In short, all one needs to do is apply heater voltage to the thing to get it generating rf, and adjust the frequency by changing the current in the two tuning coils. It puts out +16 dBm, respectable. Flash back to radar - the goal is to generate a frequency-sweeping rf signal that moves as linearly as possible. First, we need to generate that sawtooth pattern to modulate our YIG. I played with several analog sawtooth producing circuits but couldn’t find one that generated a perfectly linear ramp, and I really don’t want to have to sample the modulation signal to (try to) correct the nonlinearity in software later. Not feeling like pulling out a microcontroller for the task, I threw together this guy from things I had on hand: A TTL oscillator is cleaned up and complemented by two schmitt trigger inverters a la 74HC14. On the rising edge, a 74LS191 4-bit counter latches its incremented value, and on the falling edge, the DAC samples the value and produces the specified current. Eventually I'll replace the counter with an FPGA so I can do arbitrary waveforms (hint, a triangle wave lets you deduce both range distance and doppler shift at the same time in an FM CW radar), but for now the modulator is at least aesthetically pleasing. While the DAC in fact outputs its value in the form of current, not voltage, the current range (max 10mA) is far below what is needed to tune and modulate the YIG (around 250 mA). Alas. Thus, we use the resistor network specified in the DAC’s datasheet to convert our current source (hopefully very linearly) into a voltage signal with which we will… drive a power op-amp setup to convert voltage signals to current. One of my new favorite parts I happened to find in my ICs bin is the L272, a dual op-amp beast that can source or sink 1A continuously. Rather than using a (regular old) op amp to drive the gate of a mosfet or BJT as is common, this beast of an op amp means we can drive the tuning coil(s) of the YIG directly. Unfortunatly, the huge current capability comes at a cost: the L272 has a slew rate of 1 V/uS and a unity gain bandwidth of 350 kHz, far below what would be required to follow my above modulator signal with the 5 MHz clock on it. Drat. This limits the sweep rate and thus TX bandwidth of the radar considerably, but at least doesn’t suffer the oscillation problems with transistor-driver circuits that limit max slew rate and bandwidth there, too. In any event, we use a 10 ohm resistor on the negative side of the tuning coil to generate a voltage signal (hopefully very) linearly related to the current drawn,and use the op amp to compare this voltage with the “requested” voltage, adjusting its voltage output until the current monitor’s voltage matches. So! It works. It even turns out YIG sources tune down in frequency faster than they tune up, thus helping us match the output to the sawtooth modulation signal exactly. More to come on the radar front... Saturday, February 4. 2017Showing Off: Compressor and Turbine Blade Designs
I've spent way too much time in the last few months rebuilding my CNC mill with ballscrews, 4th axis, other upgrades, but I'm finally back in business
and ready to cut some sweet parts. I'll do a long post about the jet projects in progress, here's a sneak preview. In about a page of Common Lisp, I nab the XY values for a NACA 2408 airfoil, scale it progressively from root to tip, twist it 25 degrees, and generate G-code to cut it using either the 4th axis or vertically top-down (or detecting that your blade profile can't be milled top-down). Oh, and also serve up an HTTP interface to view the shape updates in real time using visjs. More to come... Friday, December 16. 2016Circling back: Altera Quartus 12.1 on Ubuntu
I revisited my super awesome Quartus install and Makefile post a few days ago in an attempt to replicate the setup so I can write some sweet verilog, but alas, Something in the package from Altera was different.
I tried the latest and greatest Quartus, now from Intel, which installs and works impressively well here on my desktop. But! It no longer works at all the same from the command line, which breaks my workflow. With a little tomfoolery, I was able to get things installed and working like I had them before by fetching the oldish install for Quartus 12.1SP1, and doing the following: sudo mkdir /opt/altera sudo chown jackc:wheel /opt/altera cd /tmp/kk tar xfz ~/Downloads/12.1sp1_243_quartus_free_linux.tar.gz cd 12* cd linux_installer/quartus_free mv gtar gtar-orig mv gzip gzip-orig ln -s `which tar` gtar ln -s `which gzip` gzip ./install --auto /opt/altera/12.1sp1_243 cd .. cd cd quartus_free_64bit mv gtar gtar-orig mv gzip gzip-orig ln -s `which tar` gtar ln -s `which gzip` gzip ./install --auto /opt/altera/12.1sp1_243 for x in /tmp/kk/12.1sp1_243_quartus_free_linux/devices/web/*.qda; do LD_LIBRARY_PATH=/opt/altera/12.1sp1_243/quartus/linux64 /opt/altera/12.1sp1_243/quartus/linux64/quartus_sh --qinstall -qda "$x"; done sudo su echo 'ATTR{idVendor}=="09fb", ATTR{idProduct}=="6001", MODE="666"' > /etc/udev/rules.d/altera-usb-blaster.rules udevadm control --reload-rules mkdir /etc/jtagd cp /opt/altera/12.1sp1_243/quartus/linux64/pgm_parts.txt /etc/jtagd/jtagd.pgm_parts It even works! $ LD_LIBRARY_PATH=/opt/altera/12.1sp1_243/quartus/linux64/ /opt/altera/12.1sp1_243/quartus/linux64/jtagconfig 1) USB-Blaster [2-1.3.1.3] Unable to read device chain (JTAG chain broken) Thursday, May 29. 2014Radseed: A Kernel Module for Real Randomness
While I was originally planning to write a tiny SNMP daemon for my geiger counter so as to graph trends, I decided instead to write a kernel module exposing the counters. This way, my system can use the interrupt events as a source of true randomness (radioactive decay is, by definition, truly random).
First, a quick introduction to the random number generation bits in Linux: drivers/char/random.c. This module in essence keeps track of two things: a seed value, and a pool of entropic data to mix in. At boot, the seed is set to the previous shutdown value (if available), then mixed with device-constant sources of entropy such as MAC addresses, serial numbers, and so forth. While running, drivers such as keyboards, mice, and disk controllers contribute to seed entropy by calling one of the add_*_randomness() functions defined and exported from random.c. These functions keep track of time deltas between calls, mixing the seed value with new values from the entropy pool between reads. The random module presents two char devices for userspace to get data: /dev/random and /dev/urandom. On each read(), an SHA1 hash is taken of the current seed value and returned to the user. This result is then mixed with the seed value itself as well as some data from the entropy pool. The difference between them is this: if the entropy pool becomes depleted after successive reads, /dev/random will block until more entropy data is available to mix in and hash, thus ensuring the output is non-deterministic. However, /dev/urandom will continue returning pseudorandom data even without entropy, simply mixing the seed with the resultant SHA1 hash each time around. Determining the seed value and predicting the output would require an inverse of SHA1 (no small feat), but it is nonetheless mathematically possible to do so given enough resources. As you can see, sources of good entropy are extremely important for reasonably random numbers. While human input sources like the keyboard and mouse are still valid, disk access time data is no longer usable with SSDs due to their highly characterizable behavior. Companies like Intel have implemented hardware randomness and key generation functionality, the closed-source nature of the beast has been cause for skepticism particularly in the post-NSA revelation climate - for instance, OpenSSL still doesn't use the Intel key generation instructions for AES despite significant speed benefits. The point to all of this is that good random seed data is hard to get, and radioactive decay is a great source. Back to the task subject at hand: Radseed listens for hardware interrupts on the ACK line of the parallel port. When such an event is detected, the events counter is incremented and time of last event (in jiffies) recorded. jackc@kdev0 ~ $ cat /sys/kernel/radseed/events 41 jackc@kdev0 ~ $ cat /sys/kernel/radseed/last 16316569 If you want to test graphs or whatnot without a geiger counter connected, you can trigger events manually too: jackc@kdev0 ~ $ cat /sys/kernel/radseed/trigger 1 jackc@kdev0 ~ $ cat /sys/kernel/radseed/events 42 jackc@kdev0 ~ $ cat /sys/kernel/radseed/last 16378144 Since very few things even have parallel ports anymore (plus I have a bunch of geiger-muller tubes sitting here), I'm working on a board design for a small USB geiger counter that doesn't need external power and can be plugged into anything for easy external entropy. Code is on GitHub: jackcarrozzo/radseed. Wednesday, May 14. 2014Interfacing Cirrus Logic Audio ADCs
I've been considering ideas for audio gear of various sorts over the past few months, and decided a good starting place would be a solid ADC interface from which I could prototype concepts. Lots of companies make audio converters, but I settled on two models from Cirrus Logic: the CS5361 and CS5340. They are, respectively, balanced and unbalanced two-channel 24-bit 192 khz high dynamic range delta-sigma oversampling devices.
I started by laying out a super-simple protoboard for the CS5361. Since I wanted this to be quick and easy to cut on the CNC mill, the board is single-sided with the bare minimum of filtering, and without standard mixed signal board design concepts like separate analog and digital ground planes. While this will negatively affect the noise figure a bit, I wanted to get the device up and running with the minimum investment of time in case my assumptions regarding its usage and support were incorrect. By the time I had finished the layout and cut the board, the samples order had arrived! Soldering was quick though a tad arduous - I need to use a larger 1206 footprint next time. My ugly solder job notwithstanding, I plugged the unit into a breadboard, wired up an oscillator, config pins, and the logic analyzer, and was immediately rewarded with correct operation: In short, by simply applying power, config pin states, and a master clock, the device will shift out ADC values (in 2's compliment form) msb-first on the falling edge of SCLK (ie, we sample on the rising edge): The only other line we need to worry about is LRCK, which indicates the channel being sent - you can see here that we get a left sample, then a right sample, then repeat: With the hardware working, I set about writing the Verilog modules to nab samples from the ADC and send them off via USB (using an FT245R FIFO interface I have on hand). The code is extremely simple: on the rising edge of SCLK, samples are shifted into an 8-bit register - the size of the data bus on the USB interface. Every 8 bits, that register is strobed into the FT245R and the process repeats. Byte alignment is provided by LRCK: on a start or reset condition from the USB host, the FPGA waits for a rising edge of LRCK before beginning the sampling and transmission of samples. This allows the client end to interpret the data stream without framing bytes: incoming data is simply shifted into 3-byte (24-bit) samples, left then right, and processed as desired. The code was quick to write and simulate with my favorite tools, iVerilog and GTKWave. I implemented a quick CS5361 module whose left and right channels count up and down (respectively) so as to simulate the rest of the pieces. Unfortunately I spent almost as much time debugging the code in hardware with the logic analyzer as I did writing the code, as Quartus (the Altera design software) is rather inconsistent in its handling of constants and register widths. (note: always read every line of output from the Altera synthesis toolchain - one can easily spend 4 hours trying to debug a problem that makes no sense only to find that the synthesis tool decided a constant was the wrong size and used zero instead) In any event, I did manage to squash the few Quartus oddities that had caused the hardware to operate differently from the simulated code, and verified that the USB interface looked correct using the logic analyzer. Time for more spaghetti: Time to test it out. In its current state, the FPGA will assert a reset condition on any received byte from the FIFO buffer. So, we will send a reset byte then read 24 samples of 6 bytes (3 for each channel): root@ichor ~ # echo -n 0 > /dev/ttyUSB0 && dd if=/dev/ttyUSB0 count=24 bs=6 2>/dev/null | hexdump 0000000 3238 a13f 4a68 a650 0344 bd41 6632 ceaa 0000010 78f2 28f8 9764 19ca 7185 45b4 6bfd eabf 0000020 9825 8050 65e5 6122 3adc 0830 28f0 9dfc 0000030 d026 746a e2c0 befa 57dc 1fa4 4225 7b82 0000040 a61b ed00 2320 d641 e111 b648 a2f3 8d3a 0000050 bdfb afb6 1287 5963 ff57 9c8e 63a1 3971 0000060 4bfe ac6e 5081 9fae 2b0d 5c4c 6eaa 26b7 0000070 164b 6093 8378 96d8 138c 160e e661 a81b 0000080 81bc bdae 530b ec79 3537 6ada b0cc 4773 0000090 Success! With that working, the next steps are to implement the CS5340 and add proper dynamic configuration loading. From there, I am hoping to implement ADAT input and output and a simple device driver to interface the kernel audio subsystem. I've put the code, board design, and a bit of documentation on GitHub: jackcarrozzo/cs_adcs. Monday, April 21. 2014Adventures in Linux on Sun Netra T1
I set out recently to run modern (> kernel 3.5.x) linux on a Sun Netra T1 I had laying around, and it turned into to a rather in depth process indeed. I do have a soft spot for Sparc and Sun hardware in general, and have a few of these machines that have been running FreeBSD for ages without issue. However, I was hoping to use this particular machine with a Linux kernel driver I wrote which interfaces my geiger counter, seeding the kernel random number generator with events.
In any event, I started by seeing if the Netra would netboot using DHCP, as I already had my dhcpd pointing to tftp. I dropped a Sparc Debian netboot image in TFTP at the right filename (the machine's intended IP in hex, 0A00000E in my case) but alas: lom>poweron lom> LOM event: power on Netra t1 (UltraSPARC-IIi 440MHz), No Keyboard OpenBoot 3.10.25 ME, 256 MB memory installed, Serial #14265310. Ethernet address 8:0:20:d9:ab:de, Host ID: 80d9abde. Drive not ready Boot device: net File and args: Timeout waiting for ARP/RARP packet Timeout waiting for ARP/RARP packet Timeout waiting for ARP/RARP packet Packet logs show indeed that the Netra doesn't request DHCP, only RARP: root@elan /etc/dhcp # tcpdump -n ether host 08:00:20:d9:ab:de tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 10:00:16.860634 ARP, Reverse Request who-is 08:00:20:d9:ab:de tell 08:00:20:d9:ab:de, length 50 10:00:19.519799 ARP, Reverse Request who-is 08:00:20:d9:ab:de tell 08:00:20:d9:ab:de, length 50 10:00:24.180254 ARP, Reverse Request who-is 08:00:20:d9:ab:de tell 08:00:20:d9:ab:de, length 50 OK, no problem. I installed, configured, and started rarpd: root@elan /tftpboot/sparc # cat /etc/ethers 08:00:20:d9:ab:de sparc0 root@elan /tftpboot/sparc # grep sparc0 /etc/hosts 11.0.0.14 sparc0.priv.crepinc.com sparc0 root@elan /tftpboot/sparc # rarpd -A -v -d -b /tftpboot/sparc Then again booted the machine: ok boot net Boot device: /pci@1f,0/pci@1,1/network@1,1 File and args: a00000 Fast Data Access MMU Miss Hmmmm. The machine begins loading the image, but stops at byte 0xa00000 and prints the above. Googling shows that this is a known bug on this hardware (see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=658588) - apparently the Debian netboot images got too large after Lenny and Netra is no longer supported. OK, let's try a Lenny image, and we can build the fresh kernel after install: [ 0.000000] PROMLIB: Sun IEEE Boot Prom 'OBP 3.10.25 2000/01/17 21:26' [ 0.000000] PROMLIB: Root node compatible: sun4u .25 2000/01/17 21:26' [ 0.000000] Initializing cgroup subsys cpu sun4u [ 0.000000] Linux version 2.6.26-2-sparc64 (Debian 2.6.26-29) (dannf@debian.ooorg) (gcc verrg) (gcc version 4.1.3 20080704 (prerelease) (Debian 4.1.2-25)) #1 Sun Mar 4 21:::2:17:20 UTC 2012 Linux version 2.6.26-2-sparc64 (Debian 2.6.26-29) (dannf@debian.o Nice! The kernel boots and the installer loads but... another known bug: the SCSI controller isn't located. Sigh. I then tried a few Ubuntu versions, all of which were too large and triggered the MMU miss above. Next on the list of possible distros (even just to use as a jumping off point to bootstrap the system) is Gentoo. I nabbed the netboot image, dropped it in the TFTP dir, and we were in business: ok boot net Boot device: /pci@1f,0/pci@1,1/network@1,1 File and args: 846200 PROMLIB: Sun IEEE Boot Prom 'OBP 3.10.25 2000/01/17 21:26' PROMLIB: Root node compatible: sun4u Linux version 2.6.32-gentoo-r7 (root@bender) (gcc version 4.3.3 (Gentoo 4.3.3 p1.0) ) #1 SMP Tue Apr 13 22:46:39 UTC 2010 [...] Gentoo/SPARC Netboot for Sun UltraSparc Systems Build Date: April 13, 2014 Nice! Given the number of years it's been since I built a Gentoo box, I followed the handbook for Sparc: http://www.gentoo.org/doc/en/handbook/handbook-sparc.xml. A couple notes: (1) Due to the small size of my disk and the enormous number of files in recent portage, I kept running out of inodes while untarring. I ended up making /usr much larger than it needed to be and asking mkfs for the maximum number of inodes (-i 1024) to solve it. (2) For some reason, the permissions of items in /dev on the install chroot were not to emerge's liking. chmod a+rw /dev/* provided the quick fix (for obvious reasons, don't do that on any real system). (3) The kernel I built was a bit too large, though as the handbook specifies, I was able to strip it down to the required size: (chroot) netboot linux # du -hs vmlinux 7.8M vmlinux (chroot) netboot linux # strip -R .comment -R .note vmlinux (chroot) netboot linux # du -hs vmlinux 5.7M vmlinux (4) I had originally compiled in Open Boot PROM to the kernel, however probing at boot would lock the machine: [ 40.238603] /pci@1f,0/pci@1,1/ebus@1/flashprom@10,0: OBP Flash, RD 1fff0000000[100000] WR 1fff0000000[100000] [ 40.369577] /pci@1f,0/pci@1,1/ebus@1/flashprom@10,400000: OBP Flash, RD 1fff0400000[200000] WR 1fff0400000[200000] [ 40.505971] sd 0:0:0:0: [sda] Write cache: disabled, read cache: enabled, supports DPO and FUA [ 40.619440] flash: probe of f0084fe0 failed with error -16 [ 40.691610] /pci@1f,0/pci@1,1/ebus@1/flashprom@10,800000: OBP Flash, RD 1fff0800000[200000] WR 1fff0800000[200000] [ 40.827856] flash: probe of f0085178 failed with error -16 [ 64.439127] BUG: soft lockup - CPU#0 stuck for 23s! [swapper:1] [...] [ 65.911690] I7: [ 65.963206] Call Trace: [ 65.995345] [000000000099b2ec] openprom_init+0x8/0x78 [ 66.062946] [0000000000426bcc] do_one_initcall+0xec/0x140 [ 66.135131] [0000000000976914] kernel_init_freeable+0xfc/0x1a0 [ 66.213000] [00000000007dce44] kernel_init+0x4/0x100 [ 66.279456] [0000000000405f84] ret_from_fork+0x1c/0x2c [ 66.348175] [0000000000000000] (null) Disabling "/dev/openprom Device Support", "openprom /proc Entry", and "OBP Flash Device Support" from the kernel config solved the issue - I didn't bother tracking down exactly which module was the problem as I don't need openprom support, but presumably it could be determined quickly. After rebuilding the kernel and initramfs, it boots successfully! jackc@sparc0 ~ $ uname -a Linux sparc0 3.12.13-jackc-v2 #2 Wed Apr 9 21:27:52 EDT 2014 sparc64 sun4u TI UltraSparc IIi (Sabre) GNU/Linux One strange thing of note is that Gentoo went to a multilib system for Sparc in recent versions - that is, 64 bit kernel, 32 bit userland. (see http://www.gentoo.org/proj/en/base/sparc/multilib.xml) jackc@sparc0 ~ $ file /boot/kernel-3.12.13-jackc-v2 /boot/kernel-3.12.13-gentoo-v1: ELF 64-bit MSB executable, SPARC V9, Sun UltraSPARC1 Extensions Required, relaxed memory ordering, version 1 (SYSV), statically linked, BuildID[sha1]=46a9535b4e050fbbdfdfe71cba5795502d127eb2, with unknown capability 0x410000000f676e75 = 0x1000000070433, not stripped jackc@sparc0 ~ $ file /bin/ls /bin/ls: ELF 32-bit MSB executable, SPARC32PLUS, V8+ Required, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, stripped Both 32- and 64- bit binaries can be compiled and run using the -m32 or -m64 flags, respectively, to sparc-unknown-linux-gnu-gcc. Another thing of note is that the machine will hard lock under high load, such as compiling kernels. It just so happens a thread came up on the sparclinux kernel mailinglist about a memory management bug just recently, with a few patches slated to be merged into mainline: see http://marc.info/?t=139934944100001&r=1&w=2. I'll hopefully get around to applying and testing the patches in the near future. Thursday, March 13. 2014rsyslog Remote Logging
EDIT 2015-02-19: This config is for older (<v6) versions of rsyslog; the newer syntax in v8 and above is much cleaner - plus the functionality is improved, including a bunch of awesome modules like ZMQ and Elasticsearch. Check it out: rsyslog.com/doc/master/.
This took way more slogging through docs than I expected, so perhaps this note can save someone the trouble. I've used freebsd's syslog daemon to receive remote logs and store them by file for years, but I needed to add a log host at home so that when the cable modem dies, logs still go somewhere. After much reading and messing around, here's a working incantation to keep local logs operating normally, but remote logs writing to hostname-based files. # rx remote logs (place this before any $Actions in /etc/rsyslog.conf) $ModLoad imudp $UDPServerRun 514 $template RemLog,"/var/log/remote/%HOSTNAME%.log" if $fromhost-ip !='127.0.0.1' then -?RemLog & ~ After restarting or HUPing rsyslogd and adding the new log host to my edge router, we are happy to see: root@elan ~ # ls /var/log/remote/ edgertr.priv.crepinc.com.log root@elan ~ # tail /var/log/remote/edgertr.priv.crepinc.com.log 2014-03-13T08:43:16.759006-04:00 edgertr.priv.crepinc.com 52: *Mar 13 13:28:30.121: %SYS-5-CONFIG_I: Configured from console by vty0 (10.0.0.71) Remember that, if you use %HOSTNAME% as I did above, you should either have relevant entries in /etc/hosts or accept that a nameserver failure may cause logs to end up in ip-named files. Tuesday, February 25. 2014FPGA Dual DAC Board for QAM Synthesis
Building on the simplicity and success of my DAC board paired with my FPGA dev boards, today I threw together a board with an Altera Cyclone II, two DAC9000Es, an FT245R, and supporting periphery. I'll need to check it with fresh eyes tomorrow to ensure I haven't made any mistakes, but with luck I can submit the design tomorrow evening and have the boards next week.
My DAC+FPGA pair has proved extremely useful for transmitting test signals of various sorts, taking I+Q via USB and generating the output signal in code. But, at 160 MS/s, its max frequency is quite limited. This new board has two of the same DACs, however each will simply generate the I or Q signal alone which will then be combined with an LO in a dedicated QAM modulator chip. This allows for carrier frequencies limited only by the abilities of the QAM modulator chosen, and at 160 MS/s the usable Tx bandwidth will be huge. I've chosen to terminate the DACs in SMA connectors and leave the modulator off the board entirely, as I'd like to evaluate a few different chips. Unfortunately this board will be too large for me to mill at home at the moment, but I can still quickly mill test boards for QAM modulators in about an hour. Thursday, February 20. 2014WWVB Receiver and Testing Transmitter
As I've been making steady progress on my Z80 computer, I've put a lot of thought into something to actually do with it when it's done. As tempting as it is to load up CP/M, add a video interface, and use it as my main machine, I think porting Firefox is too ambitious. For now, I've decided to add some more 7-segment displays and an RF front end to decode the WWVB time signal from an atomic clock in Colorado and hang it on the wall. If I'm still feeling ambitious, I'll add an Ethernet controller and write a driver and NTP daemon for it. Of course, this means I need a working receiver front end for 60kHz.
The WWVB signal is quite simple as far as decoding goes: the carrier has "full power" and "low power" states. The transmitter drops the carrier by 17 dB at the start of each second, and the length of time before it returns provides a single trinary value: Mark (0.8s), Not Set (0.2s), or Set (0.5s). A single digital line that goes low or high to follow the transmitter power state is quite easy to achieve with a fully analog circuit: after a bandpass to select only the 60kHz carrier, we send the signal into two peak detectors - one with a long time constant (low pass filter) to track the average signal power over several seconds, and one with a shorter time constant to track the per-second changes. Passing these two signals to a comparator, we get our nice single-bit TTL indicator of the current signal state. Plus, the longer time constant peak detector acts as an auto gain control, so no alignment is required. While I will make my own receiver as described above for the final version, I ordered a SYM-RFT module for testing. It includes an LED to indicate received carrier status and outputs the inverted carrier power state compared to the average carrier power. I quickly breadboarded it up to an FT245R USB chip and wrote a few lines of C to poll the power status and measure the length of state changes. Unfortunately, New England being quite far from Colorado, the signal is below the noise floor and has thus far been highly unreliable. The module simply flashes chaotically in the presence of any electronic noise like my monitors, and does nothing in isolation. I built the above two-stage preamp from two 2N3904's to attach to the 60kHz antenna that came with the SYM-RFT module to see if I could see any carrier on the oscilloscope. While I did get all sorts of noise and impulses, there was very little if any energy at 60kHz. Drat. Luckily, I have the tools on hand to recreate the signal so I can at least test my receiver and code. I pulled out the FPGA RF DAC board I put together a while back, and a page of Verilog later I had a compliant WWVB transmitter: After a small battle with PLLs to get a slow enough clock for 60khz, both the SYM-RFT and my USB worked fine. jackc@ichor ~/Projects/wwvb_usb $ sudo ./wwvb MARK : 950 ms NOT SET : 239 ms SET : 503 ms NOT SET : 194 ms SET : 581 ms MARK : 991 ms ^Cjackc@ichor ~/Projects/wwvb_usb $ Tuesday, February 11. 2014Z80 Proto Coming Along Nicely
I've rebuilt my previous Z80 computer and have been adding several peripherals of late. I think that ultimatly, after I decide the final design, I'll rebuild the whole thing to look pretty and be better laid out for higher clock speeds, but for now I'm continuing to prototype here.
As it stands, I have the following systems configured: CPU: Z80A - While I have some later devices with more features and faster clocks on hand, I'm testing base functionality with a run-of-the-mill original. Flash: W29C020 - Boot ROM. The device is 256 kB, but I'm only using 32k (memory map is split between RAM and ROM). Technically I could enable write functionality to the flash, but haven't done so thus far as I haven't needed it. SRAM: W24257AK - 32k. Haven't implemented any MMU or paging, but it would be trivial to do so in the future if need be. Address Decoding and Glue: 74LS138, 74LS32, 74LS04 - Some people use PLAs or GALs to do this in a single device, but I have an attachment 7400 series logic. General Purpose IO: 8255A - Provides three 8-bit ports per chip. Right now ports A and B are tied to 7-segment displays via 74LS244 octal buffers. Rather than use 7447 7-segment decoders to save 4 bits, I connected the displays directly so that I can display the A-F characters correctly via a map in ROM. This has been quite helpful while writing the BIOS. Timing: Z8430APS CTC - This guy provides four counter channels with a handy list of prescalers and vectored interrupt features. Right now the BIOS configures channel 0 to send an interrupt every 10ms for polling routines, and channel 1 to provide a compatible baud rate clock to the DART. Async Serial: Z8470APS DART - Contains a whole slew of serial comm features. Currently the BIOS configures channel A for 9600 8N1 and transmits debugging information through it. System Clock: 10MHz Osc + 74LS163 Counter - The 4-bit counter provides clocks at 5, 2.5, 1.25, and 0.625 MHz, selectable via pin header. The 555 in the upper-left corner provides a 10kHz clock signal for visual debugging also, but at this point the BIOS is far too long to sit around waiting for it to boot at that clock speed. Reset Controller: Analog! - At power on, a 1uF capacitor is slowly filled through a 1Mohm resistor to Vcc. When its voltage exceeds that set be a voltage divider (1/2 Vcc here), a comparator (TLC3702) releases the RESET_ assertion. A switch between ground and the capacitor provides another way to trigger a reset. So far so good! Hopefully I don't jinx myself here, but I haven't made a single wiring mistake yet. I have the logic analyzer sitting here ready, but every time I've added a new chip the unit has just booted right up and worked flawlessly - I can't believe it, given the sheer number of connections. By the way, I forked the assembler and fixed a few tiny things. Check it out on GitHub: z80asm. Also, I've spent a good bit of time writing emulations of the 8255, CTC, and DART in C as well as fixing the interrupt handling in my fork of z80sim: see my fork here. The file containing the my chip emulations is io.c (a work in progress at the time of writing). Tuesday, January 14. 2014Z80 Computer and Assembler Adventures
I recently pulled out the Z80 project computer I built several years ago in the hopes of adding some hardware and features to it, but was sad to find that it didn't want to operate in the slightest. A quick connection of the logic analyzer showed that the CPU was not fetching instructions. Hrm. I needed to determine if my delicate, hand-wired little computer was at fault somewhere, or if the CPU itself was upset.
First, I breadboarded the following setup to test the Z80. Since the opcode for the NOP instruction is 0x00, setting the data bus to zeros and providing correct external state causes the chip to simply count up the address bus when clocked. I pulled the data bus to 0s with 1k resistors since the chip is in an undefined state before reset and could attempt to write to the bus - bad news if you're tied to a rail. I then set WAIT_, INT_, NMI_, and BUSREQ_, leaving just a RESET_ and a clock source to add. I really like the simplicity of Z80: not only can I run the chip with only four pullups and no external components, but it will run with clock speeds all the way down to DC. That means you can single step your computer with a debounced push button as your clock - try that on a modern CPU! For this particular exercise, I rigged a 555 timer to generate a 10hz clock - slow enough to watch the address bus with LEDs. At the moment of truth, I got... nothing. The chip was tri-stating the address bus and not responding to RESET_. Unfortunately this meant I needed to dig deep into the depths to locate my box of Z80 items that I hadn't seen since college. However, not only did I find the box I was looking for quite quickly, I found a downright awesome pile of parts in there! I recalled that I had 3 extra Z80s and two 82C55's, but in reality I owned 16 Z80s of different vintages and speed grades, a few different types of 82C55, and an awesome pile of Z84 family peripheral controllers. I was very pleased. Back at my desk, I tested all 17 CPUs (the one that was in my computer, plus the 16 extra ones I had). It turns out that all of my spares are in perfect working condition, and the one in the computer was in fact dead as a door nail. Good to know! Next, I put a working CPU back in the computer, then wrote, assembled (using z80asm-1.2), and burned the following test program into flash: LD A,0x80 ; 1000 0000 - tell the 82C55 to set all ports to outputs OUT (3),A ; 0x03 is the control word address LD A,1 ; set one bit that we will rotate in the loop loop: OUT (0),A ; put the word out on port A of the 82C55 NOP RLCA ; left-rotate reg A JP loop Sure enough, it worked great in hardware. Unfortunately, I decided to test the code in an emulator before running the hardware, and ended up spending many hours debugging and rewriting the emulator's memory loading functionality to be properly endian-safe and to autodetect binary blob types, but I'll leave that rant for another time. In any event, this was a great refresher in Z80 architecture and assembly as well as the interworkings of the emulator. Now that my Z80 computer is working, I have no excuse not to add more cool things to the project... Monday, November 18. 2013Vectorplot
Since I don't own a vector analyzer, I've been working on a software implementation for the RTL SDR in flat C (using libusb1) and X11 so I can test my FPGA QAM code. It actually turned out to be much simpler than expected, and is working well thus far.
Right now it plots raw I and Q values on the plane as well as calculated FFT data. Since I haven't implemented clock recovery yet, signals appear as a circle (recall that for a frequency difference of N hz between the incoming signal and the sampling frequency, an N hz rotation around the IQ plane results - thus even a difference of a few hz is too quick to see anything but a circle). That shouldn't be very hard, and at that point it will become fully usable as a vector analyzer. Code is here: https://github.com/jackcarrozzo/vectorplot. Saturday, October 26. 2013Canon Video Comparison: T3i (600d) vs 7d
I've been a little unimpressed with the video sharpness from my Canon T3i body since I've had it. I recently determined that, likely due to constant-bitrate encoding, the specific condition causing shots to look muddled is complexity: shots of a cat or a rock may be quite sharp, but moving leaves and ripples on water are apparently too much to describe frame to frame.
I had read that the 7d has been used for several high-end movies as well as lots of commercials and shorts, so that was my go-to comparison. I was initially confused however as the T3i and 7d share almost all specs, especially related to video; both use the same APS-C sized sensor, both use 4:2:2 chroma subsampling, and both produce ~45mbit constrained baseline h.264 streams at 1080p and 29.97 fps. The only difference that I've been able to ascertain is that the 7d has two DIGIC 4 processors, whereas the T3i has but one. When my rented 7d arrived, I took both cameras with my to the pond near my house and shot some identical footage. It sure appears there is a difference: My only guess is that, with two processors, the 7d is able to spend more time encoding the video stream and as such does a better job of the task. Now that I know the 7d is in fact sharper, I've sold my T3i body and purchased a used 7d. When it arrives, I hope to do some more side-by-side shots to compare settings so as to conclusively determine the best settings for my shots. For what it's worth, the other main difference between the 7d and T3i is the autofocus: the 7d is worlds better. This isn't relevant for video since Canon bodies don't support constant autofocus during video, but for stills I appreciated it immediately. The 7d's high ISO noise may be slightly lower than the T3i but I didn't do an objective, controlled test. Tuesday, October 22. 2013Gyro-Stabilized DSLR Platform
I finally had time to put together one axis of my DSLR gyro frame today, and I am quite pleased with the results. The frame is big and heavy as it was originally intended to be a fixed-mount azimuth-altitude star and satellite rig for taking long exposures of planets and orbiting things, but it happened to be a good test bed for my gyro code. It's rock solid thus far:
Hopefully I will find time to build another axis soon so I can really see how solid both my math and my sensor are. I have a huge list of epic features to add to the project, too. I'm hoping I can get it solid enough to film with a 300mm lens and not need post-process stabilization. Wednesday, August 21. 2013Geiger Counter
I haven't done a whole lot of analog or power supply design, so I thought it'd be an interesting project to build a simple Geiger counter. In theory, their operation is very simple: provide ~500 vdc to the tube, and incoming particles will ionize the gas inside long enough to change the impedance of the tube, which we measure with a high-pass filter.
To create 500 volts from a 9v input (I'd like it to be portable), I used a 555 timer at 1khz to gate two 2n222 NPN transistors ground-side switching the input to the transformer. I tried a few HV transformers I had in the junk bin, but nothing was quite right, so I ordered a few CTX110607-R's which performed splendidly. From the output of the transformer, we go through two stages of voltage doubler (the last one acting as a rectifier and low pass filter), and voltage regulation is provided by two 200v zeniers and one 100v zenier. The signal is separated from the HV rails by a 50pf capacitor, which then goes to a comparator with one more filter between its two stages. This let me use a fast high-pass and a peak detector, as opposed to a single slow-enough-to-see-and-hear high-pass filter. After I confirmed my design with the mess on my desk, I soldered up a final version: Tuesday, June 4. 2013FPGA QAM Generation
I recently drew up a board to connect a fast DAC to FPGA dev boards for the purpose of RF generation. I chose the DAC900E from TI as it's fast (165MS/s), pretty accurate (10-bit), and extremely easy to interface (latches values in on clock edges, doesn't require any setup or external stuff).
Normally I'd cut a simple one-layer board like this on my CNC mill, but I wanted to try a low cost hobbyist PCB fab I read about via Sparkfun. The did take a very long while, but came out beautifully. Also, when the boards finally arrived, I was pleased I had picked a DAC with so few external requirements to solder. The resistors are there to prevent an output buffer short in case I soldered badly, by the way - I don't own a hot air rework setup. Right off the bat, I was pleased to see that my sine-generation test code worked great at various frequencies and bit depths (aliasing visible in the 2nd pic, its harmonics in the 3rd): With a bit more hacking, I got the FT245R interface to work such that I send I and Q values via USB, the output value is calculated from an LUT (I originally was doing the math out, but hardware multiply is very slow), and sent to the DAC. In these pics, you can see that I was generating a 500-hz tone over an AM carrier at 9.375 MHz (the 3rd image is the AM-demodulated signal shown on the spectrum analyzer). My code is on Github here. It's by no means robust or feature-rich, but it does work well in my opinion. When I have time, I'd like to see how far I can take this design. Assuming I don't find any unforseen roadblocks, the next step will be to make a board with two DAC900Es for I and Q generation that feed into a GHz-range QAM modulator that takes its carrier from a PLL on the FPGA, which will theoretically give me full TX control over a wide range of freqs. Monday, March 25. 2013Altera Quartus 12.1SP1 on Ubuntu 12.04 x86_64
I've been using Quartus in a virtual machine on my desktop since I hadn't been able to get it working on my 64 bit desktop. When I began using iVerilog and GtkWave for synthesis and simulation, my workflow efficiency went way up as I could code and debug everything in vim, then move to the annoying Quartus GUI app just to add pins and program a device. I then wrote a Makefile wrapper for the Quartus CLI tools, so once my pins were assigned I could make && make prog. However, it was still annoying that I had to boot a VM to program the device (as well as battle libvirt's USB passthrough, which works great except when it doesn't.)
Finally, I got Quartus to run properly on my desktop. I'm even more pleased than I expected to be, because it works great without the ia32-libs package (32-bit libraries... while theoretically it shouldn't break anything, I've had wierd issues in the past with it.) There are lots of older docs on Google that describe this, but they are all old and still talk about the USBfs issue (Ubuntu dropped it from their default kernel, and it took Altera a while to switch to the new /sys/bus/usb/ system. Luckily for me however, it turns out it's quite simple now, albeit a little ghetto (output from the scripts removed for clarity): root@moose /tmp # tar xfz /home/jackc/Downloads/12.1sp1_243_quartus_free_linux.tar.gz root@moose /tmp # cd 12.1sp1_243_quartus_free_linux/linux_installer/quartus_free root@moose /tmp/12.1sp1_243_quartus_free_linux/linux_installer/quartus_free # ./install --auto /usr/local/altera/12.1sp1_243 root@moose /tmp/12.1sp1_243_quartus_free_linux/linux_installer/quartus_free # cd ../quartus_free_64bit/ root@moose /tmp/12.1sp1_243_quartus_free_linux/linux_installer/quartus_free_64bit # ./install --auto /usr/local/altera/12.1sp1_243 root@moose /tmp/12.1sp1_243_quartus_free_linux/linux_installer/quartus_free_64bit # cd root@moose ~ # for x in /tmp/12.1sp1_243_quartus_free_linux/devices/web/*.qda; do LD_LIBRARY_PATH=/usr/local/altera/12.1sp1_243/quartus/linux64 /usr/local/altera/12.1sp1_243/quartus/linux64/quartus_sh --qinstall -qda "$x"; done root@moose ~ # echo 'ATTR{idVendor}=="09fb", ATTR{idProduct}=="6001", MODE="666"' > /etc/udev/rules.d/altera-usb-blaster.rules root@moose ~ # udevadm control --reload-rules root@moose ~ # mkdir /etc/jtagd && touch /etc/jtagd root@moose ~ # cp /usr/local/altera/12.1sp1_x64/quartus/linux64/pgm_parts.txt /etc/jtagd/jtagd.pgm_parts root@moose ~ # LD_LIBRARY_PATH=/usr/local/altera/12.1sp1_243/quartus/linux64/ /usr/local/altera/12.1sp1_243/quartus/linux64/jtagconfig 1) USB-Blaster(Altera) [2-1.7] 020F10DD EP3C(10|5)/EP4CE(10|6) You don't need to add startup scripts for jtagd, because any of the Quartus tools that talk to it first check that it's running, and start it if not. Here's my quick and dirty Makefile for building and programming: PROJ=iq_modulator TOPBLOCK=modulator QUBIN=/usr/local/altera/12.1sp1_243/quartus/linux64 ALTERALIBS=/usr/local/altera/12.1sp1_243/quartus/linux64 all: synth fit assemble netlist synth: LD_LIBRARY_PATH=$(ALTERALIBS) $(QUBIN)/quartus_map --read_settings_files=on --write_settings_files=off $(PROJ) -c $(TOPBLOCK) fit: LD_LIBRARY_PATH=$(ALTERALIBS) $(QUBIN)/quartus_fit --read_settings_files=off --write_settings_files=off $(PROJ) -c $(TOPBLOCK) assemble: LD_LIBRARY_PATH=$(ALTERALIBS) $(QUBIN)/quartus_asm --read_settings_files=off --write_settings_files=off $(PROJ) -c $(TOPBLOCK) timing: LD_LIBRARY_PATH=$(ALTERALIBS) $(QUBIN)/quartus_sta $(PROJ) -c $(TOPBLOCK) netlist: LD_LIBRARY_PATH=$(ALTERALIBS) $(QUBIN)/quartus_eda --read_settings_files=off --write_settings_files=off $(PROJ) -c $(TOPBLOCK) prog: LD_LIBRARY_PATH=$(ALTERALIBS) $(QUBIN)/quartus_pgm --no_banner -c 1 -m JTAG -o 'P;output_files/$(TOPBLOCK).sof' jtagconfig: LD_LIBRARY_PATH=$(ALTERALIBS) $(QUBIN)/jtagconfig Remember to change the spaces to tabs in the Makefile definitions if you paste it in! Also, one known hassle is that you need to be root or use sudo for anything in the Makefile other than 'make jtagconfig'. When I get around to fixing that, I'll update it here. EDIT: duh, my fault. The problem was that my project directory had previous output owned by root from when I was testing, and the Quartus tools didn't know how to handle that error. Oops. Wednesday, February 20. 2013All-Analog HF Transmitter
I'm going to Puerto Rico soon, and it just so happens we're staying on a beach facing the continental US. Since we won't have internet nor cell service while there, I thought it'd be fun to send tweets via HF as it would be a good excuse to building some simple analog radios. If I use slow synchronous CW driven and detected by FTDI dev boards and a few lines of C, all I need to do is hack up the radios themselves.
Starting at the TX end, I nabbed a gross piece of PCB from the pile and went to town dead-bugging the transmit chain. Yes, it looks like crap, but if it works as planned I'll design a proper board and cut it on the CNC mill. First I added the crystal oscillator, then its output buffer: Nice! We can see from the spectrum analyzer that we are indeed getting waves, albeit with some fairly serious harmonics. Now to add a low pass filter: In the first image, you can see that I added connectors between the previous stage's output and the filter's input so I can sweep the filter independently. In the next image, you can see the filter's response on the spectrum analyzer with the tracking generator providing a flat source. Finally, the last image shows our frequency response of the whole system (osc, buffer driver, and filter) - the filter successfully brought the first harmonic down to -54 dBc. Time to add another gain stage and filter: In the first pic, I'm again using the tracking generator to sweep only the response of this amplifier and filter (note that I removed the BNC connector I tacked onto the input of the first filter, and connected it directly to the output of the osc buffer). In the second, the whole chain is hooked up end-to-end. It's putting out 27 dBm (1/2W) at ~7.2 MHz, but the last amplifier transistor get warm quickly - looks like I'm going to need to replace that with something beefier. Update: Unfortunately I got wicked busy with work prior to leaving for PR and wasn't able to finish this. I do hope to pick it up again soon... Wednesday, February 13. 2013Exhaust Turbine Attempt
A few years ago, I built a gas turbine engine from an old car turbocharger with my friends Chris and Ken. Chris happens to work for a jet manufacturer for a living, so he knows a great deal about such topics. Chris and I have been plotting for some time to design a very simple two-stage axial flow single combustor engine, and the biggest thing holding us back is the ability to actually create the parts we design.
I spent some time playing with Aluminium (6061-T6) on my lathe to see if I could make a simple exhaust turbine wheel by separating a disk into fins and twisting them then sanding the edges into a semi-airfoil shape. First I roughed out the general shape I was going for, and drilled the hole through the center (my lathe bed isn't long enough to do so). I then made the finish cuts to the exterior and with the boring bar to the interior to get the shape and approximate surface finish I was looking for. Unfortunately, as I feared, the metal was too brittle to make the bend, and several fins broke off. Oh well, at least now I know that method won't work...
(Page 1 of 4, totaling 70 entries)
» next page
|
Email me:
jack {@} crepinc.com Recent Projects: Analog HF Transmitter Audi ECU Reverse Engineering Dual DAC QAM Modulator FPGA QAM Modulator Geiger Counter Gyro-Stabilized DSLR Platform Hybrid Rocket Engines Turbocharger Controller WWVB Rx and Tx Older Projects: Balancing Bot Capacitor Array CNC Mill DCIR Renderer Electric Gokart Hovercraft Low Alt. Temp. Model Shopping Cart Locker Trebuchet My Twitter occasionally shows projects I'm working on. My GitHub has code from a few projects on it. Quicksearch |