Skip to content

Commit

Permalink
Second batch of edits from Larry
Browse files Browse the repository at this point in the history
  • Loading branch information
hamsternz committed Oct 10, 2012
1 parent 1cb1c94 commit b927f74
Show file tree
Hide file tree
Showing 14 changed files with 248 additions and 263 deletions.
Binary file modified IntroToSpartanFPGABook.pdf
Binary file not shown.
55 changes: 22 additions & 33 deletions adc/content.asc
@@ -1,16 +1,16 @@
Using an ADC
------------

This chapter is only applicable to Papilio One board, as the Basys2 does not include any ADC functionality - it is still a useful read as it shows how simple periperals can be to interface to.
This chapter is only applicable to the Papilio One board when used with the LogicStart MegaWing, as the Basys2 does not include any ADC functionality - it is still a useful read as it shows how simple peripherals can be to interface to.

Unlike other project so far, I've included the full code for the module, giving some sort of reference implementation that can be used to verify your own design.
Unlike other projects so far, I've included the full code for the module, giving some sort of reference implementation that can be used to verify your own design.

The ADC
~~~~~~~

The ADC on the LogicStart is an 8 channel 12 bit ADC, with a serial interface compatible with the Serial Peripheral Interface Bus ("SPI") standard. The reference voltage for the ADC is 3.3V, giving a resolution of about 0.8mV.
The ADC on the LogicStart is an eight-channel 12-bit ADC, with a serial interface compatible with the Serial Peripheral Interface Bus ("SPI") standard. The reference voltage for the ADC is 3.3V, giving a resolution of about 0.8mV.

In the official SPI bus specifies four logic signals are called:
The official SPI bus specifications uses four logic signals. They are called:

- SCLK: serial clock (output from master);
Expand All @@ -24,51 +24,51 @@ But for this design I'm following the names used in the datasheet - which are na

- CS; Chip Select
- DIN; Date In
- DIN; Data In
- DOUT; Data Out
- SCLK; Serial Clock
To read channel 0 of the ADC it is pretty simple
To read channel 0 of the ADC it is pretty simple:

- Hold DIN low (this ensures that you read channel 0)
- Hold CS high while the ADC is idle
- Lower CS when you are ready to convert a sample
- Send 16 clock pulses of with a frequency somewhere between 8MHz and 16MHz,
- Send 16 clock pulses with a frequency somewhere between 8MHz and 16MHz
- Raise CS when finished
The data bits will be available on DOUT for clocks pulses 4 through 16.
The data bits will be available on DOUT for clock pulses 4 through 16.

image:adc/adc.png[]

To read another diffeent channel is a little harder - you need to give the ADC the bits to select the channel ''for the next sample'' on clock pulses 2, 3 and 4. These bits are sent in MSB first order.
Reading a different channel is a little harder - you need to give the ADC the bits to select the channel for the next sample on clock pulses 2, 3 and 4. These bits are sent in MSB first order.

This sounds simple enough, but as ever the difficulty is in the details. To make this work reliably the setup and holdup times must be factored in:
This sounds simple enough, but as ever the difficulty is in the details. To make this work the setup and holdup times must be factored in:

- CS must go low a few ns before the SCLK line drops for the first time
- The DOUT signal transition just after the rising edge of the SCLK signal. For reliable results it needs to be sampled mid-pulse
- The DOUT signal transitions just after the rising edge of the SCLK signal. For reliable results it needs to be sampled in the middle of the clock pulse
- The DIN signal must be given enough time to be stable before the SCLK falls
I decieded that the easiest way to do this is to run a counter at the 32MHz clock of the crystal, then the gross timings for the signals are:
I decided that the easiest way to do this is to run a counter at the 32MHz clock of the crystal, then the gross timings for the signals are:

- the SCLK signal is generate from bit 2 of a counter running at the system clock of 32MHz
- the SCLK signal is generated from bit 2 of a counter running at the system clock of 32MHz
- bits 3 through 6 indicates what bit of the frame we are on
- bits 3 through 6 indicate what bit of the frame we are on
- if bit 7 or over are set, then CS is held high.
- if bit 7 or over are set, then CS is held high
- Data is sampled when the lowest two bits are "10"
- data is sampled when the lowest two bits are "10"
To ensure that I don't have any setup and hold time issues with the interface a shift register is used to delayed the SCLK signal by one cycle, and a second shift register is used to delay DIN by three clocks. This ensures that CS and DIN have at plenty of setup and hold time.
To ensure that I don't have any setup and holdup time issues with the interface, a shift register is used to delay the SCLK signal by one cycle, and a second shift register is used to delay DIN by three clocks. This ensures that CS and DIN have plenty of setup and holdup time.


VHDL for the interface
Expand Down Expand Up @@ -171,7 +171,7 @@ begin
end rtl;
--------------------------------------

Constraints for the Papilio One board
Constraints for the Papilio One board:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The constraints required to implement the interface are:

