Homebrew Embedded DSP - PCB In Progress
Posted: Sun Feb 17, 2013 1:24 pm
I guess this is the right section for this, happy for the admin to move the thread.
I've been interested in embedded DSP for a while but haven't wanted to splash out cash on a proper DSP development board so I had a crack at making one using easy to find/implement components. The goal was to see how much could be done with cheap components with the hope of making something useful that was easy for the casual homebrewer to reproduce.
The system blocks are:
Anti-alias filter -> MCP3201 ADC ($3.61) -> ATMEGA168P @ 20MHz (~$6.50)-> MPC4822 dual DAC ($4.20) -> Reconstruction filter (not yet built, see text below)
Total parts cost is about $15, depending on how many resistors/caps/op-amps are already on hand, prices are single unit quantities from Element14.
The anti-alias filter is two cascaded 3rd order Chebyshev filters (3dB passband ripple) built from a sallen-key topology (calculator here: http://sim.okawa-denshi.jp/en/Sallenkey3Lowkeisan.htm). The signal is biased to about 2V as the ADC/DAC operate on a 4.096V reference which is internal to the DAC. Since it's a dual DAC one of them is set to full scale in software and its output used as the voltage reference on the ADC.
To select an ADC I just searched on Element14 for 12-bit ADCs in DIP packages and sorted by price, the MCP3201 was the cheapest one with AU stock. Same deal with the DAC.
The ATMEGA168P was used because I had some lying around. It is defiantly NOT a good choice for a DSP calculations, the Microchip 16-bit dsPIC range would be the best I know of in a DIP, but I don't have a programmer or any experience with them. The best processor I know of would be a Texas Instruments Piccolo F28069 USB dev board (available from Element14 or Ti estore) which has an 80MHz 32-bit floating point processor on it.
Despite using a poor choice of CPU I managed to get it doing filtering with 3rd order elliptical IIR filters. Normally IIR filters are considered highly numerically unstable unless high precision calculations are used, but I managed to get them working using 32-bit fixed point arithmetic. A single filter calculation uses about 1500 cycles on the AVR, leaving enough for an envelope follower based compression as well! To make these calculations as accurate as possible the 12-bit ADC value is left shifted 4 times so the calculation has a 16-bit dynamic range. After the filter calculation it's shifted right 4 bits to remove the gain and numerical noise in the lower 4 bits. The filters were designed using the ellip() function in MATLAB/Octave, the coefficients it returns were multiplied by 2^16 for the fixed point calculations.
The (poorly commented) source code can be found here: http://www.fireflydesign.net.au/DSP.c
The large string of NOPs in the main idle loop are to reduce sampling jitter. With just while(1){} in the idle loop the compiler produced a single rjmp instruction. This takes two cycles to complete, if the timer interrupt triggered at the end/start of this instruction it started on the next clock cycle. If, however, the timer interrupt triggered half way through the rjmp instruction there would be a clock cycle latency on the interrupt service routine. This was fairly random and caused significant sampling jitter which increases the numerical noise floor. Adding a large number of NOPs reduces the jitter as the probability of the ISR triggering during the rjmp instruction is very low.
EDIT: Forgot to talk about the reconstruction filter. Instead of building one in hardware I did a LPF on the recording. For ham radio work the radio's ceramic IF filter will remove the high frequency (>4kHz) content.
Enough waffle, have some demo videos. If anyone wants more documentation (ie: a schematic and implementation notes) I'm happy to prep the documentation.
This video is a voice demo, the one below is synthetic signals.
This is the most up to date video, it shows all the currently implemented features:
Overall description and filter demonstration
Compression + filter demo, this is the setting I'd like to use on air
Enhanced compression, I fixed a few numerical issues so the compression was a bit less noisy and doesn't overflow/clip in this video
I've been interested in embedded DSP for a while but haven't wanted to splash out cash on a proper DSP development board so I had a crack at making one using easy to find/implement components. The goal was to see how much could be done with cheap components with the hope of making something useful that was easy for the casual homebrewer to reproduce.
The system blocks are:
Anti-alias filter -> MCP3201 ADC ($3.61) -> ATMEGA168P @ 20MHz (~$6.50)-> MPC4822 dual DAC ($4.20) -> Reconstruction filter (not yet built, see text below)
Total parts cost is about $15, depending on how many resistors/caps/op-amps are already on hand, prices are single unit quantities from Element14.
The anti-alias filter is two cascaded 3rd order Chebyshev filters (3dB passband ripple) built from a sallen-key topology (calculator here: http://sim.okawa-denshi.jp/en/Sallenkey3Lowkeisan.htm). The signal is biased to about 2V as the ADC/DAC operate on a 4.096V reference which is internal to the DAC. Since it's a dual DAC one of them is set to full scale in software and its output used as the voltage reference on the ADC.
To select an ADC I just searched on Element14 for 12-bit ADCs in DIP packages and sorted by price, the MCP3201 was the cheapest one with AU stock. Same deal with the DAC.
The ATMEGA168P was used because I had some lying around. It is defiantly NOT a good choice for a DSP calculations, the Microchip 16-bit dsPIC range would be the best I know of in a DIP, but I don't have a programmer or any experience with them. The best processor I know of would be a Texas Instruments Piccolo F28069 USB dev board (available from Element14 or Ti estore) which has an 80MHz 32-bit floating point processor on it.
Despite using a poor choice of CPU I managed to get it doing filtering with 3rd order elliptical IIR filters. Normally IIR filters are considered highly numerically unstable unless high precision calculations are used, but I managed to get them working using 32-bit fixed point arithmetic. A single filter calculation uses about 1500 cycles on the AVR, leaving enough for an envelope follower based compression as well! To make these calculations as accurate as possible the 12-bit ADC value is left shifted 4 times so the calculation has a 16-bit dynamic range. After the filter calculation it's shifted right 4 bits to remove the gain and numerical noise in the lower 4 bits. The filters were designed using the ellip() function in MATLAB/Octave, the coefficients it returns were multiplied by 2^16 for the fixed point calculations.
The (poorly commented) source code can be found here: http://www.fireflydesign.net.au/DSP.c
The large string of NOPs in the main idle loop are to reduce sampling jitter. With just while(1){} in the idle loop the compiler produced a single rjmp instruction. This takes two cycles to complete, if the timer interrupt triggered at the end/start of this instruction it started on the next clock cycle. If, however, the timer interrupt triggered half way through the rjmp instruction there would be a clock cycle latency on the interrupt service routine. This was fairly random and caused significant sampling jitter which increases the numerical noise floor. Adding a large number of NOPs reduces the jitter as the probability of the ISR triggering during the rjmp instruction is very low.
EDIT: Forgot to talk about the reconstruction filter. Instead of building one in hardware I did a LPF on the recording. For ham radio work the radio's ceramic IF filter will remove the high frequency (>4kHz) content.
Enough waffle, have some demo videos. If anyone wants more documentation (ie: a schematic and implementation notes) I'm happy to prep the documentation.
This video is a voice demo, the one below is synthetic signals.
This is the most up to date video, it shows all the currently implemented features:
Overall description and filter demonstration
Compression + filter demo, this is the setting I'd like to use on air
Enhanced compression, I fixed a few numerical issues so the compression was a bit less noisy and doesn't overflow/clip in this video