geerlingguy / beast-challenge

A control system for MrBeast's 1-100 challenge
GNU General Public License v3.0
26 stars 1 forks source link

Le Potato Hardware Bringup #1

Closed geerlingguy closed 1 year ago

geerlingguy commented 1 year ago

Each room needs a Le Potato running the lights and accepting button input.

I am currently testing the Raspbian 11 for Le Potato image, and here are my notes setting it up:

  1. Flash it to microSD using Pi Imager (don't use advanced options; that doesn't seem to work)
  2. Eject and re-insert the card so I can edit files on the boot volume
  3. Create a file named userconf.txt on boot with one line: username:password, where password is generated by copying the output of the openssl passwd -6 command (Windows/Linux), or openssl passwd -1 (Mac)
  4. Create an empty file named ssh on boot
  5. Eject the card and install it into the Potato.

Profit!

geerlingguy commented 1 year ago

I2C bringup, following these instructions:

pi@raspberrypi:~ $ sudo ldto enable i2c-ao
Overlay i2c-ao: applied

pi@raspberrypi:~ $ ls -al /dev/i2c-*
crw-rw---- 1 root i2c 89, 0 Sep 22 04:17 /dev/i2c-0
crw-rw---- 1 root i2c 89, 1 Mar  2 22:23 /dev/i2c-1

pi@raspberrypi:~ $ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: 10 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- -- 

Hooray!

Now for the real test. Following the EP-0099 Docs:

# Turn on relay channel 1
i2cset -y 1 0x10 0x01 0xFF

# Turn off relay channel 1
i2cset -y 1 0x10 0x01 0x00

It worked!

So for something like a Python script we need to first initialize the bus:

sudo ldto enable i2c-ao

Then run a script with python3 relaytest.py:

import time as t
import smbus
import sys

DEVICE_BUS = 1
DEVICE_ADDR = 0x10
bus = smbus.SMBus(DEVICE_BUS)

while True:
    try:
        for i in range(1,5):
            bus.write_byte_data(DEVICE_ADDR, i, 0xFF)
            t.sleep(1)
            bus.write_byte_data(DEVICE_ADDR, i, 0x00)
            t.sleep(1) 
    except KeyboardInterrupt as e:
        print("Quit the Loop")
        sys.exit()
geerlingguy commented 1 year ago

Now working on a button. It looks like I'll need to install the le potato wiring tool, and here's a GPIO pin header reference

pi@raspberrypi:~ $ sudo apt install gpiod libretech-gpio libretech-dtoverlay
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
gpiod is already the newest version (1.6.2-1).
libretech-dtoverlay is already the newest version (0.1.2).
libretech-gpio is already the newest version (0.1.2).

But I do want to use Python, so:

sudo apt install -y python3-libgpiod

Here's a handy guide: How to control GPIO via Python 3.

