Wednesday, January 27, 2021

Trying to create a CV curve to convert exponential VCA to linear.

In this post I'll try to explain exactly how the xxx2164 (SSM2164, v2164, AS2164 etc) responds to CV and how it (in theory) can be linearised when controlled digitally. I've written V2164 throughout the post as this is the chip I have at hand, but they should all be similar.

NB: I write my math as I go along, so it reflects my way of thinking. It may not be the most direct route to the final result, nor the best way of explaining, but at least I think the results are correct

Whether or not the results are useful in practice are to be seen. The V2164 is temperature sensitive and may not follow the stated -0.033V/dB response at all (or indeed any) temperature. There may also be differences between chips, and the DAC resolution may not be high enough to prevent stepping even when using 16bit DACs.

The V2164 

V2164 has a -33mV/dB response, meaning a 33mV increase leads to a 1dB attenuation.

When using the V2164 with a 3.3V control signal, I realised that it very quickly gets very quiet and thus it's hard to set the exact gain/ attenuation that you want. As mentioned here, the usefull CV range is 2V which results in 2V / 0.033V = 60dB attenuation.

The signal amplitude is doubled/halved for every 6dB change (0.2V in our case) as noted here. That would as far as I understand, mean that the signal is halved 10 times at 2V. With a +/-5V signal input, output would be

$$((((((((((5 / 2) / 2) / 2) / 2) / 2) / 2) / 2) / 2) / 2) / 2) = 5 / 2^{10} = +/- 0.0049V$$

But what is the function / relation between CV and VCA response?


Decibel - change in amplitude 

At any time, the increase in dB between two levels \(a_0\) and \(a\), can be written as

$$d = 20 \cdot log_{10}({a \over a_0})$$

where \(log_{10}\) is the 10-logarithm. From now on I'll write just \(log\)

For example, if the initial amplitude a_0 was 1V and the new level a was 2V, the increase would be

$$d = 20 \cdot log({2 \over 1}) = 6.02dB$$

which is indeed what we said above - a doubling of amplitude is the same as a 6dB change. Let's confirm this with our calculation above - going from 0.0049V to 5V:

$$d = 20 \cdot log({5 \over 0.0049}) = 60.2dB$$

So, how can we rewrite the formula to represent the relationship between our CV and output amplitude?

Let's first express the amplitude change as a function of change in dB

$$d = 20 \cdot log({a \over a_0})$$ $$10^{({d \over 20})} = 10^{log({a \over a_0})} = {a \over a_0}$$ $${a \over a_0} = 10^{({d \over 20})}$$

Taking it one step further to make it easy to plot, we move \(a_0\) to the other side:

$$a = a_0 \cdot 10^{({d \over 20})}$$


Let's check with our initial ratio:

$$a = 1 \cdot 10^{({6.02 \over 20})} = 2$$

Just as expected. Here is a plot of this function:

X is change in dB, Y is amplitude. We can see that the initial amplitude is 1 and that 6dB gives an amplitude of 2. Increasing dB by another 6dB to 12dB shows another doubling of amplitude to 4


From decibel formula to CV response

One final step is necessary, we need to go from the general equation for change in decibel to response to our CV. This should be fairly easy. We know that the response is -0.033V per dB (note: negative volt, i.e. a voltage increase leads to attenuation, not amplification):

$$d_{dB} = {v_{V} \over {-0.033_{V \over dB}}}$$

which gives us a as a function of v volts:

$$a = a_0 \cdot 10^{({{v \over {-0.033}} \over 20})}$$ $$a = a_0 \cdot 10^{({v \over {-0.66}})}$$


Let's check:

Increasing the CV with 0.033V should attenuate the signal 1dB, meaning that a 0.2V signal should attenuate the signal 6dB, which means halving the amplitude. We choose 1 as the initial amplitude, because with CV = 0 the V2164 should have unity gain. While at it, let's rename amplitude a to gain g as that is really what we're talking about when it comes to the VCA:

