Skip to content

Add in a esp_my9291_write() function #5702

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

Closed
wants to merge 2 commits into from

Conversation

goatchurchprime
Copy link

I've finally achieved my ambition to put Micropython into a lightbulb!

These AiLights actually have a ESP8285, but the full Micropython with the mqtt-stack works fine. The lighting controller is a my9291 chip with no documentation about its protocol, and the only implementation of it in Arduino-world by bitbanging.

I put the function into the same places as the esp_neopixel_write() function, which also is implemented by some some similar timed bitbanging. I added some delays to keep the same time as the working arduino code. Bitbanging directly from Micropython does not work: If the pulses are longer than 4microseconds the chip does not accept the signal.

This is not the ideal function; it was originally meant to be 5 parameters, but the macro MP_DEFINE_CONST_FUN_OBJ_5 does not exist and it would have taken too many edits on the base code to put it in.

So I'm putting this pull-request out here for comments about whether the function is adequate or in the right place, or whether a more general purpose function for bitbanging things like my9291 could be made (if there are any other chips like this).

@jimmo
Copy link
Member

jimmo commented Feb 27, 2020

This looks good, thanks @goatchurchprime! However as with any addition to the firmware the additional code size needs to be weighed up against how generally useful it is (especially if the functionality can already be implemented in Python).

I've used the (similar, but more forgiving) MY9221 from a micro:bit before (with the driver written in Python). A very simple bit-banging driver worked fine for a single one, but it wasn't possible to get the timing right for multiple cascaded ones. I was able to make it work by using the hardware SPI peripheral for the data transfer, and then disabling the SPI and doing the latching pulses manually with GPIO.

Just a general comment on perhaps a way forward for stuff like this though where you need custom C functionality that maybe shouldn't go into the main firmware. In #5118, @mcauser added board definitions to the ESP8266 port. This allows you to define your own custom board (including any Python and C code that you want included into the firmware). Importantly, the board definition can be in your own separate repo, so that way you don't have to be managing patches on top of the main repo.

make BOARD=AILIGHT BOARD_DIR=/path/to/my/repos/boards/AILIGHT

To make a module from a .c file in your board dir, I'm fairly sure you can use MP_REGISTER_MODULE to make sure it's found (I hope this works...if it doesn't it probably should, in the same way that user c modules does).

@mcauser
Copy link
Contributor

mcauser commented Feb 27, 2020

Here's two I prepared earlier:
https://github.com/mcauser/microbit-my9221
https://github.com/mcauser/micropython-my9221

The my9291 is 4 channel and can drive 1x RGB(W) LED.
The my9221 is 12 channel and can drive 3x RGB LEDs or a 10-segment.

I was going to make a more generic micropython-my92xx driver, as there's a bunch of similar ones with supporting different channel counts. Porting it to C sounds like fun too.

@goatchurchprime
Copy link
Author

Well, my PR has served its purpose by finding the other people who know about this driver!

I definitely couldn't get bitbanging to work from Python with the chip in this lightbulb. Maybe I'd have to buy a bare chip and work with it directly as it is very inconvenient to do it in situ (the lights don't come on when it's not powered and in the socket).

HSPI can't work because it's not on the right pins.

SoftSPI toggles the SCK pin twice per bit, so unfortunately can't be used because this requires a single toggle on DCK for each DI bit.
https://github.com/micropython/micropython/blob/master/drivers/bus/softspi.c#L75

SoftQSPI has a function called nibble_write() that bitbangs 4 pins at once.
https://github.com/micropython/micropython/blob/master/drivers/bus/softqspi.c#L52
It may be possible to hack the protocol by entering each pin into the constructor twice (to make up 4) and then giving it exactly the right bit string to create the appropriate bitbanging sequence. This would be inefficient as it would take one byte per bit:
Suppose the nibble is (DI,DI,DCK, DCK), then the sequence 110 would be encoded as:

11001111 11111100 00000011

A lightbulb control string is 8 bytes (2bytes each for RGBW), so would encode in 64 bit/bytes, which would be fine. Unfortunately, the QSPI library seems only available in the stm32 boards. (Why is that?)

I think a super-generic realtime bigbanging library function would be the way to go -- if there were many more chips like this that can't be shoehorned into a known protocol. (Actually, isn't this how DMA often gets used -- by DMA-ing onto the pinmask word?)

tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Dec 15, 2021
Exclude ci checks and tests from building boards
@dpgeorge
Copy link
Member

I'll close this PR. I think the best way to maintain this code (if you want to keep it alive on the Internet) is to make it into a custom esp8266 board definition with a custom my9291 module. This is now much easier with MP_REGISTER_MODULE(), and USER_C_MODULES. See also https://github.com/micropython/micropython-example-boards

@dpgeorge dpgeorge closed this Jun 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants