#circuitpython-dev

1 messages Β· Page 45 of 1

atomic summit
#

sorry - ssh to rPI - and then serial output of DUT on rPI piped to my mac.

jaunty juniper
#

I don't understand, this is the serial output from the board

#

DUT ?

atomic summit
#

Device Under Test

#

My test jigs are rPIs and they flash and test each board and talk to the board and get data back from the bard during the test, and all of that is sent to the terminal that I am ssh-ing from. So I see the raw serial output

#

for example...

rPI: wifi connected to UM-C10 (192.168.4.59) in 4.917 secs
rPI: retrying 1
DUT: \x1b]0;\xf0\x9f\x90\x8dWi-Fi: off | code.py | 8.2.3\x1b\\\x1b]0;\xf0\x9f\x90\x8dWi-Fi: No IP | code.py | 8.2.3\x1b\\
rPI: Connecting to UM-C10 on channel 10```
midnight ember
#

\xf0\x9f\x90\x8d is indeed snake when translated to UTF-8

atomic summit
#

my wifi tests are designed to pass in under 4sec and if over, fail and retry

atomic summit
#

when I thought it was colour codes, I was going to see if I could also colour code my own output.

midnight ember
#

I'm unsure what the preprended \x1b]0; is though

#

could be color, possible

#

If it is a color will likely be a magenta

#

appears to be an escape character of some kind

#

would probably end up looking like \🐍\ probably used internally somehow

winter mortar
#

The \x1b (ESC) sequences are terminalio VT-100 speak

midnight ember
#

makes sense

jaunty juniper
#

I assume that whatever your code is that retrieves the data from serial an passes it down converts high ascii into escape characters

midnight ember
#

appears to be ansi

jaunty juniper
#

it's the code to put the status into the terminal title

midnight ember
#

makes sense

jaunty juniper
#

like that

midnight ember
#

looks like Mu decided to just remove the whole sequence. at one time in 8.0 beta it was really really messing up almost every line. like every single repl output line had a snake it was a mess.

manic glacierBOT
silent plaza
#

I don't know if this is the right place to ask this question but I'm wanting to create https://learn.adafruit.com/guggenhat-bluetooth-le-wearable-neopixel-marquee-scrolling-led-hat-display nut with circuit python using an nrf52840 or an esp32 s3 feather as the control board if not able to do with circuit python at the moment what board would be best to use with Arduino. Also if unable to be done in Circuit Python how best I ask for the features to be included in future versions of CP?

Adafruit Learning System

Your name (or any other 20 character artistic statement) in lights!

manic glacierBOT
thorny jay
#

I would say that the right place is #help-with-circuitpython ... but I don't have the Discord Skills or Right to move it there.
That guide is from 2014 so CircuitPython did not exist at the time, but I don't see anything not possible in CP.
I found this guide that might help as it display text on a NeoPixel matrix: https://learn.adafruit.com/iot-led-sign
(but this is IOT so using the wifi of the ESP32S2, no Bluetooth)
The secret sauce might be this library to have a framebuffer made of pixel: https://github.com/adafruit/Adafruit_CircuitPython_Pixel_Framebuf
Then for BLE communication you could use the app "Bluefruit connect" https://learn.adafruit.com/bluefruit-le-connect
Now you just need to find some learn guide that use the text transmission of that application... and you need some other learn guide that scroll text on a framebuffer (you could try some MatrixPortal guide, and replace the matrix part with the Neopixel equivalent).
I don't say it is easy (but a lot of things are easy with CP), but my remixing two or three guide, you have piece of code for each part.
The difficulty nowdays is to find the right guide in the learn system, because maybe what you want to do already exist.
Don't forget the feedback you could put on the Guggenhat guide to ask if a CP would be possible, or share your code if you do it.

manic glacierBOT
manic glacierBOT
#

Such a simple and neat feature!

Some more applications for it:

  • Have a permanently running app and use REPL as a debugging mode of sorts, where everything is loaded automatically.
  • Have a help message (regarding your functions) shown upon entering the repl, clearing the screen or even displaying a new ansi title.
  • Show useful board stats upon entering the repl like the temperature or the board ip.
onyx hinge
#

@atomic summit The escape code "\x1b]0;" is "Change icon name and window title" and the title is terminated by "\x1b\". Sometimes just after a first connect, the sequence is incomplete or garbled; we're not sure why and would fix it if we could. And of course when whatever's receiving the sequence isn't a compatible terminal, it might appear garbled like that. And yes, b'\xf0\x9f\x90\x8d' is 🐍 in utf-8 encoding. [I see this was discussed to a natural conclusion hours ago but I wrote this so I'm sending it anyway]

brazen hatch
#

And now it's 100% reliable (with the power of spam) and even works over telnet.

#

Making another dotfiles pr in a bit, disabling dotfiles on boards that don't have native usb

manic glacierBOT
#

They serve no purpose on boards without usb, other than looking ugly in the web-workflow.
Even if in the future those boards were to be accessed by ftp (which I plan on doing really soon), they do not apply.

A board with usb:

>>> import storage
>>> storage.erase_filesystem()

[17:18:05.090] Disconnected
[17:18:06.092] Warning: Could not open tty device (No such file or directory)
[17:18:06.092] Waiting for tty device..
[17:18:16.105] Connected
Auto-reload is on. Simply save...
buoyant lagoon
#

ive got some questions about the spi storage in circuitpython

#

when i was benchmarking erase/program times, i saw pico-sdk does 64kb erase blocks, so erase+program can run at about 80kb/sec

#

but circuitpython is using 4kb erase blocks, so it gets about 77kb/sec

#

however, if the blocks had been pre-erased, and your only having to program, it could get 625kb/sec!

#

i can also kinda see how you might bodge that ontop of fat

first, scan the entire FAT fs, find every used and unused block
second, pre-erase all unused blocks
third, keep a bitmap of pre-erased blocks, and store it somewhere, so you dont have to do 1/2 again
modify the fat block allocation algo, so it will prefer erased blocks

stuck elbow
#

what is your use case for needing fast writes?

buoyant lagoon
#

just better overall performance when copying things to flash

#

77 to 625 is a pretty big boost

stuck elbow
#

at a cost of slower startup

#

those things are usually tradeoffs, making them without a purpose in mind is not a good idea

buoyant lagoon
#

but a different filesystem, intended for flash, would also work

#

or a intermediate wear leveling layer

#

could also just be optional, so not ever board has it

slender iron
#

I think the ESP IDF has an intermediate wear leveling layer

#

I haven't looked because we don't really have a problem with wear

buoyant lagoon
#

i was thinking of using it more for pre-erase then proper wear leveling

#

but you kinda get both at the same time

#

if you just treat the entire flash as a ringbuffer, copy used blocks from tail->head, and erase everything in the middle, then your wear is more even, and things are pre-erased

slender iron
#

We're open to folks improving things. We don't have a shortage of ideas, only folks working on them.

buoyant lagoon
#

yeah

#

i also realized, i got some wires crossed
the original problem i was trying to solve, was programming a uf2 to an rp2040

so the circuitpython performance doesnt matter in that case

slender iron
#

yup, the uf2 code is in rom

buoyant lagoon
#

but the cpy performance is still rather slow

#

and can be improved

slender iron
#

It can always be improved πŸ™‚ Figuring out what to work on is the hard part

buoyant lagoon
#

yeah

#

the MBR code in the broadcom port is also rather fragile

#

if there is exactly 1 partition, it will create a second for the circuitpython drive

#

if there is exactly 2 partitions, it will expose the 2nd as MSD

#

anything else, and it breaks

#

so you cant multi-boot with pinn/noobs

#

you cant reserve the fake space on a 32gig card advertising itself as 256gig

slender iron
#

go ahead and fix it πŸ™‚

#

or file issues

buoyant lagoon
#

its a tricky thing to fix, because i can see it destroying data on an sd card when it goes wrong

#

so we would need to discuss options first

slender iron
#

issues are a better spot to discuss instead of discord since the history gets less and less accessible

buoyant lagoon
#

good point

slender iron
#

we have labels to filter by port too

buoyant lagoon
#

hmmm, bug report or feature request?

slender iron
#

I'd say enhancement since I didn't expect a CP SD card to be used for anything else

manic glacierBOT
buoyant lagoon
slender iron
#

I'll add them. Thanks!

manic glacierBOT
#

if there is exactly 1 partition, it will create a second for the circuitpython drive
if there is exactly 2 partitions, it will expose the 2nd as MSD
anything else, and it breaks
so you cant multi-boot with pinn/noobs
you cant reserve the fake space on a 32gig card advertising itself as 256gig

pinn/noobs use extended partitions for each OS, so that use-case would require adding extended partition support
and the more general case, of just having unexpected partitions, could be solved w...

manic glacierBOT
#

It doesn't seems to help for me...

Adafruit CircuitPython 8.2.4-4-g811bd12fa on 2023-08-29; BPI-PicoW-S3 with ESP32S3
>>> 
soft reboot

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.
code.py output:
sd card ready
PN532 ready !
i2s ready
waiting for a tag to playΒ·...

<serial broke>

Auto-reload is off.
Running in safe mode! Not running saved code.

You are in safe mode because:
Internal watchdog timer expired.
Press reset to exit sa...
manic glacierBOT
#

after some minor change (simple refactoring, trying to make my failing code example even more minimal), I managed to get another error:

You are in safe mode because:
CircuitPython core code crashed hard. Whoops!
Hard fault: memory access or instruction error.
Please file an issue with your program at github.com/adafruit/circuitpython/issues.
Press reset to exit safe mode.

Press any key to enter the REPL. Use CTRL-D to reload.
idle owl
#

@slender iron Are there going to be any changes to deal with the safe mode issues on the original Metro S3, or are we basically writing off those 40 boards? Mostly a curiosity. I don't need it for anything.

slender iron
#

With my PR it won't safe mode anymore. It just will say the pins are in use. I think Limor's plan is to refund folks if needed though.

idle owl
#

I knew her plan. I was curious about yours. Sounds good!

slender iron
manic glacierBOT
manic glacierBOT
#

It seems the last time a release was done with 8.2.4, the frozen libs were not updated which is causing problems with boards like the FunHouse because the version that is frozen is not compatible with settings.toml.

This was originally added when we were experiencing some issues with certain boards that used PortalBase. The M4 PortalBase boards (PyPortal MatrixPortal M4) still need this, but esp32-s2 boards have plenty of RAM and don't really need it. In order to make it easier to update,...

crimson ferry
#

Every once in a while, I have a device that consistently at least gets an exception, sometimes safemodes, from a NeoPixel exception. Espressif MCUs, but different board manufacturers.```
File "neopixel.py", line 180, in _transmit
RuntimeError: Input/output error

crimson ferry
#

espressif

buoyant lagoon
crimson ferry
#

good point

#

identically set up boards work fine

blissful pollen
#

the error is on neopixel_write which is in the core

crimson ferry
#

I used to get around it with a function that de-inited and re-inited the NeoPixel on exception, but it happens so frequently on those boards, it spends too much time doing that. Now I just move on to a different (identical) board and it's fine.

blissful pollen
#

But I'm not familiar with the RMT peripheral to really know more then that.

#

Just a quick look a couple previous setup calls don't check for error conditions.

crimson ferry
#

there must be something marginal in the hardware... somewhere ...for most identical boards to work and one not

stuck elbow
#

faulty microcontroller?

crimson ferry
#

marginal in some way maybe, i can’t think of another explanation for only one of otherwise identical units to have the issue

buoyant lagoon
#

@stuck elbow so if i wanted to add a new class, i would have to do it around here?

STATIC const mp_rom_map_elem_t videocore_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_videocore) },
    { MP_ROM_QSTR(MP_QSTR_Framebuffer), MP_ROM_PTR(&videocore_framebuffer_type) },
};

i'm thinking, there should be 3 objects, for the 3 displays, pre-created with the constructor blocked out
and then another object the user can create instances of...
how would that work exactly?

stuck elbow
stuck elbow
#

I'm not familiar with the videocore module

