raspberrypi / pico-feedback

24 stars 2 forks source link

live from new york...it's saturday night feather! feather 2040 #88

Closed ptorrone closed 3 years ago

ptorrone commented 3 years ago

Adafruit_Feather_2040

while waiting for snl to come on, we put together 4 feather rp2040's, handstencilling and then hot air. all 4 enumerate over usb, yay! next up trying out each pin with micropython ... will post some more updates!

ptorrone commented 3 years ago

houston....we have BLINK! onboard red led on pin #13

blink

blink

kilograham commented 3 years ago

sweet!

ukscone commented 3 years ago

a thing of beauty

and it's a pretty good episode of SNL too

ptorrone commented 3 years ago

tiny_horse

Wren6991 commented 3 years ago

It's such a pretty board! Does the Neopixel work? There should be a MicroPython PIO example for WS2812

ptorrone commented 3 years ago

It's such a pretty board! Does the Neopixel work? There should be a MicroPython PIO example for WS2812

testing this today / tonight!

ptorrone commented 3 years ago

quick qt - i2c testing ... with the default ssd1306 library and an aht20 library we found on github we got a plug-and-play temp+humidity sensor display going over the qwiic/stemma qt connector.

Quick QT - I2C testing 01 Quick QT - I2C testing02

ptorrone commented 3 years ago

@Wren6991 here ya go!

IMG_5145

pio rainbow neopixels - we hacked together the pio ws2812 demo with our 'essential' neopixel example code to show off color fills, chases and of course a rainbow swirl on a 16-led ring.

video (request access to view) https://drive.google.com/file/d/194NbhmR6EZeuDKbQUuf8wp6AHyZ5gA1W/view?usp=sharing

ladyada commented 3 years ago

Code for AHT20 + OLED demo:

import framebuf
import time
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import aht10   # from https://github.com/vjsyong/AHT10

WIDTH  = 128                                            # oled display width
HEIGHT = 32                                             # oled display height

i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=100000)       # Init I2C1 on Stemma QT
print("I2C Address      : "+hex(i2c.scan()[0]).upper()) # Display device address
print("I2C Configuration: "+str(i2c))                   # Display I2C config

oled = SSD1306_I2C(WIDTH, HEIGHT, i2c, addr=0x3C)       # Init oled display
aht = aht10.AHT10(i2c)

# Raspberry Pi logo as 32x32 bytearray
buffer = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|?\x00\x01\x86@\x80\x01\x01\x80\x80\x01\x11\x88\x80\x01\x05\xa0\x80\x00\x83\xc1\x00\x00C\xe3\x00\x00~\xfc\x00\x00L'\x00\x00\x9c\x11\x00\x00\xbf\xfd\x00\x00\xe1\x87\x00\x01\xc1\x83\x80\x02A\x82@\x02A\x82@\x02\xc1\xc2@\x02\xf6>\xc0\x01\xfc=\x80\x01\x18\x18\x80\x01\x88\x10\x80\x00\x8c!\x00\x00\x87\xf1\x00\x00\x7f\xf6\x00\x008\x1c\x00\x00\x0c \x00\x00\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")

# Load the raspberry pi logo into the framebuffer (the image is 32x32)
fb = framebuf.FrameBuffer(buffer, 32, 32, framebuf.MONO_HLSB)

# Clear the oled display in case it has junk on it.
oled.fill(0)

# Blit the image from the framebuffer to the oled display
oled.blit(fb, 96, 0)

# Add some text
oled.text("Raspberry Pi",5,5)
oled.text("Pico",5,15)

# Finally update the oled display so the image & text is displayed
oled.show()
time.sleep(2)

while True:
    oled.fill(0)
    oled.blit(fb, 96, 0)
    oled.text("Feather Demo", 5, 5)
    oled.text("Hum: %d %%" % aht.humidity(), 5, 15)
    oled.text("Temp: %d C" % aht.temperature(), 5, 25)
    oled.show()
    time.sleep(1)

code for neopixel ring demo

# Example using PIO to drive a set of WS2812 LEDs.

import array, time
from machine import Pin
import rp2

# Configure the number of WS2812 LEDs.
NUM_LEDS = 16
PIN_NUM = 6
brightness = 0.2

@rp2.asm_pio(sideset_init=rp2.PIO.OUT_LOW, out_shiftdir=rp2.PIO.SHIFT_LEFT, autopull=True, pull_thresh=24)
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    wrap_target()
    label("bitloop")
    out(x, 1)               .side(0)    [T3 - 1]
    jmp(not_x, "do_zero")   .side(1)    [T1 - 1]
    jmp("bitloop")          .side(1)    [T2 - 1]
    label("do_zero")
    nop()                   .side(0)    [T2 - 1]
    wrap()

# Create the StateMachine with the ws2812 program, outputting on pin
sm = rp2.StateMachine(0, ws2812, freq=8_000_000, sideset_base=Pin(PIN_NUM))

# Start the StateMachine, it will wait for data on its FIFO.
sm.active(1)

# Display a pattern on the LEDs via an array of LED RGB values.
ar = array.array("I", [0 for _ in range(NUM_LEDS)])

##########################################################################
def pixels_show():
    dimmer_ar = array.array("I", [0 for _ in range(NUM_LEDS)])
    for i,c in enumerate(ar):
        r = int(((c >> 8) & 0xFF) * brightness)
        g = int(((c >> 16) & 0xFF) * brightness)
        b = int((c & 0xFF) * brightness)
        dimmer_ar[i] = (g<<16) + (r<<8) + b
    sm.put(dimmer_ar, 8)
    time.sleep_ms(10)

def pixels_set(i, color):
    ar[i] = (color[1]<<16) + (color[0]<<8) + color[2]

def pixels_fill(color):
    for i in range(len(ar)):
        pixels_set(i, color)

def color_chase(color, wait):
    for i in range(NUM_LEDS):
        pixels_set(i, color)
        time.sleep(wait)
        pixels_show()
    time.sleep(0.2)

def wheel(pos):
    # Input a value 0 to 255 to get a color value.
    # The colours are a transition r - g - b - back to r.
    if pos < 0 or pos > 255:
        return (0, 0, 0)
    if pos < 85:
        return (255 - pos * 3, pos * 3, 0)
    if pos < 170:
        pos -= 85
        return (0, 255 - pos * 3, pos * 3)
    pos -= 170
    return (pos * 3, 0, 255 - pos * 3)

def rainbow_cycle(wait):
    for j in range(255):
        for i in range(NUM_LEDS):
            rc_index = (i * 256 // NUM_LEDS) + j
            pixels_set(i, wheel(rc_index & 255))
        pixels_show()
        time.sleep(wait)

BLACK = (0, 0, 0)
RED = (255, 0, 0)
YELLOW = (255, 150, 0)
GREEN = (0, 255, 0)
CYAN = (0, 255, 255)
BLUE = (0, 0, 255)
PURPLE = (180, 0, 255)
WHITE = (255, 255, 255)
COLORS = (BLACK, RED, YELLOW, GREEN, CYAN, BLUE, PURPLE, WHITE)

print("fills")
for color in COLORS:       
    pixels_fill(color)
    pixels_show()
    time.sleep(0.2)

print("chases")
for color in COLORS:       
    color_chase(color, 0.01)

print("rainbow")
rainbow_cycle(0)
ptorrone commented 3 years ago

neopixel

aaaand onboard neopixel is workin'

kilograham commented 3 years ago

I liked it so much, I bought the company

ptorrone commented 3 years ago

aaaand... uart testing - gps modules are a common uart accessory, this demo tests reading/writing from the uart at 9600 baud, verifying the checksum, then displaying the nmea sentence on the oled. we're indoors so there's no data fix but you can see the rtc seconds increment.

gps_demo

kilograham commented 3 years ago

We should add you a feather2040.h to pico/boards (in the PicoSDK) when you know what you want; I assume you are still using MicroPython compiled for "pico"

ladyada commented 3 years ago

code for gps + oled demo:

# Tests UART read/write with OLED output
import time
import framebuf
from machine import Pin, UART, I2C
from ssd1306 import SSD1306_I2C

i2c = I2C(1, scl=Pin(3), sda=Pin(2), freq=100000)       # Init I2C1 on Stemma QT
uart = UART(0, 9600, rx=Pin(1), tx=Pin(0)) 
oled = SSD1306_I2C(128, 64, i2c, addr=0x3D)       # Init 128*64 oled display

# if this succeeds, yuou will only get GPRMC sentences
uart.write(b'$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29\r\n\r\n')

while True:
    sentence = uart.readline().decode('utf-8').strip()
    if len(sentence) < 7 or sentence[-3] != "*":
        continue

    # Get included checksum, then calculate it and compare.
    expected = int(sentence[-2:], 16)
    actual = 0
    for i in range(1, len(sentence) - 3):
        actual ^= ord(sentence[i])
    if actual != expected:
        print("Checksum actual %02x expected %02x" % (actual, expected))
        continue

    print(sentence) # output the response
    oled.fill(0)
    oled.text("GPS UART Demo", 5, 5)
    oled.text(sentence[0:15], 5, 20)
    oled.text(sentence[15:30], 5, 35)
    oled.text(sentence[30:45], 5, 50)
    oled.show()
ladyada commented 3 years ago

We should add you a feather2040.h to pico/boards (in the PicoSDK) when you know what you want; I assume you are still using MicroPython compiled for "pico"

hihi yes, please do we could maybe get framebuf as included at the same time :) we use the same pin convention but it would be nice to have the default I2C, UART and SPI be on the marked pins / connectors. plus some pins aren't exposed (pins 7, 8, 14, 15, 21, 22, 23)

