News:

SMF for DIYStompboxes.com!

Main Menu

Simple DSP Platform

Started by markseel, May 05, 2010, 04:43:10 PM

Previous topic - Next topic

markseel

Hi All,

I've never posted to a forum before so here goes ...

I have a simple DSP platform that I will be selling and I wanted to solicit comments regarding what I have so far:

Form-Factor:

20 pin DIP (can be placed in standard 20 pin 600 mil socket).  The board is double sided (components on both sides) and is 1.0" by 0.6".  Really small!

Pin-Out:

Pin 1 (Input): Serial TX (for downloading DSP program to FLASH memory).  Serial port protocol is standard 3.3v to 5.0v RS-232 like (1 start bit, 8 data, 1 stop, no parity).
Pin 2 (Output): Serial RX - not currently implemented.  In other words, this device supports program downloads but that's it so far.
Pin 3 (Input): Reset - Active Low.  The micro-controller is held in reset when low.
Pin 4 (Output): Vaa - 3.3 volt analog voltage supply from the on-board voltage regulator.  Can be used to power external circuitry.
Pin 5 (Output): Right channel analog output.  This is connected directly to the CODEC DAC output (no analog signal conditioning is present).
Pin 6 (Output): Left channel analog output.  This is connected directly to the CODEC DAC output (no analog signal conditioning is present).
Pin 7 (Input): Left channel analog input.  This is connected directly to the CODEC ADC input (no analog signal conditioning is present).
Pin 8 (Input): Right channel analog input.  This is connected directly to the CODEC ADC input (no analog signal conditioning is present).
Pin 9 (Output): Vaa/2 - 1.65 volt analog reference voltage.  Can be used to bias external analog circuitry (i.e. a virtual ground for an op-amp/buffer).
Pin 10: Ground: This is the single ground point for both analog and digital circuitry.
Pin 11 (Output): Vdd - 3.3 volt digital voltage supply from the on-board voltage regulator.  Can be used to power external circuitry.
Pin 12 (Input): Pot 1 - Low speed ADC input #1 on the Atmel micro-controller.
Pin 13 (Input): Pot 2 - Low speed ADC input #2 on the Atmel micro-controller.
Pin 14 (Input): Pot 3 - Low speed ADC input #3 on the Atmel micro-controller.
Pin 15 (Input): Pot 4 - Low speed ADC input #4 on the Atmel micro-controller.
Pin 16 (Input): Pot 5 - Low speed ADC input #5 on the Atmel micro-controller.
Pin 17 (Output): Sig 1 - General purpose output #1.  Controlled by the DSP (connected to the DSP's serial output #2).  Can drive an LED.
Pin 18 (Output): Sig 2 - General purpose output #2.  Controlled by the DSP (connected to the DSP's serial output #3).  Can drive an LED.
Pin 19 (Output): Sig 3 - General purpose output #3.  Controlled by the DSP (connected to the DSP's serial output #4).  Can drive an LED.
Pin 20 (Input): Supply voltage.  3.6V to 24V is acceptable.  Current draw is around 48 mA regardless of supply voltage (all regulators are non-switching LDO types).

Hardware:

1) Wavefront DSP-1K IC (specifically the AL3102).  This device, for those not already familiar with it, executes a sequence of simple DSP instructions (multiply, add, mac, logarithm, anti-log, jump/skip, etc) once every sample.  In other words, the DSP program will execute it's program sequence on each sample and then repeat.  It's a simple paradigm that's easy to grasp.  The AL3102 has I2S ports that allow for up to eight analog in/out channels although this design uses only two (stereo in and stereo out).
2) Wolfson WM8731M Codec.  The codec supports 24-bit 48 kHz stereo ADC's and DAC's.  I chose this device over the Wavefront ADC and DAC to reduce power consumption and board layout size.
3) Atmel AtTiny84.  Used for the potentiometer low-speed ADC's, to store the DSP program (in FLASH), to allow for DSP program downloading via the serial port, and to update the DSP with Pot (low speed ADC) values when they change.
4) Voltage regulators.  1 for the DSP, 1 for the digital portion of the CODEC and for the micro-controller, and one for the analog portion of the CODEC.
5) 12.288 MHz crystal, various caps and resistors.

Software:

