Let's Design and Build a (mostly) Digital Theremin!

Posted: 4/5/2017 12:28:29 AM
dewster

From: Northern NJ, USA

Joined: 2/17/2012

CLI (again)

I've completely rewritten the Command Line Interface (RS232 communications with a simple software monitor of sorts).  It now allows for backspacing on the command line and sports 5 commands:

1) The Read Memory command, or "rm", can take 2, 1, or zero parameters:

<start addr> <stop addr> rm

<addr> rm

rm

Two parameters create a listing of the address:data from the start address to the stop address.  The addresses are 32 bit, data is 16 bit, and both address and data are displayed as hex.  Start and stop addresses are saved in memory, so if the "rm" command is repeated with no parameters it will use the stored values.

2) There is an identical "rr" or Read Register command for the register set.

3) The Write Memory command, or "wm", can take 2 or 1 parameters:

<addr> <data> wm

<data> wm

Two parameters write the data to the address and increment the address before storing it. The address is 32 bit, data is 16 bit. The address is saved in memory, so if the "wm" command is repeated with no address parameter it will use the stored value.

4) There is an identical "wr" or Write Register command for the register set.

5) Finally, the "crc" command takes 2 parameters:

<start addr> <stop addr> crc

This calculates the CRC32 over the address range and kicks it out as a 32 bit hex value.  It actually gives the residue rather than the CRC, the CRC is simply the bit inverse.

One trick I ran across when implementing the hex display function was to output '0' for a zero valued input, and only prefix non-zero values with the expected "0x".  This helps to quickly visually spot zero values in a memory dump.  I also made the function suppress leading zeros, so it can be easily used for any width output up to 32 bits by truncating (zero extending) the input value to whatever desired modulo width.

The old CLI code was kind of spaghetti-like, this new one is much more structured.  I'm still fairly slow at it, but I think I'm finally getting the hang of assembly coding.

Posted: 4/17/2017 2:36:28 AM
dewster

From: Northern NJ, USA

Joined: 2/17/2012

So sorry that so much of this thread is ending up about my Hive soft processor rather than digital Theremins.  I promise to get back on the latter stick shortly.

For the last couple of weeks I've been thinking about and implementing a 16 bit literal memory channel in Hive.  Since each thread has access to a dual port memory, and both ports are 32 bits wide, one could potentially read and write 64 bits each cycle, which is a fair amount of bandwidth.  Each port has a single address (address port count is how ports are basically defined in FPGAs) so the 32 bit opcode port can supply a 16 bit literal or immediate along with the 16 bit opcode.  Writing to this port is problematic because the address is constrained to the program counter value, so I'm not doing that.  But the read gives an immediate value quite early in the cycle, so it can be used for just about anything in the pipeline.  The data port access is later in the pipe so I'm only using that for data reads and writes.

I'm using this new immediate as a jump value, and freeing up space in the opcode itself means it can compare two operands rather than just the one operand to zero, and it gives a much larger jump distance (16 bits vs. 8 bits).  Though of course the immediate consumes an opcode space, it executes in only one cycle along with the opcode, so there is savings of real-time.  I'm not using it in conjunction with the data port so that's a bandwidth opportunity missed.  I've retained the 8 bit jumps because they are efficient and I end up using them a lot.

The conditionals for the old 8 bit jumps are comparisons to zero (a==0), (a!=0), (a<0), (a!<0) which assume a is signed.  These cover most conditional situations, and those they don't cover can be preceded with a subtract or XOR to give a really wide range of comparisons.  In terms of two operand comparisons, equality (a==b), (a!=b) are clearly sign agnostic, but (a<b) and (a!<b) aren't.  After much thought I decided to implement these only as signed, which gives a total of 8 conditionals for this new 16 bit immediate jump:  (a==0), (a!=0), (a<0), (a!<0), (a==b), (a!=b), (a<b), (a!<b).  Unlike one operand zero only comparison, two operand gives a natural unconditional jump by comparing (a==a) or (a!<a), and indeed I've made this an automatic substitution in the assembly language code.

I finally got the bugs out of this new FPGA SystemVerilog code, the simulator, and the assembly code this morning, and my new command line assembly code is again working with it.  It's interesting and valuable to have the SV defining the hardware, the SV hardware simulation in Quartus, my C++ Hive simulation and assembler, and special verification assembly code to serve as independent checks on the correctness of the design.  When they all work you've generally got it nailed.  Though when the architecture changes this much (a new data channel in the PC pipeline) the churn can quite time consuming.  I'm hoping this will be my final big addition for a while.  The core (without Theremin logic, but with a UART and GPIO) consumes ~2600 LE (logic elements) and hits ~196MHz.  With the Theremin logic, around 2/3 of the FPGA fabric I'm targeting is consumed, which is a nice comfortable point to be at.  Any less and it feels like something is being wasted, any more and speed problems begin to creep in, and one starts getting nervous re. room to accommodate future changes.

I also decided to move the interrupt and thread clearing logic out of the opcode space and back into the register set space.  The version register wasn't doing much, so that's now doing double duty - external interrupts can be enabled or disabled, and internal interrupts can be initiated, along with thread clears, via writes to this register.

I've only used 8 opcodes out of the free 16 spaces for these new jumps, so there is room for future addition here.

It's weird, it's taken me years to get to this point, but if I had to do it again tomorrow I could probably code up Hive in a week. Recoding the sim and assembler / disassembler would probably take months though, it's a total bear and I'm quite happy to have that behind me.

Posted: 4/18/2017 6:06:07 PM
ILYA

From: Theremin Motherland

Joined: 11/13/2005

Dewster,
the more I rape the ARM core (Cortex), the more I feel the need for FPGA on DSP. I have a feeling that our paths will someday cross.

Posted: 4/18/2017 8:30:19 PM
dewster

From: Northern NJ, USA

Joined: 2/17/2012

Hi ILYA,

There are few things in EE that drive me as nuts as is the massive pointless complexity of processors.

But the ARM has it all over Hive in terms of floating point stuff (which is what I'm grappling with at the moment) and memory (can't do more than maybe an echo in terms of reverb in Hive).  Better FPGAs have floating point hardware and more memory, but they are likely too expensive for this application.

It might make the most sense to use an FPGA w/ Hive as the front-end, and run the data back to the ARM processor via serial port or similar.  I could whip up something like that in a day.  A small CLI could let you set parameters too.  

Or a really small front-end FPGA with no Hive, only dedicated hardware.  That wouldn't be very difficult either.

System timing would require some thought, you only want one master.

It's really hard to beat the flexibility of an FPGA at the center of it all.  No oscillators, no EQ coils, most of the wiring on-chip so the soldering iron stays cold.

Posted: 4/19/2017 3:36:58 AM
Buggins

From: Porto, Portugal

Joined: 3/16/2017

the more I rape the ARM core (Cortex), the more I feel the need for FPGA on DSP. I have a feeling that our paths will someday cross.

 

ILYA, what are limitations of ARM you faced with? Theremin sensor implementation or synthesis?

 

I'm going to use ARM M4 with hard floating point support (Teensy 3.6 board). Seems good and powerful enough.

 

Posted: 4/19/2017 1:35:02 PM
dewster

From: Northern NJ, USA

Joined: 2/17/2012

The Mysteries Of SPDIF

So I come downstairs this morning and decide to turn on the prototype and look at the pitch side noise via SPDIF one last time before I replace the software load with something else I'm working on.  The pass band noise floor looks good at -60dB with no spurs, but I notice that the noise is higher after being recorded for maybe 10 seconds, with clear spurs at 32Hz, 88Hz, etc.  By simply stopping and restarting the recording the noise floor goes back to good, then back to noticeable spurs after 10 seconds or so.  It seems that this is some kind of sample sync issue, where a software buffer is running out of resync room?  But what is it syncing to in the first place?

I look in the Audition hardware setup control panel and see the analog input is selected as the sync source, which doesn't make a lot of sense to me as there isn't any straightforward way to detect sync on the analog input - they must mean the free-running analog input hardware itself is being selected as the sync source.  With no SPDIF input to my sound card to sync to I guess I'm kinda stuck with this situation.  Not the end of the world, but rather confounding when you're peeping at the noise floor, trying to improve the source, and the destination is actively screwing you up.  The spurs aren't huge (the highest at 32Hz is below -48dB) but you gotta watch everything like a hawk.

Posted: 4/19/2017 2:07:53 PM
markaudiomusic

From: Canada

Joined: 3/9/2017

dewster: This thread is fascinating - thanks. When I am finished with my final tube based theremin next year, I will continue on my digital design. This thread will most certainly be a vast resource of knowledge.

What little I know of SPDIF is that the receiver extracts the clock from the source signal. There is no other choice.  If the source ADC clock is a little unstable, or if there is noise on the line, there can be enough bit slip to introduce noise into the analogue output. I hadn't thought that it could take up to 10 seconds though. That is weird.

I use SPDIF with Toslink adapters for my home theatre system running 35 foot cables for my ATSC receiver (don't ask).  I haven't noticed any objectionable effects when watching TV, but I shudder to think what I would see on my scope of I wanted (and I don't) to look.

Keep up the good work all.

Mark

Posted: 4/19/2017 2:26:35 PM
dewster

From: Northern NJ, USA

Joined: 2/17/2012

Hi Mark,

Glad you like the thread, it's kind a rambly and long though, more of an engineer's notebook blog.  At some point I may put an index in the first post.

The source of the SPDIF sampling issue seems to be either Windows or Adobe, or maybe the driver (too many layer of software written by too many programmers who don't know what's really going on).  I'm playing with the sync source, buffer depth, etc. in the Audition control panel but nothing seems to change anything.  The spurs kick in like clockwork right at 10s of recording, it's gotta be a sync & buffer thing.

Posted: 4/19/2017 3:39:08 PM
markaudiomusic

From: Canada

Joined: 3/9/2017

While black-box programming is great for ease of interfacing, it doesn't hold a candle to a truly through-programmed piece of code, but with vast resources of memory and of processing speed (My son is building a media server for fun using two 10-core 2.3GHz processors he got by trading a day of vacation for them from his company.), one can write bloated code and not worry too much. Sad, in a way.

10 seconds to see the spurs is still weird. If it precisely predictable, there should be an integer-based solution that would point to a buffer setting or interrupt priority setting. If it is not precise, it may still be buffer based, but caused by too much noise in the SPDIF signal.

Good luck.

Mark

Posted: 4/19/2017 4:33:49 PM
ILYA

From: Theremin Motherland

Joined: 11/13/2005

"Theremin sensor implementation or synthesis?" - Buggins

Signal processing. From a dead pure sine to a living sound.

 When I started my project, I thought of using algorithms with unchanged (or relatively slowly updated) parameters (formant filter  frequency for example). Simulation of natural sound requires a lot of interrelations, and the high-quality sound requires updating the parameters at the sampling frequency.

You must be logged in to post a reply. Please log in or register for a new account.