$$g = g_0 \cdot 10^{({v \over {-0.66}})}$$

\(g_0 = 1\) (unity gain when CV is 0) gives us

$$g = 10^{({v \over {-0.66}})}$$

and finally

$$g = 10^{({0.2 \over {-0.66}})} = 0.5$$

Again, as expected. Here is a plot of the function:

X is CV in volts, Y is gain (unitless). As expected, the signal starts at 1 when the CV is 0, and drops exponentially when the CV increases. at 0.2V the gain has halved to 0.5


Finding the equation for a linear response

Great! Now we know what we're up against. Next, we need something that takes a number - our internal linear control signal, let's call it c - and converts it into something we can input to the VCA CV to counter the function above. We need something that increases it's drop at the same rate as the function above decreases its drop.

So let's see what we've got.


We want the following to be true:

$$10^{({f(c) \over {-0.66}})} = k \cdot c$$

where k is a constant (rate of change, stigningstall in norwegian), in other words, we want something that makes our exponential function linear. We already know that \(f(c) = v\) from our definition, so let's use that.


Now we need to figure out what the relationship between v and c is:

$$log(10^{({v \over {-0.66}})}) = log( k \cdot c)$$ $${v \over {-0.66}} = log( k \cdot c)$$ $$v = -0.66 \cdot log( k \cdot c)$$

This works fine for positive k (e.g. rising linear response), which is what we usually want. However, after \(k \cdot c = 1\) it becomes a negative number which we cannot represent directly with a DAC. Also, when \(k \cdot c = 0\), \(log(k \cdot c)\) is infinite, which means we can never really reach all the way down to 0 gain using an exponentially controlled VCA.

As x approaches 0 from above, y approaches infinity. When x (or rather \(k \cdot c\) in our case) is > 1, y is negative.


Combining the equation for v with our equation for g yields exactly what we want - a linear response (rate of change k times control signal c on the horizontal axis, gain g on the vertical).


For a negative k (e.g. falling response), \(log(k \cdot c)\) is not defined for positive control signals c as \(k \cdot c\) is a negative number. To still be able to use a positive control signal c to represent a falling curve, we need to add something to offset our zero point: \(log(p + k \cdot c)\) where p is the desired gain at c = 0 (e.g. what we get when we set c to 0 and combine our two equations). 

The combined response is not defined for positive values of c when k is negative. 

Adding a constant "shifts" the graph to the right. Here p is 2 and k = -0.5: we get a gain of 2 when c is 0 and a gain of 0 when c is 4. NB: This is just in theory, as explained above we cannot reach g = 2 for c = 0 because the logarithm approaches infinity. More on that further down.


p may still be present for positive values of k, however the same limitation applies - if \(p + k \cdot c < 0\) the result is not defined, and if \(-0.66 \cdot log(p + k \cdot c)\) is negative it cannot be represented directly by a DAC.


Our relation between c and v is thus:

$$v = -0.66 \cdot log( p + k \cdot c)$$

with the limitations

$$p + k \cdot c >= 0$$ $$log(p + k \cdot c) < 0$$


Using this in our equation for the VCA gives us

$$g = 10^{({{-0.66 \cdot log( p + k \cdot c)} \over {-0.66}})}$$ $$g = p + k \cdot c$$

which is indeed a straight line with gain p at \(c = 0\) and gain 0 at \(k \cdot c = -p\)


How to use this in practice

Now, we still have the issue of not being able to reach g = 0. We need to look back at what we said in the beginning, the effective CV range of the V2164 is 0 to 2V, and at 2V it has an attenuation of 60dB (or gain of -60dB). This is what we should use as our minimum value for g. The maximum value should be whatever we want as our maximum gain, noting that unity gain (g=1) is the highest we can get using a DAC directly connected to the VCA.

We need to know exactly what we mean by -60dB in this case. Here, it means -60dB down from unity gain. A change in dB from an initial value of a_0 to a new value a is written as 

