-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Protomatter: Integrate with CircuitPython #2706
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
It's still not ready for inclusion, but I've heavily reworked this PR. See the initial comment for much more information, including a checklist of known problems. The one I'm worried about is the problems with auto_refresh / surviving soft reset, because the design requires this Python Protomatter class to work. This design may simply not be workable, so hopefully @tannewt has some ideas about how to restructure it so it can work. Rotation is "probably a shallow bug" but I haven't looked at it yet. |
The 64x32 display isn't very useful for showing the console -- you get only 2 rows by 8 chars. Because of the less than useful nature of the console, I wonder if the work could be accepted in this state; and later on we can come back and work on it when we have framebuffer lcds large enough for it to matter. @tannewt ? |
@jepler What did you try when getting it to work across soft resets? Seems like you are close and having it will be useful when we support multiple panels in the future. |
I'm aware that I need to preserve
The hardest parts of preserving across a reset are specific to Protomatter and don't seem to be things that apply for true hardware framebuffers. |
I presently define _PM_allocator to call m_malloc. Here are its uses within protomatter:
|
Did you try moving the three protomatter allocations? If that works, we could add an api or simply go with hacking it. |
This branch is going back into a heavily unstable state, I'm pushing some clearly not working code as a shortcut to transfer it between a couple of my computers. |
actually the unstable version went in a branch that is not pull-requested yet. it's https://github.com/adafruit/circuitpython/compare/master..jepler:protomatter-displayio-v2 What's changed so far is:
Next steps:
I am going to choose a fixed limit of 30 RGB pins + 6 address pins, which fits in a multiple of 4 bytes. For the breakouts that adafruit sells, 6+4 is the actual number used. This is more work than I anticipated initially, but I feel like the pieces are starting to come together and my understanding of displayio and the allocators is improving as an additional benefit. |
I believe that generally speaking the code works at this point and it is ready for style review, though before it's done-done we need to get the protomatter changes merged upstream and add support for nRF on our end. |
I should explain that the test changes are not really related, see micropython#4000 for background. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have those test changes integrated already. Do you think we just messed up the merge?
(I still have a bunch of review to do on this.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking this on! I've add a number of comments. I like the directions you are going by using a "framebuf as a bus". I think there is some work to do on the Framebuf stuff to slim it down and simplify it. I think having brightness on it makes sense but it should then delegate to the framebuffer provider to implement it. A 24bit TTL display will have a backlight pin but a protomatter display will need to adjust what it outputs.
As far as the backlight, it can delegate to the underlying framebuffer (a protocol function that is permitted to be NULL), or it can use a pin as now as a fallback. protomatter uses 0 to mean pause, nonzero to mean not paused; it doesn't scale RGB values to emulate intermediate brightness levels. I have a feeling that adding a fixed off time might give better results, so if that's important we should talk to @PaintYourDragon about it. If we thought at least 2 framebuffers would do backlight via RGB pin as regular Displays do, then having the code in FramebufferDisplay will be a net reduction of copypaste backlight code. |
@tannewt I've made changes for many of your review comments, and addressed some of the others inline. Please take another look when you have a chance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as the backlight, it can delegate to the underlying framebuffer (a protocol function that is permitted to be NULL), or it can use a pin as now as a fallback. protomatter uses 0 to mean pause, nonzero to mean not paused; it doesn't scale RGB values to emulate intermediate brightness levels. I have a feeling that adding a fixed off time might give better results, so if that's important we should talk to @PaintYourDragon about it.
If we thought at least 2 framebuffers would do backlight via RGB pin as regular Displays do, then having the code in FramebufferDisplay will be a net reduction of copypaste backlight code.
I like the idea of FramebufDisplay having the brightness knobs (brightness and auto_brightness) but think the protocol should implement it and take the args on construction for the pin. We could have FramebufDisplay scale the RGB values like PixelBuf does but agree adding a fixed off time would give a better result. So, I'd removed backlight_pin for now.
|
||
//| .. method:: write(buf) | ||
//| | ||
//| Transmits the color data in the buffer to the pixels so that they are shown. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about calling this refresh() to match the other display types? I get that this would be needed if using protomatter without displayio.
protomatter_protomatter_swapbuffers(self_in); | ||
} | ||
|
||
STATIC void protomatter_protomatter_deinit_void(mp_obj_t self_in) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sounds similar to what common_hal is used for, C data structures rather than Python ones. Could you use the common_hal variants in the protocol?
These wrapper functions don't make much sense to me because the user of the protocol could just throw away the return too.
@tannewt I think I fixed all the issues you raised, except for this one. For some reason there's not a spot to reply inline, so ... Protocols vs common_hal: Protocols take mp_obj_t as the first argument, while common_hal takes a type-specific object pointer. On reflection, I prefer getting the compile-time type checking that the protocol function pointer is of the right type, even if it means introducing an intermediate function to do the casting of the argument. (I think I did it with casts when I did audio sample protocols) As always, I can change it if you feel strongly. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'm fine with the wrapper functions.
One comment on the API. I glanced at your Learn guide draft and had thoughts. Is there a library I should look at too?
Thanks!
|
||
//| :class:`~_protomatter.Protomatter` displays an in-memory framebuffer to an LED matrix. | ||
//| | ||
//| .. class:: Protomatter(width, bit_depth, rgb_pins, addr_pins, clock_pin, latch_pin, output_enable_pin, *, doublebuffer=True, framebuffer=None) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just peeking at your guide for how I can test this. I think we want these all to be kwarg-only args because they are either numbers, pins or lists of pins. Reading the code doesn't help with what is what. The current positional arguments can be required and have no default.
I'd also take in the height even though it's implicit in the address pins. It can make the framebuffer smaller than the available address pins and can also validate enough address pins are given.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I can make them kw-only.
I can make it so that height, if specified, is checked against the expected number. I'm not sure of the use case of creating a 16 line display on a 32 line panel, though.
however, the raspberry pi lib for driving these displays (I think that's the one) can drive multiple displays wired in "zigzag" fashion. In that case, the relation between the WxH of the screen is decoupled from the true width of the display. Protomatter C library doesn't support this (yet, not sure if planned).
There is a wrapper module, but it's not uploaded anywhere yet. It may just end up committed in the guide repo at this time, because I'm not sure there's time to get it into the library package on the timeline in which we want the guide to appear. Looks like I can't get the current content at this computer I'm at, but it's close to this:
There's also a |
should rename "depth" to "bit_depth". The 4 value was just in the Arduino example, gives 4096 colors (16 effective levels per primary). |
POSIX specifies that text files end in a trailing newline
- bump supervisor alloc count by 4 (we actually use 5) - move reconstruct to after gc heap is reset - destroy protomatter object entirely if not used by a FramebufferDisplay - ensure previous supervisor allocations are released - zero out pointers so GC can collect them
Co-Authored-By: Scott Shawcroft <[email protected]>
Co-Authored-By: Scott Shawcroft <[email protected]>
Just setting the timer handler to NO_INTERRUPT doesn't stop the interrupt from occurring.
This may have been contributing to fragmentation of the supervisor heap
Per @tannewt, this area "sees more churn", so it's probably the right choice here
The numbered error from the underlying library is not helpful for beginning users
- rename oe_pin -> output_enable_pin - improve and reorganize docstrings - rename swapbuffers->refresh - rename "paused" -> "brightness", change semantics slightly - common_hal several functions - clarify why the common_hal routines can't be used directly in the protocol's function pointers - whitespace cleanups - remove prototypes for nonexistent functions
…eight checking They're not readily distinguishable by type. I also added the requested height optional parameter; this is checked against the computed one. It's not feasible to use this parameter to artificailly reduce the number of used rows, because changes in the underlying C protomatter library would be required. Finally, I added a better error message when the number of RGB pins was not what was expected.
.. change the in-rom palette to be in RGB565 order
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:)
This pull request:
It anticipates that a new module adafruit_protomatter will be used to combine the two into a displayio-using led matrix driver.
Current known problems:
The code I've been using to drive it is an adaptation of the "1D Wave Simulation" ulab demo: https://gist.github.com/jepler/5b11e292193f1fcb602900ff50e8944d