buoyant lagoon
#

it looks to be a string=object mapping, for globals in this module, which can then be imported?

stuck elbow
#

yeah

buoyant lagoon
#

what i need more, is somebody that knows how C modules work in (micro|circuit)python

#

for example, what is MP_ROM_QSTR(MP_QSTR_videocore) doing?
why can i not find the definition of MP_QSTR_videocore elsewhere in the code?

#

build-raspberrypi_zero2w/genhdr/qstrdefs.generated.h:QDEF(MP_QSTR_videocore, 175, 9, "videocore")

#

ah, runtime generation

stuck elbow
#

it's a magical macro for interned strings

buoyant lagoon
#

git grep is always lying to me

stuck elbow
#

lie to it in return

buoyant lagoon
#

so, if i want to create my own class type, i would need to duplcate this line:
{ MP_ROM_QSTR(MP_QSTR_Framebuffer), MP_ROM_PTR(&videocore_framebuffer_type) },
and duplicate the struct its refering to in the other file....

#
root@d235fe3c2fdb:/circuitpython/ports/broadcom# grep test build-raspberrypi_zero/genhdr/qstrdefs.generated.h 
QDEF(MP_QSTR_test, 51, 4, "test")
#

interesting, it seems to have just found that constant in my code

#

so i just act like it exists, and then it magically exists!

buoyant lagoon
#

@stuck elbow
.locals_dict = (mp_obj_dict_t *)&videocore_framebuffer_locals_dict,

what are these locals local to?
are they attributes of the resulting Framebuffer class?

#
>>> videocore.Framebuffer.
deinit          height          width
>>> videocore.Framebuffer.width
<property>
#
STATIC const mp_rom_map_elem_t videocore_framebuffer_locals_dict_table[] = {
    { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&videocore_framebuffer_deinit_obj) },

    { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&videocore_framebuffer_width_obj) },
    { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&videocore_framebuffer_height_obj) },
};
STATIC MP_DEFINE_CONST_DICT(videocore_framebuffer_locals_dict, videocore_framebuffer_locals_dict_table);
#

yeah, attributes of the class at least

#
libg.a(lib_a-sbrkr.o): in function `_sbrk_r':
#

hmmm, if i cant malloc() then how should i reserve some memory on the GC-able heap, for this class?

blissful pollen
buoyant lagoon
#

i am still about

blissful pollen
#

m_malloc will do it

buoyant lagoon
#

how will the object get freed when the python object around it is freed?

#
STATIC mp_obj_t hvs_sprite_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
  sprite_t *sprite = m_malloc(sizeof(sprite_t), true);
  return MP_OBJ_FROM_PTR(sprite);
}

const mp_obj_type_t hvs_sprite_type = {
    { &mp_type_type },
    .flags = MP_TYPE_FLAG_EXTENDED,
    .name = MP_QSTR_Sprite,
    .make_new = hvs_sprite_make_new,
};
#

the basic idea, is that the user code will spawn one instance of this, for each on-screen sprite

#

and if circuitpython reloads the code and GC's all objects, it should clean up all sprite objects

blissful pollen
#

Can't remember if you want the second m_malloc paramter true or not. If you looked it up and that's correct ignore me.

And it should be freed when the object gets freed. The GC checks for all pointers on the stack including C ones. Some objects have a deinit() python function that will explicity free the memory

buoyant lagoon
#
>>> import videocore
>>> videocore.Sprite
<class 'Sprite'>
>>> x = videocore.Sprite()
>>> x

#

and it seems to just hang now, when viewed from the CDC uart

#

ah, i did see a deinit on the framebuffer

blissful pollen
buoyant lagoon
#

i'll copy that if i need something more complex then free

#

i guess hw uart is next...

blissful pollen
#

Did you figure out the QSTR stuff you asked earlier?

buoyant lagoon
#

yep

#

just blindly assume the constant exists, and it will magically exist, lol

blissful pollen
#

One thing that took me a while to figure out was that a QSTR is just an integer under the hood. Somewhere in the compile files you can see the mapping

buoyant lagoon
#

yep, found that file already

#

and ive delt with less magic-y interning before in the nix language

#

there is just a runtime function, to allocate/lookup a char* in the interned table

#

and then all maps use the int

buoyant lagoon
#

no backtrace or anything

buoyant lagoon
#

and then be able to access the image from C

#

>>> b = displayio.Bitmap(16,16,255)

blissful pollen
buoyant lagoon
#

heh

#

i'll need to find a uSD card then

#
You are in safe mode because:
CIRCUITPY drive could not be found or created.
#

guessed the right card on the first try!

#
import videocore
import gifio

sprite = videocore.Sprite()
gif = gifio.OnDiskGif("/discord-minecraft.gif")
sprite.image = gif 

print("Hello World!")
#

dropped a random gif from my memes folder onto the drive, and it hung

#

@blissful pollen now what? its hanging on every boot πŸ˜„

blissful pollen
#

If you're stuck that way you can get into safe mode to edit code.py

buoyant lagoon
#

how do you get into safemode?

blissful pollen
#

if sprite.image is a bitmap too you need to assign it the bitmap from the gif. The docs in the shared-bindings folder should have a decent example

buoyant lagoon
#
typedef struct {
} sprite_t;

STATIC mp_obj_t hvs_sprite_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
  sprite_t *sprite = m_malloc(sizeof(sprite_t), false);
  return MP_OBJ_FROM_PTR(sprite);
}

const mp_obj_type_t hvs_sprite_type = {
    { &mp_type_type },
    .flags = MP_TYPE_FLAG_EXTENDED,
    .name = MP_QSTR_Sprite,
    .make_new = hvs_sprite_make_new,
};
#

sprite.image just doesnt exist

blissful pollen
buoyant lagoon
#

it should have thrown an error

#

there is no neopixel on the pi-zero

blissful pollen
#

Hmm yeah I'm not sure on the pi-zero

buoyant lagoon
#

my setup is also weird

#

the main circuitpython binary is loaded over the usb-device link

#

so i can change the C code freely, without having to swap uSD cards

#

even if its hanging like this

#

oh, i got a simple hack

#

just comment out the definition for videocore.Sprite

#

AttributeError: 'module' object has no attribute 'Sprite'

#

try and make a sprite now! πŸ˜„

#
import videocore
import gifio

sprite = videocore.Sprite()
gif = gifio.OnDiskGif("/discord-minecraft.gif")
# sprite.image = gif

print("Hello World!")
#

and that simple comment, solves the hang

#

so, i'm clearly missing something in my Sprite class

#

oh, i didnt populate the locals dict

#
bindings/videocore/Sprite.c:20:25: error: expected ')' before '(' token
   20 | MP_PROPERTY_GETTER(test, (mp_obj_t)&get_test);
      |                         ^~
#

@blissful pollen the macros make it hard to see what is wrong with this

blissful pollen
#

Do you have test and get_test defined properly?

#
//|     width: int
//|     """Width of the gif. (read only)"""
STATIC mp_obj_t gifio_ondiskgif_obj_get_width(mp_obj_t self_in) {
    gifio_ondiskgif_t *self = MP_OBJ_TO_PTR(self_in);

    check_for_deinit(self);
    return MP_OBJ_NEW_SMALL_INT(common_hal_gifio_ondiskgif_get_width(self));
}

MP_DEFINE_CONST_FUN_OBJ_1(gifio_ondiskgif_get_width_obj, gifio_ondiskgif_obj_get_width);

MP_PROPERTY_GETTER(gifio_ondiskgif_width_obj,
    (mp_obj_t)&gifio_ondiskgif_get_width_obj);```

As an example
buoyant lagoon
#
STATIC mp_obj_t get_width_impl(mp_obj_t self_in) {
  return MP_ROM_QSTR(MP_QSTR_foobar);
}

MP_DEFINE_CONST_FUN_OBJ_1(get_test, get_width_impl);
MP_PROPERTY_GETTER(test, (mp_obj_t)&get_test);

STATIC const mp_rom_map_elem_t hvs_sprite_locals_dict_table[] = {
  { MP_ROM_QSTR(MP_QSTR_test), MP_ROM_PTR(&test) },
};
#

as best as i can tell, its all correct

blissful pollen
#

Yeah I'm not noticing what's off

buoyant lagoon
#
bindings/videocore/Sprite.c:20:25: error: expected ')' before '(' token
   20 | MP_PROPERTY_GETTER(test, (mp_obj_t)&get_test);
      |                         ^~
      |                         )
In file included from bindings/videocore/Sprite.c:3:
bindings/videocore/Sprite.c:23:44: error: 'test' undeclared here (not in a function)
   23 |   { MP_ROM_QSTR(MP_QSTR_test), MP_ROM_PTR(&test) },
      |                                            ^~~~
../../py/obj.h:312:24: note: in definition of macro 'MP_ROM_PTR'
  312 | #define MP_ROM_PTR(p) (p)
      |                        ^
#

i think the 2nd error, is because gcc ignored line 20, due to the 1st error

#
py/objproperty.h:#define MP_PROPERTY_GETTER(P, G) const mp_obj_property_getter_t P __attribute((section(".property_getter"))) = {.base.type = &mp_type_property, .proxy = {G}}
py/objproperty.h:#define MP_PROPERTY_GETTER(P, G) const mp_obj_property_t P = {.base.type = &mp_type_property, .proxy = {G, MP_ROM_NONE, MP_ROM_NONE}}
#

the 2 versions are a flash usage thing, so lets focus on the 2nd

#

const mp_obj_property_t test = {.base.type = &mp_type_property, .proxy = {(mp_obj_t)&get_test, MP_ROM_NONE, MP_ROM_NONE}}

#

that looks perfectly valid to me

blissful pollen
#

Yeah I still spot what's missing. Sometimes may have to do a clean compile too as some of the macros run before (random idea)

buoyant lagoon
#

wiped the build dir, no difference

#

@blissful pollen aha
#include "py/objproperty.h" was missing facepalm

blissful pollen
#

oops! It's late (at least here) so I can see it ha

buoyant lagoon
#

12:11 am here

#

still hangs though, so it wasnt the prop list

#
>>> videocore.Sprite.test
<property>
#

but the property is at least visible when i dont make a new instance

#

oh!

#

i'm calling m_malloc(0, false); ....

blissful pollen
#

Oh yeah

buoyant lagoon
#

nope

#

that wasnt it either

#
>>> s = videocore.Sprite()
sprite is at 0x3c5fa0
>>> 
>>> s
#

a printf confirms it is allocating memory for the sprite when i construct it

#

how does circuitpython know how to print an unknown class?

blissful pollen
#

Not sure on printing that, never looked into it

buoyant lagoon
#

looks like you also support animated gifs, nice

#

is it changing the backing odg.bitmap?

blissful pollen
#

it keeps the same bitmap just re-writes it each frame

buoyant lagoon
#

yeah, so that will have tearing

#

the port i'm on has enough ram to just allocate a new bitmap for each frame, and can do vsync flips if you wait for vsync

#

but i can worry about that once i'm able to actually display anything

blissful pollen
#

I didnt notice any tearing on the small displays but there is barely enough RAM in a RP2040 for one frame let alone two

buoyant lagoon
#

but i'm on the rpi-zero, with at least 256mb of ram

#

so maybe make it an argument to the class

#

odg.next_frame(reallocate=True)

#

any kind of debug flag i could enable, to see why its just silently hanging?

blissful pollen
#

you can compile with DEBUG=1

#

(I think)

buoyant lagoon
#

no difference

#

oh

#

i was wondering, how MP_OBJ_FROM_PTR(self->bitmap); turned into something that knows its of the bitmap class

#

there must be required fields!!

#

gifio_ondiskgif_t *self = m_new_obj(gifio_ondiskgif_t);

#

mp_obj_base_t base;

#

bingo

#

so circuitpython is casting my sprite to this, expecting to find the base

#

and its an undefined 32bit width....

#

πŸ’₯

#

self->base.type = &gifio_ondiskgif_type;

#

and that is critical

blissful pollen
#

oh yes it is

