RFC: Hardware API: finalising machine.Pin

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: RFC: Hardware API: finalising machine.Pin

Post by Damien » Sat Oct 22, 2016 5:10 am

tannewt wrote: First, I agree the duplication between value() and low()/high() is unneeded. Furthermore, why is value a function? Shouldn't it be a property? Its weird to me that a function reads and writes based on its arguments. However, `pin.value = True`, `last_pin_state = pin.value` and `pin.value = not pin.value` (for toggle) make more sense to me.
There are many cases of this in the API. Eg machine.freq([value]). See https://github.com/micropython/micropython/issues/378 for background discussion on this point.
The second use is for Digital IO which is `pin = machine.Pin("D13", machine.Pin.OUT); pin.high()`. Instead of changing the constructor arguments to say how you are going to use the pin, why not make it consistent with I2C and make a DigitalWrite object `led = machine.DigitalWrite(machine.Pin("D13"))`?
But then you'd need DigitalRead objects and you wouldn't be able to change the mode of the object from read to write. Pin's are objects which can be useful on their own (eg read/write logic levels), and also used to create other entities (eg i2c, spi). Similarly i2c can be used to create yet higher-level entities, like a driver.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: RFC: Hardware API: finalising machine.Pin

Post by deshipu » Sat Oct 22, 2016 9:09 am

tannewt wrote: First, I agree the duplication between value() and low()/high() is unneeded. Furthermore, why is value a function? Shouldn't it be a property? Its weird to me that a function reads and writes based on its arguments. However, `pin.value = True`, `last_pin_state = pin.value` and `pin.value = not pin.value` (for toggle) make more sense to me.
This is because pin.value() has side effects, both as input (it can change at any time without any code assigning to it) and as output (assigning to it has effects outside of just storing a new value).
tannewt wrote: Second, it feels to me like there are two main uses of Pin that I think can be split. The first use is as an identifier for a hardware peripheral backed protocol such as I2C to know which pin to use for its I2C such as `I2C(machine.Pin("SCL")...)` In this case the peripheral code will change the underlying pins state and essentially claim it.

The second use is for Digital IO which is `pin = machine.Pin("D13", machine.Pin.OUT); pin.high()`. Instead of changing the constructor arguments to say how you are going to use the pin, why not make it consistent with I2C and make a DigitalWrite object `led = machine.DigitalWrite(machine.Pin("D13"))`? That removes the need to unify alternate functions and modes between ports. Instead, the port can handle the appropriate setup in the use class (DigitalWrite, I2C and SPI etc) and a port specific Pin can expose the exact API of the port separately.
That would force all the code that actually uses the pins to allocate additional objects, which is quite costly on MicroPython.

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: RFC: Hardware API: finalising machine.Pin

Post by deshipu » Sat Oct 22, 2016 9:31 am

pfalcon wrote:Let's discuss something. I wonder if I'm the only one who ever wondered why there's no LED class in hardware API?
I guess the same reason why there is no "Piezo" class, or "Button" class, or "Potentiometer", or "Motor" -- the place for those is in the device driver code, which should use the Hardware API to implement them. Note, however, that there are "apa102", "neopixel" or "dht"-related functions, but they had been moved into random modules, because of the rigidity of the API. Also, while there is no "Ping" class, there is a time_pulse_us function, which is needed for implementing the drivers for the ultrasonic distance sensors.

I don't think it is practical to put into the API drivers of all peripherals that are present in some MicroPython-based boards and devices.

For me, the main role of the hardware API is not to become some beautiful cathedral of abstraction over all possible hardware, but a tool that lets me control a range of common devices from Python code. Bonus points if the resulting Python code is concise, readable, efficient and, well, "pythonic".

I am all for a LED class, if you think it's needed (and also a Button class), but I don't think its place is in the hardware API.

pfalcon
Posts: 1155
Joined: Fri Feb 28, 2014 2:05 pm

Re: RFC: Hardware API: finalising machine.Pin

Post by pfalcon » Sat Oct 22, 2016 11:41 am