1) The micro-controller is programmed with a kernel to allow for DSP program downloading to FLASH and to update the DSP with potentiometer values.
2) A python script for assembling and downloading the DSP program - provides a simplified programming model compared to the Wavefront assembler (The Wavefront assembler can also be used if desired).  The python script generates DSP program code and therefore allows for python code generates to be written by the user (for instance, you can write a code generator to emit DSP code for a low pass filter based on filter parameters rather than hard-coding the coefficients in the program).
3) Python sample code for DSP code generation for low and high pass shelving filters, distortion/wave shaping and interpolation and decimation (for up/down sampling when performing non-linear operations on sample data to reduce alias trash).

Other Stuff:

The use of python as a code generator makes programming this thing really easy.  I'll show an example in the next posting.  The Wavefront assembler isn't too bad either - so you can use that if learning Python is undesired (Python is a nice language though!).

The analog signal conditioning was left off of this board since that circuitry tends to be specific to the application (interfacing to instruments vs stereo line in/out for example).  Check out the Wolfson WM8731 specification for an example of interfacing to line-in and line-out (really easy).

There's a lot of low-cost (~$20 or less) boards that provide a serial connection to the PC via USB.  These devices, after being installed, provide a virtual com port for the OS.  This DSP board uses the standard serial port approach rather than I2C or SPI or USB for simplicity.

Price: $50 or so?

I hope this posting was appropriate for this forum.  The board is completed and the micro-controller firmware nearly done.  I'd be interested in comments and feedback!

Thanks!

Mark Seel
Next Audio, Inc

markseel

Hi All,

Here's some info regarding the programming model for this DSP platform.

While the DSP being used (AL3102) has an assembler I wanted to create a more simplified instruction set.

This simplified instruction set is not mandatory when using this platform (the Wavefront assembler could be used) but is does make the programming a bit easier since the DSP1K (DSP architecture name for the Wavefront AL3101 and AL3102) supports multiple operation per DSP instruction.  The DSP1K instruction set allows for data moves between the accumulator and B (temporary register), the accumulator and sample memory, multiply/accumulates using both immediate constants (stored in the instruction opcode) and sample memory as arguments.  Much of these operations can be specified to occur in parallel.  Because of the numerous combinations of operations the instruction set is somewhat large and the instruction mnemonics are a bit confusing.

The simplified programming model is as follows:

Memory Map


0x000 - 0x3FF --> Sample Memory
0x400 - 0x409 --> General Purpose Registers
0x40A - 0x40F --> Low speed ADC (Potentiometers) Values
0x410 - 0x417 --> Audio input and output samples


Instruction Set


JMP(label)            --> Jump to label
JZ (label)            --> Jump to label if Accumulator == 0.0
JNZ(label)            --> Jump to label if Accumulator != 0.0
JP (label)            --> Jump to label if Accumulator  > 0.0
JN (label)            --> Jump to label if Accumulator  < 0.0
JZP(label)            --> Jump to label if Accumulator >= 0.0
JZN(label)            --> Jump to label if Accumulator <= 0.0
PUT(address)          --> Memory[offset] = Accumulator
GET(address)          --> Accumulator = Memory[address + (Accumulator & 0xFF)]
SET(address)          --> Memory[address + (Accumulator & 0xFF)] = Accumulator
LOG()                 --> Accumulator = Logarithm16( B )
EXP()                 --> Accumulator = Antilog16( B )
00C(constant)         --> Accumulator = 0.000000000     * 0.000000000     + constant
1AC(constant)         --> Accumulator = 1.000000000     * Accumulator     + constant
AC0(constant)         --> Accumulator = Accumulator     * constant        + 0.000000000
AAC(constant)         --> Accumulator = Accumulator     * Accumulator     + constant
1CM(constant,address) --> Accumulator = 1.000000000     * constant        + Memory[address]
CM0(constant,address) --> Accumulator = constant        * Memory[address] + 0.000000000
CMA(constant,address) --> Accumulator = constant        * Memory[address] + Accumulator
ACM(constant,address) --> Accumulator = Accumulator     * constant        + Memory[address]
AMC(constant,address) --> Accumulator = Accumulator     * Memory[address] + constant
MMC(constant,address) --> Accumulator = Memory[address] * Memory[address] + constant



olilarkin

hey,

i came here looking for something just like this. Could you post some example python code for a simple effect?

thanks,

oli

markseel

Hi oli,

Not sure if this code has errors (I wrote it on the fly) but I have used the wave shaping algorithm shown in the code and it works pretty well.

