12: FPGA (DPL) Controls Raspberry Pi

Despite the FPGA DueProLogic is officially designed for Arduino, we are going to make the FPGA DueProLogic and Raspberry Pi 4B communicable.

Three tasks are implemented in this tutorial:

(A) Simultaneously press the two push buttons on FPGA  to flip the angle of RPi camera.
(B) Raspberry Pi 4B controls the external LED circuit of FPGA.
(C) Live stream the Raspberry Pi Camera on Browser via WIFI

Step 1: Build electronic circuit

Step 2: Edit Verilog code

When you buy the FPGA DueProLogic, you should receive a DVD. After you open "Projects_HDL", you should see the original HDL code file


After you set up the pin planner, add the yellow lines in the Verilog code as shown in section 2A, 2B, 2C and 2D.



2A: To activate push buttons, you have to use this code

//Push Button Switches
input wire                UBA,
input wire                UBB

To communicate with Raspberry Pi, you need to add these.

reg                        sel_send;  //activate Raspberry pi
reg                        rece;         //received from raspberry pi

2B: To assigns values to the ports, you should edit the code accordingly

assign            XIO_1[3] = start_stop_cntrl;           
assign            XIO_2[2] = rece;                       //output HIGH or LOW in LED circuit
assign            XIO_2[3] = ~UBA;                   //push button
assign            XIO_2[4] = UBB;                     //push button
assign            XIO_2[5] = sel_send;               // FPGA sends signal to raspberry pi
assign            sel_read= XIO_5[1];                 //FPGA receives signal from raspberry pi
assign            c_enable = XIO_5[2];               //XIO_5 -- UB57 -- D17
assign            LEDExt = XIO_5[5]; 

2C: If two push buttons are pressed simultaneously, the FPGA sends HIGH output to Raspberry Pi.

always @(sel_send or UBB or UBA)  //send to RPi
begin
if (UBB == 1'b0 && UBA == 1'b0)
        sel_send = 1'b1;
else
sel_send = 1'b0;
end

2D: The FPGA reads signal from Raspberry Pi with the clock frequency of 66MHz. The port XIO_2[2] is linked to 'rece'.  

always @(sel_read)          //read pi
begin
if (sel_read == 1'b1)
rece = 1'b0;
else
rece = 1'b1;
end


Then upload the compiled pof file to the FPGA. If no hardware is detected automatically, click "Hardware Setup" to correct it manually



Step 3: Upload the Raspberry Pi code. 

The purple lines allows the FPGA communicating with Raspberry Pi. If you have difficulties to set up live-stream Pi camera, please read chapter 8

Chapter 8: https://roywchpi.blogspot.com/2020/04/8-live-streaming-pi-camera-android.html

import io
import picamera
import logging
import RPi.GPIO as GPIO
import socketserver
import time
from threading import Condition
from http import server

PAGE="""\
<html>
<head>
<title>Raspberry Pi</title>
</head>
<body>
<center><h1>Live Stream from Raspberry Pi Camera</h1></center>
<center><img src="stream.mjpg" width="1024" height="768"></center>
</body>
</html>
"""
A=0;
pin = 6  #GPIO number
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(18,GPIO.OUT)
GPIO.setup(pin,GPIO.IN)


class StreamingOutput(object):
    def __init__(self):
        self.frame = None
        self.buffer = io.BytesIO()
        self.condition = Condition()    

    def write(self, buf):
        if buf.startswith(b'\xff\xd8'):
            # New frame, copy the existing buffer's content and notify all
            # clients it's available
            self.buffer.truncate()
            with self.condition:
                self.frame = self.buffer.getvalue()
                self.condition.notify_all()
            self.buffer.seek(0)
        return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            content = PAGE.encode('utf-8')
            self.send_response(200)
            self.send_header('Content-Type', 'text/html')
            self.send_header('Content-Length', len(content))
            self.end_headers()
            self.wfile.write(content)
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                        A = GPIO.input(pin)   #read FPGA
                        print(A);
                        if(A==1):
                            camera.rotation = 0
                            GPIO.output(18,GPIO.LOW)  #send to FPGA                        
                        if(A==0):
                            camera.rotation = 180
                            GPIO.output(18,GPIO.HIGH)  #send to FPGA 
                            
                            
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

with picamera.PiCamera(resolution='1024x768', framerate=24) as camera:
    output = StreamingOutput()
    camera.rotation = 180
    camera.start_recording(output, format='mjpeg')
    try:
        address = ('', 8000)
        server = StreamingServer(address, StreamingHandler)
        server.serve_forever()
    finally:
        camera.stop_recording()

Open your browser and type your IP address e.g. 192.168.xx.xxx:8000.

After all, the system should work!


Video Demo

Comments