Skip to content

Commit 2c66bab

Browse files
committed
Add Mojo alchitry project
1 parent 33321f0 commit 2c66bab

File tree

8 files changed

+464
-0
lines changed

8 files changed

+464
-0
lines changed

Firmware_alchitry/Mojo/Mojo.alp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project name="Mojo" board="Mojo" language="Lucid" version="3">
3+
<files>
4+
<component>reset_conditioner.luc</component>
5+
<component>reg_interface.luc</component>
6+
<component>pwm.luc</component>
7+
<component>uart_rx.luc</component>
8+
<component>avr_interface.luc</component>
9+
<component>counter.luc</component>
10+
<component>spi_peripheral.luc</component>
11+
<src top="true">mojo_top.luc</src>
12+
<src>lasertrigger.luc</src>
13+
<src>analogreader.luc</src>
14+
<src>cam_synchro.luc</src>
15+
<src>servo_standard.luc</src>
16+
<src>servo_stop.luc</src>
17+
<component>uart_tx.luc</component>
18+
<component>cclk_detector.luc</component>
19+
<constraint lib="true">mojo.ucf</constraint>
20+
<constraint>user.ucf</constraint>
21+
</files>
22+
</project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
NET "camera" LOC = P88 | IOSTANDARD = LVTTL | PULLUP;
2+
NET "laser1" LOC = P57 | IOSTANDARD = LVTTL | PULLUP;
3+
NET "laser2" LOC = P67 | IOSTANDARD = LVTTL | PULLUP;
4+
NET "laser3" LOC = P74 | IOSTANDARD = LVTTL | PULLUP;
5+
NET "laser4" LOC = P79 | IOSTANDARD = LVTTL | PULLUP;
6+
NET "laser5" LOC = P80 | IOSTANDARD = LVTTL | PULLUP;
7+
NET "laser6" LOC = P83 | IOSTANDARD = LVTTL | PULLUP;
8+
NET "ttl1" LOC = P104 | IOSTANDARD = LVTTL | PULLUP;
9+
NET "ttl2" LOC = P112 | IOSTANDARD = LVTTL | PULLUP;
10+
NET "ttl3" LOC = P114 | IOSTANDARD = LVTTL | PULLUP;
11+
NET "ttl4" LOC = P117 | IOSTANDARD = LVTTL | PULLUP;
12+
NET "ttl5" LOC = P118 | IOSTANDARD = LVTTL | PULLUP;
13+
NET "ttl6" LOC = P121 | IOSTANDARD = LVTTL | PULLUP;
14+
NET "servo1" LOC = P143 | IOSTANDARD = LVTTL;
15+
NET "servo2" LOC = P142 | IOSTANDARD = LVTTL;
16+
NET "servo3" LOC = P139 | IOSTANDARD = LVTTL;
17+
NET "servo4" LOC = P138 | IOSTANDARD = LVTTL;
18+
NET "servo5" LOC = P133 | IOSTANDARD = LVTTL;
19+
NET "servo6" LOC = P132 | IOSTANDARD = LVTTL;
20+
NET "pwm1" LOC = P51 | IOSTANDARD = LVTTL;
21+
NET "pwm2" LOC = P40 | IOSTANDARD = LVTTL;
22+
NET "pwm3" LOC = P35 | IOSTANDARD = LVTTL;
23+
NET "pwm4" LOC = P32 | IOSTANDARD = LVTTL;
24+
NET "pwm5" LOC = P30 | IOSTANDARD = LVTTL;
25+
NET "pwm6" LOC = P26 | IOSTANDARD = LVTTL;
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
module analogreader (
2+
input clk, // clock
3+
input rst, // reset
4+
input sample[10],
5+
input sample_channel[4],
6+
input new_sample,
7+
output channel[4],
8+
output value[8][10]
9+
) {
10+
11+
// This is used to convert 0 to 7 to its corresponding channel 0 to 1 and 4 to 9
12+
const DIGIT_TO_CHANNEL = {4d9,4d8,4d7,4d6,4d5,4d4,4d1,4d0};
13+
14+
// This is used to convert the sample channel to the corresponding LED
15+
// Most channels are invalid and will never be seen so we use 'x' as don't cares
16+
const CHANNEL_TO_LED = {4bx,4bx,4bx,4bx,4bx,4bx,4d7,4d6,4d5,4d4,4d3,4d2,4bx,4bx,4d1,4d0};
17+
.clk(clk){
18+
.rst(rst) {
19+
dff value_lib[8][10];
20+
dff ch[4];
21+
}}
22+
23+
always {
24+
channel = DIGIT_TO_CHANNEL[ch.q]; // set the channel to sample
25+
value = value_lib.q;
26+
27+
if (new_sample) { // when there is a new sample
28+
value_lib.d[CHANNEL_TO_LED[sample_channel]] = sample;
29+
ch.d = ch.q + 1; // increment the channel we are sampling
30+
if (ch.q == 7) // there are only 8 channels (0 to 7)
31+
ch.d = 0; // restart at 0
32+
}
33+
}
34+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
module cam_synchro (
2+
input clk, // clock
3+
input rst, // reset
4+
input camera,
5+
output sync[4]
6+
) {
7+
8+
.clk(clk){
9+
.rst(rst) {
10+
dff sync_count[4];
11+
dff sig_sync[2];
12+
dff sig_old;
13+
}}
14+
15+
always {
16+
sig_sync.d[0] = camera;
17+
sig_sync.d[1] = sig_sync.q[0];
18+
sig_old.d = sig_sync.q[1];
19+
20+
21+
if(sig_old.q == 0 && sig_sync.q[1] == 1){
22+
sync_count.d = sync_count.q+1;
23+
}
24+
25+
sync = sync_count.q;
26+
27+
}
28+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
module lasertrigger (
2+
input clk, // clock
3+
input rst, // reset
4+
input trig,
5+
input seq[16],
6+
input mod[3],
7+
input dura[16],
8+
input sync[4],
9+
output lasersignal
10+
) {
11+
12+
const OFF = 0;
13+
const ON = 1;
14+
const RISING = 2;
15+
const FALLING = 3;
16+
const FOLLOW = 4;
17+
18+
const NM_CYCLES = 50;
19+
var plength;
20+
21+
.clk(clk){
22+
.rst(rst) {
23+
dff sig_sync[2];
24+
dff sig_old;
25+
dff count_sig[22];
26+
}}
27+
28+
always {
29+
plength = dura*NM_CYCLES;
30+
31+
sig_sync.d[0] = trig;
32+
sig_sync.d[1] = sig_sync.q[0];
33+
sig_old.d = sig_sync.q[1];
34+
35+
if (!&count_sig.q){
36+
count_sig.d = count_sig.q + 1;
37+
}
38+
39+
lasersignal=0;
40+
41+
case(mod){
42+
OFF:
43+
lasersignal = 0;
44+
ON:
45+
lasersignal = 1;
46+
RISING:
47+
if(sig_old.q == 0 && sig_sync.q[1] == 1){
48+
count_sig.d = 0;
49+
}
50+
lasersignal = (sig_sync.q[1] && seq[15-sync]) && count_sig.q<plength;
51+
FALLING:
52+
if(sig_old.q == 1 && sig_sync.q[1] == 0){
53+
count_sig.d = 0;
54+
}
55+
lasersignal = (!sig_sync.q[1] && seq[15-sync]) && count_sig.q<plength;
56+
FOLLOW:
57+
lasersignal = (sig_sync.q[1] && seq[15-sync]);
58+
}
59+
}
60+
}
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
module mojo_top (
2+
input clk, // 50MHz clock
3+
input rst_n, // reset button (active low)
4+
output led [8], // 8 user controllable LEDs
5+
input cclk, // configuration clock, AVR ready when high
6+
output spi_miso, // AVR SPI MISO
7+
input spi_ss, // AVR SPI Slave Select
8+
input spi_mosi, // AVR SPI MOSI
9+
input spi_sck, // AVR SPI Clock
10+
output spi_channel [4], // AVR general purpose pins (used by default to select ADC channel)
11+
input avr_tx, // AVR TX (FPGA RX)
12+
output avr_rx, // AVR RX (FPGA TX)
13+
input avr_rx_busy, // AVR RX buffer full
14+
input camera,
15+
output laser1,
16+
output laser2,
17+
output laser3,
18+
output laser4,
19+
output laser5,
20+
output laser6,
21+
output ttl1,
22+
output ttl2,
23+
output ttl3,
24+
output ttl4,
25+
output ttl5,
26+
output ttl6,
27+
output servo1,
28+
output servo2,
29+
output servo3,
30+
output servo4,
31+
output servo5,
32+
output servo6,
33+
output pwm1,
34+
output pwm2,
35+
output pwm3,
36+
output pwm4,
37+
output pwm5,
38+
output pwm6
39+
) {
40+
41+
const ADDRESS_VERSION = 100;
42+
const ERROR_UNKNOW_COMMAND = 38730;
43+
const NUM_INPUT = 8; // fixed by the board
44+
const NUM_LASERS = 6;
45+
const NUM_PWM = 6;
46+
const NUM_TTL = 6;
47+
const NUM_SERVOS = 6;
48+
49+
sig rst; // reset signal
50+
51+
.clk(clk) {
52+
// The reset conditioner is used to synchronize the reset signal to the FPGA
53+
// clock. This ensures the entire FPGA comes out of reset at the same time.
54+
reset_conditioner reset_cond;
55+
56+
.rst(rst){
57+
// the avr_interface module is used to talk to the AVR for access to the USB port and analog pins
58+
avr_interface avr;
59+
reg_interface reg;
60+
61+
// adc
62+
analogreader adc;
63+
64+
// lasers
65+
lasertrigger l[NUM_LASERS];
66+
cam_synchro camsync;
67+
68+
dff sequence[NUM_LASERS][16];
69+
dff duration[NUM_LASERS][16];
70+
dff mode[NUM_LASERS][3];
71+
72+
// ttls
73+
dff ttl[NUM_TTL];
74+
75+
// servos
76+
servo_standard servo_controller[NUM_SERVOS];
77+
dff position[NUM_SERVOS][16];
78+
dff servo_sig_update[NUM_SERVOS];
79+
servo_stop servo_sig[NUM_SERVOS];// to shut down the servos 10 sec after every movement
80+
81+
// pwm
82+
pwm pulsewm[NUM_PWM](#TOP(254),#DIV(9),#WIDTH(8));
83+
dff dutycycle[NUM_PWM][8];
84+
dff pwmupdate[NUM_PWM];
85+
}
86+
}
87+
88+
always {
89+
led = 8b0;
90+
91+
reset_cond.in = ~rst_n; // input raw inverted reset signal
92+
rst = reset_cond.out; // conditioned reset
93+
94+
// connect inputs of avr
95+
avr.cclk = cclk;
96+
avr.spi_ss = spi_ss;
97+
avr.spi_mosi = spi_mosi;
98+
avr.spi_sck = spi_sck;
99+
avr.rx = avr_tx;
100+
avr.tx_block = avr_rx_busy; // block TX when AVR is busy
101+
102+
// connect outputs of avr
103+
spi_miso = avr.spi_miso;
104+
spi_channel = avr.spi_channel;
105+
avr_rx = avr.tx;
106+
107+
// connect adc to avr avr_interface
108+
avr.channel = adc.channel;
109+
adc.sample = avr.sample;
110+
adc.sample_channel = avr.sample_channel;
111+
adc.new_sample = avr.new_sample;
112+
113+
// connect reg interface to avr interface
114+
reg.rx_data = avr.rx_data;
115+
reg.new_rx_data = avr.new_rx_data;
116+
avr.tx_data = reg.tx_data;
117+
avr.new_tx_data = reg.new_tx_data;
118+
reg.tx_busy = avr.tx_busy;
119+
120+
reg.regIn.drdy = 0; // default to not ready
121+
reg.regIn.data = 32bx; // don't care
122+
123+
pwmupdate.d = NUM_PWMx{0};
124+
servo_sig_update.d = NUM_SERVOSx{0};
125+
126+
if (reg.regOut.new_cmd) { // new command
127+
if (reg.regOut.write) { // if write
128+
if (reg.regOut.address < NUM_LASERS) { // Laser modes
129+
mode.d[reg.regOut.address] = reg.regOut.data[2:0];
130+
} else if (reg.regOut.address < 10+NUM_LASERS) { // Laser duration
131+
duration.d[reg.regOut.address-10] = reg.regOut.data[15:0];
132+
} else if (reg.regOut.address < 20+NUM_LASERS) { // Laser sequence
133+
sequence.d[reg.regOut.address-20] = reg.regOut.data[15:0];
134+
} else if (reg.regOut.address < 30+NUM_TTL){ // TTL
135+
ttl.d[reg.regOut.address-30] = reg.regOut.data[0];
136+
} else if (reg.regOut.address < 40+NUM_SERVOS){ // Servo
137+
position.d[reg.regOut.address-40] = reg.regOut.data[15:0];
138+
servo_sig_update.d[reg.regOut.address-40] = 1;
139+
} else if (reg.regOut.address < 50+NUM_PWM){ // PWM
140+
dutycycle.d[reg.regOut.address-50] = reg.regOut.data[7:0];
141+
pwmupdate.d[reg.regOut.address-50] = 1;
142+
}
143+
} else { // read
144+
led = 10;
145+
if (reg.regOut.address < NUM_LASERS) { // Laser modes
146+
reg.regIn.data = mode.q[reg.regOut.address];
147+
reg.regIn.drdy = 1;
148+
} else if (reg.regOut.address < 10+NUM_LASERS) { // Laser duration
149+
reg.regIn.data = duration.q[reg.regOut.address-10];
150+
reg.regIn.drdy = 1;
151+
} else if (reg.regOut.address < 20+NUM_LASERS) { // Laser sequence
152+
reg.regIn.data = sequence.q[reg.regOut.address-20];
153+
reg.regIn.drdy = 1;
154+
} else if (reg.regOut.address < 30+NUM_TTL){ // TTL
155+
reg.regIn.data = ttl.q[reg.regOut.address-30];
156+
reg.regIn.drdy = 1;
157+
} else if (reg.regOut.address < 40+NUM_SERVOS){ // Servo
158+
reg.regIn.data = position.q[reg.regOut.address-40];
159+
reg.regIn.drdy = 1;
160+
} else if (reg.regOut.address < 50+NUM_PWM){ // PWM
161+
reg.regIn.data = dutycycle.q[reg.regOut.address-50];
162+
reg.regIn.drdy = 1;
163+
} else if (reg.regOut.address < 60+NUM_INPUT) { // Analog input
164+
reg.regIn.data = adc.value[reg.regOut.address-60];
165+
reg.regIn.drdy = 1;
166+
} else if (reg.regOut.address == ADDRESS_VERSION) { // Version
167+
reg.regIn.data = 1; // version number
168+
reg.regIn.drdy = 1;
169+
} else { // Error
170+
reg.regIn.data = ERROR_UNKNOW_COMMAND;
171+
reg.regIn.drdy = 1;
172+
}
173+
}
174+
}
175+
176+
///////////////// Lasers
177+
camsync.camera = camera;
178+
l.trig = NUM_LASERSx{camera};
179+
l.seq = sequence.q;
180+
l.mod = mode.q;
181+
l.dura = duration.q;
182+
l.sync = NUM_LASERSx{{camsync.sync}};
183+
184+
laser1 = l.lasersignal[0];
185+
laser2 = l.lasersignal[1];
186+
laser3 = l.lasersignal[2];
187+
laser4 = l.lasersignal[3];
188+
laser5 = l.lasersignal[4];
189+
laser6 = l.lasersignal[5];
190+
191+
//////////////// TTLs
192+
ttl1 = ttl.q[0];
193+
ttl2 = ttl.q[1];
194+
ttl3 = ttl.q[2];
195+
ttl4 = ttl.q[3];
196+
ttl5 = ttl.q[4];
197+
ttl6 = ttl.q[5];
198+
199+
//////////////// Servos
200+
servo_controller.position = position.q;
201+
servo_sig.update = servo_sig_update.q;
202+
servo_sig.signal_in = servo_controller.servo;
203+
servo1 = servo_sig.signal_out[0];
204+
servo2 = servo_sig.signal_out[1];
205+
servo3 = servo_sig.signal_out[2];
206+
servo4 = servo_sig.signal_out[3];
207+
servo5 = servo_sig.signal_out[4];
208+
servo6 = servo_sig.signal_out[5];
209+
210+
//////////////// PWM
211+
pulsewm.update = pwmupdate.q;
212+
pulsewm.value = dutycycle.q;
213+
pwm1 = pulsewm.pulse[0];
214+
pwm2 = pulsewm.pulse[1];
215+
pwm3 = pulsewm.pulse[2];
216+
pwm4 = pulsewm.pulse[3];
217+
pwm5 = pulsewm.pulse[4];
218+
pwm6 = pulsewm.pulse[5];
219+
}
220+
}

0 commit comments

Comments
 (0)