For those not familiar with Python the # symbol starts a comment line (I put a lot of comments in this example).
I also tried to illustrate how the code-generation can be written once and called at any time to reduce source code complexity (and code re-use).


from next import *
import numpy

# Soft clipping using exponentiation: Y = (1 - 16^(-|X|)) / e
#
# Input:     Accumulator
# Outout:    Accumulator
# Memory:    None
# Registers: None
#
# Assembly program looks like this:
#
# JP  clip_pos ; Jump to 'clip_pos' if accumulator is > 0
# JN  clip_neg ; Jump to 'clip_neg' if accumulator is < 0
# JMP clip_end ; Do nothing to the sample if it's zero
#
# clip_pos:
#
# AC0 -1.00000000 ; A = -A      --> A = -A
# EXP             ; A = 16 ** A --> A = 16 ^ -A
# AC0 -1.00000000 ; A = -A      --> A = -(16 ^ -A)
# 1AC +1.00000000 ; A = 1 - A   --> a = 1 - (16 ^ (-A))
# AC0 +0.36787944 ; A = A / e   --> a = (1 - (16 ^ (-A))) / e
# JMP clip_end
#
# clip_neg:
#
# EXP             ; A = 16 ** A --> A = 16 ^ A
# AC0 -1.00000000 ; A = -A      --> A = -(16 ^ A)
# 1AC +1.00000000 ; A = 1 - A   --> a = 1 - (16 ^ (A))
# AC0 -0.36787944 ; A = A / e   --> a = (1 - (16 ^ (A))) / -e
#
# clip_end:

def SoftClip( name ):

# Emit DSP instructions for exponentiation based soft-clipping

yield iJP ( "clip_pos" % name )
yield iJN ( "clip_neg" % name )
yield iJMP( "clip_end" % name )

yield iOFF( "clip_pos" % name )
yield iAC0( -1.00000000)  # a = -a
yield iEXP( )             # a = 16 ** a      --> a = 16 ^ (-a)
yield iAC0( -1.00000000)  # a = -a           --> a = -(16 ^ (-a))
yield i1AC( +1.00000000)  # a = 1 - a        --> a = 1 - (16 ^ (-a))
yield iAC0( +0.36787944)  # a = a / 2.718218 --> a = (1 - (16 ^ (-a))) / 2.718218
yield iJMP( "clip_end" % name )

yield iOFF( "clip_neg_%s" % name )
yield iEXP( )             # a = 16 ** a      --> a = 16 ^ (a)
yield iAC0( -1.00000000)  # a = -a           --> a = -(16 ^ (a))
yield i1AC( +1.00000000)  # a = 1 - a        --> a = 1 - (16 ^ (a))
yield iAC0( -0.36787944)  # a = a / 2.718218 --> a = (1 - (16 ^ (a))) / -2.718218

yield iOFF( "clip_end_%s" % name )

def DistortionEffect()

# Emit DSP instructions for a distortion effect
# This program is run once for each ADC/DAC (stereo) sample

# I did not include code for upsampling/decimation/downsampling/interpolation therefore there will be some aliasing trash
# in the output signal due to the non-linear operations on the sample data.  Still sounds OK though!

yield iCM0( 0x410 ) # Emit DSP instruction to obtain sample from left input channel

# Emit DSP instructions for exponentiation based soft-clipping X 3 !!!

for i in SoftClip( "stage_1" ): yield i
for i in SoftClip( "stage_2" ): yield i
for i in SoftClip( "stage_3" ): yield i

yield iPut( 0x410 ) # Emit DSP instruction to output sample to left channel

markseel

Here's some photos of the prototype board.

The top view shows the AL3102 DSP and the WM8731 Stereo CODEC.
The bottom view shows the Atmel micro-controller, linear voltage regulators and the crystal.

http://picasaweb.google.com/111829367884437703386/NextAudioDigitalAudioSignalProcessor?feat=directlink

markseel

The Python script that is used with DSP board performs the following:

1) Provides the DSP instruction code generators for the simplified DSP instruction set (shown in a previous posting).
2) Assembles DSP programs (written using Python) into a Wavefront DSP-1K (AL3101 and AL3102 DSP chips) object code.
3) Downloads object code to FLASH memory using a PC COM port (specifically using a virtual COM port created by USB to Serial converter devices - these are cheap and easy to find/buy/use).  Object code files from Wavefront's DSP-1K assembler can also be downloaded (but not simulated - yet).
4) Simulates the DSP programs in case you want to use Python to create test signals and plot time or frequency domain results, play WAVE files (not in real time), etc.

