Skip to content
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

How to deal with custom SoC/SoM implementations #165

Open
timonsku opened this issue Jan 31, 2021 · 20 comments
Open

How to deal with custom SoC/SoM implementations #165

timonsku opened this issue Jan 31, 2021 · 20 comments

Comments

@timonsku
Copy link
Contributor

I'm creating a PCB based on the RPI Compute Module 4 and have ICs attached to it that I would like to expose in a CPY fashion as a pre-configured peripheral as part of the board definition.
So this would be a sort of flavour of an existing supported board ("bare" CM4).

This is something I have not seen addressed so far but would require a solution for in order to offer a good Blinka/CPY experience.
For me its specific to the CM4 but in general this holds true I guess for any other SoM of any of the supported SoCs (BeagleBone f.e.). I'm not sure if a generic solution can exist though.

Personally I would prefer it if an EEPROM solution like used for Pi HATs could be avoided as I feel these add unnecessary bulk. My board does not have an EEPROM connected.
My favourite solution would be to have a text file in /boot that contains an ID string that overrides whatever https://github.com/adafruit/Adafruit_Python_PlatformDetect/blob/master/adafruit_platformdetect/board.py determines.
This would be quite easy to do by a user manually or by an install script.

This is something that can also be done by a user on their computer or a host side install script after flashing a generic image in case of a Pi image (and others, I think BB also worked that way) as the boot partition is readable on any OS. So that would make it possible to modify an existing SDCard/mounted eMMC to work with a specific board instance without creating a custom image for people to flash which I think would be very bad thing to have in the ecosystem if board creators feel they need to maintain their own Raspbian flavor just to have a user friendly experience (which would eventually become outdated when they stop maintaining).

@makermelissa
Copy link
Contributor

That seems like a good solution. You could also place something in /etc instead of /boot. If no file is found, it can default to the Pi CM4.

@makermelissa
Copy link
Contributor

makermelissa commented Jan 31, 2021

I'm thinking about how armbian has a /etc/armbian-release, we could do something like /etc/cm4-release

@ladyada
Copy link
Member

ladyada commented Jan 31, 2021

the only reason i'd say look at an EEPROM is there may some way to auto-load device tree overlays via eeprom (i may be mistake) which could load your DTS required for hardware

@timonsku
Copy link
Contributor Author

I'm thinking about how armbian has a /etc/armbian-release, we could do something like /etc/cm4-release

Yea that is also a sensible place! Boot just seemed like a nice place as other important settings are usually there like the config.txt so it might be a more familiar place for users (and the accessibility via a computer when mounting the image but that is not a terribly important thing to have)

@timonsku
Copy link
Contributor Author

the only reason i'd say look at an EEPROM is there may some way to auto-load device tree overlays via eeprom (i may be mistake) which could load your DTS required for hardware

I was thinking about this but I was kinda scared of the scenario of wanting to make changes to the device tree definition later on and then having either a binary or string pointer hard coded in my hardware that will take precedence unless specifically disabled in config.txt. So I foresee a lot of confusion and user errors be possible that way, I'd rather be sure that the latest version of my install process guarantees that every user will work with the latest version. Of course I could just add the disable into that install process but then the EEPROM also becomes kinda pointless after the first change anyway.

The CM4 also comes with its own EEPROM but this thinks of a scenario where you sell hardware bundled with the CM4 that you flashed during manufacturing and the user not using their own.

@tannewt
Copy link
Member

tannewt commented Feb 1, 2021

This is a similar problem to SparkFun's micromod and I think the right answer is for the board level to be at the module boundary. The board module would map between the module pinout and the IC's pinout. Then, you'd have a library for the carrier board that maps the module pinout to the board's pinout. This separation ensures that the carrier board mapping works for any module.

So, I don't think Blinka should detect Piunora, it should only know it's a CM4 and what variant. Then, have a library for Piunora that folks use.

@timonsku
Copy link
Contributor Author

timonsku commented Feb 1, 2021

That is a good point!
Makes maintenance of variants easier as well. The only problem I would see it the module board could already make assumptions about peripherals and assigns them a different use/config than the carrier library would. It would be important to ensure that the module board has no such assumptions and leaves everything unconfigured so that no conflicts arise.
The question that comes up for me there then is whether it should all just be convention or if the concept of module and carrier should be introduced explicitly. Which could be handy to also handle things like compatibility checking. Maybe a future version of that module form factor is not 100% compatible with my carrier due to a quirk.