ptorrone commented 3 years ago

next up is testing both pwm output and analog input - this common 'sweep' demo take an analog input from a potentiometer and sweeps out a mirror image on a standard servo.

servo

ladyada commented 3 years ago

code for analog/pwm servo sweep demo:

# Read a potentiometer on AD0 and control a servo pin pin 12

from machine import Pin, PWM, ADC
import time

# Analog input on AD0
adc = ADC(0)
# Construct PWM object for servo on pin 12
pwm = PWM(Pin(12))
# Set the PWM frequency to 50 hz
SERVO_FREQUENCY = 50
pwm.freq(SERVO_FREQUENCY)

min_pulse=500  # in useconds
max_pulse=2500 # in useconds

us_period = 1_000_000/ SERVO_FREQUENCY
min_dutycycle = int(min_pulse*65535/us_period)
max_dutycycle = int(max_pulse*65535/us_period)

print("PWM period %d us, min duty cycle %d, max %d" %
      (us_period, min_dutycycle, max_dutycycle))

def map_range(x, in_min, in_max, out_min, out_max):
    """
    Maps a number from one range to another.
    Note: This implementation handles values < in_min differently than arduino's map function does.
    :return: Returns value mapped to new range
    :rtype: float
    """
    in_range = in_max - in_min
    in_delta = x - in_min
    if in_range != 0:
        mapped = in_delta / in_range
    elif in_delta != 0:
        mapped = in_delta
    else:
        mapped = 0.5
    mapped *= out_max - out_min
    mapped += out_min
    if out_min <= out_max:
        return max(min(mapped, out_max), out_min)
    return min(max(mapped, out_max), out_min)

while True:
    ain = adc.read_u16()
    print("Analog input %d%%" % (ain * 100 / 65535))
    pos = int(map_range(ain, 65535, 0, min_dutycycle, max_dutycycle))
    pwm.duty_u16(pos)
    time.sleep(0.1)
kilograham commented 3 years ago

hihi yes, please do we could maybe get framebuf as included at the same time :) we use the same pin convention but it would be nice to have the default I2C, UART and SPI be on the marked pins / connectors. plus some pins aren't exposed (pins 7, 8, 14, 15, 21, 22, 23)

Copying @dpgeorge, as I'm not sure where we stand on whether we need a separte "board" concept within the rp2 port in MicroPython too (I know there is for other ports)

We can certainly add some default I2C/SPI pins in the SDK header even if the SDK itself doesn't use them (to save extra abstractions)

kilograham commented 3 years ago

P.S. I'm sure framebuf can be added by default; note I also committed @micropthon.native support for ARMv6M since I was looking at MP performance on Pico, and that seemed like a nice to have. Don't know if @dpgeorge plans to include that by default.

Frankly, yeah I suspect we're likely to want more than one MP configuration for RP2040 based boards.

aallan commented 3 years ago

pio rainbow neopixels - we hacked together the pio ws2812 demo with our 'essential' neopixel example code to show off color fills, chases and of course a rainbow swirl on a 16-led ring.

I went ahead and added this one as an example to the Pico Python SDK book.

IMG_1242

If you'd like to add the others, see the /pio/neopixel_ring/ and i2c/1306oled/ directories in the pico-micropython-examples repo for how to add a simple README.adoc. These README.adoc will get imported into PDF documentation automatically (see Appendix A of the Pico Python SDK). We take pull requests! 😆

ptorrone commented 3 years ago

mandelbrot

and video here (53 secs), request permission to view: https://drive.google.com/file/d/11iIlO1sBB_vOJg6hdqsmVabHDxVo_4lL/view?usp=sharing

ladyada commented 3 years ago

RP2040 Feather is plugged into https://www.adafruit.com/product/3315 and running

# Tests SPI and pin interaction with 2.4" TFT Featherwing

import time
from machine import Pin, SPI
from rgb import color565
import ili9341  # http://github.com/adafruit/micropython-adafruit-rgb-display
import framebuf 

spi = machine.SPI(0, baudrate=64000000, sck=Pin(18), mosi=Pin(19), miso=Pin(20))
display = ili9341.ILI9341(spi, cs=machine.Pin(9), dc=machine.Pin(10))

w, h = (240, 320) # cache width and height of LCD

# clear out the screen to test color mapping
display.fill(color565(255, 0, 0))
time.sleep(0.1)
display.fill(color565(0, 255, 0))
time.sleep(0.1)
display.fill(color565(0, 0, 255))
time.sleep(0.1)
display.fill(0)

# function to compute Mandelbrot pixels - from 1602cr demo
def in_set(c):
    z = 0
    for i in range(32):
        z = z * z + c
        if abs(z) > 100:
            return i
    return 0

# create the buffer for each line and set SPI parameters
line = bytearray(w * 2)

# draw the Mandelbrot set line-by-line - from 1602cr demo
hh = (h - 1) / 3.2
ww = (w - 1) / 2.4
for v in range(h):
    for u in range(w):
        c = in_set((v / hh - 2.3) + (u / ww - 1.2) * 1j)
        if c < 16:
            rgb = c << 12 | c << 6
        else:
            rgb = 0xF800 | c << 6
        line[2 * u] = rgb
        line[2 * u + 1] = rgb >> 8
    #display.blit_buffer(line, 0, v, w, 1)
    display._block(0, v, w-1, v, line)  # unsafe version but faster for demo
ptorrone commented 3 years ago

aand random lines demo...

random_lines

ladyada commented 3 years ago

GFX library adds shapes (lines, rectangles, triangles, etc) to displays

import time
from machine import Pin, SPI
import ili9341 # http://github.com/adafruit/micropython-adafruit-rgb-display
import gfx  # https://github.com/adafruit/micropython-adafruit-gfx
import random

spi = machine.SPI(0, baudrate=64000000, sck=Pin(18), mosi=Pin(19), miso=Pin(20))
display = ili9341.ILI9341(spi, cs=machine.Pin(9), dc=machine.Pin(10))
graphics = gfx.GFX(240, 320, display.pixel)

# Now loop forever drawing random lines.
display.fill(0)
while True:
    x0 = random.randrange(0, 240)
    y0 = random.randrange(0, 320)
    x1 = random.randrange(0, 240)
    y1 = random.randrange(0, 320)
    r = random.randrange(0, 255)
    g = random.randrange(0, 255)
    b = random.randrange(0, 255)
    graphics.line(x0, y0, x1, y1, ili9341.color565(r, g, b))