$$d = 20 \cdot log({a \over a_0})$$

For us, \(a_0\) is 1 so 

$$20 \cdot log(a) = -60$$ $$log(a) = -3$$ $$a = 10^{-3} = 0.001$$

Let \(c_{start}\) and \(c_{end}\) be the two extremes for our control signal:

This gives us two equations from \(g = p + k \cdot c\)

I) \(g_{start} = p + k \cdot c_{start}\)

II) \(g_{end} = p + k \cdot c_{end}\)

We can now pick our \(g_{start}\), \(g_{end}\), \(c_{start}\) and \(c_{end}\) to find k and p.

Let's give two examples based on whether we want a rising or falling response to our control signal. We choose to use volts as the unit for our control signal and set 0V to 5V as the range. We could also choose the range to match whatever representation we use in our code, for example 0 to 65535 if we represent the control signal as an unsigned int.


For rising control signals

\(g_{start} = 0.001\), \(g_{end} = 1\), \(c_{start} = 0V\) and \(c_{end} = 5V\)

I) \(0.001 = p + k \cdot 0 => p = 0.001\)

II) \(1 = p + k \cdot 5V\)

I + II) \(k \cdot 5V = 1 - 0.001 => k = {0.999 \over 5}\)

Finally, we insert this into our formula for v, \(v = -0.66 \cdot log(p + k \cdot c)\)

\(v = -0.66 \cdot log(0.001 + {0.999 \over 5} \cdot c)\)

Our desired response. A 0 to 5V CV gives a gain of 0.001 to 1

For falling control signals:

\(g_{start} = 1\), \(g_{end} = 0.001\), \(c_{start} = 0V\) and \(c_{end} = 5V\)

I) \(1 = p + k \cdot 0 => p = 1\)

II) \(0.001 = p + k \cdot 5V\)

I + II) \(0.001 = 1 + k \cdot 5V => k \cdot 5V = 0.001 - 1 => k = \frac{-0.999}{5}\)


It should come as no surprise that k is indeed the negative version of the result for the rising control signal, the absolute value of the rate of change is the same for both.

Again we insert this into our formula for v, \(v = -0.66 \cdot log( p + k \cdot c)\)

$$v = -0.66 \cdot log( 1 + \frac{-0.999}{5} \cdot c)$$

Increased attenuation as CV increases. 5V CV gives a gain of 0.001

From CV seen at the VCA to signal that controls the DAC

We have one final step to make all this useful.

We have from the start assumed that whatever we are working with outputs voltages directly from our control signal, and that our \(c_{end}\) outputs exactly 2V. 

This of course is not true for a DAC. We can choose to use a DAC in two ways:

  1. We use a reference voltage of 2V. The max DAC value is then 2V
  2. We use a different reference voltage, say 5V, and use external circuitry to change this into our 2V.

In both cases, we need to know what DAC control signal results in 1V at the VCA control input

Ex: 

If we're using a 16bit DAC and a 2V reference, 1V is represented as 65536 / 2 - 1

If we're using a 16bit DAC and a 5V reference, 1V is represented as 65536 / 5 - 1


Let s be the DAC control signal, \(s_{1V}\) be the DAC control signal value that results in 1V at the VCA input, and v the output voltage seen at the VCA CV input. The relationship between v and d is then

$$v = \frac{d}{s_{1V}}$$


Entering this into our expression for v, \(v = -0.66 \cdot log( p + k \cdot c)\), gives us

$$\frac{s}{s_{1V}} = -0.66 \cdot log( p + k \cdot c)$$

$$s = -0.66 \cdot s_{1V} \cdot log( p + k \cdot c)$$

There is a possible pitfall to be aware of. How well the effort to linearise the VCA works in practice depends on the DAC resolution. The VCA attenuation increases rapidly in the beginning, a very small voltage change gives a huge attenuation. If the DAC resolution is not high enough, each step changes the voltage too much and we will get audible stepping for slow moving CVs.