I put a screen shot of a simulated program (the program from the previous posting) using a sine-wave for the left input at:

http://picasaweb.google.com/111829367884437703386/NextAudioDigitalAudioSignalProcessor?feat=directlink#

Note that the simulator does not simulate the fixed-point math of the DSP-1K but rather uses the PC's floating point capabilities instead.  Therefore the simulation won't exhibit numerical problems (truncation, rounding error, log/anti-log approximation) to the same degree as the actual DSP (which uses fixed point math with S3.18 and S3.24 formats).  But it does prove useful for checking the programs general functions.

Taylor

Would this product be a development board, or is $50 what each unit would cost if you were planning to build actual pedals with it?

markseel

I don't have a seperate development board for this device that provides the USB/serial connection, line in/out or instrument (guitar) in/out jacks and associated analog circuitry (impedance matching for line in/out, high impedance buffer for guitar in, etc.  This would be an easy board to make so if there's interest I'd consider make that available somehow.

I intended this board to be used in an effects pedal and therefore tried to make it small and low power.

$50 gets you the DSP board (AL3102, WM3871, AtTiny84, regulators, crystal), the software to assemble/test/download your programs and some example code for high/low pass filters, shelving filters, interpolation/decimation, a distortion effect - maybe more when I have time.

Since the DSP programs are written using Python I was hoping that DSP modules would be developed and shared by others.

Currently for development I plug the 20-pin DIP DSP board into a breadboard, plug in a USB/serial converter, wire up an op-amp or two and hook it up to the guitar and amp.  Then I download the program and annoy everyone in the house with my lack of guitar skill!!!

I'll take a picture of my breadboard tonight and post it.

I hope this answers your question!

slotbot

#8
man nice job on teh pcb.

also just to clarify, there isnt really any way to I/O other than downloading the program? like no SPI or whatever ?

way to keep it compact though!

markseel

Thanks slotbot!  My goal was to make it as small as possible.  Pretty small footprint for a 48 MIPS DSP with 24 bit stereo in/out and connections for pots and leds.

The I/O on the board consists of:
1) Stereo analog in/out
2) Serial in (for downloading a program to flash memory
3) 5 low speed ADC inputs

The serial input, serial output, reset and low speed ADC inputs are all connected to the AtTiny84.

There aren't any SPI or I2C connections on the board but ... you could reprogram the part with custom firmware and re-purpose the boards pins that connect to the AtTiny84.

It's possible to connect an Atmel AVR programmer to this board (that's what I do when I download updated firmware) in case you want to write and burn your own firmware into flash memory.  If people are interested in that then I'll supply a schematic.


markseel

Here's some photos of the DSP board being used with a guitar connected to ADC left input and an amp connected to the DAC left output.

http://picasaweb.google.com/111829367884437703386/NextAudioDigitalAudioSignalProcessor?feat=directlink

Shown is the USB/serial converter board for downloading DSP programs to flash/eeprom, the 20-pin DSP board, a transistor buffer for the guitar input, and the AVR programmer. 

The AVR programmer is not needed for DSP algorithm development and downloading - I use it to update the AVR firmware (the firmware is used to load the DSP, send pot values to the DSP, etc, accept new DSP programs via serial transfer, etc).

markseel

Here's some sample code to create an approximated sine wave.  The Python code generates the DSP code and can be 'dropped in' to any DSP code generator program in order create any number of sine waves, each with different frequencies.

This can be used to generate test tones or to generate LFO's for chorus/flanger effects (I'll show this in an example to follow).  The Wavefront DSP doesn't have built in LFO's like the SpinSemi FV-1 so you have to code it.

The example produces a decent sine wave - more precise synthesis is possible at the expense of more program code.

Here's the Python DSP code generator and the code to simulate and download the resulting DSP code:


# -------------------------------------------------------------------------------------------------
# NAME:        SineGenerator
#
# DESCRIPTION: Generates DSP code for a sine wave generator.  This can be used to produce audible
#              test tones or for low-frequency oscillators (LFO's) for modulation (i.e. delay
#              modulation in chorus and flanger effects).
#
# ALGORITHM:   The sine wave is approximated using the following formula:
#
# PROCEDURE:   The time couting and sine approximation procedures are:
#              Sine(X) = X * (4/PI - X*4/(PI^2))
#              See 'http://www.devmaster.net/forums/showthread.php?t=5784'
#
#              1. A tick counter is used to count from 1.0 down to 0.0 and then repeat.  It's
#                 period (and the sine wave period) is determined by the argument 'sine_freq'.
#              2. The tick count is converted to a -pi to +pi range (the angle for the sine wave)
#              3. The sine angle is checked for polarity (positive or negative)
#              4. The angle is used to approximate the sine value.
#
# PARAMETERS:  samp_freq - The sampling frequency (i.e. 48000)
#              wave_freq - Sine waveform frequency (i.e. 100)
#              time_reg  - Register used to store tick/time counter
#              temp_reg  - Used to hold a temporary value during sine approximation
#         
# INPUTS::     None
# OUTPUTS:     Accumulator - Approximated sine wave sample value
#
# MEMORY:      19 Program Words, 0 Sample Memory Words, 2 Registers (1 temporary)
# -------------------------------------------------------------------------------------------------

def SineGenerator( name, samp_freq, sine_freq, time_reg, temp_reg ):

period = float(sine_freq) / float(samp_freq)

# Get current timer valu, reset if needed, update value for each sample period
yield i1CM( +0.0, time_reg )    # A = time/tick counter
yield iJP ( "%s_sinegen_1" % name )           
yield i00C( +1.0 )              # A = 1.0                --> reset time value to 1.0
yield iOFF( "%s_sinegen_1" % name )
yield i1AC( -period )           # A -= period            --> timer counts down to zero by 'period'
yield iPUT( time_reg )          # Register[time_reg] = A --> Store updated time counter
# Change range from 0:1.0 to -pi:+pi
yield i1AC( -0.5 )              # A = A - 0.5
yield iAC0( 2 * 3.14159256 )    # A = A * 2pi
# Approximate sine for positive angle
yield iJN ( "%s_sinegen_neg" % name )
yield iPUT( temp_reg )
yield iAC0( -0.405284735 )
yield i1AC( +1.273239545 )
yield iAMC( +0.0, temp_reg )
yield iJMP( "%s_sinegen_end" % name )
# Approximate sine for negative angle
yield iOFF( "%s_sinegen_neg" % name )
yield iAC0( -1.0 )
yield iPUT( temp_reg )
yield iAC0( -0.405284735 )
yield i1AC( +1.273239545 )
yield iAMC( +0.0, temp_reg )
yield iAC0( -1.0 )
yield iOFF( "%s_sinegen_end" % name )

def TestSineGenerator():

for i in SineGenerator( 48000, 1000, 0x400, 0x401 ): yield i
yield iPUT( 0x410 ) # Store sine value to left output channel

object_code       = Assemble( TestSineGenerator() )
(inputL,inputR)   = Synthesize( "sine", 1.0, 1000, 2, 48000 )
(outputL,outputR) = Simulate( object_code, True, inputL, inputR )
Plot( "tran", 48000, outputL, outputR )
Download( "COM3", object_code )



Here's the resulting DSP assembly code:


0000 1CM 400h 0.0000000
0001 JP  test_sinegen_1
0002 00C 1.0000000

test_sinegen_1:

0003 1AC -0.0208333
0004 PUT 400h
0005 1AC -0.5000000
0006 AC0 6.2831851
0007 JN  test_sinegen_neg
0008 PUT 401h
0009 AC0 -0.4052847
0010 1AC 1.2732395
0011 AMC 401h 0.0000000
0012 JMP test_sinegen_end

test_sinegen_neg:

0013 AC0 -1.0000000
0014 PUT 401h
0015 AC0 -0.4052847
0016 1AC 1.2732395
0017 AMC 401h 0.0000000
0018 AC0 -1.0000000

test_sinegen_end:

0019 PUT 410h


I posted the simulated result (graph) with a sine input signal for comparison with the simulated sine output at:

http://picasaweb.google.com/111829367884437703386/NextAudioDigitalAudioSignalProcessor?feat=directlink

All, as I continue to update this posting I feel I may be abusing this forum somewhat - not really sure.  If that's the case then let me know and I'll stop posting and start a blog entry.

Hides-His-Eyes

I think that even if it feels like you're talking to yourself, you never know when in 1, 2, 5 years time, someone will be searching for what you've said and find it extremely useful!

markseel

Here's a video!  Sorry about the poor guitar skills (I can do some power chords but that's about it!!!) ... enjoy!

