added dac#247
added dac#247David-OConnor wants to merge 2 commits intorust-embedded:masterfrom David-OConnor:dac-trait
Conversation
|
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @eldruin (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
|
@eldruin Thanks for pointing me in this direction. I was working on an example implementation for a multichannel DAC but got stuck on how to implement a .split method that would return one DAC instance for each channel. But that mostly has to do with my limited knowledge of no-std programminging in Rust. I could try to continue that too. There are a couple of things I'm not sure about. The set_voltage is not something all DACs can implement. Many DACs use an external reference to scale their output so the scaling factor for value to voltage is not known beforehand. And I'm not sure its that useful, in most applications the DAC output will be scaled to some other value using a voltage divider or opamp right after the input anyway so the user of this trait will have to add her own scaling anyway and I'm not sure if using floats for this is always a good idea. The set_enabled and disabled methods could be useful. But most DACs I've seen have more extensive power-down modes. And as this trait would represent a single channel for a multi channel DAC. How would this work if the DAC does not allow enabling/disabling single channels? My choice would be to keep this to the DAC driver specific implementation and only have a try_set_output. Also I would make the Value a generic parameter of the trait. I think that would be more consistent with how its done in similar embedded hal traits like here https://github.com/rust-embedded/embedded-hal/blob/master/src/blocking/serial.rs for example. |
|
hmm, it's probably worth considering in the context of the |
|
@mendelt Thank you for your input! |
In my mind this trait could also be used for multi channel dacs without change. The dac driver could implement a .split() method that returns a tuple of |
Ah, that makes sense, and I can't imagine a situation where you'd want to use the same dac with multiple word lenghts. |
Thank you! I was looking at using a RefCell too but was unsure if that would be the right solution. I think that means you cannot move dac-channels to an interrupt handler for example right? Or should that not be something a driver is concerned with? |
|
@mendelt: Maybe a proxy for DAC's in |
I am not sure how that would fit. I would need to play around with it. |
|
Implemented this for a multichannel DAC (8 channel AD5668) with a split method based on a RefCell like @eldruin suggested. https://github.com/mendelt/ad5668/tree/dac-hal |
|
Maybe we remove the enable part. On the two DACs I have experience with it's applicable (STM32's onboard DAC, and MCP4921), but if it's not universal, then probably not appropriate. What I'm also struggling with is arguments passing to it; eg |
Maybe I'm missing what you mean here. But isn't that part of the setup for a specific DAC? Dependencies like clocks or pins or i2c/spi busses etc can be passed to a specific DAC implementation in a constructor method specific to that DAC? There is no need to make that part of the DAC trait. |
|
I guess there's not much that can be extracted into a generic trait |
|
I switched the f303 impl to using infallible traits built into the struct, and added a pub trait SingleChannelDac {
/// Error type returned by DAC methods
type Error;
type Word;
/// Output a constant signal, given a bit word.
fn try_set_value(&mut self, value: Self::Word) -> Result<(), Self::Error>;
} |
Yeah, but I don't think that's a bad thing. It is a simple abstraction but useful. |
|
Done |
|
Looks like only half of the move of |
|
Works! I'll see if I can test this with real devices later this week. But there are no code changes so I'm pretty confident that works. And I don think thats really the point of these example implementations anyway. |
|
Could this be made to support multiple channels as well similarly to |
Not sure if I understand this correctly. The The only thing from the |
|
I was talking about making a pub trait Channel<DAC> {
type ID: Copy;
fn channel(&self) -> Self::ID;
}
pub trait Dac<DAC, Word, CHAN: Channel<ADC>> {
type Error;
fn try_set_value(&mut self, value: Word, channel: &mut CHAN) -> Result<(), Self::Error>;
}
pub trait SingleChannelDac {
type Error;
type Word;
fn try_set_value(&mut self, value: Self::Word) -> Result<(), Self::Error>;
}I am still thinking whether the |
|
Ah sorry, got it. You actually convinced me that an associated type would be a better fit here (and maybe in most places) I looked around and I don't see that many drivers, even for peripheral types that do support multiple word-lengths, implement it. I think most |
eldruin
left a comment
There was a problem hiding this comment.
What do you think @David-OConnor?
|
I haven't used a multi-channel DAC before, so can't say what makes the most sense. |
|
I like the extra flexibility, but I have some trouble imagining a use for this. There might be dacs that have a reduced precision low-power mode? Or support low precision fast operation? But I haven't encountered them. @eldruin just out of curiosity, for the multichannel example. What is the use of the Channel trait? Cant you just use a type parameter or associated type to determine how to select channels? I think the primary use case is to allow for the use of tuples to select channels in banks right? |
eldruin
left a comment
There was a problem hiding this comment.
Ok, this is almost good to go.
Just two missing things:
- Add an entry about this trait to the changelog
- Add this trait to the prelude
eldruin
left a comment
There was a problem hiding this comment.
Ok, almost there!
- There is still a conflict in the Changelog. Please rebase this branch to the master branch and resolve it.
- Also, could you name the commit something like "Added single-channel DAC trait"?
Thank you!
|
Done |
1 similar comment
|
Done |
eldruin
left a comment
There was a problem hiding this comment.
Thank you!
I suggested a last fix to the documentation. Could you accept it and squash everything into one commit again?
eldruin
left a comment
There was a problem hiding this comment.
Hmm, there is still a conflict in the changelog file.
|
Do you know how to fix it? IIRC I tried both ways - when it had the What should the Added section of the changelog look like? |
|
Ok that worked. Thanks! |
|
Oh, great! I must have made some mistake before. |
|
Thoughts? |
|
Is there an MCU HAL implementation of this trait somewhere? The PR I linked above was closed. |
|
"try_" |
|
I would wrap the I would not use it on any real projects in this state though, without |
|
After a discussion on Matrix and further consideration, I don't think DAC is appropriate for EH. |
Basic features only. Could get more complicated with triggers, multi-channel features etc, but for now, would prefer to keep it simple and general, to avoid becoming too provincial.