-
Notifications
You must be signed in to change notification settings - Fork 238
Open
Labels
Description
In the v0.1.0 release of this crate we have a digital::OutputPin
that represents a single digital output pin. That trait is useful for, e.g., implementing the NSS pin of a SPI interface but not enough to implement 8 or 16 bit parallel port interfaces where all the pins need to change at the same time (atomically) to meet timing requirements (e.g. LCD interfaces) -- using 16 impl OutputPin
would result in them changing state at different time intervals.
I think the obvious trait to use would be the following:
/// A digital output "port"
///
/// `Width` is the size of the port; it could be `u8` for an 8-bit parallel
/// port, `u16` for a 16-bit one, etc.
///
/// **NOTE** The "port" doesn't necessarily has to match a hardware GPIO port;
/// it could for instance be a 4-bit ports made up of non contiguous pins, say
/// `PA0`, `PA3`, `PA10` and `PA13`.
pub trait OutputPort<Width> {
/// Outputs `word` on the port pins
///
/// # Contract
///
/// The state of all the port pins will change atomically ("at the same time"). This usually
/// means that state of all the pins will be changed in a single register operation.
fn output(&mut self, word: Width);
}
cc @kunerd
neu-rah, rubberduck203, luojia65, eflukx and tgross35
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
Gpio
API #11kunerd commentedon Jan 22, 2018
Never thought about this, but you are right, without an atomic set the communication timing could become broken by interrupts. But, wouldn't we than need an
InputPort
and anInputOutputPort
, too?japaric commentedon Jan 22, 2018
Possibly. You let me know what you need for your driver. :-)
idubrov commentedon Feb 2, 2018
I like the idea of being able to drive multiple pins separately as a single atomic thing -- for the timing reasons you've mentioned.
However, for the purpose of HD44780 LCD, I think, timings on data output are less important than being able to use pins from different GPIO ports (like GPIOA/GPIOB).
Even if bit operation is interrupted by, well, interrupt, it does not matter for HD44780 as data is transferred via dedicated "pulse" on EN bit after all data pins are set.
Given that flexibility of LCD, it would be tempting to assign pins to it which are "left" from the more demanding devices (like those requiring timer PWM, atomic operations on across multiple pins, etc), which could lead to the situation when all pins are taken from different ports.
Theoretically, you can design this trait to be able to span multiple ports and make it "do its best" to do as little operations as possible...
japaric commentedon Feb 3, 2018
@idubrov in that case I think we can split the atomic property into a marker trait so that
where T: digital::OutputPort + Atomic
will toggle all the pins atomically whereaswhere T: digital::Output
may or may not change the state of the pins atomically. A driver for the HD44780 could make use of the latter bound.kunerd commentedon Feb 8, 2018
I have done some quick testing and @idubrov seems to be right, for the HD44780 LCD driver the timing doesn't matter. The only situation where the output can become corrupted is an Interrupt that changes the state of the display Pins. Now, the question is, should preventing that be a part of the embedded-hal crate? If not I will go by with the
InputPin
,OutputPin
andIoPin
traits.idubrov commentedon Feb 8, 2018
Well, in an ideal world, where you can have a perfect cut & slice on your GPIO (like all pins of GPIOA+GPIOB+GPIOC => Slice1 + Slice2 + Slice3), your interrupt should not have "mutable"/"exclusive" access to the same slice as your non-interrupt code writing to the display.
Regarding Atomic, my concern (could be unfounded, I haven't really done a lot of thinking), is that if you go for that "perfect solution" so to speak, with all these Atomic traits, ability to mix and match multiple pins, etc, wouldn't the complexity make it hard to use/implement?
idubrov commentedon Feb 8, 2018
Though, if you can have it, I would certainly love the solution that allows me to:
@kunerd @japaric
therealprof commentedon Feb 8, 2018
I see you guys are all very ST centric. ;) Are few things are more awkward in the ST world (like having different GPIO banks and sometimes high/low registers) while others are quite a bit more comfortable, like not having to use 10 different registers to send/receive data on an I2C port or having to manually reset events after them being triggered.
However one thing that pretty much all devices have in common is that often registers have to be split into individual bits or group of bits and ideally the control over the bits should be movable into abstracted types which cannot easily be done at the moment.
This should be abstracted in a way that allows a type to exercise control over exactly the required bits but nothing more which in some cases may mean it be done atomically (either due to the availability of bitbanding or separate set/clear registers) while in other cases it will mean that RMW is required.
japaric commentedon Feb 13, 2018
@idubrov all those sound like configuration details that both the trait and the generic driver author don't have to concern themselves about. Do you think the proposed trait would get in the way of implementing any / all of that configurability? I don't think so but won't know for sure until I sit down and try to implement it. I don't have a use case that requires implementing something so elaborated though so don't count on me implementing that.
if you don't have bit banding you can do the RMW operation in a critical section and not require the token.
18 remaining items