Summary of useful results

The general equation to linearise the response of the V2164 is

$$s = -0.66 \cdot s_{1V} \cdot log( p + k \cdot c)$$

where 

  • \(s\) is the DAC control signal value, possibly an unsigned int for a 16bit DAC
  • \(s_{1V}\) is the DAC control signal value that gives 1V at the VCA input (e.g. 65536 / 5 - 1 with a 5v reference)
  • \(p\) is the desired VCA gain at c = 0
  • \(k\) is the rate of change (gain / control)
  • \(c\) is our internal control signal with a unit of our choosing
\(p\) and \(k\) are found by selecting min/max gain and min/max control signal values, and solving the following two equations with two unknowns:

I) \(g_{start} = p + k \cdot c_{start}\)

II) \(g_{end} = p + k \cdot c_{end}\)

In practice, gain can never reach 0. For a positive k, p must be > 0. For a negative k we need need to use a g_{end} > 0.

Remember

- k changes when we change between volts and int value for our internal control signal.

- c and s do not have to use the same units

- c is assumed to be positive in all calculations above, but it may very well be possible to use negative values here. I just haven't checked.

- low DAC resolution will lead to audible stepping


Further thoughts

If I remember correctly, the V2164 allows gain > 1 by using a negative CV.  Without actually trying, I would think that using the equations above would suffice for this as well. If you want to add 3dB of extra gain, just extend the desired attenuation down to -63dB and then add - 0.1V (3  * -0.033V) to the DAC output to shift everything 3dB up. I have not tested this though.

To linearise a different VCA with a different response, "just" replace -0.033V/dB in the initial equation for the CV response and the resulting linearising equation. The general cases are:

Let b be the CV response in volts per dB (-0.033V/dB for the V2164). We then get that:

gain as a function of CV is:

$$g = g_0 \cdot 10^{\frac{v}{b * 20}} $$

necessary linearising equation is

$$v = 20 \cdot b \cdot log( p + k \cdot c)$$

and the DAC control value for producing that v is

$$s = 20 \cdot b \cdot s_{1V} \cdot log( p + k \cdot c)$$


The end. Time to try this in real life!


Footnote: All graphs are made using https://www.desmos.com/calculator






Friday, January 22, 2021

Exponential VCA v2164 and CV response

A quick note on the effect of a linear CV on the V2164. I connected a pot between 3.3v and 0. When turning the pot, nothing is heard until the pot is 2/3 of the way to max (CV drops from 3.3 to 0 as the v2164 expects a reversed CV, 0 being max on/unity gain).

Measuring the CV at this point shows as expected, around 1.2V. This means that for the rest of the pot's travel, it has no audible effect. This further strengthens my belief in using linear VCAs for the XM8. Alternatively, one could use a 0 to 1.5v cv, but it will never fully turn off the VCA. 

I'm looking forward to testing the same with a CEM3360/AS3360


Update: This article says that the effective CV range is 2V, which is more like what I experienced:

http://www.sdiy.org/philgallo/mgbvca.html

SPI error handling on the PIC16F

Various stuff happens in the SPI module that indicate errors. Here is a short description of what is going on.

Double buffering

SPI on the PIC16F uses a double buffer consisting of SSPxSR and SSPxBUF. 

SSPxSR is the shift register directly connected to the input, it receives bits when the clock runs. Once 8 bytes have been received, it transfers its content to SSPxBUF, sets the SSPxSTAT.BF (buffer full) bit and raises the SSPxIF interrupt. The BF bit is cleared automatically when reading SSPxBUF.

Data to be transferred is written to SSPxBUF and shifted out either immediately (for master) or the next time the other device runs the clock (for slave).

The following two bits indicate errors in transmission:


SSPxCON1.WCOL

Write Collision. Is set if the user tries to write a new byte to SSPxBUF before the current one has been shifted out/transferred. The data written to SSPxBUF is ignored, and all future writes are also ignored until the WCOL is cleared by the user.