buoyant lagoon
#
>>> s
<Sprite>
>>> 
#

now it can find the type and tell me what type it is

blissful pollen
#

πŸŽ‰

buoyant lagoon
#
>>> s.test
'foobar'
#

and the getter works

#

now to change the code.py back...

#

AttributeError: can't set attribute 'image'
and then make another property

#

ok, so i have a mp_obj_t value, which came from the gif.bitmap

#

how do i assert that it is a bitmap....

#
displayio_bitmap_t *bitmap = m_new_obj(displayio_bitmap_t);
bitmap->base.type = &displayio_bitmap_type;```
#

i could check for that exact type?

#

displayio_bitmap_t *bitmap = mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap);

#

this occurs in many places

#

TypeError: bitmap must be of type Bitmap, not OnDiskGif

#

it even gives a nice error, due to forgetting about .bitmap

#
>>> sprite.image
>>> sprite.image = gif.bitmap
>>> sprite.image
<Bitmap>
#

yep, progress!

#
>>> sprite.width
0
>>> sprite.width = 10
>>> sprite.width
10
#
#define simpleprop(name) \
    static mp_obj_t c_getter_##name(mp_obj_t self_in) { sprite_t *self = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT(self->name); } \
    static mp_obj_t c_setter_##name(mp_obj_t self_in, mp_obj_t value) { sprite_t *self = MP_OBJ_TO_PTR(self_in); self->name = mp_obj_get_int(value); return mp_const_none; } \
    MP_DEFINE_CONST_FUN_OBJ_1(fun_get_##name, c_getter_##name); \
    MP_DEFINE_CONST_FUN_OBJ_2(fun_set_##name, c_setter_##name); \
    MP_PROPERTY_GETSET(prop_##name, (mp_obj_t)&fun_get_##name, (mp_obj_t)&fun_set_##name)

#define prop_entry(name) { MP_ROM_QSTR(MP_QSTR_##name), MP_ROM_PTR(&prop_##name) }

simpleprop(width);

STATIC const mp_rom_map_elem_t hvs_sprite_locals_dict_table[] = {
  { MP_ROM_QSTR(MP_QSTR_test), MP_ROM_PTR(&test_prop) },
  { MP_ROM_QSTR(MP_QSTR_image), MP_ROM_PTR(&image_prop) },
  prop_entry(width),
};
#

@blissful pollen behold!!, the power of macros!!

#

i'm surprised MP_QSTR_##name even worked, lol

#
>>> import videocore
>>> import gifio
>>> gif = gifio.OnDiskGif("/discord-minecraft.gif")
>>> sprite = videocore.Sprite()
sprite is at 0x3c61e0
>>> sprite.width
0
>>> sprite.height
0
>>> sprite.image = gif.bitmap
>>> sprite.width
313
>>> sprite.height
245
#

and now the w/h default to the input bitmap, when they started out at 0

blissful pollen
#

Nice, congrats!

buoyant lagoon
#
>>> sprite.maybe_regen()
regen time
>>> sprite.maybe_regen()
not dirty
>>> sprite.image = gif.bitmap
>>> sprite.maybe_regen()
regen time
>>> sprite.maybe_regen()
not dirty
#

and dirty tracking works

#

now, i need to actually generate the display list

#

https://github.com/librerpi/lk-overlay/blob/master/platform/bcm28xx/hvs/hvs.c#L142C24-L164

void hvs_regen_noscale_noviewport(hvs_layer *l) {
  assert(l->dlist_length >= 7);
  assert(l->premade_dlist);
  uint32_t *d = l->premade_dlist;
  // CTL0
  d[0] = CONTROL_VALID
    | CONTROL_PIXEL_ORDER(HVS_PIXEL_ORDER_ABGR)
    | CONTROL_UNITY
    | CONTROL_FORMAT(gfx_to_hvs_pixel_format(l->fb->format))
    | CONTROL_WORDS(7);
  // POS0
  d[1] = POS0_X(l->x) | POS0_Y(l->y) | POS0_ALPHA(0xff);
  // POS2, input size
  d[2] = POS2_H(l->fb->height) | POS2_W(l->fb->width) | (l->alpha_mode << 30);
  // POS3, context
  d[3] = 0xDEADBEEF;
  // PTR0
  d[4] = (uint32_t)l->fb->ptr | 0xc0000000;
  // context 0
  d[5] = 0xDEADBEEF;
  // pitch 0
  d[6] = l->fb->stride * l->fb->pixelsize;
}
#

for basic sprites, it just needs 7 entries like this

#

and thats basically everything i need on the sprite side, for basic stuff

#

now i need the hvs side...

#

@blissful pollen now comes the fun part
i want to spawn 3 instances of the HvsChannel class, but not allow the user to create more
i think i can do the 2nd part, by just not having a .make_new

but then the 1st part, i need to create the 3 structs, and MP_ROM_PTR them??

#

wow, got that all right on the first try!

#
typedef struct {
  mp_obj_base_t base;
  uint32_t channel;
} hvs_channel_t;

extern hvs_channel_t hvs_channels[3];

hvs_channel_t hvs_channels[3] = {
  [0] = {
    .base.type = &hvs_channel_type,
    .channel = 0,
  },
  [1] = {
    .base.type = &hvs_channel_type,
    .channel = 1,
  },
  [2] = {
    .base.type = &hvs_channel_type,
    .channel = 2,
  },
};

const mp_obj_type_t hvs_channel_type = {
  { &mp_type_type },
  .name = MP_QSTR_HvsChannel,
};


STATIC const mp_rom_map_elem_t videocore_module_globals_table[] = {
    { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_videocore) },
    { MP_ROM_QSTR(MP_QSTR_Framebuffer), MP_ROM_PTR(&videocore_framebuffer_type) },
    { MP_ROM_QSTR(MP_QSTR_Sprite), MP_ROM_PTR(&hvs_sprite_type) },
    { MP_ROM_QSTR(MP_QSTR_HvsChannel0), MP_OBJ_FROM_PTR(&hvs_channels[0]) },
};
buoyant lagoon
#
>>> videocore.HvsChannel1.width
1280
>>> videocore.HvsChannel1.height
1024
>>> videocore.HvsChannel1.enabled
0
#

mp_obj_new_bool was what i wanted

#
>>> import videocore
>>> videocore.HvsChannel0.enabled
False
>>> videocore.HvsChannel1.enabled
True
>>> videocore.HvsChannel2.enabled
False
>>> videocore.HvsChannel1.width
1280
>>> videocore.HvsChannel1.height
1024
#

@blissful pollen hows that look? πŸ˜„

#

now comes the next fun part...
i need to accept a list of Sprite objects, regen each, and then blast them into the display-list memory

buoyant lagoon
#

i wrote the rest of that code, ran it, and the screen just goes blank....

#

the stride, is half the width!!

#

w: 313, h: 245, stride: 157, bits per value: 16

#

aha

#

i forgot to call next_frame() the first time

#

what i should be seeing

#

what i'm actually seeing

#

i changed it from RGB332 to RGB555, and now i'm seeing 4 copies

#

the problem now, is that i need to understand what the data format is within displayio_bitmap_t

#

displayio_bitmap_write_pixel() should have answers

#

d[6] = s->bitmap->stride * 4; helps some

#

i can now just barely make out the pig, and the whole shape is there

#

and switching back to 555, i can now see just a single corrupted image, fully in the right shape!

#

let me try turning on animation, just for the hck of it

#

other then the colors, its looking amazing

#

oh, i might as well play with other sprite features, until i figure out color

#

now performance is horid πŸ˜„

#

ah, the printf's are to blame

#

i think its the framebuffer repl, thats always redrawing painfully slow

manic glacierBOT
#

the initial 2d accel code, tested and working on a pi-zero
it should work on the entire vc4 family, bcm2836/2836/2837, just need to update BCM_PERIPH_BASE_VIRT, or find an existing constant that does the same job

will work on it more tomorrow, but am open to comments

features:

  • [x] displaying a bitmap at set coords, with 1:1 scale
  • [ ] up/down scaling
  • [ ] sprite wide alpha
  • [ ] moving the REPL framebuffer into a sprite
  • [ ] properly handling colors

example code.py:
`...

buoyant lagoon
#

if anybody wants to test what ive done while i'm sleeping, its ^

wraith crow
#

On the road today/tomorrow otherwise I'd be on it! Can't wait to check it out when I get back πŸ™‚

buoyant lagoon
#

morning

#

with the newest code.py, its now able to cycle thru all of the gif frames, and it can animate the X/Y coords

blissful pollen
buoyant lagoon
#

but now i need to understand how displayio bitmaps handle colors

#

ah, let me try 565

blissful pollen
#

The examples in the OnDiskGif docs give some hints how it works with displayio

buoyant lagoon
#

565 is still broken, but it looks better

#

the dark grey sides of the hole are showing up mostly green

#

but the brighter bottom sides are showing up dark purple

#

let me try the other color orders...

blissful pollen
#

There is 565 swapped too

buoyant lagoon
#
#define HVS_PIXEL_ORDER_RGBA                    0
#define HVS_PIXEL_ORDER_BGRA                    1
#define HVS_PIXEL_ORDER_ARGB                    2
#define HVS_PIXEL_ORDER_ABGR                    3
#

the hardware supports these 4 orders

#

ARGB and ABGR both look the same

#

but now i have an idea

#

from python, how would i generate a bitmap that is 32x32, and solid red?

#

or would it be faster to just whip up a test image in a gif, lol

#

actually....

#

if i just convert this to gif...

blissful pollen
#

Look up the displayio bitmap, it isn't too hard to generate a bitmap

#

I'm off to work for the day though so probably won't get a chance to check here, though this is more interesting

buoyant lagoon
#

ValueError: width must be <= 320

#

ah dang, your gif library has a max width

#

w: 32, h: 32, stride: 1, bits per value: 1

#

ah, but creating my own image, breaks things very much

#

it switched to a 1 bit per pixel format

#

because i gave Bitmap() diff args

#

looks like i will need more testing, for each bit-depth, and better docs on the internals

#
bitmap = displayio.Bitmap(32 * 3, 32 , (1<<16)-1)
bitmaptools.fill_region(bitmap, 0, 0, 32, 32, 31);
bitmaptools.fill_region(bitmap, 32, 0, 64, 32, (63 << 5));
bitmaptools.fill_region(bitmap, 64, 0, 32*3, 32, (31 << 11));
sprite.image = bitmap
#

HVS_PIXEL_ORDER_ABGR and the above, produces red/green/blue bars
HVS_PIXEL_ORDER_ARGB and the above, produces blue/green/red bars

#

i should just expose color order, as a param....

turbid radish
#

Some other test patterns

buoyant lagoon
#

the root problem, was that gifio was byte-swapping all 16bit ints, to make SPI controllers happy

manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 8.2.0 on 2023-07-05; Raspberry Pi Pico with rp2040

and also tried on

Adafruit CircuitPython 8.2.4 on 2023-08-22; Raspberry Pi Pico with rp2040

Code/REPL

lista=[1,2,3,4]
print(lista.reverse())

Behavior

list reverse() returns None

Description

I am expecting to see a reversed list [4,3,2,1] not None

Additional information

None

buoyant lagoon
manic glacierBOT
mental nexus
#

Awesome, jepler! It’s always a giant leap from black screen to something on the screen, as there are many different ways to make black screens and only limited number of ways to make pixels show up.

mortal kernel
#

Quick question about message translations. I'm putting new/modified strings into circuitypython.pot and assuming that there's some external process that will automagically get the translations into the various .po files. Is there something more I need to do?

onyx hinge
#

@mortal kernel pre-commit will tell you to run "make translate", which updates circuitpython.pot. We use weblate for users to contribute translations, and it also takes care of adding new messages to the individual language .po files, so there's nothing for you to do. https://hosted.weblate.org/projects/circuitpython/main/

Hosted Weblate

CircuitPython is being translated into 20 languages using Weblate. Join the translation or start translating your own project.

mortal kernel
onyx hinge
#

@slender iron design question for you. Some dot clock displays require configuration via a SPI bus; some real world designs place that SPI bus on an I2C I/O expander, because it's only used once at startup and the bus speed is unimportant (on the order of a few hundred bits are transacted once when setting up the display) ... and CP will want to do this at boot time outside of a VM for a board with an integrated display, or from circuitpython code if the display is NOT integrated or the user wants to re-initialize the display for any reason. SOOO... should bitbangio.SPI in the core be extended so that anything with a .value property can be used, in addition to a microcontroller.Pin? or would you prefer to see a different approach and if so what?

#

(this assumes the I/O expander would also have a core implementation I guess)

#

the espressif lcd devkit and limor's 2nd prototype dotclock tft board are both this way

buoyant lagoon
#

i had just thrown a random mp_raise_ValueError(translate("too many sprites, unable to pageflip reliably")); into some code i recently wrote

#

will that be handled automatically?

slender iron
#

finds it

onyx hinge
#

Ooh I'll look at that this afternoon!

slender iron
#

They need native io expander support there too

#

so I think it's worth doing

#

the CYW is kinda like that too

buoyant lagoon
#

originally, there was just a linux c binary, that bit-banged the whole thing

slender iron
#

@buoyant lagoon Ideally you wouldn't add a new sprite class. Instead change the TileGrid implementation to use them under the hood

buoyant lagoon
#

but more recently, linux was setup to drive it with an {i2c/spi}-gpio driver, so it showed up as a normal device and the driver bit-banged

buoyant lagoon
slender iron
#

A tilegrid is a superset of a sprite

buoyant lagoon
#

does tilegrid support scaling?
does it support viewports?

slender iron
#

it only supports integer scaling now

buoyant lagoon
#

is it a int scale factor, or just seperate src and dst w/h?

slender iron
#

a tilegrid is a grid of indices into a spritesheet

#

a 1x1 tilegrid is a sprite

#

int scale factor

#

the advantage of making tilegrid use it is that existing code will just work then

buoyant lagoon
#

ah, so thats not going to be able to fully utilize the rpi hw

#

yeah

slender iron
#

could you make one sprite per tile in the grid internally?

buoyant lagoon
#

what ive been calling viewports, is just fiddling with the starting addr, to render a sub-rect of an image

slender iron
#

right, so that's what the index of a tile does

buoyant lagoon
#

so you can take a 64x64 bitmap
treat it as a grid of 8x8 tiles, each 8x8 pixels

and then just render a single tile from that bitmap

#

in the little-kernel driver, its just viewport_x and viewport_y, an offset from the top-left of the original image

#

and then viewport_w and viewport_h, to set how big of a tile it crops out

manic glacierBOT
buoyant lagoon
#

then it would accept a sprite sheet where the sprites vary in size

#

but the index of TileGrid is a far simpler api for users

slender iron
#

right now displayio assumes fixed tile sizes

buoyant lagoon
#

i can see how you might use TileGrid for fixed size sprites
and then maybe a new SpriteSheet for non-fixed sizes in the future?

slender iron
#

so you could add videocore.Sprite but also re-implement TileGrid with it

buoyant lagoon
#

i'll look into the docs, make some demos with TileGrid, and try adapting that...

slender iron
#

foamyguy has done good work with it

buoyant lagoon
#

the other question, is about pixel formats, color order, and palettes

slender iron
#

the outer API is usually RGB888 and then converted internally

stuck elbow
buoyant lagoon
#

from what i can see, displayio.Bitmap() acts like a palette with 1 to 65535 colors

slender iron
buoyant lagoon
#

but a lot of things (gifio) treat it as rgb565

slender iron
#

ya, I think of Bitmap of "values" that get mapped to colors

buoyant lagoon
#

but there is no palette attached to the bitmap

#

so i have no way of just accepting a bitmap and displaying it

stuck elbow
buoyant lagoon
#
  sprite.image = gif.bitmap
  sprite.color_order = 2
#

i need to add extra parameters like this

#

in this case, 2 refers to HVS_PIXEL_ORDER_XRGB

slender iron
buoyant lagoon
#

ah

slender iron
#

Palette uses color converter code internally to map the RGB888 values to the destination color space

buoyant lagoon
#

but the rpi hw also supports palettes

#

1bit/2bit/4bit/8bit palettes are allowed

#

you give it an array of RGBA8888's, for whatever size you chose

slender iron
#

right, so by re-implementing tilegrid with hardware, you can have the hw do that conversion for you

#

I guess you'd reimplement pallete then too

buoyant lagoon
#

but only if the user doesnt try and do packed 5bit palettes

#

or 9bit palettes

slender iron
#

displayio doesn't support it

#

it's power of two too

buoyant lagoon
#

ah, nice

#

the other thing, is the REPL text console

#

i suspect its configured in the mmu as uncached ram, and just scrolling it is a major performance bottleneck

#

how best would i re-direct that to a bitmap/tilegrid, and then access it for inclusion in my sprite list?

slender iron
#

it is a tilegrid internally already

buoyant lagoon
#

so i just need to change it to use cached ram, and get a pointer to it

slender iron
#

right now the videocore implements a displayio framebuffer

#

so it uses all of the displayio code to render the tilegrids into the framebuffer

buoyant lagoon
#

the instant i run videocore.HvsChannel1.set_sprite_list(), that framebuffer vanishes, and never comes back

slender iron
buoyant lagoon
#

so i need to access its tilegrid object, and then i can have a videocore.HvsChannel1.show_text_console = True or similar

slender iron
#

it's all displayio still

buoyant lagoon
#

oh, and what about dynamically changing the size of that terminal?

#

lets say python code decides to put the terminal on the left half, and do gfx on the right half?

slender iron
#

the one weird trick the terminal uses is tilegrid's ability to change what index is starts the first row

#

it can do that already

buoyant lagoon
#

thats easy enough if you dont want wrapping

#

just add stride * row_offset to the starting addr

slender iron
#

it does wrap to make scrolling easier

buoyant lagoon
#

ah, i implemented exactly that on the rpi

slender iron
#

you could cheat it internally by making the buffer twice as long and saving values to two spots

buoyant lagoon
slender iron
#

on rpi you have plenty of ram

buoyant lagoon
#

it used memcpy() to scroll the entire screen

#

youll notice how slow it is

slender iron
#

displayio isn't fast for fullscreen updates now anyway

buoyant lagoon
#

i assume the current displayio terminal is using a ringbuffer for the display, but still has to memcpy() to paint it into the framebuffer?

slender iron
#

the tilegrid to framebuffer process is pretty heavy

buoyant lagoon
#

this is my re-implementation of littlekernel gfxconsole, using 2 sprites to draw the 2 halves of the ringbuffer

#

so it can scroll with zero copies

slender iron
#

it's more than just memcpy because you are doing tile indexing plus color conversion

#

nice!

#

it'd be very cool to hw accelerate displayio

buoyant lagoon
#

this will also allow dual monitor on all pi models

#

assuming you configure the displays first in config.txt

stuck elbow
#

@buoyant lagoon can it also do that when displaying on an spi display connected to the pi?

buoyant lagoon
#

and not just mirror, fully independent displays

buoyant lagoon
slender iron
#

that'd be very cool. we don't support dual displays very well yet

buoyant lagoon
#

for the pi4, dual hdmi will just come up automatically

#

but i havent fully confirmed how pi4 hvs works

#

i was being stuborn, and trying to bring the pi4 up from reset with zero blobs πŸ˜›

stuck elbow
buoyant lagoon
#

ah, not yet

#

i would need to figure out how the transposer works

#

the transposer is basically a mode in the 2d core, where it just writes the fully composited frame back to ram

#

then you can just dma it out SPI

#

the 2d hardware natively supports dpi, smi, dsi, hdmi, and vec

#

dpi is just parallel digital color, like the hyperpixel

#

smi is undocumented, and is more of an 8080 style bus, where you assert a strobe for each write

#

vec is the ntsc/pal encoder

#

for anything else, you would just write it back to ram, and then dma it somewhere custom

buoyant lagoon
#

that seems to be an array of tilegrids that make up the screen

#

oh, one reason to use my custom Sprite class over TileGrid, is caching the displaylist

slender iron
#

displaylist is the list of sprites?

#

that's what a Group maintains

buoyant lagoon
#
void hvs_regen_noscale_noviewport(sprite_t *s) {
  uint32_t *d = s->dlist;
  // CTL0
  d[0] = CONTROL_VALID
    | CONTROL_PIXEL_ORDER(s->color_order)
    | CONTROL_UNITY
    | CONTROL_FORMAT(s->pixel_format)
    | CONTROL_WORDS(7);
  // POS0
  d[1] = POS0_X(s->x) | POS0_Y(s->y) | POS0_ALPHA(0xff);
  // POS2, input size
  d[2] = POS2_H(s->bitmap->height) | POS2_W(s->bitmap->width) | (s->alpha_mode << 30);
  // POS3, context
  d[3] = 0xDEADBEEF;
  // PTR0
  d[4] = ((uint32_t)s->bitmap->data) // assumes identity map, should be physical addr
    | 0xc0000000; // and tell HVS to do uncached reads
  // context 0
  d[5] = 0xDEADBEEF;
  // pitch 0
  d[6] = s->bitmap->stride * 4;

  //printf("w: %d, h: %d, stride: %d, bits per value: %d\n", s->bitmap->width, s->bitmap->height, s->bitmap->stride, s->bitmap->bits_per_value);
}
slender iron
#

but you have have tree of groups

buoyant lagoon
#

this is a 7 x 32bit structure, that describes a single sprite

#

if a sprite hasnt changed, then i dont have to re-generate this structure

#

and i can just copy it into the displaylist for the next frame

#

which saves some cpu

slender iron
#

so that's what tilegrid should maintain

#

and group should combine them to produce the displaylist

buoyant lagoon
#

ah, so the group is basically the same as my videocore.HvsChannel1.set_sprite_list([format1, format2, format3, format4])

#

is a tilegrid object bound to a single display driver?

stuck elbow
#

I think there is no explicit bond, but the display logic assumes only one display is displaying any object

#

because there is a linked list internally

buoyant lagoon
#

and on the rpi, all 3 hvs channels can consume the same format, and infact, share the displaylist ram

#

but each needs its own copy of the displaylist

#

basically, there is an uint32_t dlist[4096] in MMIO space
for each 1:1 scaled sprite, you write 7 slots
plus 1 slot to end the list

then you put the starting index into another control reg

#

a scaled sprite takes up 14 slots

#

a palette takes an extra 1 slot in the sprite itself, plus N slots to hold the N RGBA8888 colors

slender iron
#

I think tilegrid's ensure they are only in one group at a time

buoyant lagoon
#

so sharing a palette between multiple sprites will reduce the usage

slender iron
#

since groups have coordinates and scaling that propagate into the tilegrid

#

palettes can be shared

buoyant lagoon
#

and the TileGrid holds a pointer to the palette?

slender iron
#

ya, to the pixel_sharder

#

which is a palette or color converter

#

tilegrids are ordered by their order in groups

#

ie z-depth

buoyant lagoon
#

perfect

#

the entries in the hw dlist also have to be in z-depth order

#

it draws them first to last

#

internally, there is a FIFO that can hold a few scanlines

#

when that FIFO has room for 1 scanline, the hardware will start parsing the display list, and copying/blending pixels into the FIFO memory

#

it can draw 4 pixels/clock for unscaled sprites

#

2 pixels/clock for scaled sprites

#

and 1 pixel/clock for palette based formats

#

if it can draw all of the sprites in the scanline within the deadline (normal racing the electron beam stuff), then it can keep up and everything is fine

#

the FIFO gives it a couple scanlines of wiggle room, so it isnt too fragile

#

and the 2d core will take turns generating scanlines for up to 3 displays, each in its own FIFO

#

if no sprite covers a given pixel, then the color is undefined (whatever was already in the fifo), and you get weird effects

#

but there is an optional background fill, that will pre-write a configurable constant to the whole scanline, at the cost of more clock cycles

#

there is also hardware dithering support

#

for context, this was setup to do an r/g/b face from 0% to 100%
but the top 2 bits of green are mis-configured (hw uart conflicts)

#

in this example, dithering is off, so you can see some hard steps in the darker regions, when the camera isnt over-exposed

#

this image, then has hardware dithering enabled
but the top 2 bits are still mis-configured, which makes bit0 wiggling far more visible

manic glacierBOT
slender iron
#

I think palette has a dither flag too

#

that or colorconverter

#

mainly for color eink improvements iirc

buoyant lagoon
#

for the rpi hardware, dithering is a screen-wide option

slender iron
buoyant lagoon
#

you define the output bit depth
24bit 888
18bit 666
16bit 565
or 15bit 555

and you define a dithering mode

0 = No dithering
1 = Accumulate rounding error horizontally.
2 = As 1, but also apply pseudo-random noise. The noise generator is reset at the start of each frame.
3 = As 2, but the noise generator is free-running. This setting will produce a shimmering effect on static images that may be distracting.

#

internally, it operates on rgb888, and then it will dither down to the configured depth, as it fills the FIFO with scanlines

manic glacierBOT
slender iron
#

ah, I see

buoyant lagoon
#

ive RE'd that part of the hardware, so i could expose it in circuitpython easily

#

but hdmi is already 8bit
most dsi i assume are 8bit?
composite i assume is 8bit, but its analog, hard to tell without a scope and test patterns

#

so only DPI really needs it

#

and then youve lost all your gpio

slender iron
#

we're just starting to support DPI

manic glacierBOT
slender iron
#

most of what we support is 565 over spi or 8080

buoyant lagoon
#

there are 2 ways to do DPI

#

1: just use the legacy firmware options to setup DPI in config.txt, then it will show up as one of the hvs channels in my code

#

2: i know how to bringup DPI fully from scratch, so circuitpython could do all of the timing params

buoyant lagoon
#

you configure how many clock cycles long the setup/strobe/hold/pace periods are

#

then you just load DMA up with a buffer, and point it at SMI, and let it rip!

slender iron
#

HDMI is the most interesting part of the pi for me anyway

#

but nice to know we could accelerate other displays too

buoyant lagoon
#

ive been struggling with hdmi init on the open firmware

#

but if your leaning on the closed firmware, its easy to hijack things after init is done

#

later tonight/tomorrow, i need to go over the tilegrid and group apis, write some example code, and then try throwing a group at my driver

#

also, how might i allow full rgba8888 or yuv images? the hw supports them

#

displayio.CIRCUITPYTHON_TERMINAL, ah nice, so thats just exposed to python

idle owl
#

@buoyant lagoon Do you want to be added to the circuitpythonistas role? I dont' know if we've already offered it, or if you're even interested. But you've been super active lately with CP. The role means you get pinged twice a week about the Monday Community meetings. And your name shows up purple. Let me know if you'd like to be added! No worries if not!

buoyant lagoon
#

sure, add me

idle owl
#

Done!

buoyant lagoon
#

ive been listening in on those meetings, but somehow missed yesterdays

idle owl
#

Next week is Tuesday, FYI.

buoyant lagoon
#

ah, maybe it was last monday that i missed

idle owl
#

@buoyant lagoon The role also lets you speak during the meetings, if you're ever up for participating.

slender iron
orchid basinBOT
manic glacierBOT
manic glacierBOT
buoyant lagoon
manic glacierBOT
#

Just a small taste of difficulty. The RP2 places IOPORT and Cortex-M0+ registers above the 2G line in its address map. As it is, memorymap.AddressRange() treats its start argument as signed integer, so it will not accept an address above the 2G line. Digging deeper, unsigned integer argument interpretation and validation isn't implemented in runtime. This problem also affects the NRF53 series.

manic glacierBOT
#

I do have :

  • an esp32-c3 qt py
  • a magtag (esp32-s2)
  • a circuit playground express (not esp but that would be my test group)

but all of them would require a bit of soldering/desoldering with my current code.

I'm currently trying to get a crashing code that does not need actual hardware connected. I mostly still need to get rid of the nfc pn532. I tried to replace the pn532.read_passive_target() with spamming somewhat similar spi command but it does not crash. So my next step is ...

manic glacierBOT
manic glacierBOT
buoyant lagoon
#

oh, on the subject of hdmi audio

you need to encode the audio data into a IEC958 format, which supports up to 8 PCM channels
then configure a DMA block to copy it into a hw fifo

other then the encoding step, that sounds very similar to how i2s and pwm would do audio on most other boards

does circuitpython have any pre-existing framework for managing the dma and ringbuffer, and keeping the buffer topped up with audio data?

karmic skiff
#

Is there an equivalent of the Decimal class?

manic glacierBOT
#

Instead of changing the IDF could we enable CONFIG_SPIRAM_USE_CAPS_ALLOC? I'm not sure how many other modules will start trying to use PSRAM then but maybe that's ok. We don't really need it all for CP.

I was reluctant to do this because it looked like a big change (we like to just manage the PSRAM ourselves so we always have a nice big contiguous heap). As far as I understand it, we have to change that if we change this setting. If I'm wrong about that then I'd be happy to change it.

mental nexus
manic glacierBOT
#

Protomatter matrix library 1.6.1 (c9c1189) addresses some issues with ESP32-S3. Drive strength compilation issue is fixed, pixel clock is slightly reduced to help w/visual glitches.

The prior release, 1.6.0, if not already in use by CircuitPython, addresses M4 issues. Also a slight pixel clock reduction, and additionally the clock duty cycle is semi-configurable -- perhaps this could be exposed as a named arg in Python, and ignored if not supported by arch. See _PM_setDuty() comments in th...

orchid basinBOT
manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 8.2.4 on 2023-08-22; ESP32-S2-DevKitC-1-N4R2 with ESP32S2
Board ID:espressif_esp32s2_devkitc_1_n4r2
UID:0740D17F678D

Code/REPL

# https://learn.adafruit.com/adafruit-ov5640-camera-breakout/lcd-mirror-demo
from debugfun import breakpoint
import busio
import digitalio
import espcamera
import board
import displayio
from adafruit_st7789 import ST7789
import time


