OpenCores
URL https://opencores.org/ocsvn/wbfmtx/wbfmtx/trunk

Subversion Repositories wbfmtx

[/] [wbfmtx/] [trunk/] [rtl/] [wbfmtxhack.v] - Blame information for rev 4

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 4 dgisselq
////////////////////////////////////////////////////////////////////////////////
2 2 dgisselq
//
3
// Filename:    wbfmtxhack.v
4
//              
5
// Project:     A Wishbone Controlled FM Transmitter Hack
6
//
7
// Purpose:     This Hack is based off of two things: 1) the interface spec
8
//              of the WB controlled PWM audio device, and 2) a Raspberry Pi
9
//      Hack I was shown that converted the RPi PWM device into an FM
10
//      transmitter.  So, the question is, can a GPIO pin be turned into an
11
//      FM transmitter that can be heard throughout the house?
12
//
13
//      We'll try and do this properly: We'll use a Numerically Controlled
14
//      Oscillator to generate our signal, but only grab the top bit out of
15
//      that oscillator.  We'll then send this bit to the GPIO pin (a.k.a.
16
//      antenna) to see if it can accomplish our goals.
17
//
18
//      WB Control/Registers:
19
//      1'b0:   Next Sample
20
//
21
//              The top bits of this 'next sample' will indicate the number
22
//              of clock ticks before we generate a need next sample interrupt.
23
//              If these top bits are zero, the sample rate will not be
24
//              adjusted.  The value to set here is the value of the clock
25
//              rate divided by the desired sample rate.  Hence, if the clock
26
//              rate is 80MHz, setting this to 10e3 (unsigned) would set us up
27
//              for an 8kHz sample rate, whereas setting these upper 16 bits to
28
//              1814 would specify a sample rate closer to 44.1kHz.
29
//
30
//              The lower 16 bits specify the value of the next sample.
31
//
32
//              Since we'll be dealing with FM modulation, we'll try to arrange
33
//              that this sixteen bit sample will correspond to a maximum
34
//              FM deviation of about 75 kHz.
35
//
36
//
37
//      1'b1:   The Oscillator "Frequency" (really stepsize).  This should be
38
//              used to control/determine the "RF frequency" this device can
39
//              transmit on.  
40
//
41
//              To transmit at 0Hz, set this to zero.  To transmit at
42
//              CLKSPEED/2 Hz, set this to 32'h8000_0000.  Hence for a 
43
//              transmit frequency of X, set this value to 
44
//
45
//              OSXFREQ = 2^32 * X / CLKSPEED
46
//
47
//              Where X and CLKSPEED share the same units.  But how shall we
48
//              transmit at speeds of anything higher than CLKSPEED/2?  By
49
//              aliasing up.  Hence, set X to your actual frequency value,
50
//              divide by the clockspeed and multiply by 2^32.  Remove any
51
//              bits that don't fit in the top 32 and you are there.
52
//
53
//              This also gives us about 20 mHz resolution for our Carrier
54
//              frequency--overkill perhaps, but it should work.
55
//
56
//      So ... how do we create our 75 kHz deviation?  We want:
57
//
58
//      MAX_STEPSIZE = 2^32 * (X + 75kHz * sample / 2^15) / CLKSPEED
59
//      = OSXFREQ = (2^32 * sample / 2^15 / CLKSPEED * 75 kHz)
60
//      = 123 * sample ~= 128 * sample = sample << 7.
61
//
62
//      Thus, by shifting our input sample value a touch, we can multiply by
63
//      nearly the exact constant we want.
64
//
65
// Creator:     Dan Gisselquist, Ph.D.
66
//              Gisselquist Technology, LLC
67
//
68 4 dgisselq
////////////////////////////////////////////////////////////////////////////////
69 2 dgisselq
//
70 4 dgisselq
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
71 2 dgisselq
//
72
// This program is free software (firmware): you can redistribute it and/or
73
// modify it under the terms of  the GNU General Public License as published
74
// by the Free Software Foundation, either version 3 of the License, or (at
75
// your option) any later version.
76
//
77
// This program is distributed in the hope that it will be useful, but WITHOUT
78
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
79
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
80
// for more details.
81
//
82
// You should have received a copy of the GNU General Public License along
83
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
84
// target there if the PDF file isn't present.)  If not, see
85
// <http://www.gnu.org/licenses/> for a copy.
86
//
87
// License:     GPL, v3, as defined and found on www.gnu.org,
88
//              http://www.gnu.org/licenses/gpl.html
89
//
90
//
91 4 dgisselq
////////////////////////////////////////////////////////////////////////////////
92
//
93
//
94 2 dgisselq
module  wbfmtxhack(i_clk,
95
                // Wishbone interface
96
                i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
97
                        o_wb_ack, o_wb_stall, o_wb_data,
98
                o_tx, o_int);
99
        parameter       DEFAULT_RELOAD = 16'd1814; // 44.1kHz at a 80MHz clock
100
        input   i_clk;
101
        input   i_wb_cyc, i_wb_stb, i_wb_we;
102
        input           i_wb_addr;
103
        input   [31:0]   i_wb_data;
104
        output  reg             o_wb_ack;
105
        output  wire            o_wb_stall;
106
        output  reg     [31:0]   o_wb_data;
107
        output  wire            o_tx;
108
        output  reg             o_int;
109
 
110
        reg     [31:0]   nco_step, nco_phase;
111
 
112
        // How often shall we create an interrupt?  Every reload_value clocks!
113
        // If VARIABLE_RATE==0, this value will never change and will be kept
114
        // at the default reload rate (44.1 kHz, for a 100 MHz clock)
115
        reg     [15:0]   reload_value;
116
        initial reload_value = DEFAULT_RELOAD;
117 3 dgisselq
 
118
        // Data write, but we use the upper 16 bits to set our sample rate.
119
        // If these bits are zero, we ignore the write--allowing users to
120
        // write samples without adjusting the sample rate.
121
        always @(posedge i_clk) // Set sample rate
122 2 dgisselq
                if ((i_wb_cyc)&&(i_wb_stb)&&(~i_wb_addr)&&(i_wb_we)
123
                                &&(|i_wb_data[31:16]))
124
                        reload_value <= i_wb_data[31:16];
125 3 dgisselq
 
126
        // Set the NCO transmit frequency
127
        initial nco_step = 32'h00;
128
        always @(posedge i_clk)
129 2 dgisselq
                if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_addr)&&(i_wb_we))
130
                        nco_step <= i_wb_data[31:0];
131
 
132 3 dgisselq
        reg             ztimer;
133 2 dgisselq
        reg     [15:0]   timer;
134 3 dgisselq
        initial ztimer = 1'b0;
135
        always @(posedge i_clk) // Be true when the timer is zero
136
                ztimer <= (timer[15:0] == 16'h1);
137
        initial timer = reload_value;
138 2 dgisselq
        always @(posedge i_clk)
139 3 dgisselq
                if (ztimer)
140 2 dgisselq
                        timer <= reload_value;
141
                else
142
                        timer <= timer - 16'h1;
143
 
144
        reg     [15:0]   next_sample, sample_out;
145 3 dgisselq
        initial sample_out  = 16'h00;
146
        initial next_sample = 16'h00;
147 2 dgisselq
        always @(posedge i_clk)
148 3 dgisselq
                if (ztimer)
149 2 dgisselq
                        sample_out <= next_sample;
150
 
151
        reg             next_valid;
152
        initial next_valid = 1'b1;
153
        initial next_sample = 16'h8000;
154
        always @(posedge i_clk) // Data write
155
                if ((i_wb_cyc)&&(i_wb_stb)&&(i_wb_we)&&(~i_wb_addr))
156
                begin
157 3 dgisselq
                        // Write with two's complement data
158 2 dgisselq
                        next_sample <= i_wb_data[15:0];
159
                        next_valid <= 1'b1;
160 3 dgisselq
                end else if (ztimer)
161 2 dgisselq
                        next_valid <= 1'b0;
162
 
163 3 dgisselq
        // The interrupt line will remain high until writing a new data value
164
        // clears it.  This design does not permit turning off this interrupt.
165
        // If the interrupt needs to be turned off, then ignore it in the 
166
        // interrupt controller.
167 2 dgisselq
        initial o_int = 1'b0;
168
        always @(posedge i_clk)
169
                o_int <= (~next_valid);
170
 
171 3 dgisselq
        // Adjust the gain for a maximum frequency offset just greater than
172
        // 75 kHz.  (We would've done 75kHz exactly, but it required a multiply
173
        // and this doesn't.)
174 2 dgisselq
        initial nco_phase = 32'h00;
175
        always @(posedge i_clk)
176
                nco_phase <= nco_phase + nco_step
177
                        + { {(32-16-7){sample_out[15]}}, sample_out, 7'h00 };
178
        assign  o_tx = nco_phase[31];
179
 
180
        always @(posedge i_clk)
181
                if (i_wb_addr)
182
                        o_wb_data <= nco_step;
183
                else
184
                        o_wb_data <= { reload_value, sample_out[15:1], o_int };
185
 
186
        initial o_wb_ack = 1'b0;
187
        always @(posedge i_clk)
188
                o_wb_ack <= (i_wb_cyc)&&(i_wb_stb);
189
        assign  o_wb_stall = 1'b0;
190
 
191
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.