SSPxCON1.SSPOV

Receive overflow. Is set if a new byte is received before the old one is read. Only used when device is an SPI slave. Slave must read SPPxBUF even before transfers to prevent the setting of this bit. On overflow, the current byte in SSPxSR is lost. 

In my DCO I check this when SS is driven high, before copying received data to where the user program expects to find it.


SSPxCON3.BOEN

Buffer overwrite enable. If set to high, data is written to the SSPxBUF even if the current byte has not been read. The datasheet does not say explicitly that it does or does not set the SSPOV bit, but it can safely be ignored. BOEN is used if we want to chain SPI slaves as one long shift register - data written to the slave will automatically be transferred to the SSPxBUF and shifted out once the next byte is received, without being touched by the user code. This way, one can keep the slave select pin low, transfer any number of bytes corresponding to the number of slaves connected, and then raise the slave select pin once all data has been transferred.

This is NOT used for my DCO as it will receive three bytes for each slave before the SS is driven high and thus has its own logic for shifting data internally.


SS pin 

The slave select pin synchronises reception. When in use it will be held high until the master is ready to communicate. The master will lower the pin, then transfer data and finally rise it. Using the SS pin makes sure data does not become out of sync and allows multiple slaves on the same SPI bus.

When the SS pin is driven high, the SPI bit counter is reset to 0, even if less than 8 bits have been received, meaning we will never get out of sync as long as SS is used.


SPI Initialisation

I can't find it right now, but I read that SPI must be initialised only when the clock is in the idle state. It may be that this is just because if not we risk getting incomplete/corrupt data, but it still seems like a good practice.

The way I've achieved this in the DCO is to initialise the SPI when the SS pin goes high the first time. That means that the master can either drive the SS pin low and high again, or it will happen automatically if data is transferred (but the data transferred will be lost) if the slave has restarted for some reason, or starts after the master has sent its first byte. This may not be the solution for everyone but it is sufficient for me. A different option would be to use some other scheme where an additional pin on the slave signals its status as "ready to receive" or similar.

To be able to do this, I had to both set use of SS to true and map a pin as SS, and add an edge trigger interrupt to the same pin. The edge bit should be set to 1 (rising edge).

Another PS for the use of SPI: The TRIS bits for the pins in use must be set manually upon initialisation;

SDI (TRIS set = input)

SDO (TRIS cleared = output)

SS (TRIS set = input)

SCK (TRIS cleared = output for master and TRIS set = input for slave)

Any function not desired may be disabled by setting the opposite data direction/TRIS value.

Wednesday, January 20, 2021

+/-12v vs +/-15v in XM8

CEM3360 may run at +/-12V or +15/-5 to -9V. Because of this, I have to reconsider if I should run the XM8 on +/-12V or +/-15V. I have done a quick review of my modules to see if they are 12v compliant.

Of my modules, these will run fine on 12v

  • Bitcrusher
  • DCO. NB: Needs 3v3 reference voltage
  • Reconstruction filter
  • Distortion
  • Sample & Hold


These will have to be fixed

  • CEM3340
  • Moog filter
  • Ring mod - looks like it's doing some kind of biasing
  • Super saw
  • Wave shaper - may just add external reference
  • V2164 VCA - R9 must be 6k instead of 7.5k according to http://www.sdiy.org/philgallo/mgbvca.html


These are unknowns

  • Jupiter 6 and Juno filters - use +/-15V for trimming and for setting an absolute cutoff for CVs, rest seem ok
  • Noise - has 220k res to 15v at input, need to test
  • v2164 - MD goes to 15v, may be possible to use 12v.


More on CEM3360 and voltages:

https://synth-diy.org/pipermail/synth-diy/2019-April/171021.html

On 3360: https://kassu2000.blogspot.com/2019/03/dual-vca.html

Tuesday, January 19, 2021

Envelopes, VCAs and linear vs exponential

TL;DR: 

  • Use linear VCAs when controlling them digitally, even when controlling audio. That lets you generate whatever control slope you want in software.
  • The VCA response is always exponential, not logarithmic. The only time we're actually talking about something looking more like a logarithmic response is in classic "RC" envelopes where the attack part is more logarithmic. Logarithmic control signals are generally only used to linearise an exponential VCA.

The full text

Through testing the digital envelopes in combination with the v2164 VCA, I realised that all is not good. It was particularly hard to dial in the sustain level as it dropped so fast when turning the pot due to the exponential nature. This made me realise that I had to revisit the topic of envelopes to fully understand how it is done in practice.

My initial confusion stems from the fact that people keep saying that you should use exponential VCAs for audio because they more closely approximate the way our hearing works. While this may be true when using the VCA as a volume control alone, it isn't necessary true elsewhere in the synth.

There is a lot of confusion about the use of the terms log(arithmic) and exp(onential) in the synth world, both when talking about potentiometers, VCAs and envelopes. I'll not go into detail, but just conclude that the slope/response is almost always exponential, not logarithmic. The only time we're actually talking about something looking more like a logarithmic response is in classic "RC" envelopes where the attack part is more logarithmic, and even here it is just an exponential response turned "upside down" (charging a cap instead of uncharging it). Logarithmic control signals are generally only used to linearise the response of an exponential VCA.

Another thing that is repeated is that using an exponential envelope with a linear VCA is the same as using a linear envelope with an exponential VCA. That is almost true, but with an exponential envelope controlling a linear VCA, you get direct control of the sustain level whereas when a linear envelope controls an exponential VCA, we get the "mapped" version of the sustain level which is significantly lower than the control voltage - which may be what you want but I found it hard to actually get the necessary control.

There's another point to be made though. When people talk about exponential envelopes, I suspect they mean the classic ones that is the result of charging and discharging capacitors, "RC" response. Those have a rapid increase upwards at the start of the attack and a rapid decrease at the start of decay. Using a linear envelope with an exponential VCA would give you a slow attack. 

A better name for the stages in an "RC" response envelope seems to be concave upwards and concave downwards. This is not what you get with an exponential VCA controlled by a linear envelope. 

Top: A linear envelope. Middle: The effect of feeding the linear envelope above through an exponential VCA. Note that the attack slopes downward and that the sustain level is significantly lower than the linear input as an exponential VCA drops very fast in the beginning. An exponential envelope would have the same shape but you would of course control the sustain level directly. Bottom: "RC" response, the classic envelope shape you get from charging/discharging a capacitor.


A lot of other versions exists. When you dive into the realm of digitally generated envelopes you find stuff like the Alpha Juno multi stage envelopes where the slope changes on a per-stage basis.

Alpha Juno lets you set envelope by specifying Time and Level for each stage. Slope varies from stage to stage, sometimes being linear (1, 2) and sometimes exponential (3, 4). These envelopes are purely digital.


One question was still unanswered for me - with an exponential envelope, should one make it control an exponential or a linear VCA? I've concluded that it has to control a linear VCA. The issue with sustain level speaks clearly of this. You want the response of the envelope, not an exponential version of it - especially when doing digital envelopes as you can pretty much do whatever shape you like. Hopefully, the resolution of the CV is high enough to mimic exponential growth with a fairly good quality even at low volumes.


What VCA chip to use in the XM8

Having to use linear VCAs kind of sucks. I was hoping to use the v2164 quad VCA extensively because it offers four VCAs in a compact package and at a reasonable price. If envelopes should control linear VCAs, and if I want to be able to patch envelopes anywhere, I also need to use linear VCAs everywhere. My best option seems to be the AS3330, which is a dual lin/exp VCA costing almost twice that of the V2164 meaning I have to spend four times as much on VCAs. That in itself kind of suck, but it will also take twice the space on the PCB which REALLY sucks. 

I will give the V2164 a final try though. If I can generate a logarithmic control signal, the output response will be linear. There is a very standard circuit going around that does this by combining two 2164s, but that sort of defeats the purpose. I have to do it digitally. This may result in very low resolution for the higher volumes, we'll just have to see.

Update: AS3364 is a quad linear VCA, that may be a good option. Unfortunately it's +/- 12V, not 15. I've ordered 10 of them for testing. I also realised that I have both AS3330 and AS3360 chips that I can try if I want. The AS3364 seems to be a dual AS3360 but with the exponential inputs removed, the text and specs in the datasheet is almost identical. This is good as it makes it possible to replace the AS3364 (which is an Alpha Rpar specific chip) with two 3360s on an adapter board later, should one fail and no replacements be available.


Resources

https://www.muffwiggler.com/forum/viewtopic.php?t=217707

https://www.muffwiggler.com/forum/viewtopic.php?t=115675

https://www.gearslutz.com/board/electronic-music-instruments-and-electronic-music-production/984069-embarrassing-question-explain-alpha-junos-envelopes.html

https://musicianonamission.com/adsr/

https://www.muffwiggler.com/forum/viewtopic.php?t=102357

First test with envelopes

It's alive! Last night I did the first test with a DCO, envelope and VCA. It worked quite well, some "thud" sounds at the start of the envelope, and a big issue with the DCO pitch that I later tracked down to it ignoring the low 8 bits of the pitch int, but it does indeed play notes :-D 

Here is a video of the test: https://www.youtube.com/watch?v=0isvi7EzVX4

I have yet to figure out the exact pitch bug but I have to send six bytes instead of three and every 2nd byte is ignored. It may have been intentional and should be a fairly easy fix. Also, I should considering resetting SPI buffers etc on SS high.

I did run into some issues with high DCO update frequencies (>100 times per second) so that needs to be checked too.

The envelopes however, works a bit strange. I guess that exponential VCAs is the reason, I had to have a very high value for the sustain level to get any sound. I will study this closer.

Also, to speed things up in the CV department (now the CVs have a 1kHz refresh rate) I need to replace the clock and mux, here are some alternative clocks:

https://datasheet.lcsc.com/szlcsc/Texas-Instruments-TI-SN74HC4040DR_C6848.pdf

https://datasheet.lcsc.com/szlcsc/TOSHIBA-74VHC163FT_C150161.pdf

SN74HC393



Monday, January 11, 2021

DCOs and 3.3v

A quick note on the DCO and Vdd. 

The chosen flash memory runs at max 4.6V. The Teensy 4.0 is 3.3v and not 5v compliant. That means we should probably run the DCOs at 3.3v too. However, that means the DACs must run with a 3.3v reference voltage too, as Vref cannot exceed Vdd. Thus we have to recalculate the charge voltages and possibly change the integrator cap too, to still be able to make a 5v output wave.

Also, we need to add an external resistor in parallel with R7 to get the correct calibration voltage.

Thursday, January 7, 2021

Winbond W25Q128JVSQ memory

I bought a bunch of flash memory chips from JLCPCB last time I placed an order there, to use with the DCOs and elsewhere where memory is needed. I chose the Winbond W25Q128JVSQ as it was quite cheap, part of the basic parts at JLCPCB and 128Mbit/16MB which should be plenty for the DCOs.

I thought it would be fairly easy to integrate with but boy was I wrong! :-D I've spent so much time now getting it to work properly. First I couldn't figure out how to write to it, then I got all wrong values back. I spent several evenings debugging this little bugger but FINALLY it works.

I will connect the chip to the same SPI bus as the DAC on the DCO, so it's important that it works with the same SPI mode as the DAC8830. Fortunately this seems to be the case, it works in both SPI mode 0 and 3. Both these have stable data on the rising edge of the clock, mode 0 has a clock idle low and mode 3 has clock idle high. The DAC8830 seems to work with mode 0 so I think I'll be fine.

So what did go wrong?