Another reason for maybe introducing these concepts is for boards that are in this in-between state of being a dev board and being a module. The Pi Pico is a good example. It is a dev board but is also sold in reels of tape for pick and placing.
That would mean you would likely see carriers using the pico as an implementation of the controller and not as a dev board. In this case you might want to have some defaults pre-configured though, not so if it is used as a module instead.

@tannewt
Copy link
Member

tannewt commented Feb 2, 2021

A module's software should only make assumptions that are dictated by the module spec. I don't know where to formalize the carrier idea. Maybe circuitpython.org can have another grid for carriers that link to the corresponding library.

One existing example is our featherwing library: https://github.com/adafruit/Adafruit_CircuitPython_FeatherWing

@timonsku
Copy link
Contributor Author

timonsku commented Feb 2, 2021

Well in the case of something like the CM4 that is a completely open ended piece of hardware and wholly defined by the carrier. Other things like MicroMod might be more specific here but I would not say this is not the norm. SoM are intended to be a light abstraction layer on top of a SoC and not define an application in any way (e.g. a full board).
The issue comes if you treat a module also as board, like it can be the case with the Pi Pico. In that case the board might want to setup standard peripherals on certain pins when you view it as a dev board but this would be problematic if I implement it as a module as I then stand in conflict with my carrier specific library.
If that differentiation can't be made then I'm not sure we can then treat carriers any different from boards and rather as any other implementations of the specific SoC/MCU e.g. a board.

I can see how that can get problematic at scale with such a massive system like MicroMod where everything is supposed to work in any combination of SoMs and carriers and having lots of each.
But then again we also have a massive amount of boards that are a SAMD21 implementations with just differing peripherals usages and I'm not sure if they really are that different from that just because there is an added interconnect.

@tannewt
Copy link
Member

tannewt commented Feb 2, 2021

Well in the case of something like the CM4 that is a completely open ended piece of hardware and wholly defined by the carrier.

The CM4 defines things like flash, ram and connectivity though too. Do we have one build for each carrier and CM4 variant combination?

But then again we also have a massive amount of boards that are a SAMD21 implementations with just differing peripherals usages and I'm not sure if they really are that different from that just because there is an added interconnect.

I'm not sure what the right thing is. The library approach has a nice clean separation of concerns but could limit what the software could auto-init.

@timonsku
Copy link
Contributor Author

timonsku commented Feb 2, 2021

The CM4 defines things like flash, ram and connectivity though too. Do we have one build for each carrier and CM4 variant combination?

I guess here is where the difference between Blinka and CPY comes in as storage and RAM is handled by the OS so blinka does not have to care about such differences as CPY has to. If it were not for the different HW ID there is no difference between a CM4 and a Raspberry Pi 4 SBC. The only thing that needs to be supported is the SoC.

It would not work out for me if I could not rely on the fact that I'm free to use peripherals as I wish. E.g. if the underlying board inits some pins as SPI by default even though I want to use them for I2C.
I do appreciate the library approach and it would make it a lot easier to update for me than if it were bundled with Blinka / CPY.

We might not need to explicitly have the concept of a carrier (the way to handle them on cpy.org can be separate I think) but maybe its enough if a library can ask for the board to not initialize any peripherals when importing?
Here my lack of Python skill shows as I don't know if that is possible with Python modules or the way that the board object works, which is probably also quite different between Blinka and CPY?

But my idea is that a user would not import the board at all when using a carrier but only import the carrier library and the library takes care of importing everything correctly and exposing its own pin aliases and default peripherals.

In that case another option could be a function call to the board object to de-initialize/free everything that the board might have created, if that can't be specified on import to not happen to begin with.

@makermelissa
Copy link
Contributor

The way it is now is it uses the chip like we have defined for the Pi 4 and the board is a combination of the SoM and IO Carrier board which work for many people, especially since Raspberry Pi provides a schematic of this and expects you to just remove what you won't use for custom carrier boards. If there is a custom carrier board that differs significantly, I think it makes sense to add it as a new "board" and I think the easiest way to tell the platformdetect that it's different is to create some kind of ID file like mentioned earlier in this issue. This is a very similar approach to the one that many boards using the popular AllWinner H3 have taken with Armbian.

