diff --git a/IntroToSpartanFPGABook.pdf b/IntroToSpartanFPGABook.pdf index 7dab108..c09f553 100644 Binary files a/IntroToSpartanFPGABook.pdf and b/IntroToSpartanFPGABook.pdf differ diff --git a/adc/content.asc b/adc/content.asc index cf28f66..ac12e11 100755 --- a/adc/content.asc +++ b/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); @@ -24,14 +24,14 @@ 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) @@ -39,36 +39,36 @@ To read channel 0 of the ADC it is pretty simple - 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 @@ -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: @@ -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. diff --git a/audio/content.asc b/audio/content.asc index b2bbb9d..fd6d0d4 100755 --- a/audio/content.asc +++ b/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. @@ -43,7 +43,7 @@ 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 @@ -51,11 +51,11 @@ Of course there are a few little tricks: 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] --------------------------------------------------------------- @@ -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 @@ -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 @@ -109,7 +109,7 @@ 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[] @@ -117,7 +117,7 @@ If you pull the unused pins out of the header strip you might just be able to ho 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -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! @@ -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). diff --git a/block-ram/content.asc b/block-ram/content.asc index 60bd715..e9d00aa 100755 --- a/block-ram/content.asc +++ b/block-ram/content.asc @@ -14,14 +14,14 @@ On the Spartan 3E each RAM block has 18 kilobits of RAM, and can be presented to The most common configuration I've used is 2048 words of 8 bits, but it can be configured as one of either 16k x 1bit, 8k x 2 bits, 4k x 4 bits, 2k x 8 bits, 2k x 9 bits, 1k x 16 bits, 1k x 18 bits, 512 x 32 bits, 512 x 36 bits or 256 x 72 bits. -The blocks are especially useful as they are dual-port - there are two independent address, read and write ports that simplifies many designs (such as building FIFOs). +The blocks are especially useful as they are dual-port - there are two independent address, read and write ports that simplify many designs (such as building FIFOs). See http://www.xilinx.com/support/documentation/application_notes/xapp463.pdf for complete documentation and some very cunning uses for BRAM. -Using the Core Generator with BRAM +Using the CORE Generator with BRAM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Using the Core generator makes build BRAM components very simple - and if required it also transparently constructs larger memories out of multiple primitives. In the project you will use the core generator as creating them directly in VHDL is quite cumbersome and complex. +Using the CORE generator makes building BRAM components very simple - and if required it also transparently constructs larger memories out of multiple primitives. In the project you will use the CORE Generator as creating them directly in VHDL is quite cumbersome and complex. Preparing the project ~~~~~~~~~~~~~~~~~~~~~ @@ -47,9 +47,9 @@ You should get a module that looks like this: end Behavioral; -------------------------------------- -We now need to add a couple of wizard generated components. +We now need to add a couple of Wizard generated components. -Using the IP core generator +Using the IP CORE Generator ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Add a new source file to the project: @@ -63,11 +63,11 @@ You will be presented with the "Select IP" dialogue box. Tick the "Only IP compa image:block-ram/m11s3.png[] -Navigate down into "Basic Elements"/"Binary Counter" and click next +Navigate down into "Basic Elements"/"Binary Counter" and click "Next" image:block-ram/m11s4.png[] -After a long delay the options for Binary Counter will appear. Set the "Output Width" to 30 - and if you want, click on the "Datasheet" button: +After a long delay, the options for Binary Counter will appear. Set the "Output Width" to 30 - and if you want, click on the "Datasheet" button: image:block-ram/m11s5.png[] @@ -77,7 +77,7 @@ In the Hierarchy window you will now have a "counter30" component. Click on it a image:block-ram/m11s6.png[] -Copy and paste the userful bits into your top level project - add a signal "counter" to be connected to the output of the counter. Here's the completed source: +Copy and paste the useful bits into your top level project - add a signal "counter" to be connected to the output of the counter. Here's the completed source: [source,vhdl] -------------------------------------- @@ -116,13 +116,13 @@ Add another new IP module called "memory", but this time select the Block Memory image:block-ram/m11s7.png[] -The block memory generator has 6 pages of settings - at the moment we only need to enter things on the first three. +The Block Memory Generator has 6 pages of settings - at the moment we only need to enter things on the first three. -Just click "next" on the first screen: +Just click "Next" on the first screen: image:block-ram/m11s8.png[] -Select that we want a single port ROM, then click "Next": +Select that we want a Single Port ROM, then click "Next": image:block-ram/m11s9.png[] @@ -132,7 +132,7 @@ image:block-ram/m11s10.png[] Don't bother going through the rest of the screens - they don't apply at the moment - just click "Generate" -You will now have another component, and you can view it's instantiation template. +You will now have another component, and you can view its instantiation template. image:block-ram/m11s11.png[] @@ -191,9 +191,9 @@ image:block-ram/m11s12.png[] Setting the contents of the ROM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -At the moment the ROM is blank (all '0's). When the FPGA is configured the contents of the block RAM can be set to values that are predefined in the configuration bit stream. +At the moment the ROM is blank (all '0's). When the FPGA is configured, the contents of the block RAM can be set to values that are predefined in the configuration bit stream. -Page 4 of the block memory generator gives you the option to set the contents of the ROM using a ".coe" file. Here's enough of the file that you will be able to write your own from scratch: +Page 4 of the Block Memory Generator gives you the option to set the contents of the ROM using a ".coe" file. Here's enough of the file that you will be able to write your own from scratch: -------------------------------------- memory_initialization_radix=10; @@ -220,13 +220,13 @@ Here's another, using binary (as memory_initialization_radix=2) for a memory wit Create a sample file of 8 bit binary values - make the '1' bits zig-zag from left to right, or some other pattern - the more lines the merrier. Call it "flashy.coe". -Edit the "memory" component (just double click it in the Hierarchy tree) and skip through to Page 4. Set the initialisation file to flashy.coe. +Edit the "memory" component (just double-click it in the Hierarchy tree) and skip through to Page 4. Set the initialisation file to flashy.coe. image:block-ram/m11s13.png[] -It is always a good idea to click on the "show" button - it will give you a warning if your '.coe' file is not correct. Click the 'Generate' button to update the IP module. +It is always a good idea to click on the "Show" button - it will give you a warning if your '.coe' file is not correct. Click the 'Generate' button to update the IP module. -As an aside there are other ways to do this, allowing you to inject contents (e.g. maybe bootloader) after the '.bit' file is built. This allows you to avoid a length rebuild of a whole project just to change the initial values in a BRAM. It is also a good way to allow an end-user to customise the '.bit' file without providing access to your source code. Seach for "xilinx data2mem" in Google. +As an aside, there are other ways to do this, allowing you to inject contents (e.g., maybe bootloader) after the '.bit' file is built. This allows you to avoid a lengthy rebuild of a whole project just to change the initial values in a BRAM. It is also a good way to allow an end-user to customise the '.bit' file without providing access to your source code. Search for "Xilinx data2mem" on Google. The finishing touches ~~~~~~~~~~~~~~~~~~~~~ diff --git a/dcm/content.asc b/dcm/content.asc index f87df7c..c9b8d0c 100755 --- a/dcm/content.asc +++ b/dcm/content.asc @@ -10,32 +10,32 @@ DCMs receive an incoming clock and can do the following and more: * Generate a faster or slower clock signal using an input clock as a reference -* Generate signals with a known phase shift (e.g. 90, 180 or 270 degrees out of phase) +* Generate signals with a known phase shift (e.g., 90, 180 or 270 degrees out of phase) -* Correct clock duty cycles, ensuring that the high and low times are 50%. +* Correct clock duty cycles, ensuring that the high and low times are 50% * Phase shift the internal FPGA clock signals to compensate for internal clock distribution delays -DCMs can also be cascaded, allowing multiple clocks to be used. For example +DCMs can also be cascaded, allowing multiple clocks to be used. For example, one external 50MHz clock can be used to generate 100MHz controlling memory -and 25MHz for the VGA pixel clock +and 25MHz for the VGA pixel clock. Because of this flexibility they are quite complex to use. I find using -the Core Generator is the best way configure a DCM. +the CORE Generator is the best way to configure a DCM. Using the Wizard ~~~~~~~~~~~~~~~~ -Pick any project you like, and add a "New Source", using the "IP (Core +Pick any project you like, and add a "New Source", using the "IP (CORE Generator...)" option to create a component "my_dcm": image:dcm/m14s1.png[] -One again choose the "Only IP compatible with chosen part" +Once again choose the "Only IP compatible with chosen part" option, then drill down to "Single DCM_SP": image:dcm/m14s2.png[] -Click "Next" then "Finish" to start the Core Generator. +Click "Next" then "Finish" to start the CORE Generator. You will then be presented with this dialog box: @@ -44,7 +44,7 @@ image:dcm/m14s3.png[] Just click "OK" to open the Clocking Wizard's General Setup dialogue box: Here you can choose what signals you will use and set the input clock -frequency. The most common outputs I use is the CLKFX (which is the synthesized +frequency. The most common output I use is the CLKFX (which is the synthesized output frequency). You may want to untick the RST (reset) signal if this is the only clock for the entire project: @@ -65,13 +65,13 @@ You will now get the summary screen, where you can click "Finish": image:dcm/m14s7.png[] -Once generated you will be able to use the instantiation templates +Once generated, you will be able to use the instantiation templates to add a "my_dcm" component to your project. Project - Use a DCM ~~~~~~~~~~~~~~~~~~~ -* Add a DCM to one of your projects (e.g. project 4.1). +* Add a DCM to one of your projects NOTE: Remember to update not only the signal monitored by rising_edge(), but also the signal used on the process sensitivity list. diff --git a/ending/content.asc b/ending/content.asc index cc90de2..7986762 100755 --- a/ending/content.asc +++ b/ending/content.asc @@ -1,27 +1,27 @@ Closing ------- -Sorry! All finished! Apart from the advanced feature of the I/O -blocks (such as DDR2 input and outputs) you have pretty much played +Sorry! All finished! Apart from the advanced features of the I/O +blocks (such as DDR2 inputs and outputs) you have pretty much played with all the features of the Spartan 3E. So if you are still keen to learn more: -* have a read through the Xilinx AppNotes library. The ones on +* Have a read through the Xilinx AppNotes library. The ones on creative uses of BRAM and MULT18s is full of good ideas -* read through full Spartan 3E User Guide - it will make some sense now. +* Read through full Spartan 3E User Guide - it will make some sense now -* create a system using the PicoBlaze embedded processor +* Create a system using the PicoBlaze embedded processor -* sell or gift your development board to a friend and move up to +* Sell or gift your development board to a friend and move up to one with off-chip RAM, ROM, DACs, ADCs, Ethernet... -* try a different FPGA vendor's board - that will really make your head hurt +* Try a different FPGA vendor's board - that will really make your head hurt * Have a go at building something really nifty If there is something I have missed or you want to say thanks send me an -email - or maybe send me postcard to me at 370 Ellesmere Junction Road, +email - or maybe send me a postcard to me at 370 Ellesmere Junction Road, Springston 7616, Canterbury, New Zealand. It will be fun to see if I actually get any cards! diff --git a/epp/content.asc b/epp/content.asc index f3b8f93..61bff5b 100755 --- a/epp/content.asc +++ b/epp/content.asc @@ -19,16 +19,16 @@ address up to 256 8-bit registers that can be implemented within the FPGA. These registers can either be read by the host PC one byte at a time, or a "Repeat" function can be called to read multiple bytes from the same register. -The most "make or break" shortcoming of this interface is that there is no interrupt -signal going back to the host which would allow the FPGA it's attention. Unlike when -using RS232 this forces the host software to poll the FPGA at regular intervals - +The "make or break" shortcoming of this interface is that there is no interrupt +signal going back to the host which would allow the FPGA get its attention. Unlike when +using RS-232 this forces the host software to poll the FPGA at regular intervals - which is not ideal for responsiveness or CPU usage. Resources ~~~~~~~~~ * http://www.digilentinc.com/data/software/adept/dpimref%20programmers%20manual.pdf documents the FPGA side of the interface -* http://digilentinc.com/Data/Products/ADEPT/DPCUTIL%20Programmers%20%20Reference%20Manual.pdf documents the host side of interface +* http://digilentinc.com/Data/Products/ADEPT/DPCUTIL%20Programmers%20%20Reference%20Manual.pdf documents the host side of the interface * http://www.digilentinc.com/Products/Detail.cfm?Prod=ADEPT2 for the latest Adept SDK The FPGA side of the interface @@ -39,17 +39,17 @@ The following signals make up the interface: |=============================================== | Name | Type | Description | DB(7 downto 0) | INOUT | Data bus -| WRITE | IN | Write Enable (active Low) - data will be written from the host during this cycle +| WRITE | IN | Write enable (active low) - data will be written from the host during this cycle | ASTB | IN | Address strobe (active low) - data bus will be captured into the address register -| DSTB | IN | Data Strobe (active low) - bus will be captured into the currently selected data register -| WAIT | OUT | Asserted when FPGA read to accept data, +| DSTB | IN | Data strobe (active low) - the bus will be captured into the currently selected data register +| WAIT | OUT | Asserted when FPGA is ready to accept data | INT | OUT | Interrupt request - not used | RESET | IN | Reset - not used |=============================================== Read Transaction ~~~~~~~~~~~~~~~~ -The steps in a read transaction are +The steps in a read transaction are: * Host lowers ASTB or DSTB to commence read of either the address register or the selected data register * FPGA presents data on data bus @@ -59,15 +59,15 @@ The steps in a read transaction are * FPGA removes the data from the data bus * FPGA lowers WAIT to finish transaction -Write transaction +Write Transaction ~~~~~~~~~~~~~~~~~ -The steps in a write transaction are +The steps in a write transaction are: -* Host presents data on data DB() -* Host lowers Write Enable to 0 -* Host lowers either ASTB or DSTB to commence write of either the address register or the selected data register. +* Host presents data on the data bus +* Host lowers write wnable to 0 +* Host lowers either ASTB or DSTB to commence write of either the address register or the selected data register * FPGA raises WAIT once data is captured -* Host raises ASTB or DSTB, removes data from bus and raises Write Enable +* Host raises ASTB or DSTB, removes data from bus and raises write enable * FPGA lowers WAIT to finish transaction FSM diagram @@ -98,17 +98,17 @@ The constraints required to implement the interface are: VHDL for the FPGA interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This source allows you to set the LEDs and read the switches from the PCs. +This source allows you to set the LEDs and read the switches from the PC. It has a few VHDL features that you won't have seen up to now: -* The EppDB (EPP Data bus) is INOUT - a tristate bidirectional bus. When you -assign "ZZZZZZZZ" (high impedance) to the signal it will then 'read' as the +* The EppDB (EPP Data Bus) is INOUT - a tri-state bidirectional bus. When you +assign "ZZZZZZZZ" (high impedance) to the signal it will then \'read' as the input from the outside world. This is only really useful on I/O pins - within -the FPGA tristate logic is implemented using multiplexers +the FPGA all tri-state logic is implemented using multiplexers. * It uses an enumerated type to hold the FSM 'state'. This is only really useful -if you don't want to use bits withing the state value to drive logic (which is -usually a good way to get glitch free outputs). +if you don't want to use individual bits within the state value to drive logic (which is +usually a good way to get glitch free outputs) [source,vhdl] @@ -204,6 +204,7 @@ usually a good way to get glitch free outputs). end if; end process; end Behavioral; + -------------------------------------- @@ -252,15 +253,14 @@ Connecting isn't that simple, but it's not that hard either. Three functions are } ------------------------------------------------------- -[NOTE] -------------------------------------------------------- The first time you make use of the interface you may need to call one more function only once to present a dialogue box allowing you to select which FPGA board will be your default device: * DvmgStartConfigureDevices() -------------------------------------------------------- + +Once used, the settings will be saved in the registry and will persist. Connecting to the EPP port of that device ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -285,7 +285,7 @@ Reading a port is achieved with either of these functions: * DpcGetReg() - Read a single byte from a register * DpcGetRegRepeat() - Read multiple bytes from a register -Here's an example function that opens the EPP port and reads a single register +Here's an example function that opens the EPP port and reads a single register: [source,c] ------------------------------------------------------- @@ -317,11 +317,11 @@ Here's an example function that opens the EPP port and reads a single register Writing to a register ~~~~~~~~~~~~~~~~~~~~~ -Reading a port is achieved with either of these functions: +Writing to a port is achieved with either of these functions: -* DpcGetReg() - Read a single byte from a register +* DpcPutReg() - Read a single byte from a register -* DpcGetRegRepeat() - Read multiple bytes from a register +* DpcPutRegRepeat() - Read multiple bytes from a register Here's an example function that opens the EPP port and writes to a single register @@ -393,11 +393,11 @@ design" project from http://www.digilentinc.com/Products/Detail.cfm?Prod=BASYS2 image:epp/m18s1.png[] * Create a C program that opens the interface and reads a single byte from -registers 5 and 6 and displays the value to the screen. +registers 5 and 6 and displays the value to the screen -* Close of Adept and check that your C program also shows the state of the switches on the Basys2. +* Close off Adept and check that your C program also shows the state of the switches on the Basys2 -* Expand you C program to write to the value of the switches to register 1 - this is the LEDs. +* Expand your C program to write to the value of the switches to register 1 - this is the LEDs You now have the host side of bidirectional communication sorted! @@ -406,12 +406,10 @@ Project - Implementing the FPGA end of the interface * Create a new FPGA project -* Create a module that implements the EPP protocol - or use the one above if Digilent's reference design if you want. +* Create a module that implements the EPP protocol - or use the one of Digilent's reference designs if you want -* Connect writes of register 1 to the LEDs. +* Connect writes of register 1 to the LEDs * Connect reads of register 5 or 6 to the switches * Test that your design works just as well with your program as Digilent's reference design - - diff --git a/fsm/content.asc b/fsm/content.asc index 98f950c..6ea3260 100755 --- a/fsm/content.asc +++ b/fsm/content.asc @@ -4,28 +4,28 @@ Implementing Finite State Machines Up to now the projects have been very 'linear' - mostly counters that work like clockwork. Now we are going to investigate how you can get your logic to allow external signals change it's behaviour, rather than just processing the results. -The technique introduced is used in many different areas of a design, such as +The technique introduced is used in many different areas of a design, such as: * Communication protocols, where data may be sent asynchronously or different data required different responses * Scheduling of control signals in a memory controller * Decoding and executing instructions in a CPU * Control of simple machine -* Implementing simple user interfaces. +* Implementing simple user interfaces Introduction to the project ~~~~~~~~~~~~~~~~~~~~~~~~~~~ For the project we are going to build a combination lock, which works as follows: -- All switches must be turned off. +- All of the switches must be turned off -- then switch 7 must be turned on +- Then switch 7 must be turned on - Then switch 6 must be turned on -- then Switch 5 must be turned on +- Then switch 5 must be turned on -- then Switch 4 must be turned on +- Finally switch 4 must be turned on If this sequence is followed, all the LEDs will turn on and stay on until all switches are moved back to off. @@ -64,13 +64,13 @@ So when the system is in the "START" state the options are either: - Otherwise we go to the "ERROR" state. -Likewise, in the "ERROR" state the options are +Likewise, in the "ERROR" state the options are: - If switches are set to "0000000" we go to the "START" state. - Otherwise we go to the "ERROR" state. -If I have designed it correctly the only way to get to the "OPEN" state is to move the +If I have designed it correctly, the only way to get to the "OPEN" state is to move the switches through "00000000", "10000000", "11000000", "11100000", then finally to "11110000" Implementing in VHDL @@ -124,13 +124,13 @@ In your project's process it is usually easiest to code it using a CASE statemen end if; -------------------------------------- -Project 14.1 - Combination lock 1 +Project - Combination lock 1 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Code the above FSM to implement the combination lock. To give some feedback on success set LEDs to "11111111", and -* Test it in the simulator, using this in the test bench stimulus process +* Test it in the simulator, using this in the testbench stimulus process [source,vhdl] -------------------------------------- @@ -160,15 +160,15 @@ Solutions are: * Debounce the switch signals using logic within the FPGA -* Sample the switches at intervals that should mask any bounce (e.g. 1/10th of a second) +* Sample the switches at intervals that should mask any bounce - perhaps every 1/10th of a second -* Update the FSM to allow for switch bounces. +* Update the FSM to allow for switch bounces The "debounce" solutions are all relatively hard, while updating the FSM will only need a few lines of code. -Project 14.2 - Combination lock 2 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Project - Combination lock 2 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Trace through the FSM diagram to work out why a bounce causes it to fail diff --git a/module17/content.asc b/module17/content.asc index fb69a66..17222ce 100755 --- a/module17/content.asc +++ b/module17/content.asc @@ -1,22 +1,22 @@ -Recieving data from the outside world +Receiving data from the outside world ------------------------------------- -In the last module we created one-way communicaiton from the FPGA to a PC. It would be really good if we could send data from the PC back to the FPGA too. +In the last chapter we created one-way communication from the FPGA to a PC. It would be really good if we could send data from the PC back to the FPGA too. To allow this to happen we need to be able to recover the sender's clock - a process called clock recovery. Problems with clock recovery and framing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Synchronising with an incoming signal is usually a hard problem to solve. But for short transfers using low bit rates (like RS232) it is pretty easy to solve by oversampling the incoming signal. Although this isn't the most efficient method it is easy to understand and implement. +Synchronising with an incoming signal is usually a hard problem to solve. But for short transfers using low bit rates (like RS-232) it is pretty easy to solve by oversampling the incoming signal. Although this isn't the most efficient method it is easy to understand and implement. -If the incoming signal has a bit rate is 9600 baud your design over samples the signal at four times this speed (38400), thus ensuring that for each received bit we will have two good samples. +If the incoming signal has a bit rate of 9600 baud, your design oversamples the signal at four times this speed (38400), ensuring that for each received bit we will have at least two good samples. The next challenge is then to work out which pairs of bits are good, and where a frame starts and ends. Here's my solution. -As discussed in the last module an RS232 frame starts with a Start bit ('L'), has eight data bits and ends with a stop bit ('H'). To receive the data use a 40 bit shift register initialised to '1's, and then capture the incoming signal into the left hand end of a shift register. +As discussed in the last chapter an RS-232 frame starts with a start bit (low), has eight data bits and ends with a stop bit (high). To receive this data, use a 40-bit shift register initialised to '1's, and then capture the incoming signal into the left-hand end of a shift register. -After 40 samples we will have the following bits Where '-' is 'don't care' and '??' are pairs of matching 'LL' or 'HH' bits (as they will have been sampled in the sample bit windows): +After 40 samples we will have the following bits where '-' is 'don't care' and '??' are pairs of matching 'LL' or 'HH' bits (as they will have been sampled in the sample bit windows): (MSB) (LSB) -HH--??--??--??--??--??--??--??--??--LL- @@ -46,7 +46,7 @@ The test to see if we have received a valid frame we need to check the following * Check that bits(2 downto 1) are both '0' -If all this is true we can then capture the byte, set a signal to indicate receiving of the byte then reset the shift register back to the empty state, preventing false triggering: +If all this is true we can capture the byte, and set a signal to indicate receiving of the byte then reset the shift register back to the empty state, preventing false triggering: [source,vhdl] -------------------------------------- @@ -59,12 +59,12 @@ Wow - much easier than expected. So what is the catch? Problems with this solution ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The main problem with this solution is that the sending clock and receiving clock must be closely matched. A drift of 2.5% (1/40) in clocks will be enough that the sampling of the start bit and stop bit will be one sample out of step from each other - but will still work with a very 'crisp' signal. +The main problem with this solution is that the sender's clock and the receiver's clock must be closely matched. A drift of 2.5% (1/40) in clocks will be enough that the sampling of the start bit and stop bit will be one sample out of step from each other - but will still work with a very 'crisp' signal. -If there is a difference of 5% in timing the first and last sample will be two sample periods out of step, and will never be able to receive the data correctly. +If there is a difference of 5% in timing the first and last sample will be two sample periods out of step, and the design will never be able to receive the data correctly. -Project 17.1 -~~~~~~~~~~~~ -* Create a project that receives characters over RS232 and displays them on the LEDs or seven segment display -* Merge the code from project 16 and 17 to create your own RS232 RX/TX component. +Project - Build a UART +~~~~~~~~~~~~---------- +* Create a project that receives characters over RS-232 and displays them on the LEDs or seven segment display +* Merge the code from the previous project, creating your own RS-232 RX/TX component diff --git a/multiplier/content.asc b/multiplier/content.asc index f1c80dd..09aab6d 100755 --- a/multiplier/content.asc +++ b/multiplier/content.asc @@ -7,15 +7,15 @@ you need multiplication - and this is where FPGAs really shine. After going through the basics of binary multiplication you'll be introduced to the embedded multiplier blocks in the Spartan 3E. The XC3S250E FPGAs have -twelve of these blocks, allowing you to do number crunching of well over a 2 -billion 18 bit multiplications per second, allowing it to compete with a desktop CPU core. +twelve of these blocks, allowing you to do number crunching of well over two +billion 18-bit multiplications per second, allowing it to compete with a desktop CPU core. Performance of binary multiplication ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Binary multiplication is complex - implementing multiplication of any -two 'n' bit numbers approximately n*(n-1) full adders, n half adders and n*n 'AND' operations. +two n-bit numbers requires approximately n*(n-1) full adders, n half adders and n*n 'AND' operations. -To multiply the four bit binary numbers "abcd" by "efgh" the following +To multiply the four-bit binary numbers "abcd" by "efgh" the following operations are needed (where '&' is a binary AND): + a&h b&h c&h d&h @@ -25,8 +25,8 @@ operations are needed (where '&' is a binary AND): --- --- --- --- --- --- --- --- = ? ? ? ? ? ? ? ? -Multiplication also has a big implication for your designs performance - because of the -'carries' required, multiplying two 'n' bit numbers takes around twice as long as adding two 'n' bit numbers. +Multiplication also has a big implication for your design's performance - because of the +'carries' required, multiplying two n-bit numbers takes around twice as long as adding two n-bit numbers. It also consumes a very large amount of logic if multiplication is implemented in the generic logic blocks within the FPGA. @@ -34,21 +34,21 @@ implemented in the generic logic blocks within the FPGA. Multiplication in FPGAs ~~~~~~~~~~~~~~~~~~~~~~~ -To get around this, most FPGAs include multiple multiplier blocks - a +To get around this, most FPGAs include multiple multiplier blocks - an XC3S100 has four 18 bit x 18 bit multipliers, and a XC3S250 has twelve! -To improve performance multipliers also include additional registers, -allowing the multiplicands and result to be registered withing the multiplier -block. There are also optional registers within the multiplier that holds -the partial result half way through the multiplication. +To improve performance, multipliers also include additional registers, +allowing the multiplicands and result to be registered within the multiplier +block. There are also optional registers within the multiplier that hold +the partial resulthalf way through the multiplication. Using these internal registers greatly improves throughput performance by removing the routing delays to get the inputs to and from the multipliers, -but a the cost of increased latency - measured in either time between two -number being given to the multiplier and the result being available, or the +but at the cost of increased latency - measured in either time between two +numbers being given to the multiplier and the result being available, or the number of clock cycles. -When all these internal registers are enabled the multiplier works as follows +When all these internal registers are enabled the multiplier works as follows: |=========================== | Clock cycle | Action | 0 | A and B inputs are latched @@ -64,34 +64,34 @@ A useful case might be processing Red/Green/Blue video values, where each channe An annoying case is where feedback is needed of the output value back into the input. If the math isn't in your favor you may be better off not using any registers at all - it may -even be slightly faster and running at one third the clock speed will use less power. +even be slightly faster and running at one-third the clock speed will use less power. What if 18x18 isn't 'wide' enough? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -What if you want to use bigger numbers? say 32 bits? Sure! +What if you want to use bigger numbers? Say 32 bits? Sure! -Just like in decimal when multiplying two two digit numbers "ab" and "cd" is calculated +Just like in decimal when multiplying pairs of two-digit numbers "ab" and "cd" is calculated as "a*c*10*10 + b*c*10 + a*d*10 + b*d" the same works - just replace each of a,v,c,d with an 18 bit number, and each '10' with 2^18. As the designer you have the choice of either: * using four multipliers and three adders, with a best-performance latency of - 5 cycles with a throughput of one pair of A and B values per clock + 5 cycles, and with a throughput of one pair of A and B values per clock * using the same multiplier to calculate each of the four intermediate products, with -a best-performance latency of 13 cycles (four 3-cycle multiplication plus the final addition) -and with careful scheduling you can process three input pairs every 12 cycles. +a best-performance latency of 13 cycles (four 3-cycle multiplications plus the final addition) +and with careful scheduling you can process three input pairs every 12 cycles -Project - Digital Volume control +Project - Digital volume control ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Revisit the Audio output project -* Use the core generator to add an IP multiplier, with an 8 bit unsigned input +* Use the CORE Generator to add an IP multiplier, with an 8 bit unsigned input for the volume and the other matching your BRAM's sample size -* Add a multiplier between the block BRAM and the DAC, using the value of switches as the other input. +* Add a multiplier between the block BRAM and the DAC, using the value of switches as the other input * Use the highest output bits of the multiplier to feed the DAC diff --git a/rs232tx/content.asc b/rs232tx/content.asc index 8486ef9..6e42b04 100644 --- a/rs232tx/content.asc +++ b/rs232tx/content.asc @@ -3,14 +3,14 @@ Communicating with the outside world So, after displaying something on a VGA monitor, how do we talk to a PC? -In this chapter you will build the transmit part of a serial (RS232) +In this chapter you will build the transmit part of a serial (RS-232) interface, using shift registers. On the Papilio One you can talk directly to the USB interface, but on the Basys2 you will need a USB to 3.3V Serial breakout board. -What is RS232? +What is RS-232? ~~~~~~~~~~~~~~ -RS232 is a very old standard originally used to interface digital systems with +RS-232 is a very old standard originally used to interface digital systems with analogue phone lines and other data circuits. It enables relatively low speed communication between devices, and is relatively simple to implement. @@ -26,20 +26,20 @@ If hardware handshaking is not used only three wires are needed: Which signal a device listens to for incoming data and which signal it actively sends data is very confusing. If the device is a "DTE" (Data Terminating Equipment) it transmits on TX and listens on RX. If the device is "Data Communicating Equipment" -(e.g. a modem) it listens for data on TX and transmits on RX. +(e.g., a modem) it listens for data on TX and transmits on RX. The standard speeds range from 75 baud up to 115,200 baud, with 9600 or 19200 being the most common speeds for data that is presented to people (such as on a serial console). -As well as baud speed both ends of a connection must be using the same frame +As well as baud speed, both ends of a connection must be using the same frame parameters - the most common being one start bit, eight data bits, no parity -bit and one stop bit. As the frame is ten bits long at 9600 baud you can send 960 bytes per second. +bit and one stop bit. As the frame is ten bits long, at 9600 baud you can send 960 bytes per second. There is a whole lot more to the standard, mostly around how senders and receivers control the flow of data to ensure that data does not overrun receiving buffers. When using modern hardware at slow speeds handshaking isn't really an issue. -Here's what it looks like on the wire: +Here is what the signal should look like on the wire: image:rs232tx/m16s1.png[] @@ -49,8 +49,8 @@ Generating an RS-232 signal For this project we need a shift register (well two actually). So what does a shift register look like in VHDL? -Here is a 16 bit register that loops from bit 0 to bit 15 - a much simpler -way to generate one pulse every 16 cycles than using a counter +Here is a 16-bit register that loops from bit 0 to bit 15 - a much simpler +way to generate one pulse every 16 cycles than using a counter. [source,vhdl] -------------------------------------- @@ -62,7 +62,7 @@ way to generate one pulse every 16 cycles than using a counter end if; -------------------------------------- -For RS-252 we use pretty much this construct, but feed in the the idle bit value ('1'). +For RS-252 we use pretty much this construct, but feed in the idle bit value ('1'). This code will send the 'Z' character once (after which the shift register is filled with '1's): [source,vhdl] @@ -77,15 +77,15 @@ This code will send the 'Z' character once (after which the shift register is fi end if; -------------------------------------- -The user data is bits 8 downto 1 is the "byte" of user data - bit 0 is +The user data is bits 8 downto 1 - this is the "byte" of user data - bit 0 is the start bit, and bit 9 is the stop bit. I chose the ASCII code for 'Z' as it will still be a 'Z' regardless of if the least or most significant -bit gets transferred first - very useful for testing! +bit gets transferred first - very useful for initial testing! The only problem with the code so far is that we are transmitting at the clock speed - either 32,000,000 or 50,000,000 baud! To control the rate of sending we also need a counter that allows a bit to be sent at 9600 -baud - once every 3333 cycles (at 32MHz) or once every 5208 clock cycles (@50MHz): +baud - once every 3,333 cycles (at 32MHz) or once every 5,208 cycles (@50MHz): [source,vhdl] -------------------------------------- @@ -107,7 +107,7 @@ baud - once every 3333 cycles (at 32MHz) or once every 5208 clock cycles (@50MHz We can make it send the same data over and over again by making the shift register longer and looping the shift register's output back on its input. -To do this it needs longer shift register, ensuring that we have some +To do this it needs a longer shift register, ensuring that we have some quiet space following the stop bit to allow the receiver to frame the data correctly: @@ -129,8 +129,8 @@ data correctly: end if; -------------------------------------- -(This code should be enough to enable you to test your RS232 port actually -sends data as expected). +This code should be enough to enable you to test your RS-232 port actually +sends data as expected. Sending variable data ~~~~~~~~~~~~~~~~~~~~~ @@ -138,8 +138,8 @@ To make this useful you really need to be able to send different data bytes. And to do this correctly you have to know when the interface is busy. The easiest way to do this is to have a second shift register which is -filled with '1's when the character is loaded into 'shiftreg' and filled -with '0's as bits are transmitted. Once this second shift register is +filled with \'1's when the character is loaded into \'shiftreg' and filled +with \'0's as bits are transmitted. Once this second shift register is all zeros, then things are ready for the next byte to be sent: [source,vhdl] @@ -177,13 +177,13 @@ message until it recovers from the bad bit. Connecting your FPGA board to a PC ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -CAUTION: Connecting the FPGA directly to your serial port will most likely ruin your FPGA``` +CAUTION: Connecting the FPGA directly to your serial port will most likely ruin your FPGA -Most modern PCs do not have RS232 ports, and if they do they are expecting the higher -voltage levels that standard RS232 uses - the standards uses up to +/- 25V! +Most modern PCs do not have RS-232 ports, and if they do they are expecting the higher +voltage levels that standard RS-232 uses - the standard uses up to +/- 25V! To connect to a PC over USB you can use something like Sparkfun's "FTDI Basic 3.3V - USB -to Serial" (http://www.sparkfun.com/products/9893) and wire jumpers. Here's my setup: +to Serial" (http://www.sparkfun.com/products/9893) and jumper wires. Here's my setup: image:rs232tx/m16s2.png[] @@ -191,18 +191,18 @@ TIP: If you are using the Basys2 and want to talk to a true standards compliant you want to avoid issues caused by loose wires you can use the RS-232 PMOD http://www.digilentinc.com/Products/Detail.cfm?Prod=PMOD-RS232 with your Basys2. -Project 16.1 -~~~~~~~~~~~~ -* Create a project that sends 'Z' over RS-232 +Project 16 +~~~~~~~~~~ +* Create a project that sends \'Z' over RS-232 * Create a project that sends the state of switches(3 downto 0) over RS-232 ** You could increase the length of the shift register and send multiple bytes ** You could convert the data to ASCII and send four switches in a single byte -** You could map the 16 possible values into 16 contiguous printable characters (A-Q perhaps) -* Change it to only send a byte when the switches change. +** You could map the 16 possible values into 16 contiguous printable characters (maybe characters A through P) +* Change it to only send a byte when the switches change * Extend the project to send the state of all eight switches Challenge ~~~~~~~~~ -* What would happen if the input to the RS232 TX component was to change, and then change back to its +* What would happen if the input to the RS-232 TX component was to change, and then change back to its original state in less than 1/960th of a second? Can loss of data be avoided? diff --git a/seven-seg/content.asc b/seven-seg/content.asc index f377281..383a161 100755 --- a/seven-seg/content.asc +++ b/seven-seg/content.asc @@ -5,7 +5,7 @@ Now is a good time to cover a little more VHDL, and use it to efficiently implem The VHDL 'case' statement ~~~~~~~~~~~~~~~~~~~~~~~~~ -Much like "switch()" in C, VHDL has the CASE statement that allows you to choose different between multiple different paths through your code based on the value of a signal. Although it is largely functionally equivalent to nested 'IF's it is far easier to write, and is implemented more efficiently within the FPGA. +Much like "switch()" in C, VHDL has the CASE statement that allows you to choose between multiple different paths through your code based on the value of a signal. Although it is largely functionally equivalent to nested 'IF's it is far easier to write, and is implemented more efficiently within the FPGA. It looks much like this: @@ -28,13 +28,13 @@ It looks much like this: -------------------------------------- -It differs from most similar constructs in programming languages in that all possible cases must be covered, so it pays to remember that STD_LOGIC signal can have other states than just \'1\' or \'0\' - most designers choose to use the \'least harmful\' actions on an unexpected value. Like an "IF" statement, "CASE" can only be used inside a process - and remember to include the signals being tested in the process's sensitivity list when a "CASE" is used outside of an "IF RISING_EDGE(clk) THEN" block. +It differs from most similar constructs in programming languages in that all possible cases must be covered, so it pays to remember that a STD_LOGIC signal can have other states than just \'1' or \'0' - most designers choose to use the \'least harmful' actions on an unexpected value. Like an "IF" statement, "CASE" can only be used inside a process - and remember to include the signals being tested in the process's sensitivity list when a "CASE" statement is used outside of an "IF RISING_EDGE(clk) THEN" block. Excellent practice for using the CASE statement is driving the seven segment display - you can use it twice. One CASE statement decodes which segments to light, and a second CASE statement selects which digit is active at any time. Project - Displaying digits ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -These projects are a lot of work and might take a couple of sittings, but you will build up a great understanding of the seven segment displays. If you are feeling confident combine a few of the steps and race through. +These projects are a lot of work and might take a couple of sittings, but you will build up a great understanding of the seven segment displays. If you are feeling confident, combine a few of the steps and race through. * Add "anodes(3 downto 0)" and "sevenseg(6 downto 0)" as outputs to your top level design, and then add the following constraints to your ucf file: @@ -74,15 +74,15 @@ NET "anodes<1>" LOC = "J12"; NET "anodes<0>" LOC = "F12"; -------------------------------------- -* In your top level design, connect the output to 'sevenseg' and 'dp' to the switches. within the design set anodes to "1110" then build the design. (The anodes are "active low", so this value should enable only the rightmost digit of the sevenseg displays). +* In your top level design, connect the outputs 'sevenseg' and 'dp' directly to the inputs from the switches. Within your design set anodes to "1110" then build the design. As the anodes are "active low" this value should enable only the rightmost digit of the sevenseg displays. -* Work out and document the the switch patterns required to give the digits 0 through 9, and the letters A through F. +* Work out and document the switch patterns required to give the digits 0 through 9, and the letters A through F. * Build a 'CASE' statement to decode the binary of switches(3 downto 0) and display it on the first seven segment display - remember that at least switches(3 downto 0) has to be included in the sensitivity list of the process acting on them, as there is no clock being used. Multiplexing digits ~~~~~~~~~~~~~~~~~~~ -If each digit is displayed quick succession the eye can be fooled into seeing all four displays as being lit at the same time. As we have four digits we can use to two bits of a suitably sized counter to select which is to be lit. If if the design switches digits too fast it will not give them enough time to light up, and too slow will call flickering. Something around 200Hz to 1kHz seems to work best. +If each digit is displayed in quick succession the eye can be fooled into seeing all four displays as being lit at the same time. As we have four digits we can use two bits of a suitably sized counter to select which is to be lit. If the design switches digits too fast it will not give them enough time to light up, and too slow will cause flickering. Something around 200Hz to 1kHz seems to work best. |===================================== | counter bits | value for anodes | values for sevenseg() @@ -96,13 +96,13 @@ You can either decide to decode the four digits in each option of the CASE state Project - Using the Seven segments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* Update your project to multiplex all four display and showing the values of switches(3 downto 0) on all digits +* Update your project to multiplex all four displays and show the values of switches(3 downto 0) on all digits -* Update your project to multiplex all four display and showing the values of switches(3 downto 0) on digit 0 and 1, and the value of switches(7 downto 4) on digit 2 and 3 +* Update your project to multiplex all four displays and show the value of switches(3 downto 0) on digits 0 and 1, and the value of switches(7 downto 4) on digits 2 and 3 -* Update your project show the highest 16 bits of a counter over all four digits. +* Update your project to show the highest 16 bits of a counter over all four digits. -* Create a new module that can display four digits on the seven segment display. This will be useful for any project you design that uses the sevenseg displays. Its interface signals should something like: +* Create a new module that can display four digits on the seven segment display. This will be useful for any project you design that uses the sevenseg displays. Its interface signals should look something like: [source,vhdl] -------------------------------------- diff --git a/tri-state/content.asc b/tri-state/content.asc index e6d49fa..cd9a249 100755 --- a/tri-state/content.asc +++ b/tri-state/content.asc @@ -1,48 +1,47 @@ Using tri-state logic --------------------- -After reviewing all the learning to date I realised that I have failed to cover tri-state logic! Although common when building using individual chips it only really makes an apperance in FPGA designs when interfacing to external componenets (explaining why it was only seen when interfacing to the Basys2's bidirectional EPP port). +After reviewing all the learning to date I realised that I have failed to cover tri-state logic! Although common when building projects using individual chips it only really makes an appearance in FPGA designs when interfacing to external components (explaining why it was only seen when interfacing to the Basys2's bidirectional EPP port). What is tri-state logic? ~~~~~~~~~~~~~~~~~~~~~~~~ -Put simply, tri-state logic is where a signal can be either "logic high level", "logic low level" or "not actively driven" - '1', '0' and 'Z' in VHDL. This allows the same wire / signal to be used as both an input or output, or allow multiple devices to share "share" a common bus. +Put simply, tri-state logic is where a signal can be either "logic high level", "logic low level" or "not actively driven" - '1', '0' and 'Z' in VHDL. This allows the same wire / signal to be used as both an input or output, or allow multiple devices to "share" a common bus. -The most familiar example is a RAM chip's data bus. During the read cycles the memory chip drives the data bus, and during write cycles the memory controller drives the data bus. To enable this most RAM chips have a signal called "Output Enable" ("OE") that tells the chip when to drive the bus. +The most familiar example is a RAM chip's data bus. During the read cycles the memory chip drives the data bus, and during write cycles the memory controller drives the data bus. To enable this, most RAM chips have a signal called "Output Enable" ("OE") that tells the chip when to drive the bus. -On a tristate bus all devices on the bus can read the value of the bus at any time, but to avoid data corruption your design must ensure that one device should drive the bus at any time. Should two or more devices try to drive the bus to different values at the same time the data on the bus will be corrupted. -If this overlap of multiple devices driving the bus lasts for only for a short time the error may not noticed, but you will get high power usage -and signal integrity as the drivers are saturated. +On a tri-state bus all devices on the bus can read the value of the bus at any time, but to avoid data corruption your design must ensure that one device should drive the bus at any time. Should two or more devices try to drive the bus to different values at the same time the data on the bus will be corrupted. +If this overlap of multiple devices driving the bus lasts for only a short time then an error may not occur, but you will get increased power usage and signal integrity issues as the output drivers are saturated. -How is tri-state logic used within a FPGA -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In short, for the Spartan 3E it isn't. To avoid timing and power issues the design tools ensure that any signals are only ever driven by one device. +How is tri-state logic used within an FPGA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In short, for the Spartan 3E it isn't. To avoid timing and power issues, the design tools ensure that any signals are only ever driven by one device. -Any internal tri-state logic within a design is mapped into a hidden "input" and "output" signals. The bus is then implemented with a multiplexer that selects the active 'output' signal and then delivers that signal to all the inputs. +Any internal tri-state logic within a design is mapped into hidden "input" and "output" signals. The bus is then implemented with a multiplexer that selects the active 'output' signal and then delivers that signal to all the inputs. -How is tri-state logic use when interfacing with a FPGA -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +How is tri-state logic is use when interfacing with an FPGA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Most general purpose I/O pins are of an FPGA are driven by a tri-state driver, and the pin is monitored by an input buffer. +Most general purpose I/O pins of an FPGA are driven by a tri-state driver, and the pin is monitored by an input buffer. -When any internal tri-state is attached to an I/O pin it is implemented as three signals driving an IOBUF component: +When any internal tri-state signal is attached to an I/O pin it is implemented as three signals driving an IOBUF component: image:tri-state/m20s1.png[] * 'T' controls the state of the tri-state driver * 'O' is the value of the pin -* 'I' is the value that will be sent to the pin when 'T' is asserted. +* 'I' is the value that will be sent to the pin when 'T' is asserted -(Yes, the signal names do seem the wrong way around, but they are from the IOBUFs point of view) +Yes, the signal names do seem the wrong way around, but they are from the IOBUF's point of view. Project - using tri-state logic ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Sadly this project is Basys2 only - as on the Papilio plus the LogicStart MegaWIng uses all the I/O pins. It is possible to remove the MegaWing and connect directly to the headers on the Papilio One if you want... +Sadly this project is Basys2 only - as on the Papilio One the LogicStart MegaWing uses all the I/O pins. It is possible to remove the MegaWing and connect directly to the headers on the Papilio One if you want... * Create a new project * Configure two of the PMOD pins. Remember to define the PMOD pins as "INOUT"! -* Have 2 LEDs show the status to the two pins on a PMOD connector, +* Have 2 LEDs show the status of the two pins on a PMOD connector, [source,vhdl] ------------------------------------------------------- @@ -59,13 +58,13 @@ Sadly this project is Basys2 only - as on the Papilio plus the LogicStart MegaWI ------------------------------------------------------- * Put a 300 Ohm + resistor between the two pins (to limit the current if both pins are driven at once) -* Put a voltmeter across the resistor. +* Put a voltmeter across the resistor * Play around with the design -** What is the highest voltage you can over the resistor? +** What is the highest voltage you can place over the resistor? ** How much power is this ( remember P=V^2/R) -* using a third slide switch decide which of the pins will be in high-Z mode. Something like: +* Using a third slide switch decide which of the pins will be in high-Z mode. Something like: [source,vhdl] ------------------------------------------------------- @@ -81,6 +80,6 @@ Sadly this project is Basys2 only - as on the Papilio plus the LogicStart MegaWI end process; ------------------------------------------------------- -* Play around with it. +* Play around with it ** What is the highest voltage you can get over the resistor now? ** How much power is this? diff --git a/vga/content.asc b/vga/content.asc index 075a1e8..5208f4b 100755 --- a/vga/content.asc +++ b/vga/content.asc @@ -11,13 +11,13 @@ Let me know if I haven't given enough directions on how to implement this module [NOTE] .Special note for Basys2 users ============================================================ -The Basys2 reference manual infers that the oscillator on the board isn't too stable. Digilent recommends to use an quality aftermarket oscillator to correct this, but the reference manual has the wrong part number - you want to order a SGR-8002DC-PCC-N from Digikey (the only place that seems to have it!) +The Basys2 reference manual infers that the oscillator on the board isn't too stable. Digilent recommends using a quality aftermarket oscillator to correct this, but the reference manual has the wrong part number - you want to order a SGR-8002DC-PCC-N from DigiKey (the only place that seems to have it!). -Test your board/monitor compatibility using the the board self test that is in the flash, or from the file from Digilent's web site if you suspect that this is an issue. +You can test your board/monitor compatibility using the board self test that is in the flash, or from the file from Digilent's web site if you suspect that this is an issue. -I have not been able to get an current 1080p HD LCD monitor to display a picture (although I've only tried two), but it works on plenty of CRTs. +I have not been able to get a current 1080p HD LCD monitor to display a picture (although I've only tried two), but it works on plenty of CRTs. -A cheep fix may be adding additional load to the power supply with a 150 Ohm resistor will help - see http://www.youtube.com/watch?v=bVee4dDwO1k +A cheap fix may be adding additional load to the power supply with a 150 Ohm resistor will help - see http://www.youtube.com/watch?v=bVee4dDwO1k I have had no such issues with my Papilio One - I've even generated signals 1920 x 1080 @ 60Hz (145MHz). ============================================================ @@ -28,28 +28,28 @@ For this demo we will be aiming at 640x480. As detailed on http://tinyvga.com/vg How does the VGA interface work? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In the "good ol' days" most monitors were analogue devices, using Cathode Ray Tubes. Two signals controlled the position of the electron beam on the display. +In the "good ol' days" monitors were analogue devices, using Cathode Ray Tubes. Two signals are used control the position of the electron beam on the display. Vertical sync (vsync) ^^^^^^^^^^^^^^^^^^^^^ -This signal gets pulsed every 60th of a second, and took the electron beam back to the top of the screen. Once back a the top of the screen the monitor would scan the beam slowly down the screen. +This signal is pulsed every 60th of a second, and takes the electron beam back to the top of the screen. Once back at the top of the screen the monitor would scan the beam slowly down the screen. -In this video mode the pulse is negative pulse of 0.063555ms, every 16.6832ms. +In this video mode the pulse is negative pulse of 0.063555ms duration, every 16.6832ms. Horizontal sync (hsync) ^^^^^^^^^^^^^^^^^^^^^^^ -This signal is a pulsed every 1/31,468th of a second, and causes the electron beam to return to the left hand side of the monitor. Once there the beam scans rather more rapidly to the right hand side. +This signal is a pulsed every 1/31,468th of a second, and takes the electron beam to the left hand side of the monitor. Once there the beam scans rather more rapidly to the right hand side. -In this video mode it is a positive pulse of 3.8133068us every 31.777557us. +In this video mode, it is a positive pulse of 3.8133068us duration every 31.777557us. When properly timed, the correct hsync and vsync timings caused the electron beam to scan the whole visible area, so all that is needed is the colour signals. The colour signals - red, green and blue ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -These are analogue signals which controlled the intensity of each colour, and each pixel gets 1/25,175,000th of a second. +These are analogue signals which control the intensity of each colour, and each pixel lasts 1/25,175,000th of a second. -These must only driven only for the correct portion of horizontal scan as the monitor uses the "blanking interval" to register what voltages are used for black. -You have two blanking intervals - the horizontal blanking interval (either side of the hsync pulse) and the vertical blacking interval (either side of the vsync pulse. +These signals should only be driven for the correct portion of the horizontal scan, as the monitor uses the "blanking interval" to register what voltages are used for black. +There is two blanking intervals - the horizontal blanking interval (either side of the hsync pulse) and the vertical blacking interval (either side of the vsync pulse. Pins used to drive the VGA connector ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -60,16 +60,16 @@ Ten pins are used to drive the VGA connecter - the Red, Green and Blue signals u .The constraints for the Papilio board are: ========================================================================= - NET "HSYNC" LOC = "??" | DRIVE = 2; - NET "VSYNC" LOC = "??" | DRIVE = 2; - NET "Red<2>" LOC = "??" | DRIVE = 2; - NET "Red<1>" LOC = "??" | DRIVE = 2; - NET "Red<0>" LOC = "??" | DRIVE = 2; - NET "Green<2>" LOC = "??" | DRIVE = 2; - NET "Green<1>" LOC = "??" | DRIVE = 2; - NET "Green<0>" LOC = "??" | DRIVE = 2; - NET "Blue<2>" LOC = "??" | DRIVE = 2; - NET "Blue<1>" LOC = "??" | DRIVE = 2; + NET "HSYNC" LOC = "J14" | DRIVE = 2; + NET "VSYNC" LOC = "K13" | DRIVE = 2; + NET "Red<2>" LOC = "F12" | DRIVE = 2; + NET "Red<1>" LOC = "D13" | DRIVE = 2; + NET "Red<0>" LOC = "C14" | DRIVE = 2; + NET "Green<2>" LOC = "G14" | DRIVE = 2; + NET "Green<1>" LOC = "G13" | DRIVE = 2; + NET "Green<0>" LOC = "F14" | DRIVE = 2; + NET "Blue<2>" LOC = "J13" | DRIVE = 2; + NET "Blue<1>" LOC = "H13" | DRIVE = 2; ========================================================================= @@ -116,7 +116,7 @@ The vertical blanking interval is the front porch + sync pulse + back porch = 4 The RGB signal ~~~~~~~~~~~~~~~ -The Basys2 board can generate only 256 colours - four shades of red, 8 shades of green and 8 shades of blue. It does this using a passive D-to-A converter made up of a dozen of so resistors. There really isn't much more to say! +Both baords can generate only 256 colours - eight shades of red, eight shades of green and four shades of blue. It does this using a passive D2A converter made up of a dozen or so resistors. There really isn't much more to say! Pseudo-code implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -136,7 +136,7 @@ Implementation of the hsync and vsync signals should be coming clear. Here it is hcount = hcount + 1 end if - if vcount >= 490 and vcount < 491 then + if vcount >= 490 and vcount < 492 then vsync = '0' else vsync = '1' @@ -158,13 +158,13 @@ Project - Displaying something on a VGA monitor ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Create a new project to drive the VGA device. It needs to accept a clk signal and generate hsync, vsync, red(2 downto 0), green(2 downto 0) and blue(2 downto 1) outputs. '''Note that it is Blue(2 downto 1) not Blue(2 downto 0)''' -* Add a implementation constraint file and add the definitions for 'clk' and the 10 VGA signals. +* Add an implementation constraint file and add the definitions for 'clk' and the 10 VGA signals. -* Implement the horizontal counter (you will need a 10 bit counter). Remember to include the unsigned library ("use IEEE.STD_LOGIC_UNSIGNED.ALL;") so you will be able to do numeric operations on STD_LOGIC_VECTOR signals. +* Implement the horizontal counter (you will need a ten-bit counter). Remember to include the unsigned library so you will be able to do numeric operations on STD_LOGIC_VECTOR signals. * Run it in the simulator, and verify the pulse widths and direction. -* Implement the vertical counter (once again you will need a 10 bit counter). You can also verify this in the simulator, but as you need to simulate 16,667us to see the whole frame it can take a while! +* Implement the vertical counter (once again you will need a ten-bit counter). You can also verify this in the simulator, but as you need to simulate 16,667us to see the whole frame it can take a while! * To generate a white image, assign '1's to all the RGB signals during the active time. Test this too in the simulator. You only want to see '1's for the first 640 pixel clocks of the first 480 lines. @@ -176,7 +176,7 @@ Project - Displaying something on a VGA monitor A common cause of problems ~~~~~~~~~~~~~~~~~~~~~~~~~~ -It looks as though this code doesn't need to go into a "if rising_edge(clk) then..." block: +It looks as though this code doesn't need to go into an "if rising_edge(clk) then..." block: if hcount >= 656 and hcount < 752 then hsync = '0' @@ -190,9 +190,9 @@ It looks as though this code doesn't need to go into a "if rising_edge(clk) then vsync = '1' end if -For maximum reliably it does. As the counters ripple between two values (remember, at about 0.1ns per bit) the binary value of the counters will be in transition. If the signals are not buffered in a flip-flop the hsync and vsync can contain unpredictable pulses of around 1ns wide. You won't see these in simulation, and not many of use have a 1GHz Logic Analyser or 'scope, but it is really there. +For maximum reliably, it does. As the counters ripple between two values (remember, at about 0.1ns per bit) the binary value of the counters will be in transition. If the signals are not buffered in a flip-flop, the hsync and vsync can contain unpredictable pulses of around 1ns wide. You won't see these in simulation, and not many of us have a 1GHz Logic Analyser or 'scope, but it is really there. -I've generated a 1440x900 signal (105MHz clock rate) and used logic to display objects on the screen. If I didn't buffer the RGB values the objects wouldn't show correctly or had fuzzy edges. Registering all the VGA signals made these problems go away, as the signals were solidly high or low for the entire clock duration. +I've generated a 1440x900 signal (105MHz clock rate) and used logic to display objects on the screen. If I didn't buffer the RGB outputs, the objects wouldn't show correctly or had fuzzy edges. Registering all the VGA signals made these problems go away, as the signals were solidly high or low for the entire clock duration. -This is only an annoyance while generating VGA signals, but if you are interfacing into other devices (e.g. SRAM) this can cause you no end of heartache. A few 'implementation time' tool options are available that can alter this too, by forcing all the I/O flip-flops to be put as close to the pin as possible, instead of being buried away in the middle of the FPGA fabric. It is also possible to add an "IOB=TRUE" constraint to your UCF file to enable this behaviour on a pin by pin basis. +This is only an annoyance while generating VGA signals, but if you are interfacing into other devices (e.g., SRAM) this can cause you no end of heartache. A few 'implementation time' tool options are available that can alter this too, by forcing all the I/O flip-flops to be put as close to the pin as possible, instead of being buried away in the middle of the FPGA fabric. It is also possible to add an "IOB=TRUE" constraint to your UCF file to enable this behaviour on a pin by pin basis.