flash = digitalio.DigitalInOut(board.IO45...
orchid basinBOT
#

Hi, not sure I have ever seen a piece of code on circuitpython.org.

Maybe the best place could be to create a simpletest_code.py next to the board definition in circuitpython repo, as suggested in the first in the weed topic of this week meeting:
https://github.com/adafruit/adafruit-circuitpython-weekly-meeting/blob/main/2023/2023-08-28.md

Now that would be the first time it is ever done, there might be discussion on the best place to put that.

I would also insist on putting a bit of code...

orchid basinBOT
#

When I was posting this PR, I didn't see the code snippet as example code, I was thinking it was part of a board caution or warning. I had a feeling that some other boards did something similar when there was a minor revision that swapped a pin or two out or for the boards that don't have native USB.

Now that I've thought about it more, and poked around on circuitpython.org, I think those notes/cautions were probably added to the Adafruit product pages. I'm thinking for community provided...

manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 8.2.4 on 2023-08-22; Adafruit Feather ESP32-S3 Reverse TFT with ESP32S3
Board ID:adafruit_feather_esp32s3_reverse_tft

Code/REPL

import board
import digitalio
import busio
import asyncio
import binascii
import os
import time
import ssl
import socketpool
import wifi
import adafruit_minimqtt.adafruit_minimqtt as MQTT
from adafruit_httpserver import (
    Server,
    REQUEST_HANDLED_RESPONSE_SENT,
    ...
manic glacierBOT
buoyant lagoon
#
frame 6
frame 29
frame 52
frame 12
frame 35
frame 58
frame 18
#

i modified the C code, to expose the hw frame counter from the 2d core on the rpi

#

but just the framebuffer (which isnt accelerated yet), adds enough latency to prints, to make it skip over 20 frames, lol

#
frame 0
frame 4
frame 7
frame 11
frame 14
frame 18
frame 22
frame 25
frame 29
frame 32
frame 36
frame 39
frame 43
frame 46
frame 50
frame 53
frame 57
frame 61
#

disabling some code in board_init() removed that, and now its better

buoyant lagoon
#
delta: 3 scanline: 945/1024 overhead: 0.0359802 next: 0.05
delta: 3 scanline: 964/1024 overhead: 0.0360107 next: 0.05
delta: 3 scanline: 936/1024 overhead: 0.0370178 next: 0.05
delta: 3 scanline: 920/1024 overhead: 0.0359802 next: 0.05
delta: 3 scanline: 889/1024 overhead: 0.0370178 next: 0.05
delta: 3 scanline: 855/1024 overhead: 0.0369873 next: 0.05
#

and with a few more lines of code, it reports where the scanout is within a frame

manic glacierBOT
#

Resolves #8334 by adding memorymap support to the RP2 port. Also makes these additional changes:

  • Changed memorymap hal function prototypes to use size_t rather than uint32_t arguments, allowing prototypes to work with different port word sizes.
  • Changes memorymap.AddressRange() start argument from signed to an unsigned int to allow ranges to be specified anywhere in the entire port address map. Added support to the runtime for unsigned int arguments.
  • Added wrap-around checking for m...
manic glacierBOT
manic glacierBOT
manic glacierBOT
manic glacierBOT
lone sandalBOT
manic glacierBOT
manic glacierBOT
#

Looked into pin drive strength (i.e., current) support on several (but not all) of the microcontrollers supported by CP and they break down like this:

  • Unsupported. Broadcom, cxd56.
  • Normal/Stronger. Atmel samd.
  • One of four values. Espressif, RP2.
  • Standard/High with logic 0/1 specificity. nrf

Any thoughts generalizing all this variation?

manic glacierBOT
#

@makermelissa on the 9.0 alpha 1.8 build or 8.2.4? I've since switched to the alpha build which works much better. I can go back to 8.2.4 for more testing if needed.

I still get intermittent hard faults on 9.0 alpha but it only when saving code.py. A hard reset usually fixes it and will run indefinitely. I do not get hard faults while the program is running, only happens on file save (using Mu). A good example of the hard fault during save can be seen in the live demo on this weeks [8...

manic glacierBOT
manic glacierBOT
#

@eightycc Note that the drive strength for PIO was reduced since the previous discussion, to fix a specific use. (I was worried when I saw that, but fortunately it doesn't seem to affect my project too much.) https://github.com/adafruit/circuitpython/pull/7558

So it seems what I was saying in the OP is not the case, and we really need the general drive strength API, as you already started discussing over here: https://github.com/adafruit/circuitpython/issues/1270#issuecomment-1703614207

manic glacierBOT
manic glacierBOT
#

Hi everyone,

I would like to connect a keyboard to a Raspberry Pico (RP2040) with the data+ and data- cables of the USB and check the content of an input string.
From the circuitpython forum I know that recently it has been implemented the usb_host library to use the PIO of the Pico and I tried using my Pico W board with the following script:

import board
import usb_host
import sys

h = usb_host.Port(board.GP0, board.GP1)

while True:
    print(sys.stdin.read(1))

H...

manic glacierBOT
#

Hi Could you explain what you mean by that? What is "it" in your sentence? Does the firmware prevent using pins on the nRF##?

Using an external ble hardware uses pins of the main board, which in most of my projects is not possible, since those pins are already in use. Also, the external hardware takes up space which further complicates the setup.

Furthermore, it makes no sense to work around the above constraints since the pico already has the hardware capability and even Micropython...

manic glacierBOT
manic glacierBOT
manic glacierBOT
#

Is there a way to collect the .bin artifacts for the Makerfabs 7" build or the HACKtablet?

The HACKtablet artifact isn't being built by Jeff's PR yet but I've attached the one I've built. I don't see the Makerfabs artifact, I think you normally find the artifacts by clicking on the "checks" tab on this page and then select "Build CI", the artifacts would be at the very bottom but I only see [adafruit_esp32s3_rgb_tft_experiment](https://github.com/adafruit/circuitpython/suites/15737310922...

#

Keep in mind that the latest build from main isn't compatible with .mpy files so you need to grab .py versions of any libraries you want to use.

Here's the code I'm using to initialize the display.

import displayio
import framebufferio
import dotclockframebuffer
import board

displayio.release_displays()

fb=dotclockframebuffer.DotClockFramebuffer(**board.TFT,**board.TIMINGS800)
display=framebufferio.FramebufferDisplay(fb)
manic glacierBOT
#

Hi,

I just started with CP9.0.0 and usb_host on my PicoW yesterday and also came across that issue. I fixed it by switching the Pico PIO state-machines for USB D+ and D- and got it running....sort of. Here's the diff:

diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c
index 93d19acd6..6b9aeae55 100644
--- a/ports/raspberrypi/common-hal/usb_host/Port.c
+++ b/ports/raspberrypi/common-hal/usb_host/Port.c
@@ -122,8 +122,8 @@ usb_h...
manic glacierBOT
manic glacierBOT
manic glacierBOT
#

I've been thinking about this and have some suggestions for how this might be done:

  • Use generic language to describe drive strength, for example: STRONGEST/STRONG/WEAK/WEAKEST or HIGHEST/HIGH/LOW/LOWEST. For ports that support only two levels, HIGHEST/HIGH would map to high level and LOW/LOWEST to the low level. For example, 8 mA drive for the RP2 would be DriveStrength.HIGH. Adding a fifth level DEFAULT would set DriveStrength to the reset value for the port. Ports that do not support s...
manic glacierBOT
#

Thanks jepler and RetiredWizard. I got the makerfabs display working with the binary and the awesome ESP webserial uploader.

Agreed on the difficulty to find GitHub artifacts, I clicked and clicked but didn't know the secret pathway to find what I was looking for.

Special thanks RetiredWizard for the setup instructions for the display, these worked perfectly on the makerfabs binary too.

![IMG_8699](https://github.com/adafruit/circuitpython/assets/33587466/730bc0cb-eea2-4dd4-b06b-c...

manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 8.2.4 on 2023-08-22; Adafruit Feather ESP32-S2 TFT with ESP32S2
Board ID:adafruit_feather_esp32s2_tft
UID:487F305FFE63

Code/REPL

class SimpleClass:

    def __init__(
        self,
        param1: int,
        param2: str,
    ):
        self.param1 = param1
        self.param2 = param2

    @property
    def property1(self):
        print(dir(self)) # <-- This is the line that causes the board to c...
#

CircuitPython version

Adafruit CircuitPython 8.2.4 on 2023-08-22; Adafruit Feather ESP32-S2 TFT with ESP32S2
Board ID:adafruit_feather_esp32s2_tft
UID:487F305FFE63

Code/REPL

class ParentCLass:
    def __init__(self, param1: int, param2: int):
        self.param1 = param1
        self.param2 = param2

    @property
    def property1(self):
        return (self.param1, self.param2)


class ChildClass(ParentCLass):
    def __init__(self, param1: i...
manic glacierBOT
#

Weird. I just tried this on Adafruit CircuitPython 8.2.4 on 2023-08-22; Saola 1 w/Wroom with ESP32S2 and after typing in the class above in REPL paste mode, instantiating SimpleClass in the REPL, and doing dir() if a few ways I get weird results, but no crash:

>>> simple_object = SimpleClass(1, "2")
>>> dir()
['simple_object', 'SimpleClass', '__name__', '__file__']
>>> dir(simple_object)
['__class__', '__init__', '__module__', '__qualname__', '__dict__', 'param1', 'param2', ...
manic glacierBOT
manic glacierBOT
#

CPython supports so called positional only parameters (PEP 570) with as the name say, cannot be passed using their name.
They are useful when a function e.g. accepts a value that has not special meaning, it is simply a value.

Example:

def some_function(positional_only, /, positional_or_keyword, *, keyword_only):
    pass

some_function(1, 2, keyword_only=3)
some_function(1, positional_or_keyword=2, keyword_only=...
manic glacierBOT
#

Sorry guys, I can't find the modified library any more :(
I experimented with the sensor for an afternoon, decided it was too much work and my student would just have to use an older ST sensor. The board with that code on it then probably went to another student when I ran short on QT Pys. That's one downside of having the source directly on the device I guess.

So, I am back to the L4CD lib and example, with the minor modifications of setting the I2C to 1 MHz. Works only up to 2.2 m. I ma...

brazen hatch
spare jacinth
#

Is that FTP from or to (or both) CircuitPython? πŸ‘€

brazen hatch
#

ftp server on CP

#

client on my thinkpad

#

I will get a ftp client on CP too, but much later

#

tbh, I don't see why this couldn't be a built-in module for the big boi boards.
it's not that complicated tbh..

manic glacierBOT
#

...or use:

context = ssl.create_default_context()
context.load_verify_locations()

with a CA string or .pem file

...or use:

context = ssl.create_default_context()
context.load_verify_locations()

with a CA string or .pem file

I'm admittedly not the sharpest python tool in the chest, but I assumed I'd be able to pass a bundle .pem file to load_verify_locations but I get an error about processing CRT (8015)....

brazen hatch
#

I will first make it fully in python and then make it in C

#

Then I will πŸ™‚

#

It's honestly simplier than telnet

crimson ferry
#

storage.remount? SD?

brazen hatch
#

It just uses the os funcs in it's current form, so it will work with anything mounted

#

I didn't get as far as to write just yet..

#

I am doing the LIST command right now

#

I implemented ACTIVE, and will finish LIST with it.

#

then I will implement GET with PASV

#

In the core implementation we should prolly not have as many options as I have here though.

#

Maybe just PASV or it being should be settable by settings.toml

midnight ember
#

I was going to ask if that was on CP but then I was like nah no way. That's pretty amazing. πŸ‘

buoyant lagoon
#

i saw mention before that the text console is a TileGrid
is it a bitmap being displayed in one, or is it one tile for every single character and then letting displayio draw the fonts?

brazen hatch
#

LIST is done, now onto modesetting and pasv

#

And I haven't even entered jank mode. It's all decent code thus far.

buoyant lagoon
#

πŸ˜„

brazen hatch
#

modesetting done

#

Can now be viewed over dolphin

#

Speedrun any% ftp

buoyant lagoon
#

nice

manic glacierBOT
#

This is probably a duplicate of

There may be two separate problems.

First, dir() is implemented differently in CircuitPython than in desktop Python. In particular, calling dir() on an object actually retrieves all of the object's property values, which can have side effects. When a property getter calls dir() on the object, this creates an unbounded recursion. I did not find this explicitly documented anywhere so it m...

#

I found that when I increased the amount of 'grace area' in the stack check from 1kB to 2kB I didn't reproduce the problem anymore. There's no particular justification for this value that I could find; it depends how much "additional stuff" can be placed on the stack subsequent to a call to mp_stack_check and I don't think there's any simple way to calculate the maximum such value.

diff --git a/main.c b/main.c
index 94a3feac6b..d0727beb53 100644
--- a/main.c
+++ b/main.c
@@ -1...
manic glacierBOT
random junco
#

<@&356864093652516868> Reminder - there is no meeting today due to the Labor Day Holiday in the US. Meeting is normal time tomorrow at 2pm EST / 11am PST. See you then!

upper ocean
#

Hey folks, does anyone here use VS Code when developing with circuitpython? I keep running into an issue where, due to the size of the circuitpython repo (ie all of its submodules), VS Code will often spawn dozens of rg processes whenever I do anything with the editor that could trigger indexing, searching, referencing, etc. It can sometimes get so bad that it completely maxes out my cpu and freezes VS Code.

I'm sure I can fix it by configuring VS Code to ignore certain paths, but thought I'd first check if anyone else here has run into this issue and already has a decent workaround? Thanks!

mortal kernel
mortal kernel
upper ocean
upper ocean
manic glacierBOT
manic glacierBOT
#

I had another look. Modifying the initialization parameters for the CX gave me about 270 cm maximum in the default mode For long range, it seems the histogram mode is required, and this by necessity requires a bunch of code from the library. Working manually, I don't see a python rewrite happening. The code is way too long (even single files) for the AI code rewriting tools I could find. So, I am back to either compiling the C code and using that or just not using this soft-sensor (reminds me...

lone sandalBOT
manic glacierBOT
manic glacierBOT
#

I had another look. Modifying the initialization parameters for the CX gave me about 270 cm maximum in the default mode. For long range, it seems the histogram mode is required, and this by necessity requires a bunch of code from the library. Working manually, I don't see a python rewrite happening. The code is way too long (even single files) for the AI code rewriting tools I could find. So, I am back to either compiling the C code and using that or just not using this soft-sensor (reminds...

atomic summit
#

Hi folks. Based on there being new commits i the 8.2 branch, can I safely assume there's be an 8.2.5 or higher before 9.0 ?

manic glacierBOT
tulip sleet
atomic summit
tulip sleet
#

easier to merge from 8.2.x to main so we've been preferring 8.2.x instead of doing a lot of backports

atomic summit
#

Nah, it was merged already a while ago 😦

manic glacierBOT
#

I had a combination of different causes that at led to my issue:

  • a not so clean solder-point on the D+ cabling => more solder for a more reliable connection
  • a very nitpicky USB device (a Micro RP2040 from SBcomponents) => other boards work just fine (that SBcomponents board works just fine with the examples from Pico-PIO-USB - so it's something within circuitpython that behaves different)
  • invoking usb_host.Port(...) in boot.py doesn't work => invoking it from code.py does work

Not...

manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 9.0.0-alpha.1-25-g000d22f25 on 2023-08-30; VCC-GND YD-ESP32-S3 (N16R8) with ESP32S3

Code/REPL

import wifi
from socketpool import SocketPool
from adafruit_requests import Session

pool = SocketPool(wifi.radio)
_socket = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
_socket2 = pool.socket(pool.AF_INET, pool.SOCK_STREAM)

_socket.bind(("0.0.0.0", 20))
_socket.listen(1)
_socket2.bind(("0.0.0.0", 21))
_socket...
manic glacierBOT
manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 8.2.4 on 2023-08-22; micro:bit v2 with nRF52833

Code/REPL

from microbit import *

while True:
    display.show("Coucou !")

Behavior

Serial console setup

Auto-reload is off.
Running in safe mode! Not running saved code.

You are in safe mode because:
CircuitPython core code crashed hard. Whoops!
Hard fault: memory access or instruction error.
Please file an issue with your program at github....

manic glacierBOT
#

Had to tweak the close(). Then it works on raspberrypi, but espressif gets stuck in _socket2.accept() (client times out on connect).

import wifi
from socketpool import SocketPool

pool = SocketPool(wifi.radio)
_socket = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
_socket2 = pool.socket(pool.AF_INET, pool.SOCK_STREAM)

_socket.bind(("0.0.0.0", 20))
_socket.listen(1)
_socket2.bind(("0.0.0.0", 21))
_socket2.listen(1)
a = _socket.accept()
b = _socket2.accept()
a[0].cl...
manic glacierBOT
manic glacierBOT
#

Hey - I am not using circuitpython but I have the same issue with micropython AND even with plain Arduino Blinky Sketch.
If I am running Micropython it was working perfectly fine for like 2 weeks and then this issue appeared. I factory-resetted the device multiple times and tried re-soldering USB connections and everything. I know it is not the right place but maybe someone can help anyway. Here are some facts:

  • Device worked perfectly fine for ~2 weeks
  • REPL started to disappear
  • a...
manic glacierBOT
#

@justmobilize the library has 37k lines in total. Not complicated code, but a complicated structure. It's not impossible, sure, but I will certainly not do it :)
I thought it might be a good job for an AI, just parsing all the things and putting it into Python syntax, maybe even simplifying a bit. But it seems the volume is just too much currently.

@MarkJB: I feel like it's a dead end, but here are my changes: https://github.com/veloyage/Adafruit_CircuitPython_VL53L4CD/commit/f3f42bc076...

manic glacierBOT
#

watch -n0.2 'netstat | grep "board-ip-here"' to monitor all connections and their status.
The second one, as stated above is stuck at SYN_WAIT.
It could just be a oopsie, sending the SYN response to the wrong connection for all I know.

Regarding asyncio, I drafted this:

import asyncio
import wifi
import socketpool
from sys import stdout

conn1 = None
conn2 = None

async def tcpserver1():
    s = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
    s.bind(("0.0.0.0", 20))...
brazen hatch
#

And now we escale the situation to a safe mode issue..

#

I made a reproducible safemode with it..

manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 9.0.0-alpha.1-25-g000d22f25 on 2023-08-30; VCC-GND YD-ESP32-S3 (N16R8) with ESP32S3

Code/REPL

import wifi
from socketpool import SocketPool

pool = SocketPool(wifi.radio)
_socket = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
_socket.bind(("0.0.0.0", 20))
_socket.bind(("0.0.0.0", 21))

print("Accepting 1")
_socket.listen(5)
a = _socket.accept()
print("Accepting 2")
b = _socket.accept()
print("Accepted...
brazen hatch
#

I just woke up and decided to break esp today.

manic glacierBOT
#

Got backtrace:

? 0x420968c6:0x3fceaf60 0x420976a1:0x3fceaf80 0x420992f6:0x3fceafb0 0x4209e32a:0x3fceb020 0x420a1fee:0x3fceb050 0x42093d91:0x3fceb070
0x420968c6: tcp_pcb_num_cal at /home/bill88t/git/circuitpython/ports/espressif/esp-idf/components/lwip/lwip/src/core/tcp.c:1875
0x420976a1: tcp_pcb_num_cal at /home/bill88t/git/circuitpython/ports/espressif/esp-idf/components/lwip/lwip/src/core/tcp.c:1888
 (inlined by) tcp_alloc at /home/bill88t/git/circuitpython/ports/espressif/esp-idf/...
manic glacierBOT
manic glacierBOT
#

But PASV doesn't work with sequential connection to the control port, then the data port?

PASV tl;dr workflow explanation:

  1. Open port 21 for control.
  2. User connects on 21.
  3. User authenticates.
  4. User sends the PASV command to start the data socket.
  5. Server decides on a port to use, and opens it up (.listen()).
  6. Server sends the RFC defined formatted reply to the client over the control connection.
  7. Client immediately connects to the ip:port the server sent in step 6...
manic glacierBOT
#

New discovery!

If the web workflow is disabled, you can do 2 binds.
So in reality you cannot do 3 binds.

import wifi
from socketpool import SocketPool
from sys import exit

try:
    wifi.radio.connect("Thinkpood", "REDACTED")
except:
    pass
if not wifi.radio.connected:
    print("No wifi")
    exit(0)

pool = SocketPool(wifi.radio)
_socket = pool.socket(pool.AF_INET, pool.SOCK_STREAM)
_socket.bind(("", 20))
_socket.listen(1)
_socket2 = pool.socket(pool.AF_INET,...
manic glacierBOT
#

First, dir() is implemented differently in CircuitPython than in desktop Python. In particular, calling dir() on an object actually retrieves all of the object's property values, which can have side effects. When a property getter calls dir() on the object, this creates an unbounded recursion. I did not find this explicitly documented anywhere so it may be that we should improve documentation in this area. This difference is inherited from Micropython and we aren't likely to lif...

manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 8.2.4 on 2023-08-22; Adafruit ItsyBitsy nRF52840 Express with nRF52840

Code/REPL

This code demonstrates the issue:

import busio
import board
import time

uart_hw = busio.UART(board.TX, board.RX)

while True:
    print("Spin Loop")
    time.sleep(0.5)


For comparison, this code works OK. The only difference is the use of the `board.UART()` singleton:
```python
import board
import time

uart_hw ...
brazen hatch
#

Github moment

#

Anybody taking PR-by-email?

#

jk

manic glacierBOT
#

I did plently of esp debugging.
I only however managed to down as far as lwip_accept in ports/espressif/common-hal/socketpool/Socket.c:272.
With esp_log we can see there, the 2nd/3rd socket not being accepted.
I tried going deeper, but the internal logging of lwip doesn't get printed no matter what I do.
Importing esp_log, is a mess I cannot figure out.

I will have to leave it you you guys from there on out.
(Perhaps C3 can prove itself not being a paperbrick and help with some jt...

onyx hinge
#

Ahoy <@&356864093652516868> -- as yesterday was a US holiday, we're having the meeting TODAY in about 70 minutes. Take a moment to add your notes, and then if you can join us in the voice chat. https://docs.google.com/document/d/1P6AwndR-BBldT7jIzLpO72B9nSmnz7VJexO96ttI2O0/edit?usp=sharing

slender iron
buoyant lagoon
#

ahhh, that will be an interesting stress test then

brazen hatch
#

I wonder, maybe it would be even better if I permit wifi conn (and only wifi), on reloads.
Cause now it only runs that stuff on boot.

#

@crimson ferry Opinion?

crimson ferry
#

I think raspberrypi works that way?

#

or, at least wifi survives a reload

buoyant lagoon
#

assuming a basic 80x24 terminal, thats 1920 characters
and you need 7 words per sprite
which is 13k words, wont fit!

buoyant lagoon
slender iron
#

13k words won't fit where?

buoyant lagoon
#

the displaylist is only 4096 words long

#

and you need 7 words for each sprite/tile

#

so if you had one sprite for each character in the text console, you would run out after ~580 characters

slender iron
#

πŸ‘

#

could do one bitmap/sprite per tilegrid

buoyant lagoon
#

that would kinda negate the benefits of hw accel

#

so i was thinking, only something with a high tile count, like the text console, would pre-render into a bitmap

#

and things with a low tile count, can be fully hw accelerated

slender iron
#

ya, that's fine

#

the one tile case is most common I think

buoyant lagoon
#

ive also got another issue

#

how do i know when the tiles in a tilegrid have changed?

#

ive not found any hooks yet, and dont know if its timer based?

#

so ive just modified my test code.py to re-run board.DISPLAY.show() for each update

crimson ferry
#

With Web Workflow enabled, I think the assumption is: always connected, though robust apps do need to manage the connection since there are ways it can fail that the core does not recover from.

brazen hatch
#

K, imma go make it reconnect on reloads and add that to the docs too.

crimson ferry
#

other core devs probably have more reasoned ideas about this

brazen hatch
#

Well, I am here and I can be pinged. I can also be pinged in the issue directly.
And it's not like I will (or can) merge it on my own.
The only reason it's not connecting upon reload, is because of the delay of starting up allothat

#
// TODO: Do our own scan so that we can find the channel we want before calling connect.
// Otherwise, connect will do a full slow scan to pick the best AP.

// We can all connect again because it will return early if we're already connected to the
// network. If we are connected to a different network, then it will disconnect before
// attempting to connect to the given network.
#

Yea, the slow scan, is a slow scan.

slender iron
buoyant lagoon
#

so i would need to hook that function? but i want some tilegrids to render to a bitmap, while others update the hw accel

slender iron
#

I assume you'd reimplement it with your accelerated version of displayio

buoyant lagoon
#

but that doesnt cover the high tile count stuff, like the framebuffer

#

also bbl

manic glacierBOT
tulip sleet
#

@onyx hinge we can hear you

onyx hinge
#

give me a moment please

ember iris
#

If you're using a webbrowser sometimes refreshing the page helps when you can't hear someone

#

Tuesday meetings are weird πŸ˜„

midnight ember
#

off by one error but not an error

manic glacierBOT
slender iron
random junco
gilded cradle
#

I can read

slender iron
#

I'm here too

slender iron
#

πŸ‘

random junco
#

I shared the wind chimes with Anne too, such a cool project

midnight ember
plucky tulip
midnight ember
#

Very cool @random junco !

#

taking pictures of matrix panels is hard because of scan lines

random junco
#

quite!

midnight ember
#

congrats on the new office space @slender iron !

slender iron
midnight ember
#

Thank you for hosting @onyx hinge

ember iris
#

Thanks all! have a good week!

onyx hinge
#

@tulip sleet @slender iron do you want to take a moment to set a time to talk about 1.20? I am out FRIDAY, I'm busy much of THURSDAY afternoon, so today or tomorrow would be good if it's feasible for you two as well

slender iron
tulip sleet
onyx hinge
#

OK, can we do it at around 16:00 ET / 15:00 CT / 13:00 PT ? I think that's about 80 minutes from now.

slender iron
#

i should be able to and will let you know if I'll be late

cedar veldt
#

Hi, I think I remember reading somewhere that the 9.x library bundle is waiting on something specific, is that right?

brazen hatch
#

1.19 has gone through, causing mpy's version to change, but 1.20 will change it again

#

so libs won't be built for 9.x till that happens

midnight ember
#

and retooling mpy-cross to work with the new stuff they're doing.

brazen hatch
midnight ember
#

yup, without mpy there won't be any publicly released libraries, so at a minimum have to wait for that to happen.

#

you can still work on libraries in .py format if that's your goal

cedar veldt
#

Thanks, I see!

cedar veldt
midnight ember
#

with all the changes they're doing that would be a moving target as they update mpy-cross.

cedar veldt
midnight ember
#

alpha for the developers not for users, not even close to user ready and things will very much change before a 9.0 rc

cedar veldt
#

Ah so it could still happen?

brazen hatch
tulip sleet
onyx hinge
#

Here is the notes document for next Monday’s CircuitPython Weekly meeting. It is at the normal time of 11am Pacific / 2pm Eastern here on Discord. Everyone is encouraged to attend! Please add your hug reports and status updates even if you’ll be attending the meeting - it’s super helpful! If you are unable to attend but would still like to include updates, feel free to include them in the notes and we’ll read them off during the meeting. Hope to see you there! <@&356864093652516868> https://docs.google.com/document/d/1M51kkQVUANGjwe9rhnOsSs7U6e_x8YQp_7LXxGnx3Xg/edit?usp=sharing

midnight ember
#

i usually beta test releases looking for bugs, it's pointless for me to even try with 9.0 alpha builds currently because things will change too much between now and whenever they start merging and folding everything in for 9.0... it kind of hasn't even really started yet. the s3 bucket stuff is still using all 8.x libraries.

manic glacierBOT
midnight ember
#

because it's all still on 8.x mpy and esp-idf. it's too soon.

cedar veldt
manic glacierBOT
manic glacierBOT
brazen hatch
slender iron
#

back to my desk now

brazen hatch
#

My PR's are in. I am finally done.

#

btw, now I can do pasv with web-workflow off
If I make a wrapper in ljinux that closes the telnet shell and immediately opens ftpd...
hehe
if then I detect the quit and swap back to telnet..

slender iron
#

@tulip sleet ready to chat?

tulip sleet
onyx hinge
manic glacierBOT
#

I figured I'd give this a shot as at least from the outside the LYWSD02 seems awfully similar. It displays the same data and it seems to share the same UUID https://github.com/adafruit/Adafruit_CircuitPython_BLE_LYWSD03MMC/blob/8bc79c6fcb72699c159129e8a1b0d27a5eaec9f7/adafruit_ble_lywsd03mmc.py#L66

So I put adafruit_ble_lywsd03mmc.py in my libs directory and copied over the content from ble_lywsd03mmc_simpletest.py to my main.py.
The only thing I changed was change line 19
https://gi...

manic glacierBOT
#

Jepler, just a few things I remember were issues specific to the S3. Perhaps you have resolved them.

  • I got tearing because the ESP-IDF is set to automatically trigger a refresh from some internal timer. I had to turn off the IDF’s auto refresh and created a function where I could allow CP to call for refreshes. This may have been include in v5.0 but I have not verified. That added another issue where typically CP (expecting the display to have its own memory) doesn’t call for a refres...
onyx hinge
manic glacierBOT
#

If I understand correctly, the raspberrypi behavior (wifi connection surviving reload with or without Web Workkflow) will change if MicroPython fixes issue 9505 (and we merge it), but this PR would auto-[re]connect wifi on either port if Web Workflow is enabled.

@anecdata cyw43 is a persistent object we just never reset.
Our implementation is just not bothering disconnecting it, so it persists.
That's all there is to that.
Our picow wifi stuff is all of our own, not really taking...

manic glacierBOT
#

Now that auto-connect can be used with or without web workflow, and wifi.radio.stop_station() has been implemented on raspberrypi, we should consider disconnecting wifi across reload in the non-Auto-Connect case. This would make raspberrypi code behave more like espressif code.

In the Auto-Connect case, the presumption is that wifi should stay up as much as possible, and wifi will now survive reloads. But in the non-Auto-Connect case, it's counterintuitive for...

#

Hi, apologies and I should have updated this issue here but I do get this regularly:
CircuitPython core code crashed hard. Crikey!
Hard fault: memory access or instruction error

Although I'm only developing the software for the ESP32-S3 at the moment and not using it properly so I assumed that this is a regular occurance and was a known problem being worked on. I also have a lot of python code in at the moment and it's difficult to upload it all but I have no problem with doing that if y...

#

The adjectives I am not so sure about, in case we have a case of even more choices. But how about 0 for the default or "normal" level, 1, 2, 3, etc., for higher, and -1, -2- 3, etc. for lower? Anything out of range gets set to the max for the board, and you can query. The API could also return the mA value separately, and maybe you could even set it that way. But it has to be a small implementation to fit on the smaller boards.

I am not sure there always is a "default", but maybe there i...

#

Pushing back for these reasons: Overall, memorymap is a "beware, there be dragons here" sort of feature, so I prefer having a comprehensive view of the RP2 memory map and leaving its use to the discretion of the programmer. The other ports (espressif and nrf) that support memorymap do map RAM/SRAM/DRAM. Finally, it's useful to have a view into memory as a poor person's low-level debugger.

manic glacierBOT
orchid basinBOT
mortal kernel
#

I'm hitting a problem with the 8.2.x branch. There are several uncommited changes on the branch which is a bit odd. Specifically, I'm encountering a problem building mpy-cross that looks related to "modified content" in tools/huffman. Wondering if anyone can lend me a clue?

#

I may have borked my forked repository by first forking just main and then several days later adding the 8.2.x branch from the upstream repository?

#

(.venv) rabeles@ub2004:~/Development/circuitpython-8xx$ make -C mpy-cross
make: Entering directory '/home/rabeles/Development/circuitpython-8xx/mpy-cross'
Use make V=1, make V=2 or set BUILD_VERBOSE similarly in your environment to increase build verbosity.
Traceback (most recent call last):
File "/home/rabeles/Development/circuitpython-8xx/mpy-cross/../py/maketranslationdata.py", line 30, in <module>
import huffman
ModuleNotFoundError: No module named 'huffman'
make: *** [../py/py.mk:274: build/genhdr/compression.generated.h] Error 1
make: Leaving directory '/home/rabeles/Development/circuitpython-8xx/mpy-cross'
(.venv) rabeles@ub2004:~/Development/circuitpython-8xx$ git status
On branch 8.2.x
Your branch is up to date with 'origin/8.2.x'.

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
(commit or discard the untracked or modified content in submodules)
modified: frozen/circuitpython-pcf85063a (modified content)
modified: frozen/circuitpython_ef_music (modified content)
modified: frozen/circuitpython_picoed (modified content)
modified: frozen/mixgo_cp_lib (modified content)
modified: frozen/pew-pewpew-lcd (modified content)
modified: frozen/pew-pewpew-standalone-10.x (modified content)
modified: lib/quirc (modified content)
modified: ports/espressif/esp-idf (modified content)
modified: ports/raspberrypi/lib/PicoDVI (modified content)
modified: ports/silabs/tools/slc_cli_linux (modified content)
modified: ports/stm/st_driver/stm32f4xx_hal_driver (modified content)
modified: tools/huffman (modified content)

no changes added to commit (use "git add" and/or "git commit -a")
(.venv) rabeles@ub2004:~/Development/circuitpython-8xx$

stuck elbow
mortal kernel
#

I did make fetch-all-submodules after checking out 8.2.x.

stuck elbow
#

if you enter the submodule directory and do git status, it will tell you exactly what's changed

#

you can do git reset --hard in that directory to force the files to the exact content of the checked out version

#

it will delete any changes that are not commited

mortal kernel
stuck elbow
#

you don't need to fork it, just clone it again to a new directory

manic glacierBOT
#

CircuitPython version

Adafruit CircuitPython 8.2.4 on 2023-08-22; Adafruit QT Py ESP32-S3 no psram with ESP32S3

Code/REPL

import os
import supervisor
import wifi

print(f"Connected={wifi.radio.connected} IP={wifi.radio.ipv4_address}")
if os.getenv("WIFI_SSID") and not wifi.radio.connected:
    print(f"Connecting...")
    wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD"))
print(f"Connected={wifi.radio.connected} IP={wifi.radio.ipv...
mortal kernel
manic glacierBOT
#

Yes, almost anytime there's contention for the access to the SPI bus the display will shift and tear, but, it self heals. we're hoping IDF 5 will improve things, and will fine tune then.

I didn't encounter the problem you're mentioning with the lack of automatic refresh. the "relax_on_idle" flag does need to be set to false to get automatic refresh, but that seemed to be all that was necessary.

manic glacierBOT
manic glacierBOT
#

Umm. This is a scenation I not only tested, but also works on my boards..

Simplifying to:

import wifi
import supervisor
from time import sleep

wifi.radio.enabled = 0

sleep(3)
supervisor.reload()

Does not produce any hardfaults..

And the example code needs fixing:

import os
import supervisor
import wifi
from time import sleep

print(f"Connected={wifi.radio.connected} IP={wifi.radio.ipv4_address}")
if os.getenv("CIRCUITPY_WIFI_SSID") and not wifi.radio...
manic glacierBOT
manic glacierBOT
#

@gfghjjk Thank you for working on the Russian translation.

Please note that due to technical limitations, it's not OK to use characters like β€” (em dash) in the Russian translation. Instead, use the ASCII equivalent - (called dash or hyphen)

The reason is that, for every translation where it's possible, we want to have a simple way to reduce the Unicode value of every character to a single byte. For the russian translation, this is done by letting 0-127 be the ASCII equivalent, and value...

manic glacierBOT
#

This is something Adafruit is getting interested in at the moment too: Ladyada has shown a prototype dot clock LCD board with the esp32-s3 which uses PCA9554 as an I/O expander including for buttons and for a low-speed SPI bus.

For early testing it was OK for us to just bit bang the SPI bus from Python code but we'll want something better.

This makes me think that it's important to generalize the I/O expander. For now I think it's probably OK to hard code the I2C bus, chip type(s) and a...

#

Here's an example of how introducing a "protocol" will help. Instead of having a separate preprocessor ifdef for each possible kind of IO expander, it would become a call like return mp_proto_get(obj, MP_QSTR_Pin) != NULL. This protocol would be implemented by microcontroller.Pin, as well as the cyw43 pin, the tca9555 pin, and the PCA9554.

The protocol structure would have a number of function pointers, for getting & setting value, direction, & pull.

Then the common_hal_digitalio_digi...

manic glacierBOT
#

Hi @jepler

This is something Adafruit is getting interested in at the moment too: Ladyada has shown a prototype dot clock LCD board with the esp32-s3 which uses PCA9554 as an I/O expander including for buttons and for a low-speed SPI bus.

Oh, that is exciting to hear!

For early testing it was OK for us to just bit bang the SPI bus from Python code but we'll want something better.

This makes me think that it's important to generalize the I/O expander. For now I think it's ...

manic glacierBOT
#

The adjectives I am not so sure about, in case we have a case of even more choices. But how about 0 for the default or "normal" level, 1, 2, 3, etc., for higher, and -1, -2- 3, etc. for lower? Anything out of range gets set to the max or min for the board, and you can query. The API could also return the mA value separately, and maybe you could even set it that way. But it has to be a small implementation to fit on the smaller boards.

I'd rather standardize on fewer choices that are po...

#

Is it possible that I have a faulty board?

I doubt it. These errors are usually a software problem.

If it isn't then I'll try and get something that is repeatable and upload the code here.

A small, reproducible code snippet is always best for debugging.

Is there more information about the problem that I can do with CircuitPython to get it to output more details?

You can build a version of CircuitPython that will output the ESP-IDF logging over UART and it'll include a bac...

#

I'd rather standardize on fewer choices that are portable. LOWEST and HIGHEST are the first two obvious choices. One for fast signalling and one for driving LEDs and such. We'd default to HIGHEST.

If LOWEST and HIGHEST are the only names being used, then I'd prefer just LOW and HIGH.

I suggested signed integers to avoid LOW, LOWER, LOWEST kind of naming, which can be head-scratching, since it's not all that quantitative. So for instance -100 and 100 are definitely "lowest" and "highes...

#

If we had the space, I'd suggest also including DigitalInOut.drive_strengths, which would return a tuple of port-specific available drive strengths, in mA. Then the code can choose. Setting DigitalInOut.drive_strength would then have to either set a valid drive strength exactly, or (alternatively, a more forgiving API) would set the nearest one (or floor or ceil).

#

I have added this board to main branch but noticed only circuitpython 9.x.x build is available And also no direct download and installation option on page. Userd have to find that build from s3.

This board is comparatively new and manufacturer tergets beginner audience. So trying to make new users journey as smooth as possible.

To make this board available for circuitpython 8.2.x trying to backport it.

thanks.

#

Not sure that HIGHEST is the best choice for the default. Consider the RP2 which has an IOVDD_MAX of 50mA. It's easy to exceed this driving just a few LEDs at 12mA which would underpower QSPI and break XIP.

People shouldn't be using drive strength to limit LED current. It doesn't work that way, e.g. setting 4mA drive strength doesn't actually limit the current to 4mA, you just get a voltage drop which may or may not limit current by much, depending what you're driving.

So you could ...

manic glacierBOT
manic glacierBOT
#

the only artifact is mpy-cross?

No idea man. Actions sus.

How does this work on ESP? This shared supervisor code shouldn't need port-specific defines.

@tannewt This PR exists to just make raspberrypi act the same way as espressif.
The espressifwifi connection is not preserved upon reload, however theraspberrypi` one is, since the object is persistent. With this change, both will close their wifi connection on reload.

manic glacierBOT
#

Running some experiments to pin current on RP2 (Adafruit Feather RP2040) I'm seeing some strangeness in the programmed values in PADS_BANK0. Here's a dump after I've programmed D5, D6, D9-D12 (GPIO7-GPIO12) for output and driven them high:

Pad 0: 92
Pad 1: 92
Pad 2: 92
Pad 3: 92
Pad 4: 72
Pad 5: 72
Pad 6: 72
Pad 7: 92
Pad 8: b2
Pad 9: 92
Pad 10: 92
Pad 11: 92
Pad 12: 92
Pad 13: 92
Pad 14: 92
Pad 15: da
Pad 16: 70616430
Pad 17: 3
Pad 18: 0
Pad 19: 3
Pad 20: 0
Pad ...
manic glacierBOT
#
  • Fixes #8299

Use the new repo https://github.com/adafruit/certificates as a submodule instead of https://github.com/adafruit/nina-fw. This new repo provides a revised roots.pem that fixes the problems introduced in 8.2.2 when the nina-fw cert bundle was updated.

idle owl
#

@tulip sleet If I have the Metro M7, with 8MB of QSPI flash, running CircuitPython, about how much flash memory is left over for me to do things with?

#

The RP2040 with 16MB flash had about half left. Is "half" correct, or is it a static amount?

tulip sleet
#

have to look, but you can just see how large CIRCUITPY is by asking the host OS to tell you

idle owl
#

Oh ok

#

I haven't gotten that far yet, so I figured I would ask.

#

I can verify it later. Or leave it out.

tulip sleet
#

i can plug one in and see

idle owl
#

That also works

tulip sleet
#

about 6.2MB

idle owl
#

Thank you

tulip sleet
idle owl
#

I said "around 6"

manic glacierBOT