deshipu wrote:
pfalcon wrote:Let's discuss something. I wonder if I'm the only one who ever wondered why there's no LED class in hardware API?
I guess the same reason why there is no "Piezo" class, or "Button" class, or "Potentiometer", or "Motor" -- the place for those is
Yeah, but you missed my point. What I'm saying in my last message (http://forum.micropython.org/viewtopic. ... =10#p15016) is: "there's no LED class, and as soon as we start considering how to implement it (inside or outside of machine module), we face an issue of inverted signals".

So, how do we want to deal with it? The current answer is "oops, we didn't think about it!" (Yeah, even the epic thread at https://github.com/micropython/micropython/issues/1430 doesn't have any occurrence of word "inverted"). If we happen to handle inverted signals on the level of Pin class, then there's no special need for LED, Button classes in the first approximation at all - using Pin with user's ability to use inverted signal would work quite well.

So, question of supporting configurable inversion on the Pin level is very decisive actually - by answering that we'll know whether we want to support: 1) really lightweight and close to the actual hardware (as in: "least common denominator hardware") interface, or 2) more involved interface with more functionality (including "emulated" functionality) and internal state.

I'm the vocal proponent of approach #1. But the issue of inverted signals is important user-facing issue which needs to be addressed somehow, and then if it's decided that it needs to be addressed on Pin level, many of my arguments would lose their value.
Awesome MicroPython list
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/

Damien
Site Admin
Posts: 647
Joined: Mon Dec 09, 2013 5:02 pm

Re: RFC: Hardware API: finalising machine.Pin

Post by Damien » Sat Oct 22, 2016 1:12 pm

I have created a PR to update the machine.Pin docs to closely match the Hardware API definition in the wiki. See here: https://github.com/micropython/micropython/pull/2546

pfalcon
Posts: 1155
Joined: Fri Feb 28, 2014 2:05 pm

Re: RFC: Hardware API: finalising machine.Pin

Post by pfalcon » Sat Oct 22, 2016 3:54 pm

Damien wrote:I have created a PR to update the machine.Pin
Thanks. So that answers the question whether we should put "finalised" description into the docs (vs wiki) and who'd be doing that ;-). I've added some inline comments, but it would be nice to discuss general approach too. So, we know the problem with docs: for a long time wipy port was a limiting force, which caused docs to be correct for wipy and incorrect for all other ports which upgraded to newer Hardware API. Well, my commit https://github.com/micropython/micropyt ... 7e81f94cc5 broke the ice, and now docs can be correct for more ports, possibly at the expense of being not fully correct for wipy. Well, it would be nice to talk out our position in that regard explicitly. And kind of depends on on the state of cc3200 port in general. Which is: over last half-year, there was only 30 commits to it, and only one from the port maintainer. As an extra unconfirmed bit of info, judging only from KickStarter updates, LoPy and either Pycom products may be based on outdated (well, WiPy adhoc) Hardware API.

Another questions is whether we want to move towards a single documentation set for all ports (as was raised previously), and specific approach to that (some options are in inline comments to the PR above).
Awesome MicroPython list
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/

chrismas9
Posts: 152
Joined: Wed Jun 25, 2014 10:07 am

Re: RFC: Hardware API: finalising machine.Pin

Post by chrismas9 » Sat Oct 22, 2016 5:48 pm

Let's discuss something. I wonder if I'm the only one who ever wondered why there's no LED class in Hardware API?

And here's the question - do we want to deal with inverted signals? And using word "signal" actually suggests the right way to deal with it from OO perspective:

LED = machine.Signal(machine.Pin(A0), inverted=True)
+1 on adding an LED API.
So, question of supporting configurable inversion on the Pin level is very decisive actually - by answering that we'll know whether we want to support: 1) really lightweight and close to the actual hardware (as in: "least common denominator hardware") interface, or 2) more involved interface with more functionality (including "emulated" functionality) and internal state.

I'm the vocal proponent of approach #1. But the issue of inverted signals is important user-facing issue which needs to be addressed somehow, and then if it's decided that it needs to be addressed on Pin level, many of my arguments would lose their value.
I was involved in the lengthy discussion about the original machine API development. My recollection was that machine would provide low level support for the MCU hardware, but not for on board or off board peripherals. So -1 for adding LED API to machine. Where do you draw the line at adding peripheral drivers to machine? Every board will have different on board peripherals so every port will have a different machine API. I think it will be too hard define a standard peripheral API that won't be broken by the next more feature packed version of that peripheral. For example if LED class were copied from pyb how do we support a future board with RGB LEDs? There is no LED.colour defined.

@pfalcon I tend towards your approach #1 but I think it is a bit restrictive by not permitting "emulated functionality". That would preclude software emulation of I2C in ESP8266. May I suggest a slightly more liberal, but still low level definition.

machine API should include
1. support for MCU core functions such as Reset, Power Management.
2. support for all non peripheral specific on chip hardware, eg Timer, PWM, IRQ.
3. all generic busses, including pin.
4. When the MCU does not implement a common bus function in hardware it can be emulated, eg I2C, one-wire.
5. I think USB should be in machine.
6. I think SD card goes in periph. But should there be an underlying SDIO interface in machine? Many W-Fi chips use SDIO interface.

machine should not support any specific peripherals. These should be supported by libraries that use the cross platform compatible machine API.
1. no LED, SERVO, ACCEL, BUTTON, etc
2. no INVERT for pins. This is not a built in function of the MCU GPIO hardware and is only needed for certain peripherals, eg LED and can be implemented in the peripheral libraries that need it. Also using invert with pins leads to pin.value(0) setting the pin to a logic 1 which is confusing. Inverted pins should use assert and deassert.
3. even though some MCU's have built in busses for LCD, CAMERA , etc I don't think they should be in machine for two reasons (a) they are not on all MCU's and we don't want to emulate them, and (b) LCD and CAMERA interfaces are for specific peripherals, they are not generic.
4. One may argue that I2S is like LCD and CAMERA, ie a specific interface for an audio codec. However the interface is not audio specific and I use I2S with TI industrial ADC's to measure non audio things, so I think the basic functions of I2S, ie streaming data, should be in machine.

To satisfy existing users of pyb, and to provide an easy way to get started with on board peripherals I think there should be a periph API for things like LED SERVO, ACCEL.This keeps machine clean and allows pyb to be deprecated. The advantage of pyb is its device drivers don't need port assignments. LED(1) is the RED LED on all boards, irrespective of what GPIO is it connected to. The periph API should use the same syntax as an off board peripheral driver would, but without the need to specify hardware mapping.
Where should Neopixel go? Not in machine, its very specific to one type of LED and other LEDs will need modified support. In periph? Its not usually an on board device and needs hardware assignments. Maybe there should be a third (common devices) library?

It's not a priority now as it doesn't affect the existing functions in the hardware API, but it would be useful to read and write parallel data to LCD,s, FPGA registers, etc with the efficiency of byte or word transfers without having to write your own MCU specific driver, eg PA<7..0> connected to an external ADC, DAC or LCD. Due to MCU or pin usage limitations it's not always possible to memory map them with RDn, Rn and CSn bus controls. Writing data in parallel and just bit banging a strobe is much more efficient than bit banging the whole data port. Some devices, like parallel ADC's don't even need a strobe. You either just read whenever you want a value and get the last conversion, or you wait for an interrupt and just read the data.

I summary I am not proposing any changes to machine except to formally allow emulation of common interfaces if they are missing from the MCU hardware. At the same time I think if machine needs changing then now is the time to do it, before v2.0. It's more about what to do with all the higher level peripheral drivers that I think should be kept out of machine.

My personal preference is to include pin toggle and open drain for both coding and efficiency reasons. I won't vote on them. I'll leave the details of the API to the experts.

Regards, Chris

pfalcon
Posts: 1155
Joined: Fri Feb 28, 2014 2:05 pm

Re: RFC: Hardware API: finalising machine.Pin

Post by pfalcon » Sat Oct 22, 2016 6:41 pm

chrismas9 wrote:So -1 for adding LED API to machine.
Note that nobody proposed to add LED API so far. I used an example of LED because there can be active-high and active-low LEDs, so we need to apply thought to this problem and issue a conclusion (for the current iteration of HW API), i.e. I don't think it's ok to ignore it, like we've done so far.
@pfalcon I tend towards your approach #1 but I think it is a bit restrictive by not permitting "emulated functionality".
There's no restriction of "no permitting". Vice-versa, there's a freedom of "not requiring".
That would preclude software emulation of I2C in ESP8266. May I suggest a slightly more liberal, but still low level definition.
No, unrelated. In this thread we discuss only and only the Pin class, as the topic thread and @dpgeorge's starting message suggest. So, any "emulated functionality" in this discussion is in relation to the Pin class, unless noted otherwise. The whole idea behind "no emulated stuff" movement is to be able to bring a new port quickly (literally, by writing 5 lines), by enjoying bitbanging I2C, SPI, etc. implementations we already have.
machine API should include
I can't reasonably comment on what machine API should include, because it's far too large topic. The only way to approach is class by class, and this topic deals with Pin class. I however shared my outlook how the whole matter should be approached in an earlier message: we should be wary of any scope creep, i.e. any additions. (For the current iteration). So, by that logic, machine API should include what it includes now (taking the freshest port, esp8266 as the reference), and well, nothing more (so far). My bringing up a question of inverted signals for Pin class is an exception (violation if you want) to the rule I myself propose, and by bringing it up, I'll be double-conservative regarding adding anything else. Again, for the current iteration. (The current iteration will finish when all active ports will have the same level of support for it, and we have up-to-date docs; then we can start with a new iteration and subscribing to implement more stuff.)
Awesome MicroPython list
Pycopy - A better MicroPython https://github.com/pfalcon/micropython
MicroPython standard library for all ports and forks - https://github.com/pfalcon/micropython-lib
More up to date docs - http://pycopy.readthedocs.io/

User avatar
marfis
Posts: 215
Joined: Fri Oct 31, 2014 10:29 am
Location: Zurich / Switzerland

Re: RFC: Hardware API: finalising machine.Pin

Post by marfis » Sat Oct 22, 2016 7:43 pm

1. no LED, SERVO, ACCEL, BUTTON, etc
2. no INVERT for pins. This is not a built in function of the MCU GPIO hardware ...
my view as well. Pins have no inverted characteristics, but module have (LED's etc).

I personally don't care which way "high" or "low" is written (be it set_value, high, low..). Main point is that it is reasonably fast and it's consistent across ports.

pins.csv, pins_af.csv:
The current implementation is limited: it specifies a name for the pin and a list of alternative functions. No way to define IRQ capabilities for example (and other things like slew rate etc). Maybe the CSV files could be rearranged/improved so that it contains this information as well (possibly moving away from CSV files to python data structures)? Using python data structures would allow the file to be frozen so it's available for the uPy VM. That may be nice to have if you want to write generic code for different MCU's.

The whole concept could be taken even further by specifying the whole MCU within a CSV/JSON/py file but I think that's not realistic at this point in time (Linux has apparently such an approach, the linux device tree: DTS)

User avatar
deshipu
Posts: 1388
Joined: Thu May 28, 2015 5:54 pm

Re: RFC: Hardware API: finalising machine.Pin

Post by deshipu » Sat Oct 22, 2016 7:44 pm

pfalcon wrote: So, how do we want to deal with it? The current answer is "oops, we didn't think about it!"
I like how you have here answered your own question about why we need to revisit the hardware api spec. I think that it's great that we can take whatever experience we have gathered in the time since, and apply it to improving the API.

On the other hand, I have to admit that, although I have written materials for workshop for beginners in the microcontroller programming (and ran those workshops multiple times, with about 50 people so far), used eight different ports of MicroPython, implemented drivers for over twenty different devices, such as displays and sensors, and built and programmed in MicroPython four robots, I have never really had a problem that would require me to use a pin with an inverted signal. A simple "not" usually solved any issues. So I don't feel like there is enough information gathered to make a decision about this at the moment. As I understand, you have much more extensive experience, so perhaps you could share it, so that we can discuss it properly and come up with a solution that solves the actual root cause of the problem, not necessarily implement the particular solution that you came up with. (Just in case you are going to interpret this as sarcasm, it is not, I mean literally what I wrote, and I really hope you can share your experience, though I understand, that you might be too busy to do it.)
Last edited by deshipu on Sat Oct 22, 2016 9:07 pm, edited 1 time in total.

Post Reply