@timonsku
Copy link
Contributor Author

timonsku commented Feb 3, 2021

Yea makes sense. I'm open to both approaches really, as long as I can provide an easy solution to users :)

@tannewt
Copy link
Member

tannewt commented Feb 3, 2021

I guess here is where the difference between Blinka and CPY comes in as storage and RAM is handled by the OS so blinka does not have to care about such differences as CPY has to.

Yup, I'm thinking ahead to how we'd put CircuitPython on it. :-)

I'm still not sure we want board to equal carrier though. It'll break whenever we have a difference in modules that require a different build. This is more obvious now with MicroMod but I wouldn't be surprised to find CM4 compatible modules that aren't broadcom based in the future.

But my idea is that a user would not import the board at all when using a carrier but only import the carrier library and the library takes care of importing everything correctly and exposing its own pin aliases and default peripherals.

Yup, that'd be my expectation to. Just like we have microcontroller.pin now in CPU but no one uses it afaik.

@timonsku
Copy link
Contributor Author

timonsku commented Feb 5, 2021

Yup, I'm thinking ahead to how we'd put CircuitPython on it. :-)

oh I see :)

I'm still not sure we want board to equal carrier though. It'll break whenever we have a difference in modules that require a different build. This is more obvious now with MicroMod but I wouldn't be surprised to find CM4 compatible modules that aren't broadcom based in the future.

Yea thats fair. Again as long as I can ensure that I can have a clean slate for my library without the user taking specific action in their code I'm good (other than me dictating what your default import should look like). Can gladly handle this via libraries. Asynchronous maintenance is kinda good here as a carrier will likely be more feature rich than a plain board and might need updates more frequently than CPY releases.

Yup, that'd be my expectation to. Just like we have microcontroller.pin now in CPU but no one uses it afaik.

ah what is this microcontroller.pin feature? I don't think I have seen that

@makermelissa
Copy link
Contributor

ah what is this microcontroller.pin feature? I don't think I have seen that

It's related to the original MicroPython support.

@tannewt
Copy link
Member

tannewt commented Feb 5, 2021

ah what is this microcontroller.pin feature? I don't think I have seen that

It's related to the original MicroPython support.

I don't think MicroPython has it. We present pins with their chip level names in addition to the board names:

Adafruit CircuitPython 6.2.0-beta.1-66-g7f5d8b8ac-dirty on 2021-02-04; Adafruit Feather RP2040 with rp2040
>>> import microcontroller.pin
>>> print(dir(microcontroller.pin))
['__class__', 'GPIO0', 'GPIO1', 'GPIO10', 'GPIO11', 'GPIO12', 'GPIO13', 'GPIO14', 'GPIO15', 'GPIO16',
'GPIO17', 'GPIO18', 'GPIO19', 'GPIO2', 'GPIO20', 'GPIO21', 'GPIO22', 'GPIO23', 'GPIO24', 'GPIO25',
'GPIO26', 'GPIO27', 'GPIO28', 'GPIO29', 'GPIO3', 'GPIO4', 'GPIO5', 'GPIO6', 'GPIO7', 'GPIO8', 'GPIO9']
>>> import board
>>> print(dir(board))
['__class__', 'A0', 'A1', 'A2', 'A3', 'D0', 'D1', 'D10', 'D11', 'D12', 'D13', 'D24', 'D25', 'D4', 'D5', 'D6',
'D9', 'I2C', 'MISO', 'MOSI', 'NEOPIXEL', 'NEOPIXEL_POWER', 'RX', 'SCK', 'SCL', 'SDA', 'SPI', 'TX']

The names refer to the same objects under the hood.

@makermelissa
Copy link
Contributor

Ah, I did not know this. :)

@timonsku
Copy link
Contributor Author

timonsku commented Feb 5, 2021

I don't think MicroPython has it. We present pins with their chip level names in addition to the board names:
The names refer to the same objects under the hood.

Oh thats a great feature!

@makermelissa makermelissa transferred this issue from adafruit/Adafruit_Blinka May 10, 2021
@makermelissa
Copy link
Contributor

Transferring to Platform Detect as this is more of a detection issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants