You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This continues what started being discussed in #1405. The Pin API as far as the constructor (and the init()) method is concerned needs to be modified a bit in order to make it more general and suitable for a wide range of MCUs. Here's my proposal:
Pin(pin, mode, *, type=Pin.PP, pull=None, af=0)
mode can be IN, OUT or AF
type can be PP or OD. Irrelevant when mode=Pin.IN.
pull can be PULL_UP, PULL_DOWN or None (or PULL_NONE but we could save on QSTRs)
af is only relevant when mode=Pin.AF. Alternate functions can vary widely from micro to micro so I think it's OK for the values of this param to be port specific.
That looks reasonable to me, and if we decide to go forward with this, I'm happy to change the stmhal stuff to implement this (and keep the older stuff for backwards compatability - perhaps with an ifdef for size considerations - so ifdef on).
That looks reasonable to me, and if we decide to go forward with this, I'm happy to change the stmhal stuff to implement this (and keep the older stuff for backwards compatability - perhaps with an ifdef for size considerations - so ifdef on).
—
Reply to this email directly or view it on GitHub.
I'd rather not have PP and OD separate. I think it's simpler to have just mode and pull (ignore for now alternate function). Then mode would be one of: IN, OUT or OUT_OD. In this case OUT would be push-pull (and we provide OUT_PP as an alias on pyboard for legacy support). Or, IN, OUT and OD.
There may also be an analog mode for some MCUs (eg mode=Pin.ANALOG); but this could be encompassed by ADC setup and/or alternate-function.
There are other things we can support:
pull strength (available on ESP8266)
drive strength (available on CC3200)
speed (available on STM)
To support pull strength, those chips with it can have PULL_DOWN as the default strength, and provide PULL_DOWN_4K or whatever for specific strengths (or use STRONG, WEAK etc).
But maybe this is overcomplicating it. Most people will only ever use direction and pull up/down.
drive strengths and pull strengths start to become more important when the speeds start increasing, and trace lengths start getting longer. When I was working on phone chips we'd often have to increase both on the dev boards (which were way bigger than a phone) and reduce them (for power considerations) on a real phone (which often have 10 layer boards to get all of the traces routed).
I like having PULL_DOWN just be a "default" and let the board config decide what's appropriate for the default.
I think having OUT imply OUT_PP sounds reasonable (I'd do the same for AF). OD usage is alot less common (bit banged i2c and speciality power considerations are typically where this is used). I guess you could also use it for interfacing with odd voltages (i.e. have an external pullup to the desired voltage).
AF_OD is useful for the voltage conversion thing. If you were interfacing with a 1.8v part that wasn't 3.3v tolerant (for example) then you could use AF_OD with external pullups that pullup to 1.8v, or you were interfacing with a 5v part that didn't properly recognize 3.3v as a high (I've done that before). Using AF_OD on the PWM would allow the voltage translation chip to be eliminated (for example, this H-Bridge chip https://www.pololu.com/product/712/specs needs 4v to get a proper logic high)
Do we need to support both AF_OD and AF_PP (with AF=AF_PP)?
We do. For instance, the CC3200 needs to configure the pins with mode=AF and type=OD for I2C operation, otherwise it doesn't work (simply assigning the AF to SDA or SCL is not enough).
I'd rather not have PP and OD separate. I think it's simpler to have just mode and pull
Yes, it is simpler, but less flexible and will be harder to map to other MCUs in the future. I'd prefer to have it separate, even if it doesn't make much sense for the pyboard (but it makes sense for the CC3200).
There are other things we can support:
pull strength (available on ESP8266)
drive strength (available on CC3200)
speed (available on STM)
We could do two things:
Leave this extra options out of the basic API and let each port provide the ones it needs.
Make them part of the basic API and simply ignore them if not supported.
Yes, it is simpler, but less flexible and will be harder to map to other MCUs in the future.
I'm not convinced it's less flexible. Both cc3200 and stmhal are pretty much the same when configuring GPIO: they have a general mode (IN, OUT, AF, ANALOG) and then 1 bit to select PP or OD, 1 bit for PULL_UP and 1 bit for PULL_DOWN. cc3200 has an extra 2 bits for drive strength, and stmhal has bits for io speed.
We can do it 3 different ways:
All in one: mode= one of IN, IN_PU, IN_PD, OUT, OUT_OD, AF, AF_OD, ... (this is how Espruino does it, you probably also want OUT_OD_PU, AF_OD_PU, etc).
All separated: mode= IN, OUT, AF, ANALOG; drive= PP, OD; pull= NONE, UP, DOWN (then strength=...; af=...; etc).
Hybrid of above: mode= IN, OUT, OUT_OD, AF, AF_OD, ANALOG; pull= NONE, UP, DOWN (then strength=...; af=...; etc).
[Note that mbed has 2 config values: direction= INPUT or OUTPUT, and type= PULL_NONE, PULL_UP, PULL_DOWN and OPEN_DRAIN (so no OD with PU).]
We want either 2 or 3, since they are the most flexible, and I'd say they both have the same flexibility.
One advantage(?) of 2 is that the drive parameter can be extended to include the drive strength when an MCU supports that. Eg drive=PP_2MA for cc3200. Then it doesn't need the strength parameter. drive=PP would give the default strength. (Is strength relevant for OD? If so then you'll need to do, eg, drive=OD_4MA.)
Ultimately we want the following features:
Base-line config is simple, easy, short, common across MCUs and for the most case all you'll need. Eg pin = Pin('X', Pin.OUT) or pin = Pin('Y', Pin.IN, Pin.PULL_UP). Then code like the onewire driver will work on all uPy boards.
Easy path for individual ports to support more sophisticated features such as AF, drive strength
All in one: mode= one of IN, IN_PU, IN_PD, OUT, OUT_OD, AF, AF_OD, ... (this is how Espruino does it, you probably also want OUT_OD_PU, AF_OD_PU, etc).
This is crazy for me, hard to read and will lead to like a hundred values to cover all the possible combinations. The fact that others do it doesn't mean that it's right. For instance, the Arduino Pin API is extremely simple to the point that it sucks (mode: INPUT, OUTPUT, or INPUT_PULLUP, that's it, pff...).
[Note that mbed has 2 config values: direction= INPUT or OUTPUT, and type= PULL_NONE, PULL_UP, PULL_DOWN and OPEN_DRAIN (so no OD with PU).]
This is absurd. It's perfectly fine (and logical) to want OD with a PU.
Ultimately we want the following features:
Base-line config is simple, easy, short, common across MCUs and for the most case all you'll need. Eg pin = Pin('X', Pin.OUT) or pin = Pin('Y', Pin.IN, Pin.PULL_UP). Then code like the onewire driver will work on all uPy boards.
Easy path for individual ports to support more sophisticated features such as AF, drive strength
I agree with both.
One advantage(?) of 2 is that the drive parameter can be extended to include the drive strength when an MCU supports that.
The problem with that is, that if a MCU doesn't support drive strengths and a driver library in Python uses drive=PP_2MA it will fail. If instead the strength is passed separately it can simply ignore it and continue.
I vote for either 2 or 3, but I think we should keep the special values (drive strength, pull strength, speed, etc) passed as separate params.
Does anyone know if drive strength and (signal) speed can be mapped to each other? To me it looks like they are different ways to specify driver output impedance: reducing the impedance increases the drive strength and increases the signal transition speed. It also increases the power required.
If we can determine that the likely target architectures support at most one of [speed, drive strength, output impedance] then we can safely assume that it really is just different names for the same parameter. In this case we could either choose a common name that can be shared across ports, or accept all names and map them to the same underlying parameter (if it exists for that port) for compatibility across ports.
On Aug 6, 2015, at 4:18 PM, Bryan Morrissey [email protected] wrote:
Does anyone know if drive strength and (signal) speed can be mapped to each other? To me it looks like they are different ways to specify driver output impedance: reducing the impedance increases the drive strength and increases the signal transition speed. It also increases the power required.
If we can determine that the likely target architectures support at most one of [speed, drive strength, output impedance] then we can safely assume that it really is just different names for the same parameter. In this case we could either choose a common name that can be shared across ports, or accept all names and map them to the same underlying parameter (if it exists for that port) for compatibility across ports.
—
Reply to this email directly or view it on GitHub.
One architecture that I have some experience with is the Analog Devices Blackfin. The data sheets for these devices provide detailed plots of current vs pin voltage and rise/fall times vs load capacitance for each driver type, even plotting for different pin supply voltages (1.8, 2.5, 3.3V). It all amounts to a detailed specification of output impedance.
For the STM32F405 (pyboard processor) the corresponding information can be found in 'Table 50. I/O AC characteristics' of http://www.st.com/web/en/resource/technical/document/datasheet/DM00037051.pdf
There are 2 OSPEEDRy bits; for each of the four available output configurations the table lists maximum frequency and maximum rise/fall times for different values of load capacitance and VDD. Again, this looks like a specification of output impedance, for which we have four possible choices.
It seems to me that for drive strength (speed, impedance, etc) we are likely choosing from at most four values; each port can assign names to these values (i.e. low = 0, med = 1, fast = 2, high = 3) but this doesn't preclude passing integer values for script portability across ports. A port that doesn't support drive strength (cc3200?) can just ignore the parameter.
Interesting. The CC3200 does support drive strength.
Sorry, I did a quick scan of the cc3200 data sheet and missed it. I see it now; options are 2, 4, 8, and 14mA; strength is implemented via 3 bits, 14mA is achieved by activating all of the drivers:
2mA + 4mA + 8mA = 14mA
The specified rise and fall times for the cc3200 aren't a perfect match for the pyboard, but probably close enough for this API to treat them as the same.
When declaring a pin as an output, I think it makes sense to provide an initial value for the pin, so that it doesn't "glitch". So I'd propose that we add a value=0/1 argument.
I'm happy with @danicampora's suggestion just above. Except that drive_str is not the best name (str means string in Python). It could be just drive, or strength or out_power.
I prefer drive because it covers drive strength (current limit) and drive speed (slew rate). An instance of where slew rate important is when you have a lot of simultaneous switching outputs you want low slew rate, but you would want high slew rate on SPI if you were running it at say 20MHz. Some chips limit the number of fast simultaneous switching outputs per ground pin to prevent ground bounce which can crash it.
re: drive_strength - STM uses 'speed' for this parameter, which I found confusing coming to this architecture given that it has nothing to do with clock speed. The EE in me likes 'impedance', but it is probably a non-starter for two reasons: First, it would be defined as reciprocal to 'strength'; low impedance <--> high strength. Second, it would only make sense to EE's and not to most software developers ;)
I'm happy with either drive or strength being LOW, MED, HIGH, so long as it can also be specified directly as an integer. That way we don't need to specify finer granularity in the API but it can still be accessed if the architecture offers it. We can talk about slew later when it becomes an issue, and let @dhylands decide if / how to implement it on the teensy. @chrismas9 - agreed; and I appreciate the details regarding slew rate.
I prefer drive because it covers drive strength (current limit) and drive speed (slew rate). An instance of where slew rate important is when you have a lot of simultaneous switching outputs you want low slew rate, but you would want high slew rate on SPI if you were running it at say 20MHz. Some chips limit the number of fast simultaneous switching outputs per ground pin to prevent ground bounce which can crash it.
—
Reply to this email directly or view it on GitHub.
So drive means whatever a given port defines it to mean (something to do with strength)? And all ports provide LOW_DRIVE, MED_DRIVE and HIGH_DRIVE constants?
drive is good, but it just occurs to me that drive = Pin.LOW or drive = Pin.HIGHmight be confused for specifying a level. drive_current avoids the ambiguity entirely, if we think it is worth a few extra bytes / keystrokes. Maybe drive_cur? Or resolve it by @dpgeorge suggestion of naming the constant LOW_DRIVE instead?
So drive means whatever a given port defines it to mean (something to do with strength)? And all ports provide LOW_DRIVE, MED_DRIVE and HIGH_DRIVE constants?
An open-drain is a LOW_DRIVE and HIGH_FLOAT output, and a push-pull is LOW_DRIVE and HIGH_DRIVE ;-). We might look for words more connected with force or speed, like SOFT, MODERATE, HARD, or EASE, PUSH, SLAM.
An open-drain is a LOW_DRIVE and HIGH_FLOAT output, and a push-pull is LOW_DRIVE and HIGH_DRIVE ;-). We might look for words more connected with force or speed, like SOFT, MODERATE, HARD, or EASE, PUSH, SLAM.
Well, finding the perfect name is almost impossible... what about naming the drive constants LOW_STRENGTH, MED_STRENGTH and HIGH_STRENGTH ? or too long ?
Activity
dhylands commentedon Aug 3, 2015
That looks reasonable to me, and if we decide to go forward with this, I'm happy to change the stmhal stuff to implement this (and keep the older stuff for backwards compatability - perhaps with an ifdef for size considerations - so ifdef on).
danicampora commentedon Aug 4, 2015
Cool, let's wait a bit for @dpgeorge 's opinion.
dpgeorge commentedon Aug 5, 2015
I'd rather not have PP and OD separate. I think it's simpler to have just
modeandpull(ignore for now alternate function). Thenmodewould be one of:IN,OUTorOUT_OD. In this caseOUTwould be push-pull (and we provideOUT_PPas an alias on pyboard for legacy support). Or,IN,OUTandOD.There may also be an analog mode for some MCUs (eg
mode=Pin.ANALOG); but this could be encompassed by ADC setup and/or alternate-function.There are other things we can support:
To support pull strength, those chips with it can have
PULL_DOWNas the default strength, and providePULL_DOWN_4Kor whatever for specific strengths (or use STRONG, WEAK etc).But maybe this is overcomplicating it. Most people will only ever use direction and pull up/down.
dhylands commentedon Aug 5, 2015
drive strengths and pull strengths start to become more important when the speeds start increasing, and trace lengths start getting longer. When I was working on phone chips we'd often have to increase both on the dev boards (which were way bigger than a phone) and reduce them (for power considerations) on a real phone (which often have 10 layer boards to get all of the traces routed).
I like having PULL_DOWN just be a "default" and let the board config decide what's appropriate for the default.
I think having OUT imply OUT_PP sounds reasonable (I'd do the same for AF). OD usage is alot less common (bit banged i2c and speciality power considerations are typically where this is used). I guess you could also use it for interfacing with odd voltages (i.e. have an external pullup to the desired voltage).
dpgeorge commentedon Aug 6, 2015
I think OD is very useful when it's available, so should certainly be an option.
Do we need to support both AF_OD and AF_PP (with AF=AF_PP)?
dhylands commentedon Aug 6, 2015
AF_OD is useful for the voltage conversion thing. If you were interfacing with a 1.8v part that wasn't 3.3v tolerant (for example) then you could use AF_OD with external pullups that pullup to 1.8v, or you were interfacing with a 5v part that didn't properly recognize 3.3v as a high (I've done that before). Using AF_OD on the PWM would allow the voltage translation chip to be eliminated (for example, this H-Bridge chip https://www.pololu.com/product/712/specs needs 4v to get a proper logic high)
danicampora commentedon Aug 6, 2015
We do. For instance, the CC3200 needs to configure the pins with
mode=AFandtype=ODfor I2C operation, otherwise it doesn't work (simply assigning the AF to SDA or SCL is not enough).Yes, it is simpler, but less flexible and will be harder to map to other MCUs in the future. I'd prefer to have it separate, even if it doesn't make much sense for the pyboard (but it makes sense for the CC3200).
We could do two things:
dpgeorge commentedon Aug 6, 2015
Ok, we need PP & OD for AF mode.
I'm not convinced it's less flexible. Both cc3200 and stmhal are pretty much the same when configuring GPIO: they have a general mode (IN, OUT, AF, ANALOG) and then 1 bit to select PP or OD, 1 bit for PULL_UP and 1 bit for PULL_DOWN. cc3200 has an extra 2 bits for drive strength, and stmhal has bits for io speed.
We can do it 3 different ways:
[Note that mbed has 2 config values: direction= INPUT or OUTPUT, and type= PULL_NONE, PULL_UP, PULL_DOWN and OPEN_DRAIN (so no OD with PU).]
We want either 2 or 3, since they are the most flexible, and I'd say they both have the same flexibility.
One advantage(?) of 2 is that the
driveparameter can be extended to include the drive strength when an MCU supports that. Egdrive=PP_2MAfor cc3200. Then it doesn't need thestrengthparameter.drive=PPwould give the default strength. (Is strength relevant for OD? If so then you'll need to do, eg,drive=OD_4MA.)Ultimately we want the following features:
pin = Pin('X', Pin.OUT)orpin = Pin('Y', Pin.IN, Pin.PULL_UP). Then code like the onewire driver will work on all uPy boards.danicampora commentedon Aug 6, 2015
This is crazy for me, hard to read and will lead to like a hundred values to cover all the possible combinations. The fact that others do it doesn't mean that it's right. For instance, the Arduino Pin API is extremely simple to the point that it sucks (mode: INPUT, OUTPUT, or INPUT_PULLUP, that's it, pff...).
This is absurd. It's perfectly fine (and logical) to want OD with a PU.
I agree with both.
The problem with that is, that if a MCU doesn't support drive strengths and a driver library in Python uses
drive=PP_2MAit will fail. If instead the strength is passed separately it can simply ignore it and continue.I vote for either 2 or 3, but I think we should keep the special values (drive strength, pull strength, speed, etc) passed as separate params.
danicampora commentedon Aug 6, 2015
I don't think drive strength is relevant for OD.
blmorris commentedon Aug 6, 2015
Does anyone know if drive strength and (signal) speed can be mapped to each other? To me it looks like they are different ways to specify driver output impedance: reducing the impedance increases the drive strength and increases the signal transition speed. It also increases the power required.
If we can determine that the likely target architectures support at most one of [speed, drive strength, output impedance] then we can safely assume that it really is just different names for the same parameter. In this case we could either choose a common name that can be shared across ports, or accept all names and map them to the same underlying parameter (if it exists for that port) for compatibility across ports.
danicampora commentedon Aug 6, 2015
I'll investigate.
blmorris commentedon Aug 6, 2015
One architecture that I have some experience with is the Analog Devices Blackfin. The data sheets for these devices provide detailed plots of current vs pin voltage and rise/fall times vs load capacitance for each driver type, even plotting for different pin supply voltages (1.8, 2.5, 3.3V). It all amounts to a detailed specification of output impedance.
For the STM32F405 (pyboard processor) the corresponding information can be found in 'Table 50. I/O AC characteristics' of http://www.st.com/web/en/resource/technical/document/datasheet/DM00037051.pdf
There are 2 OSPEEDRy bits; for each of the four available output configurations the table lists maximum frequency and maximum rise/fall times for different values of load capacitance and VDD. Again, this looks like a specification of output impedance, for which we have four possible choices.
It seems to me that for drive strength (speed, impedance, etc) we are likely choosing from at most four values; each port can assign names to these values (i.e. low = 0, med = 1, fast = 2, high = 3) but this doesn't preclude passing integer values for script portability across ports. A port that doesn't support drive strength (cc3200?) can just ignore the parameter.
danicampora commentedon Aug 6, 2015
Interesting. The CC3200 does support drive strength.
blmorris commentedon Aug 6, 2015
@danicampora -
Sorry, I did a quick scan of the cc3200 data sheet and missed it. I see it now; options are 2, 4, 8, and 14mA; strength is implemented via 3 bits, 14mA is achieved by activating all of the drivers:
2mA + 4mA + 8mA = 14mA
The specified rise and fall times for the cc3200 aren't a perfect match for the pyboard, but probably close enough for this API to treat them as the same.
9 remaining items
dhylands commentedon Aug 11, 2015
When declaring a pin as an output, I think it makes sense to provide an initial value for the pin, so that it doesn't "glitch". So I'd propose that we add a value=0/1 argument.
dpgeorge commentedon Aug 11, 2015
I'm happy with @danicampora's suggestion just above. Except that
drive_stris not the best name (str means string in Python). It could be justdrive, orstrengthorout_power.dhylands commentedon Aug 11, 2015
I think you could also shorten drive_strength to either just drive or strength. I don't see any ambiguity for either one.
chrismas9 commentedon Aug 11, 2015
I prefer drive because it covers drive strength (current limit) and drive speed (slew rate). An instance of where slew rate important is when you have a lot of simultaneous switching outputs you want low slew rate, but you would want high slew rate on SPI if you were running it at say 20MHz. Some chips limit the number of fast simultaneous switching outputs per ground pin to prevent ground bounce which can crash it.
blmorris commentedon Aug 11, 2015
re: drive_strength - STM uses 'speed' for this parameter, which I found confusing coming to this architecture given that it has nothing to do with clock speed. The EE in me likes 'impedance', but it is probably a non-starter for two reasons: First, it would be defined as reciprocal to 'strength'; low impedance <--> high strength. Second, it would only make sense to EE's and not to most software developers ;)
I'm happy with either
driveorstrengthbeingLOW,MED,HIGH, so long as it can also be specified directly as an integer. That way we don't need to specify finer granularity in the API but it can still be accessed if the architecture offers it. We can talk aboutslewlater when it becomes an issue, and let @dhylands decide if / how to implement it on the teensy.@chrismas9 - agreed; and I appreciate the details regarding slew rate.
danicampora commentedon Aug 11, 2015
Ok I like
drivetoo. I think that adding the optionalvalueparam to the constructor is also a good idea. Does everyone agree?dpgeorge commentedon Aug 11, 2015
So
drivemeans whatever a given port defines it to mean (something to do with strength)? And all ports provideLOW_DRIVE,MED_DRIVEandHIGH_DRIVEconstants?blmorris commentedon Aug 11, 2015
driveis good, but it just occurs to me thatdrive = Pin.LOWordrive = Pin.HIGHmight be confused for specifying a level.drive_currentavoids the ambiguity entirely, if we think it is worth a few extra bytes / keystrokes. Maybedrive_cur? Or resolve it by @dpgeorge suggestion of naming the constantLOW_DRIVEinstead?danicampora commentedon Aug 11, 2015
Yes.
pramasoul commentedon Aug 12, 2015
An open-drain is a LOW_DRIVE and HIGH_FLOAT output, and a push-pull is LOW_DRIVE and HIGH_DRIVE ;-). We might look for words more connected with force or speed, like SOFT, MODERATE, HARD, or EASE, PUSH, SLAM.
danicampora commentedon Aug 13, 2015
Well, finding the perfect name is almost impossible... what about naming the
driveconstantsLOW_STRENGTH,MED_STRENGTHandHIGH_STRENGTH? or too long ?pfalcon commentedon Sep 13, 2015
Should this be closed in favor of #1430?
danicampora commentedon Sep 13, 2015
Yes, thanks.
Merge pull request micropython#1408 from hathach/nrf52_pulsein