Expand All @@ -197,22 +197,11 @@ The constraints required to implement the interface are:
NET "clk" LOC="P89" | IOSTANDARD=LVCMOS25 | PERIOD=31.25ns;
--------------------------------------


Project - Playing with the ADC
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Modify the above project to output all 12 bits, and display it on the Seven Segment display in hex.

A jumper wire with a 100Ohm resistor is useful for testing, but only test using the GND, 2.5V and 3.3V singnals - connecting the ADC to 5V will damage it! Another option is to use one of the colour channels on the VGA socket, giving you a range of sixteen test values.

* If you multiply the value received by 129/16, you have a range of 0 to 33016 - very close to 10,000*Vin). The multiplication is wasy to do in logic, but can you convert the remaing binary back to Decimal to display on the seven segment display? One easy way would be to build a Decimal counter, that counts up to the sampled value.
* Modify the above project to output all 12 bits, and display the value on the Seven Segment display in hex.

A jumper wire with a 100 Ohm resistor is useful for testing, but only test using the GND, 2.5V and 3.3V signals - connecting the ADC to 5V will damage it! Another option is to use one of the colour channels on the VGA socket, giving you a range of sixteen test values.

* If you multiply the value received by 129/16, you have a range of 0 to 33016 - very close to 10,000*Vin. The multiplication is easy to do in logic, but can you convert the resulting binary back to decimal to display on the seven segment display? One easy way would be to build a decimal counter, that counts up to the sampled value.
37 changes: 18 additions & 19 deletions audio/content.asc
@@ -1,27 +1,27 @@
Generating analogue signals
---------------------------

One of the nice features of FPGAs is how versitile the I/O pins are. I this chapter we will make a standard I/O pin generate an analogue signal, playing a tone using a waveform that is stored in block RAM
One of the nice features of FPGAs is how flexible the I/O pins are. In this chapter we will make a standard I/O pin generate an analogue signal, playing a tone using a waveform that is stored in block RAM.

This module is largely based on Xilinx's AppNote xapp154.pdf
This module is largely based on Xilinx's AppNote xapp154.pdf.

One bit (Delta Sigma) DAC
~~~~~~~~~~~~~~~~~~~~~~~~~
You are most probably familiar with Pulse Width Modulation (PWM) - It is when a signal of a constant frequency has its duty cycle modulated to generate different power levels. If a PWM signal is passed through a low pass filter you end up with an analogue voltage that is proportional to the duty cycle. PWM is used in power supplies, light dimmers and motor controllers and such.
You are most probably familiar with Pulse Width Modulation (PWM), when a signal of a constant frequency has its duty cycle modulated to generate different power levels. If a PWM signal is passed through a low pass filter you end up with an analogue voltage that is proportional to the duty cycle. PWM is used in power supplies, light dimmers and motor controllers and such.

Delta Sigma modulation is a lot like that, but without the constant frequency of PWM. It has a output that 'hunts' for the desired output value. A one bit DAC has only two output values (1 or 0), and it generates the value which when included in a running average brings it closest to the desired level:
Delta Sigma modulation is a lot like that, but without the constant frequency of PWM. It has an output that 'hunts' for the desired output value. A one bit DAC has only two output values (1 or 0), and it generates the value which when included in a running average brings it closest to the desired level:

* To generate a level of 0.5 the output will be "10101010101..."
* To generate 0.25 the output will be "000100010001...."
* To generate 0.25 the output will be "000100010001..."
* To generate 0.66 the output will be "110110110110110".
* To generate 0.66 the output will be "110110110110110..."
All of these signals average out to the desired value but have different frequencies.

Um, that looks really hard to do
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It's not that hard at all. For this example work in decimal to make it clearer, but implementation in binary is just the same.
It's not that hard at all. For this example, work in decimal to make it clearer, but implementation in binary is just the same.

To make a Delta Sigma DAC with 100 output levels you need an accumulator with two decimal digits, and you use the "carry to the hundreds" as the output. Just keep adding the desired output level to the two digits and the "carry to the hundreds" will be a stream of ones and zeros that averages to the desired level.

Expand All @@ -43,19 +43,19 @@ Pretty simple!

Of course there are a few little tricks:

* Do it quick enough so that at the highest required frequency you have enough '1's and '0' to average over
* Do it quick enough so that at the highest required frequency you have enough \'1's and \'0's to average over
* Careful design of an analogue output filter is required for best performance
* Do not use all the DAC's range, as the spectrum of noise at either end is problematic
Rough back-of-the-envelope bandwidth and effective resolution calculation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you need to produce signals at 22kHz have to use at least a 44kHz playback frequency. If the one-bit DAC runs at 25MHz there is a little of a five hundred output values (ones and zeros) to average over in 1/44000th of a second - giving you at best 9 bit resolution at that frequency.
If you need to produce signals at 22kHz, you have to use at least a 44kHz playback frequency. If the one-bit DAC runs at 25MHz there is a just over five hundred output values (ones and zeros) per 1/44000th of a second at best you have nine-bit resolution at that frequency.
Doing it in VHDL
~~~~~~~~~~~~~~~~
Here is the code for an 8 bit DAC - It is pretty much a "count by 'n'" counter:
Here is the code for an 8 bit DAC. It is pretty much a "count by 'n'" counter:
[source,vhdl]
---------------------------------------------------------------
Expand Down Expand Up @@ -86,7 +86,7 @@ end Behavioral;

Connecting up the headphones
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
On the Papilio One, just plug amplified speakers into the socket and use the following constraint. You need t use amplified speakers as the output impedance is around 3.3k ohm.
On the Papilio One, just plug amplified speakers into the jack and use the following constraint:

[NOTE]
.Constraint for the Papilo One
Expand All @@ -96,7 +96,7 @@ On the Papilio One, just plug amplified speakers into the socket and use the fol

Connecting headphones to the Basys2
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unlike the Papilio One + Megawing combo the Basys2 does not have an audio output, so we need to use a PMOD port. The PMODs on the Basys2 board have four signal wires from the FPGA, a ground and a 3.3V power connection. For the JA header on the BASYS2 board the constraints are:
Unlike the Papilio One + LogicStart MegaWing combo the Basys2 does not have an audio output, so we need to use a PMOD port. The PMODs on the Basys2 board have four signal wires from the FPGA, a ground and a 3.3V power connection. For the JA header on the Basys2 board the constraints are:

[NOTE]
.Contraints for the Basys2
Expand All @@ -109,15 +109,15 @@ Unlike the Papilio One + Megawing combo the Basys2 does not have an audio output

CAUTION: Make sure that you don't short the power pins. Shorting out ground and power will upset your USB port and/or your FPGA board

For this project connect a set of stereo earphones between pins 0 and pins 1 and the ground. To do this I used a header strip, 3.5mm socket and a length of wire:
For this project connect a set of stereo earphones between pin 0 and pin 1 and the ground. To do this I used a header strip, 3.5mm jack and a length of wire:

image:audio/m12s1.png[]

If you pull the unused pins out of the header strip you might just be able to hold the 3.5mm jack in place at the correct time...

The inductive nature of the headphones/earphones proves to be a pretty good low pass filter for the high frequency signals so no additional components are needed - but if you want to you can include a suitable capacitor in series to prevent average DC voltage running through them.

[INFO] The Basys2 board have a 200 ohm resister in series with the FPGA output pin. This makes the PMOD connectors somewhat protected against ESD, overvoltage and shorts. For this project it it also acts as a voltage divider reducing the DC bias and the peak to peak voltages that go through the headphones/earphones.
The Basys2 board has a 200 ohm resistor in series with the FPGA output pin. This makes the PMOD connectors somewhat protected against ESD, overvoltage and shorts. For this project it also acts as a voltage divider reducing the DC bias and the peak to peak voltages that go through the headphones/earphones.

Project - Wave file generation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -126,11 +126,11 @@ In the prior project we hooked a block RAM to the LEDs, and used it to flash the

* Make a COE file containing the samples for a sine wave (something like "f(n) = int((sine(n*PI()/1024)+1)*100)+128" will give you values between 28 and 228 that you can use).
* Load it into the flashylighs project and check that the lights look OK.
* Load it into the flashylights project and check that the lights look OK.
* To generate an audible tone we need to cycle through this somewhere around 400 times per second - so we need to use counter(15 downto 6) to address the ROM component. This should generate a tone of one cycle every 65536 clocks = 381.4Hz
* Add a 8 bit DAC to your project and connect it to the audio output. Remember to add the appropriate constraints to your project!
* Add an 8 bit DAC to your project and connect it to the audio output. Remember to add the appropriate constraints to your project!
* Build and download the design. If you connect your headphones you should have a tone!
Expand All @@ -141,9 +141,8 @@ Challenges
* The Spartan 3E-250 has 24K of on-chip memory. That's enough for 2 seconds of telephone quality 11kHz/8 bit audio....
* If you connect the two high address bits on RAM to switches you can have four different waveforms, each with 256 samples per cycle. e.g Square, Saw, Ramp, Sine.
* If you connect the two high address bits on RAM to switches you can have four different waveforms, each with 256 samples per cycle, possibly allow you to generate Square, Saw, Ramp and Sine waves from one project.
* By right-shifting the samples you can control the volume - and with a 'wider' DAC you can keep the least significant bits. Remember to 'sign-extend' the sample when you shift it (e.g. y(8 downto 0) = x(7) & x(7 downto 0)).
* The design is quite lo-fi - very 8 bit!, Make the DAC into 16 bits, and changing the ROM to have a data width of 16 (you will also need a new '.coe' file with samples expanded out to match the range of the 16 bit values).
* The design is quite lo-fi - very 8 bit! You could extend the DAC to 16 bits, and of course changing the ROM to have a data width of 16 (you will also need a new '.coe' file with samples expanded out to match the range of the 16 bit values).

0 comments on commit b927f74

Please sign in to comment.