6
\$\begingroup\$

Problem

I'm writing a verilog program that does the trapezoidal integration method (where a review is also welcome, wink wink). But turns out you need input for these kind of things, so in the overly complicated setup I'm doing, I'm writing a python program on a Raspberry Pi to output inputs for the FPGA which then outputs to a d to a which outputs to an oscilloscope which is where you all go, "Thank goodness I'm not that programmer" and I go half mad.

The main requirements for the code is that it output each bit of the input for the FPGA at a separate pin, as serial data is slower, and that the output be two's complement (i.e., the signals are signed integers, so the bits given to the FPGA must also be signed).

Approach

My code can be broken up into three phases: signal generation, signal conversion, and signal output.

Signal generation

Right now, I'm just using a simple square wave. This is done using

x = 0
signal = 1
while x <= 25:
    if x % 2 == 0:
        signal*=-1
    signals.append(signal)
    x+=1

Signal conversion

This iterates over signals and applies twos_comp() to each. twos_comp() converts the integer to its binary representation (carefully slicing off all the unneeded nonsense) and then if the original value was greater than zero, just returns that. Otherwise, the number is inverted using the invert() function, and then has one added to it, and is returned. Type conversions are rife, and this whole thing is rather hack-y.

This assumes 8 bit numbers.

Signal output

Using RPi.GPIO, a clock pin (which is mapped to the FPGA's clock) is setup and a set of 8 pins is setup for the signal. Again, parallel not serial. For each item in the new list generated by twos_comp(), the program waits for the clock's rising edge (I know this is somewhat frowned upon, but the output needs to be synced to the clock and the clock is also pretty fast, so it's not like it's going to be waiting for a while (50 mega hertz, can be faster). Then, for each item in the 8-bit number, it's outputted to the appropriate pin.

Concerns/reviewing

Any and all comments are welcome in this review, with speed comments (especially in the latter part of the program) extra welcome as I want it to be able to keep up with the FPGA clock. (Speed in the first part obviously isn't as necessary as it all can be done before the FPGA starts up. I also don't know if RPi.GPIO will be able to output the bits fast enough.) As I mentioned earlier, the invert() and twos_comp() functions are...kinda hacky.

Thanks!

Code

import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BCM)
x = 21
while x <= 28: #signal pins
    GPIO.setup(x, GPIO.OUT)
    x+=1
GPIO.setup(5, GPIO.IN) #clock

signals = []
bit_signals = []

def invert(bit_val):
    new_val = []
    for i in bit_val:
        new_val.append(str(int(not(int(i)))))
    return ''.join(new_val)

def twos_comp(val):
    bin_val = format(val, '09b')[-8:]
    if val < 0:
        return format(int(invert(bin_val),2) + int('1', 2), '08b')
    else:
        return bin_val

x = 0
signal = 1
while x <= 25:
    if x % 2 == 0:
        signal*=-1
    signals.append(signal)
    x+=1

for i in signals:
    bit_signals.append(twos_comp(i))

for i in bit_signals:
    GPIO.wait_for_edge(5, GPIO.RISING)
    counter = 21
    for k in str(i):
        GPIO.output(counter, k) #k will be 0 or 1 which is accepted input
        counter += 1

GPIO.cleanup()
\$\endgroup\$
  • \$\begingroup\$ Pasting your code into create.withcode.uk which has a Raspberry Pi simulator that includes the RPi.GPIO library throws the error ExternalError: TypeError: pin is undefined on line 6. Is your code broken? \$\endgroup\$ – C. Harley Aug 7 '18 at 8:05
  • \$\begingroup\$ @C.Harley I am not getting this error on my actual Raspberry Pi =) \$\endgroup\$ – heather Aug 7 '18 at 15:03
4
\$\begingroup\$

You should start by organising your code better. Try to avoid global variables and group together code in functions.

In addition, you should learn about list comprehensions. They make initializing your signals way easier.

import RPi.GPIO as GPIO

def twos_comp(i):
    ...

def gpio_setup(inputs, outputs):
    GPIO.setmode(GPIO.BCM)
    for pin in inputs:
        GPIO.setup(pin, GPIO.IN)
    for pin in outputs:
        GPIO.setup(pin, GPIO.OUT)

def main(input_pin, output_pins):    
    signals = [1 if i % 2 else -1 for i in range(26)]
    bit_signals = [twos_comp(i) for i in signals]

    for i in bit_signals:
        GPIO.wait_for_edge(input_pin, GPIO.RISING)
        for pin, k in zip(output_pins, str(i)):
            GPIO.output(pin, k) #k will be 0 or 1 which is accepted input

if __name__ == "__main__":
    in, out = [5], range(21, 29)
    gpio_setup(in, out)
    main(in[0], out)
    GPIO.cleanup()

And finally, there are better ways to do twos complement. A nice one is for example here.

\$\endgroup\$
  • 2
    \$\begingroup\$ This is a lot cleaner than my code. Thank you very much. Do you have any thoughts on how fast RPi.GPIO can be updating the pins at the end, and if it can keep up with the FPGA clock? \$\endgroup\$ – heather Aug 7 '18 at 16:06
  • 1
    \$\begingroup\$ @heather You're welcome. I have no idea, since I never tried to use them, sorry. \$\endgroup\$ – Graipher Aug 7 '18 at 16:07
  • 2
    \$\begingroup\$ Okay, cool, thanks. Probably a question more appropriate for Raspberry Pi.SE anyway =) \$\endgroup\$ – heather Aug 7 '18 at 16:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.