I am plugged into physical GPIO pins 39 (GND) and 40 (Linux #83, sysfs #484, name GPIOX_4).

Screen Shot 2023-03-02 at 9 11 25 PM
geerlingguy commented 1 year ago
pi@raspberrypi:~ $ gpiodetect
gpiochip0 [aobus-banks] (11 lines)
gpiochip1 [periphs-banks] (100 lines)
pi@raspberrypi:~ $ gpioinfo periphs-banks
gpiochip1 - 100 lines:
    line   0:      unnamed       unused   input  active-high 
    line   1:      unnamed       unused   input  active-high 
    line   2:      unnamed       unused   input  active-high 
    line   3:      unnamed       unused   input  active-high 
    line   4:      unnamed       unused   input  active-high 
    line   5:      unnamed       unused   input  active-high 
    line   6:      unnamed       unused   input  active-high 
    line   7:      unnamed       unused   input  active-high 
    line   8:      unnamed       unused   input  active-high 
    line   9:      unnamed       unused   input  active-high 
    line  10:      unnamed       unused   input  active-high 
    line  11:      unnamed       unused   input  active-high 
    line  12:      unnamed       unused   input  active-high 
    line  13:      unnamed       unused   input  active-high 
    line  14: "Eth Link LED" unused input active-high 
    line  15: "Eth Activity LED" unused input active-high 
    line  16:   "HDMI HPD"       unused   input  active-high 
    line  17:   "HDMI SDA"       unused   input  active-high 
    line  18:   "HDMI SCL"       unused   input  active-high 
    line  19: "HDMI_5V_EN" "regulator-hdmi-5v" output active-high [used]
    line  20: "9J1 Header Pin2" unused input active-high 
    line  21: "Analog Audio Mute" "enable" output active-high [used]
    line  22: "2J3 Header Pin6" unused input active-high 
    line  23: "2J3 Header Pin5" unused input active-high 
    line  24: "2J3 Header Pin4" unused input active-high 
    line  25: "2J3 Header Pin3" unused input active-high 
    line  26:    "eMMC D0"       unused   input  active-high 
    line  27:    "eMMC D1"       unused   input  active-high 
    line  28:    "eMMC D2"       unused   input  active-high 
    line  29:    "eMMC D3"       unused   input  active-high 
    line  30:    "eMMC D4"       unused   input  active-high 
    line  31:    "eMMC D5"       unused   input  active-high 
    line  32:    "eMMC D6"       unused   input  active-high 
    line  33:    "eMMC D7"       unused   input  active-high 
    line  34:   "eMMC Clk"       unused   input  active-high 
    line  35: "eMMC Reset"      "reset"  output   active-low [used]
    line  36:   "eMMC CMD"       unused   input  active-high 
    line  37: "ALT BOOT MODE" unused input active-high 
    line  38:      unnamed       unused   input  active-high 
    line  39:      unnamed       unused   input  active-high 
    line  40:      unnamed       unused   input  active-high 
    line  41: "eMMC Data Strobe" unused input active-high 
    line  42:  "SDCard D1"       unused   input  active-high 
    line  43:  "SDCard D0"       unused   input  active-high 
    line  44: "SDCard CLK"       unused   input  active-high 
    line  45: "SDCard CMD"       unused   input  active-high 
    line  46:  "SDCard D3"       unused   input  active-high 
    line  47:  "SDCard D2"       unused   input  active-high 
    line  48: "SDCard Det"         "cd"   input   active-low [used]
    line  49:      unnamed       unused   input  active-high 
    line  50:      unnamed       unused   input  active-high 
    line  51:      unnamed       unused   input  active-high 
    line  52:      unnamed       unused   input  active-high 
    line  53:      unnamed       unused   input  active-high 
    line  54:      unnamed       unused   input  active-high 
    line  55:      unnamed       unused   input  active-high 
    line  56:      unnamed       unused   input  active-high 
    line  57:      unnamed       unused   input  active-high 
    line  58:      unnamed       unused   input  active-high 
    line  59:      unnamed       unused   input  active-high 
    line  60:      unnamed       unused   input  active-high 
    line  61:      unnamed       unused   input  active-high 
    line  62:      unnamed       unused   input  active-high 
    line  63:      unnamed       unused   input  active-high 
    line  64:      unnamed       unused   input  active-high 
    line  65:      unnamed       unused   input  active-high 
    line  66:      unnamed       unused   input  active-high 
    line  67:      unnamed       unused   input  active-high 
    line  68:      unnamed       unused   input  active-high 
    line  69:      unnamed       unused   input  active-high 
    line  70:      unnamed       unused   input  active-high 
    line  71:      unnamed       unused   input  active-high 
    line  72:      unnamed       unused   input  active-high 
    line  73:  "Green LED" "librecomputer:system-status" output active-high [used]
    line  74: "VCCK Enable" unused input active-high 
    line  75: "7J1 Header Pin27" unused input active-high 
    line  76: "7J1 Header Pin28" unused input active-high 
    line  77: "VCCK Regulator" unused input active-high 
    line  78: "VDDEE Regulator" unused input active-high 
    line  79: "7J1 Header Pin22" unused input active-high 
    line  80: "7J1 Header Pin26" unused input active-high 
    line  81: "7J1 Header Pin36" unused input active-high 
    line  82: "7J1 Header Pin38" unused input active-high 
    line  83: "7J1 Header Pin40" unused input active-high 
    line  84: "7J1 Header Pin37" unused input active-high 
    line  85: "7J1 Header Pin33" unused input active-high 
    line  86: "7J1 Header Pin35" unused input active-high 
    line  87: "7J1 Header Pin19" unused input active-high 
    line  88: "7J1 Header Pin21" unused input active-high 
    line  89: "7J1 Header Pin24" unused input active-high 
    line  90: "7J1 Header Pin23" unused input active-high 
    line  91: "7J1 Header Pin8" unused input active-high 
    line  92: "7J1 Header Pin10" unused input active-high 
    line  93: "7J1 Header Pin16" unused input active-high 
    line  94: "7J1 Header Pin18" unused input active-high 
    line  95: "7J1 Header Pin32" unused input active-high 
    line  96: "7J1 Header Pin29" unused input active-high 
    line  97: "7J1 Header Pin31" unused input active-high 
    line  98: "7J1 Header Pin7" unused input active-high 
    line  99:      unnamed       unused   input  active-high
geerlingguy commented 1 year ago

Testing the LED inside the button, I can get output with:

gpioset --mode=time --sec=1 periphs-banks 83=1

That lights it up, but only connected one way—since LEDs are diodes they only work in one orientation. There's no indication on the button hardware itself which way is correct, so we'll need to find a quick way to light the LED then mark which side is + and which is -... which goes to GPIO and which to ground.

geerlingguy commented 1 year ago

And I wired up the button to pin 36 (number 82), and this is now working, accepting my button presses:

pi@raspberrypi:~ $ gpioget --bias=pull-up periphs-banks 82
1
pi@raspberrypi:~ $ gpioget --bias=pull-up periphs-banks 82
0
pi@raspberrypi:~ $ gpioget --bias=pull-up periphs-banks 82
1
pi@raspberrypi:~ $ gpioget --bias=pull-up periphs-banks 82
1
pi@raspberrypi:~ $ gpioget --bias=pull-up periphs-banks 82
0
geerlingguy commented 1 year ago

If I try the example gpiomon.py I get an error "No such device":

pi@raspberrypi:~ $ /usr/share/doc/python3-libgpiod/examples/gpiomon.py periphs-banks 82
Traceback (most recent call last):
  File "/usr/share/doc/python3-libgpiod/examples/gpiomon.py", line 37, in <module>
    lines.request(consumer=sys.argv[0], type=gpiod.LINE_REQ_EV_BOTH_EDGES)
OSError: [Errno 19] No such device

Asked about it in the Le Potato forums: https://hub.libre.computer/t/how-to-control-gpio-via-python-3/601/42

I might have to write an event loop differently and just brute force check on the status of the pin over and over. Still should be plenty fast, but more annoying, programming-wise.

Aside: great article on the gpiod integration in the kernel: https://ostconf.com/system/attachments/files/000/001/532/original/Linux_Piter_2018_-_New_GPIO_interface_for_linux_userspace.pdf?1541021776

geerlingguy commented 1 year ago

Oh, uh...

Just to update you, the Amlogic GXL family has an interrupt controller that is able to monitor up to 8 interrupts. Each monitored interrupt can be falling or rising edge and monitoring both counts as 2 interrupts. So it’s very limited and reserved mostly for device-tree bound devices. You can look at the dtoverlays in the libretech-wiring-tool to see how it’s done. Due to the small number of monitorable interrupts, it is easy to exceed this if gpio_to_irq is enabled so upstream decided to leave that disabled for this SoC family. This effectively prevents gpiomon from working.

From: https://hub.libre.computer/t/interrupt-capable-pins-on-aml-s905x-cc/67/6?u=geerlingguy

geerlingguy commented 1 year ago

It looks like Armbian might support the rising edge interrupts: https://hub.libre.computer/t/gpiomon-does-not-work-on-a-le-potato-running-your-suggested-ubuntu-image/83/5

Going to see if there's a hack I can do with an overlay to get it working with the Raspbian image. Or we can just try Armbian. No skin off my back!

geerlingguy commented 1 year ago

Testing with Armbian, it looks like the image uses root and 1234 and requires setting a password on first login.

On first boot with a freshly-flashed microSD card, the board seems to take 3-5 minutes to finish filling a 32GB card before it reboots into Armbian.

There's actually an entire setup wizard (which is slightly annoying) that goes through everything including setting up a locale. Not sure if it's all required, but eventually you create a user account then get dumped back on the CLI as root. I logged out, then logged back in as the account I created.

To enable I2C, I had to run sudo armbian-config and then go to System > Hardware > [*] i2cA.

Now I see the device:

pi@lepotato:~$ ls -al /dev/i2c-*
crw-rw---- 1 root i2c 89, 0 Mar  3 22:38 /dev/i2c-0
crw-rw---- 1 root i2c 89, 1 Mar  3 22:38 /dev/i2c-1

And... unfortunately we're not seeing the relay at all on the bus :/

To make things easier, I added the user to the i2c group: sudo adduser pi i2c

geerlingguy commented 1 year ago

Testing GPIO at least, I tried sudo apt install -y gpiod and it's already there, so then I ran sudo apt install -y python3-libgpiod, and it did install the python library. Testing my test script now...

I have to run with sudo, and I'm getting that same:

PermissionError: [Errno 1] Operation not permitted

Drat.

geerlingguy commented 1 year ago

Whee! Getting the i2c working requires compiling our own overlay from the libretech-wiring-tool project:

wget https://raw.githubusercontent.com/libre-computer-project/libretech-wiring-tool/master/libre-computer/aml-s905x-cc/dt/i2c-ao.dts
sudo armbian-add-overlay i2c-a.dts  # this compiles the overlay into /boot/overlay-user/i2c-a.dtbo
sudo reboot

(We will need to automate that, as well as the python GPIO library install.)

Then on reboot:

pi@lepotato:~$ i2cdetect -l
i2c-0   i2c         Meson I2C adapter                   I2C adapter
i2c-1   i2c         DesignWare HDMI                     I2C adapter            

pi@lepotato:~$ i2cdetect -y 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- -- 
10: 10 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

I also had to install python3-smbus so I could use the bus in my Python test script.

Whew. Now on to getting rising edge detection on one of the GPIO pins...

geerlingguy commented 1 year ago

There's no gpio group on Armbian, so I could modify the gpio filesystem points and set up a group, but I'm lazy, so I'm just going to throw sudo at it.

geerlingguy commented 1 year ago

Trying a few different GPIO pins:

[ 1103.739324] gpio irq setup: hwirq: 0x5B irqfirst: 0x59 irqlast: 0x6B pin[81]
[ 1103.739546] genirq: Setting trigger mode 3 for irq 52 failed (meson_gpio_irq_set_type+0x0/0x68)
[ 1147.805176] gpio irq setup: hwirq: 0x61 irqfirst: 0x59 irqlast: 0x6B pin[87]
[ 1147.805423] genirq: Setting trigger mode 3 for irq 53 failed (meson_gpio_irq_set_type+0x0/0x68)
[ 1149.301159] gpio irq setup: hwirq: 0x62 irqfirst: 0x59 irqlast: 0x6B pin[88]
[ 1149.301405] genirq: Setting trigger mode 3 for irq 54 failed (meson_gpio_irq_set_type+0x0/0x68)

After adding some more, eventually I run out:

...
[ 1520.683876] genirq: Setting trigger mode 3 for irq 56 failed (meson_gpio_irq_set_type+0x0/0x68)
[ 1522.597196] gpio irq setup: hwirq: 0x6D irqfirst: 0x53 irqlast: 0x58 pin[75]
[ 1522.597219] meson-gxl-pinctrl c8834000.bus:pinctrl@4b0: no more irq for pin[75]
[ 1529.683749] gpio irq setup: hwirq: 0x27 irqfirst: 0x24 irqlast: 0x33 pin[29]
[ 1529.683826] irq_meson_gpio: No channel available
[ 1534.178476] gpio irq setup: hwirq: 0x6A irqfirst: 0x59 irqlast: 0x6B pin[96]
[ 1534.178553] irq_meson_gpio: No channel available
geerlingguy commented 1 year ago

Yay! Using LINE_REQ_EV_RISING_EDGE I can get it to work now!

Of course... I'm getting this annoying behavior where when I click in, I get like 30 RISING EDGE notifications:

^[[A^Cpi@lepotato:~$ sudo ./gpio-test.py 
gpiochip1['gpiochip1:82 /7J1 Header Pin38/', 'gpiochip1:81 /7J1 Header Pin36/']
'RISING EDGE (1889.233528982) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.233593567) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.233608692) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.233985909) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234013493) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234033118) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234049577) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234329917) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234361001) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234395793) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234444253) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234475128) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234497462) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234512837) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234537838) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234688216) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234712759) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234718634) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234724384) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234742259) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.234758051) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1889.235335398) source('gpiochip1:82 /7J1 Header Pin38/')'

and when I release, a few more for good measure:

'RISING EDGE (1890.994243722) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1890.994314015) source('gpiochip1:82 /7J1 Header Pin38/')'
'RISING EDGE (1890.994406351) source('gpiochip1:82 /7J1 Header Pin38/')'

We'll have to debounce in code (or set up a capacitor-based debounce circuit... but we don't have time for a custom PCB or anything...

geerlingguy commented 1 year ago

I added some code to detect rising edge:

def rising_edge_detect(event_source, event_value, event_time):
    global bounce_timer

    # A note on debouncing: I tried to find a way using the value to get whether
    # we were truly getting a 'down' click or 'up' release. And I failed.
    # Miserably. There is no reliable way (at least not with the arcade switches
    # I've been testing) to determine whether a press is happening on the down
    # or up side of the falling edge on this board. And we don't have time to
    # print our own debounce circuit, so this function is what you get.
    time_now = time.perf_counter_ns()
    if ((time_now - bounce_timer) > bounce_limit):
        button_click(event_source, event_value, event_time)
        # Reset bounce timer so further noise won't be registered.
        bounce_timer = time.perf_counter_ns()

I have done it, it is written.

geerlingguy commented 1 year ago

Hardware seems to be checking out now. On to future tasks!

I will work on automating the setup before closing this out though.

geerlingguy commented 1 year ago

Closing this and following up with automation in #14.