I'll explain the last thing first - reading back data. I managed to write data, but whenever I had multiple 1s followed by a zero, I'd lose at least one 1, and the missing bytes would be padded with 1s at the end! I wrote 0xAA (0b10101010), but reading it back it was always 0x87 (0b100001111). The first bit seemed to be correct at all times though. I checked 10-15 different values and the pattern seemed to be stable.

I did everything I could think of - writing to different memory locations, replacing the flash chip, slowing down the SPI bus - I even considered testing the memory with a separate PIC16F18346 (e.g. without the DAC on the SPI bus) but couldn't find any in my office (I'm testing from the DCO board).

Finally I tried adding a decoupling cap to the 3v3 input of the flash chip and it immediately worked! Turning the SPI bus speed back up to 8MHz also worked fine (on a side note, 8MHz SPI sampled at 24MSamples/sec on the Saleae Logic 8 does not seem to be fast enough to read it properly.

I'm so happy but also a bit mad at myself for neglecting to do this from the start.


So, what else. First of all, the JVSQ version of the chip is a bit special - it starts up in a different mode than usual but I don't think I ended up doing anything about that (or if I did it got persisted the first time, I need to recheck that. Also, the chip has two pins - pin 3 (HOLD) and pin 7 (WP). They are not needed in normal operation. I've tried both leaving them floating and connecting them to 3v3, both cases seem to work fine. The audio board for the Teensy has them both wired to 3v3 so I guess that's the safer option:

NB! Add a 100nF cap between pin 8 and GND for decoupling. When using with the DCO board, connect MISO/MOSI and SCLK to the DAC SPI bus pins, and CS to one of the UTIL pins

The CS pin needs to track the power supply pin on startup, so a pull-up resistor from CS to 3v3 is necessary.


Now to the procedure for writing and reading.

First of all, this being flash memory it has to be erased before it can be written. writing can only change values from 1 to 0, so erasing sets all bits to 1. 

To be able to erase, we must first remove the write protection - every time. This is done by sending 0x06 (as a separate command, pull CS low and return it to high before continuing.

Then send 0x20 (Sector erase, erases 4k bytes. Larger erases are also available) followed by three address bytes that should hit a 4k boundary.

After doing this we need to wait for the operation to complete before doing anything else. This is checked by sending 0x05, and then reading the result of status register 1 (in a loop) until bit 0 is 1.


Writing works the same way. First remove the write protection (0x06). Then send 0x02, followed by three address bytes, followed by 1 to 256 data bytes. NB: Writing wraps to a 256 byte page, so if you don't start at the page start but write 256 bytes, you will start writing from the page start once the end is reached.

After completion, we once again have to wait for the correct status, just as with erase.


Now we're ready to read. Reading is easy, just write 0x03 followed by three address bytes, then read the bytes you want.


SPI

I was confused by the various SPI modes. First of all, the datasheet for the PIC16F18346 says that data is written transmitted on idle to active or active to idle. It took a long time before I understood that this is in fact when the data CHANGES, not when it should be read. Transmit on idle to active means READ on active to idle.

To make matters worse, the text in the winbond flash datasheet (https://www.winbond.com/resource-files/w25q128jv%20revf%2003272018%20plus.pdf) says "The DO output pin is used to read data or status from the device on the falling edge of CLK". That is NOT SPI mode 0 or 3. Fortunately, the example timing diagrams show that the data is in fact to be read on the rising clock edge as is expected for SPI mode 0 and 3.

To top it all, the values of the two params of SPI mode (CPOL - clock polarity and CPHA - clock phase) are not consistent between different producers or places of documentation. Looking at these two, notice that the CPHA values for mode 2 and 3 don't match:

https://en.wikipedia.org/wiki/Serial_Peripheral_Interface

https://www.analog.com/en/analog-dialogue/articles/introduction-to-spi-interface.html#

The actual edges used matches though, so it's just a case of using different values for settings. Very confusing.