-
Notifications
You must be signed in to change notification settings - Fork 39
Add support for the ADC peripheral #114
base: master
Are you sure you want to change the base?
Conversation
Are you planning make this compatible with #rust-embedded/embedded-hal#101 ? |
Hmm, I didn't know that PR was a thing. I'll have a closer look later but it looks like it could be supported fairly easily |
@TheZoq2 It would be great if you could also address:
Not really a problem but why not address this right away? |
Mostly because for my application, I don't need maximum speed. Als because I couldn't find the page where I originally got the idea to set it to 6. I can look into doing it properly tonight. |
I found the place in the manual where they explain the required timings and updated the branch to reflect that. It should now ensure that the ADC clock runs at 14 MHz or less |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you wrote ADC clock can not exceed 14 MHz
If desired > 8 we should divide by 16
src/rcc.rs
Outdated
// Integer division +1 for ceil operation | ||
let desired = sysclk / 14_000_000; | ||
|
||
if desired >= 8 { 0x11 } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use stm32f103xx::rcc::ADCPREW as AdcPrescaler;
if desired > 8 { AdcPrescaler::DIV16 }
rcc.cfgr.modify(|_, w| w.adcpre().variant(adc_prescaler))
Good catch! I updated it with both suggestions |
Have you noticed you have to use bigger divider? |
I did, but for some reason I thought changing it to I changed it back to |
72 MHz / 14 MHz = 5.14 > 4 |
Unless i'm misstaken, the code, as it looks after my latest commit divides by 6 in this case which gives a real speed of 72/6 = 12 MHz which is correct, right? |
Yes. |
Yes, another good catch. Thanks! I pushed a new commit with a fix |
implementation of em-hal adc for L0x1: https://github.com/thenewwazoo/stm32l0x1-hal/blob/master/src/adc.rs |
Great work @TheZoq2!. Just to let you know, the ADC traits have been published in embedded-hal@0.2.2. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please fix the conflict and make sure the code and examples compile without warnings (I'm getting 3).
cdeb6a8
to
c1e95a4
Compare
Hi, please consider to use this ADC clock configuration instead: |
Also it would be nice to have a nonblocking read implementation, like it is proposed here: |
I finally got around to rebasing this against the current version. I'll try and find some time to rewrite it to use the embedded-hal implementation soon. @tib888 I assume you're talking about allowing the user to chose the frequency, if so I'll try and implement that as well |
I have now implemented the embedded_hal adc traits to replace the pin handling I did before |
Looking good. |
Not only that, it actually implements the divider calculation (more precise version) and the config register setting too, so you could have been used the whole file as is.
|
@TheZoq2 have you tested the read_raw implementation? |
@tib888 I tested it briefly by running the examples/adc.rs and it seems to work. Though it might not be a bad idea to check if a conversion is already happening... |
I'm not sure why my test didn't catch this earlier, but @tib888 was right, it does get stuck in an infinite loop. Unfortunately I can't reproduce it in the example but I did experience it in my main project. I have pushed a fix which works but does have issues when running more than one read at a time: let (mut chan1, mut chan2) = (None, None);
while chan1 == None && chan2 == None {
if let Ok(val) = pa1.read() {chan1 = Some(val)};
if let Ok(val) = pa2.read() {chan2 = Some(val)};
} In this case, the values of |
@TheZoq2 What about this solution below?
It could be used like this:
|
@tib888 That's defenitively a solution that I would prefer over runtime errors. However, as far as I can tell, it is not compatible with the |
@TheZoq2 I agree, so we could propose there an improvement in embedded_hal. |
This adds the ability to run single AD conversions similar to what was suggested in #92.
Here are a few potential issues with this implementation:
RCC and clocks
Right now, the prescaler for the ADC is set to divide the system clock by 6 as
I read somewhere that it is required to get accurate readings when the sysclock
is running at 72 MHz.
Hardcoding this value is kind of ugly since you could do less prescaling when the sysclock
is slower than 72 MHz. Is that a problem for this initial implementation?
Type safety
This implementation makes sure that the ADC can only be used on a pin which is configured
as an analog input and also maps pins to their corresponding channel.
However, this means that you can't run the ADC on channels without an associated pin like
chanel 16 which is a temperature sensor. Do we want to make
Adc::read
pub? What happensif you run a conversion on a pin that is not configured as analog input?
Also, is there a nicer way to implement the mapping between pins and channels?