~\Desktop\github\ECE5730-Final-Project\final\main.c

1/**
2 * This is the code for the final project of ECE 5730
3 * Project Name: Microwave Imaging System
4 * Author: Zehao Li(zl823) and Kapil Gangwar(kg434)
5 * Date: 12/11/2023
6 * Description: This project is to build the Microwave Imaging System with two Vivaldi antennas
7 aims to achieve good-resolution 2D imaging through circular motion and 3D image reconstruction
8 by vertical movement of the subject using scattering parameter messurements.
9
10 * HARDWARE CONNECTIONS
11 - GPIO 2 ---> STEP on the A4988 Stepper Motor Driver 1
12 - GPIO 3 ---> DIR on the A4988 Stepper Motor Driver 1
13 - GPIO 7 ---> Pin1 on the Keyboard
14 - GPIO 8 ---> Pin2 on the Keyboard
15 - GPIO 9 ---> Pin3 on the Keyboard
16 - GPIO 10 ---> Pin4 on the Keyboard
17 - GPIO 11 ---> Pin5 on the Keyboard
18 - GPIO 12 ---> Pin6 on the Keyboard
19 - GPIO 13 ---> Pin7 on the Keyboard
20 - GPIO 14 ---> STEP on the A4988 Stepper Motor Driver 2
21 - GPIO 15 ---> DIR on the A4988 Stepper Motor Driver 2
22 - GPIO 16 ---> VGA Hsync
23 - GPIO 17 ---> VGA Vsync
24 - GPIO 18 ---> 330 ohm resistor ---> VGA Red
25 - GPIO 19 ---> 330 ohm resistor ---> VGA Green
26 - GPIO 20 ---> 330 ohm resistor ---> VGA Blue
27 - RP2040 GND ---> VGA GND
28 - RP2040 GND ---> Switch ---> RP2040 RUN
29 - RP2040 GND ---> GND on the A4988 Stepper Motor Driver 1 and 2
30 - RP2040 3V3 ---> VDD on the A4988 Stepper Motor Driver 1 and 2
31
32 - External 12V power supply ---> VMOT on the A4988 Stepper Motor Driver 1 and 2
33 - External 12V ground ---> GND on the A4988 Stepper Motor Driver 1 and 2
34 */
35
36
37// Include standard libraries
38#include <stdio.h>
39#include <stdlib.h>
40#include <math.h>
41#include <string.h>
42// Include PICO libraries
43#include "pico/stdlib.h"
44#include "pico/multicore.h"
45// Include hardware libraries
46#include "hardware/pwm.h"
47// Include custom libraries
48#include "vga_graphics.h"
49#include "pt_cornell_rp2040_v1.h"
50
51// Macros for fixed-point arithmetic (faster than floating point)
52typedef signed int fix15 ;
53#define multfix15(a,b) ((fix15)((((signed long long)(a))*((signed long long)(b)))>>15))
54#define float2fix15(a) ((fix15)((a)*32768.0))
55#define fix2float15(a) ((float)(a)/32768.0)
56#define absfix15(a) abs(a)
57#define int2fix15(a) ((fix15)(a << 15))
58#define fix2int15(a) ((int)(a >> 15))
59#define char2fix15(a) (fix15)(((fix15)(a)) << 15)
60#define divfix(a,b) (fix15)( (((signed long long)(a)) << 15) / (b))
61#define min(a,b) ((a<b) ? a:b)
62#define max(a,b) ((a<b) ? b:a)
63#define abs(a) ((a>0) ? a:-a)
64#define SIGN(x) ((x > 0) - (x < 0))
65#define PI 3.14159
66
67// semaphore
68static struct pt_sem vga_semaphore; // VGA drawing semaphore
69const int dirPin_rotation = 3; // rotation direction pin
70const int stepPin_rotation = 2; // rotation step pin
71const int dirPin_lift = 15; // lift direction pin
72const int stepPin_lift = 14; // lift step pin
73int stepsPerRevolution; // Steps per revolution
74float degree = 0.0; // degree of the rotation
75int redius = 100; // redius of the circle
76int rotate_flag = 0; // flag to rotate the plate
77#define FRAME_RATE 16667 // 60 Hz frame rate
78#define BASE_KEYPAD_PIN 7
79#define KEYROWS 4
80#define NUMKEYS 12
81static int idx;
82static int old_idx;
83unsigned int keycodes[12] = { 0x28, 0x11, 0x21, 0x41, 0x12,
84 0x22, 0x42, 0x14, 0x24, 0x44,
85 0x18, 0x48} ;
86unsigned int scancodes[4] = { 0x01, 0x02, 0x04, 0x08} ;
87unsigned int button = 0x70 ;
88int lift = 0; // stop the lift
89int page = 0; // Main Page
90int stop = 0; // stop flag for the rotation
91int manual_auto = 0; // Initial Stop Flag
92int auto_index = 0; // indicator of the auto initial configuration step
93int temp_step = 0; //temp hold for rotation degree
94int temp_step2 = 0; // temp hold for rotation interval
95int temp_step3 = 0; // temp hold for lift interval
96int interval = 0; // set auto rotation interval
97int interval2 = 0; // set auto lift interval
98static int new_x ; // new end x pos of the pointer on the circle
99static int new_y ; // new end y pos of the pointer on the circle
100char deg[50]; // degree in string
101char temp[50]; // temp string for rotation degree
102char temp1[50]; // temp string for auto rotation interval
103char temp2[50]; // temp string for auto lift interval
104
105// Interrupt service routine
106void on_pwm_wrap() {
107 // Clear the interrupt flag that brought us here
108 pwm_clear_irq(pwm_gpio_to_slice_num(5));
109 // Signal VGA to draw
110 PT_SEM_SIGNAL(pt, &vga_semaphore);
111}
112
113void draw_UI(){ // Only call Draw UI when the page is changed
114 fillRect(440, 200, 200, 280, BLACK);
115 drawRect(440, 200, 200, 280, WHITE);
116 setCursor(450, 210);
117 setTextColor2(WHITE, BLACK);
118 switch (page){
119 case 0: // at Main Page
120 writeString("Main Page");
121 setCursor(450, 230);
122 writeString("1. Manual");
123 setCursor(450, 250);
124 writeString("2. Auto");
125 break;
126 case 1: // at Manual Page
127 writeString("Manual Page");
128 setCursor(450, 230);
129 writeString("1. Rotation");
130 setCursor(450, 250);
131 writeString("2. Lift");
132 setCursor(450, 270);
133 writeString("#. Back");
134 break;
135 case 11: // at Manual Rotation Page
136 writeString("Manual Rotation Page");
137 setCursor(450, 230);
138 writeString("0-9. Input");
139 setCursor(450, 250);
140 writeString("*. Confirm");
141 setCursor(450, 270);
142 writeString("#. Back");
143 setCursor(450, 290);
144 writeString(temp);
145 break;
146 case 12: // at Manual Lift Page
147 writeString("Manual Lift Page");
148 setCursor(450, 230);
149 writeString("2. Up");
150 setCursor(450, 250);
151 writeString("5. Down");
152 setCursor(450, 270);
153 writeString("3. Up 1cm");
154 setCursor(450, 290);
155 writeString("6. Down 1cm");
156 setCursor(450, 310);
157 writeString("#. Back");
158 break;
159 case 2: // at Auto Page
160 writeString("Auto Page");
161 switch (auto_index){
162 case 0:
163 setCursor(450, 230);
164 writeString("Rotation degree:");
165 setCursor(450, 250);
166 writeString("0-9. Input");
167 setCursor(450, 270);
168 writeString("*. Confirm");
169 setCursor(450, 290);
170 writeString("#. Back to main");
171 setCursor(450, 310);
172 writeString(temp);
173 break;
174 case 1:
175 setCursor(450, 230);
176 writeString("Rotation interval in seconds:");
177 setCursor(450, 250);
178 writeString("0-9. Input");
179 setCursor(450, 270);
180 writeString("*. Confirm");
181 setCursor(450, 290);
182 writeString("#. Back to main");
183 setCursor(450, 310);
184 writeString(temp);
185 setCursor(450, 330);
186 writeString(temp1);
187 break;
188 case 2:
189 setCursor(450, 230);
190 writeString("Manual Lift Control");
191 setCursor(450, 250);
192 writeString("2. Up");
193 setCursor(450, 270);
194 writeString("5. Down");
195 setCursor(450, 290);
196 writeString("*. Confirm");
197 setCursor(450, 310);
198 writeString("#. Back to main");
199 setCursor(450, 330);
200 writeString(temp);
201 setCursor(450, 350);
202 writeString(temp1);
203 break;
204 case 3:
205 setCursor(450, 230);
206 writeString("Lift interval in cm:");
207 setCursor(450, 250);
208 writeString("0-9. Input");
209 setCursor(450, 270);
210 writeString("*. Confirm");
211 setCursor(450, 290);
212 writeString("#. Back to main");
213 setCursor(450, 310);
214 writeString(temp);
215 setCursor(450, 330);
216 writeString(temp1);
217 setCursor(450, 350);
218 writeString(temp2);
219 break;
220 }
221 break;
222 }
223}
224
225void detect_keypad(){
226 //Scan the keypad!
227 static uint32_t keypad ;
228 for (idx=0; idx<KEYROWS; idx++) {
229 // Set a row high
230 gpio_put_masked((0xF << BASE_KEYPAD_PIN),
231 (scancodes[idx] << BASE_KEYPAD_PIN)) ;
232 // Small delay required
233 sleep_us(1) ;
234 // Read the keycode
235 keypad = ((gpio_get_all() >> BASE_KEYPAD_PIN) & 0x7F) ;
236 // Break if button(s) are pressed
237 if (keypad & button) break ;
238 }
239 // If we found a button . . .
240 if (keypad & button) {
241 // Look for a valid keycode.
242 for (idx=0; idx<NUMKEYS; idx++) {
243 if (keypad == keycodes[idx]) break ;
244 }
245 // If we don't find one, report invalid keycode
246 if (idx==NUMKEYS) (idx = -1) ;
247 }
248 // Otherwise, indicate invalid/non-pressed buttons
249 else (idx=-1) ;
250}
251
252void draw_rotation_platform(){
253 // draw circle
254 drawCircle(320, 240, redius, WHITE);
255 drawLine(320, 240, new_x, new_y, BLACK);
256 new_x = 320 + redius * sin(-degree*PI/180);
257 new_y = 240 + redius * cos(-degree*PI/180);
258 drawLine(320, 240, new_x, new_y, WHITE);
259}
260
261void draw_rotation_text(){
262 setCursor(250, 400);
263 setTextColor2(BLACK, BLACK);
264 writeString(deg);
265 setCursor(250, 400);
266 setTextColor2(WHITE, BLACK);
267 sprintf(deg, "%s%.2f", "Current Degree is ", degree);
268 writeString(deg);
269}
270
271// Thread that draws to VGA display
272static PT_THREAD (protothread_vga(struct pt *pt))
273{
274 // Indicate start of thread
275 PT_BEGIN(pt) ;
276 // Variables for maintaining frame rate
277 static int begin_time ;
278 static int spare_time ;
279 setTextSize(1);
280
281 sprintf(temp, "%s%.2f", "Current Degree is ", temp_step*1.8);
282 draw_rotation_platform();
283 draw_rotation_text();
284 draw_UI();
285
286 while(1) {
287 // Measure time at start of thread
288 begin_time = time_us_32();
289
290 detect_keypad();
291
292 switch(page){
293 case 0: // at Main Page
294 if (old_idx != idx){
295 if (idx == 1){
296 page = 1; // go to the manual page
297 draw_UI();
298 }else if (idx == 2){
299 page = 2; // go to the auto page
300 draw_UI();
301 }
302 }
303 break;
304 case 1: // at Manual Page
305 manual_auto = 1; // at Manual Mode
306 if (old_idx != idx){
307 if (idx == 1){
308 page = 11; // go to the rotation page
309 draw_UI();
310 }else if (idx == 2){
311 page = 12; // go to the lift page
312 draw_UI();
313 }else if (idx == 11){
314 page = 0; // go back to the main page
315 draw_UI();
316 manual_auto = 0; // change to stop
317 }
318 }
319 break;
320 case 11: // at Manual Rotation Page
321 if (old_idx != idx){
322 if (stop == 1 && idx == 0){ // continue to rotate by one step
323 stop = 0;
324 }
325 else if (idx <= 9 && 0 <= idx){ // integer
326 temp_step = temp_step * 10 + idx;
327 if (temp_step > 200){
328 temp_step = 200;
329 }
330 sprintf(temp, "%s%.2f", "Degree Selection: ", temp_step*1.8);
331 draw_UI();
332 }else if (idx == 10){ // confirm
333 stepsPerRevolution = temp_step;
334 rotate_flag = 1;
335 temp_step = 0;
336 stop = 0;
337 }else if (idx == 11){ // go back to the manual page
338 page = 1; // go to manual page
339 temp_step = 0;
340 rotate_flag = 0;
341 stop = 1;
342 sprintf(temp, "%s%.2f", "Degree Selection: ", temp_step*1.8);
343 draw_UI();
344 }
345 }
346 break;
347 case 12: // at Manual Lift Page
348 if (idx == 2){ // go up manually
349 lift = 1; // up manual
350 }else if (idx == 5){ // go down manually
351 lift = 2; // down manual
352 }else if (idx == 3 && old_idx != idx){ // go up by 1cm
353 lift = 3; // up by 1cm
354 }else if (idx == 6 && old_idx != idx){ // go down by 1cm
355 lift = 4; // down by 1cm
356 }else if (idx == 11 && old_idx != idx){ // go back to the manual page
357 page = 1; // go to the manual page
358 lift = 0; // stop the lift
359 draw_UI();
360 }
361 break;
362 case 2: // at Auto Page
363 switch (auto_index){
364 case 0: // at auto rotation degree selection page
365 if (old_idx != idx){
366 if (idx <= 9 && 0 <= idx){ // integer
367 temp_step = temp_step * 10 + idx;
368 if (temp_step > 200){
369 temp_step = 200;
370 }
371 sprintf(temp, "%s%.2f", "Degree Selection: ", temp_step*1.8);
372 draw_UI();
373 }else if (idx == 10){ // confirm
374 stepsPerRevolution = temp_step;
375 temp_step = 0;
376 temp_step2 = 0;
377 temp_step3 = 0;
378 auto_index = 1; // go to the lift page
379 draw_UI();
380 }else if (idx == 11){ // go back to the manual page
381 page = 0; // go to main page
382 temp_step = 0;
383 temp_step2 = 0;
384 temp_step3 = 0;
385 draw_UI();
386 }
387 }
388 break;
389 case 1: // at auto interval time selection page
390 if (old_idx != idx){
391 if (idx <= 9 && 0 <= idx){ // integer
392 temp_step2 = temp_step2 * 10 + idx;
393 sprintf(temp1, "%s%d%s", "Degree Interval: ", temp_step2, "(s)");
394 draw_UI();
395 }else if (idx == 10){ // confirm
396 interval = temp_step2;
397 auto_index = 2; // go to height adjust page
398 temp_step = 0;
399 temp_step2 = 0;
400 temp_step3 = 0;
401 draw_UI();
402 }else if (idx == 11){ // go back to the rotation degree selection page
403 page = 0; // go to main page
404 temp_step = 0;
405 temp_step2 = 0;
406 temp_step3 = 0;
407 draw_UI();
408 }
409 }
410 break;
411 case 2: // at auto lift page
412 if (idx == 2){ // go up
413 gpio_put(dirPin_lift, 0);
414 sleep_ms(2);
415 gpio_put(stepPin_lift, 1);
416 sleep_ms(2);
417 gpio_put(stepPin_lift, 0);
418 sleep_ms(2);
419 }else if (idx == 5){ // go down
420 gpio_put(dirPin_lift, 1);
421 sleep_ms(2);
422 gpio_put(stepPin_lift, 1);
423 sleep_ms(2);
424 gpio_put(stepPin_lift, 0);
425 sleep_ms(2);
426 }else if (idx == 10 && old_idx != idx){ // confirm
427 auto_index = 3; // go to lift selection page
428 temp_step = 0;
429 temp_step2 = 0;
430 temp_step3 = 0;
431 draw_UI();
432 }else if (idx == 11 && old_idx != idx){ // go back to the interval time selection page
433 page = 0; // go to main page
434 temp_step = 0;
435 temp_step2 = 0;
436 temp_step3 = 0;
437 draw_UI();
438 }
439 break;
440 case 3: // at auto lift selection page
441 if (old_idx != idx){
442 if (idx <= 9 && 0 <= idx){ // integer
443 temp_step3 = temp_step3 * 10 + idx;
444 sprintf(temp2, "%s%d%s", "Lift Interval: ", temp_step3, "(cm)");
445 draw_UI();
446 }else if (idx == 10){ // confirm
447 interval2 = temp_step3;
448 temp_step = 0;
449 temp_step2 = 0;
450 temp_step3 = 0;
451 manual_auto = 2;
452 draw_UI();
453 }else if (idx == 11){ // go back to the rotation degree selection page
454 page = 0; // go to main page
455 temp_step = 0;
456 temp_step2 = 0;
457 temp_step3 = 0;
458 draw_UI();
459 }
460 }
461 break;
462 }
463
464 if (idx == 11 && old_idx != idx){ // go back to the Main Page
465 page = 0; // go to the main page
466 manual_auto = 0; // change to stop
467 }
468 break;
469 default:
470 break;
471 }
472
473 //printf("%d %d %f\n",page, temp_step, degree);
474 //printf("idx: %d\n",idx);
475 old_idx = idx;
476
477 spare_time = FRAME_RATE - (time_us_32() - begin_time) ;
478 // yield for necessary amount of time
479 PT_YIELD_usec(spare_time) ;
480 } // END WHILE(1)
481
482
483 // Indicate end of thread
484 PT_END(pt);
485}
486
487int count = 0;;
488static PT_THREAD (protothread_serial(struct pt *pt))
489{
490 // Indicate start of thread
491 PT_BEGIN(pt) ;
492 int s; // step
493
494 if (manual_auto==1){ // at manual mode
495 // motor rotation
496 if (rotate_flag == 1 && stop == 0){
497 //Set motor direction clockwise
498 gpio_put(dirPin_rotation, 1);
499 // Spin motor
500 degree += stepsPerRevolution * 1.8;
501 draw_rotation_platform();
502 draw_rotation_text();
503 for(int x = 0; x < stepsPerRevolution; x++){
504 gpio_put(stepPin_rotation, 1);
505 sleep_ms(10);
506 gpio_put(stepPin_rotation, 0);
507 sleep_ms(10);
508 }
509 if (degree >= 360.0){
510 rotate_flag = 0;
511 degree = 0.0;
512 sprintf(temp, "%s%.2f", "Current Degree is ", temp_step*1.8);
513 draw_UI();
514 draw_rotation_platform();
515 draw_rotation_text();
516 }
517 stop = 1;
518 }
519 // Motor Lift
520 switch (lift){
521 case 1: // if up manual
522 gpio_put(dirPin_lift, 0);
523 sleep_ms(2);
524 gpio_put(stepPin_lift, 1);
525 sleep_ms(2);
526 gpio_put(stepPin_lift, 0);
527 sleep_ms(2);
528 lift = 0; // stop the lift
529 break;
530 case 2: // if down manual
531 gpio_put(dirPin_lift, 1);
532 sleep_ms(2);
533 gpio_put(stepPin_lift, 1);
534 sleep_ms(2);
535 gpio_put(stepPin_lift, 0);
536 sleep_ms(2);
537 lift = 0; // stop the lift
538 break;
539 case 3: // if up by 1cm
540 gpio_put(dirPin_lift, 0);
541 for(int x = 0; x < 545; x++){
542 gpio_put(stepPin_lift, 1);
543 sleep_ms(6);
544 gpio_put(stepPin_lift, 0);
545 sleep_ms(6);
546 }
547 lift = 0; // stop the lift
548 break;
549 case 4: // if down by 1cm
550 gpio_put(dirPin_lift, 1);
551 for(int x = 0; x < 545; x++){
552 gpio_put(stepPin_lift, 1);
553 sleep_ms(6);
554 gpio_put(stepPin_lift, 0);
555 sleep_ms(6);
556 }
557 lift = 0; // stop the lift
558 break;
559 default:
560 break;
561 }
562 }else if (manual_auto == 2){ // at auto mode
563 //Motor Rotation auto run
564 int step = 200 / stepsPerRevolution;
565 for(int i = 0; i < step; i++){
566 // Set motor direction clockwise
567 gpio_put(dirPin_rotation, 1);
568 // Spin motor
569 printf("%f",degree);
570 degree += stepsPerRevolution * 1.8;
571 draw_rotation_platform();
572 draw_rotation_text();
573 for(int x = 0; x < stepsPerRevolution; x++){
574 gpio_put(stepPin_rotation, 1);
575 sleep_ms(10);
576 gpio_put(stepPin_rotation, 0);
577 sleep_ms(10);
578 }
579 sleep_ms(interval*1000);
580 }
581 degree = 0.0;
582 for (int i=0; i<interval2;i++){
583 gpio_put(dirPin_lift, 0);
584 for(int x = 0; x < 545; x++){
585 gpio_put(stepPin_lift, 1);
586 sleep_ms(6);
587 gpio_put(stepPin_lift, 0);
588 sleep_ms(6);
589 }
590 sleep_ms(interval*1000);
591 //Motor Rotation auto run
592 int step = 200 / stepsPerRevolution;
593 for(int i = 0; i < step; i++){
594 // Set motor direction clockwise
595 gpio_put(dirPin_rotation, 1);
596 // Spin motor
597 degree += stepsPerRevolution * 1.8;
598 draw_rotation_platform();
599 draw_rotation_text();
600 for(int x = 0; x < stepsPerRevolution; x++){
601 gpio_put(stepPin_rotation, 1);
602 sleep_ms(10);
603 gpio_put(stepPin_rotation, 0);
604 sleep_ms(10);
605 }
606 sleep_ms(interval*1000);
607 }
608 degree = 0.0;
609 }
610 }
611
612 // Indicate end of thread
613 PT_END(pt);
614}
615
616// Entry point for core 1
617void core1_entry() {
618 pt_add_thread(protothread_vga) ;
619 pt_schedule_start ;
620}
621
622int main() {
623 // Initialize stdio
624 stdio_init_all();
625
626 gpio_init(stepPin_rotation);
627 gpio_init(dirPin_rotation);
628 gpio_init(stepPin_lift);
629 gpio_init(dirPin_lift);
630 gpio_set_dir(stepPin_lift, GPIO_OUT);
631 gpio_set_dir(dirPin_lift, GPIO_OUT);
632 gpio_set_dir(stepPin_rotation, GPIO_OUT);
633 gpio_set_dir(dirPin_rotation, GPIO_OUT);
634
635
636 // Initialize the keypad GPIO's
637 gpio_init_mask((0x7F << BASE_KEYPAD_PIN)) ;
638 // Set row-pins to output
639 gpio_set_dir_out_masked((0xF << BASE_KEYPAD_PIN)) ;
640 // Set all output pins to low
641 gpio_put_masked((0xF << BASE_KEYPAD_PIN), (0x0 << BASE_KEYPAD_PIN)) ;
642 // Turn on pulldown resistors for column pins (on by default)
643 gpio_pull_down((BASE_KEYPAD_PIN + 4)) ;
644 gpio_pull_down((BASE_KEYPAD_PIN + 5)) ;
645 gpio_pull_down((BASE_KEYPAD_PIN + 6)) ;
646
647 // Initialize VGA
648 initVGA() ;
649
650 // start core 1
651 multicore_reset_core1();
652 multicore_launch_core1(core1_entry);
653
654 // start core 0
655 pt_add_thread(protothread_serial) ;
656 pt_schedule_start ;
657}
658