http://www.youtube.com/watch?v=1N9kv1R110U

Taylor

I guess I'm wondering how this positions itself in relation to, for example the FV-1. The price is much higher per unit, so is this mainly intended for DIYers only? I really like the FV-1, but would be interested in a solution with more pot inputs with faster read times. I'm just trying to figure out if/how this could be implemented in a unit for sale. I may be misunderstanding what this is for, though.

It's a cool accomplishment in any case. Your distortion sounds pretty good IMO.

markseel

#15
Hi Taylor,

The FV-1: 6 MIPS, 128 byte instruction memory, 32K(?) sample memory, built in LFO's, 3 pots, 3 switch inputs (outputs too?), clipping led, 40-60 mA, 3.3V, program assembler, sample source -- and 8 built in reverberation effects.

The Next Audio DSP board: 48 MIPS, software based LFO's, 1K instruction memory, 1K sample memory, 5 pots, 3 led outputs, 50 mA, 3.6 to 24V, program assembler, sample source

SpinSemi make a development board (never used it).  The Next Audio DSP board is intended to be used for development as well as deployment.  The FV-1 chip could easily be put on a small board as I did with the Wavefront chip.

The FV-1 seems more geared towards delay-based effects (not so much program mem, lots of sample mem).  The Wavefront part seems more geared towards equalization and computation.  Both architectures share the same paradigm (MAC instruction sequence per audio sample).  The wavefront part has a -7.9999 to +7.9999 numerical range while the FV-1 part is something like -2.0 to +1.9999.  Both have log/exp functions.

How much is the FV-1?  I suppose an FV-1 solution would also need a crystal and some passives - seems pretty low cost.

My DSP board, unfortunately, isn't so cheap.  The AL3102, CODEC, micro-controller and crystal probably costs $15 to $20 in low quantities.  Add the board and passive and perhaps we're at $25.  That's why I planned to sell them for $50 (I have to procure parts, assemble/solder and test the units).  I'm not sure how to bring that price down - perhaps if I can plan for sales to exceed 100 then I can procure at volume pricing.

OCT provides an FV-1 based board that measures 1.2" by 2.1" for $27.50.  Doesn't look like you can program it (someone correct me if I'm wrong).

Small Bear sells the fv-1 for $17.50.  You'd have to add the crystal, board and passives beyond that.

Any thoughts?

Taylor

Ok, that's a good rundown.

OCT sells the chip direct for less than Small Bear. I'm not sure if they don't want the price posted online since it's not on their website, but you can contact them for the specifics.

Can the Wavefront address external memory?

markseel

Nope, the Wavefront DSP is limited to 1K of sample data RAM (on chip) - no external sample RAM - bummer.
For delay effects this limits delay times to 21 msec with 48 kHz sampling, or 31 msec with 30 kHz sampling.
Not good for reverb/delay.  But it should be OK for chorus/flanging.
I'm going to try a chorus soon and see how it sounds.
The FV-1 has 32K - huge in comparison.  It only has 128 bytes of program RAM (6 MIPS) but that seems to be more than enough for a reverb effect.


audioartillery

I like how tiny these are.  They could be nice for embedding inside a guitar for an on-board effect.

The python assembler is a nice touch.

markseel

Here's another prototype (the prototype is fully functional but it has a different micro-controller and a different pin-out than the up-coming revision).

http://picasaweb.google.com/111829367884437703386/NextAudioDigitalAudioSignalProcessor#5472795123412796562
http://picasaweb.google.com/111829367884437703386/NextAudioDigitalAudioSignalProcessor#5472795126661512594

It will have 10 pins (plus a programming pad) instead of 20 pins (see previous postings).  It will also cost less then the 20-pin device.

Pin-out: Two pins for 3.3V and GND, 4 pins for stereo in/out (24 bit, 48 kHz), and 4 pins for pots.  There's one exposed pad for downloading the DSP program to non-volatile (flash) memory via the serial protocol (1 start bit, 8 data bits, 1 stop bit).

Like the 20-pin unit it uses the Wavefront AL3102 DSP, Wolfson WM8731 Stereo Codec and the Atmel AtTiny84 micro-controller.  It does not have linear v-regs on-board therefore the supply voltage is 3.3V rather than 3.6-24V, nor does it have LED outputs.

Since it's a SIP module it takes up very little board space (can be mounted up-right).  I'm sending the board artwork out tomorrow and should have boards ready in 4-6 weeks.