Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I read/write analog values #14

Closed
Altaflux opened this issue Jun 23, 2019 · 3 comments
Closed

How do I read/write analog values #14

Altaflux opened this issue Jun 23, 2019 · 3 comments

Comments

@Altaflux
Copy link

I don't seem to find a way to read analog input using this library. I suppose that it is either not currently supported or considered too high level for this library.

Is there an example on to achieve this (read and possibly write analog values) using Rust?

@dylanmckay
Copy link
Member

or considered too high level for this library.

It is definitely within the scope of this library, but nobody has gotten around to it yet.

We haven't written an abstraction layer for it, but it should be possible to do on a chip-dependent manner by manually reading the IO registers (https://docs.rs/ruduino/0.1.2/ruduino/cores/atmega328/index.html) like you would in C/C++ to perform the operation.

Otherwise, a new trait can be written for IO registers implementing analog IO inside the (ruduino::modules](https://docs.rs/ruduino/0.1.2/ruduino/modules/index.html) namespace with functions for reading and writing. The build script can then be modified so that it also looks up which of the registers are for analog IO and emits a impl for the new trait for each and every analog IO register the device supports. That is how the other abtstraction layers are implemented would give first-class support for analog IO.

Is there an example on to achieve this (read and possibly write analog values) using Rust?

It is probably possible to do this using embedded-hal, perhaps the folks on #13 have an example.

@Altaflux
Copy link
Author

Altaflux commented Jul 1, 2019

Thanks for the response. I was able to rewrite analogRead() and init() from arduino to Rust so that's success.

I will try to port over more functionality from the arduino libraries to rust and build a usable platform as I think it will be great for developers familiar with the Arduino toolkit and want to code on Rust. If anything I produce is useful for ruduino or other projects I will try to chime in.

I don't think my Rust knowledge is still good enough to contribute to this project directly butI am interested on expanding the functionalities of ruduino.

@Altaflux Altaflux closed this as completed Jul 1, 2019
@Altaflux
Copy link
Author

Altaflux commented Jul 2, 2019

@dylanmckay for those interested this is what I came up with.
Referenced material:
https://garretlab.web.fc2.com/en/arduino/inside/arduino/wiring_analog.c/analogRead.html
and the code of arduino.

 unsafe fn init() {
    // this needs to be called before setup() or some functions won't
    // work there
    unsafe {
        asm!("sei"::);
    }
    // on the ATmega168, timer 0 is also used for fast hardware pwm
    // (using phase-correct PWM would mean that timer 0 overflowed half as often
    // resulting in different millis() behavior on the ATmega8 and ATmega168)
    atmega328::TCCR0A::set(atmega328::TCCR0A::WGM01);
    atmega328::TCCR0A::set(atmega328::TCCR0A::WGM00);

    // set timer 0 prescale factor to 64
    // this combination is for the standard 168/328/1280/2560

    atmega328::TCCR0B::set(atmega328::TCCR0B::CS01);
    atmega328::TCCR0B::set(atmega328::TCCR0B::CS00);

    // enable timer 0 overflow interrupt
    // atmega328::TIMSK0::set(atmega328::TIMSK0::TOIE0); Setting this breaks it

    // timers 1 and 2 are used for phase-correct hardware pwm
    // this is better for motors as it ensures an even waveform
    // note, however, that fast pwm mode can achieve a frequency of up
    // 8 MHz (with a 16 MHz clock) at 50% duty cycle
    atmega328::TCCR1B::write(0);
    // set timer 1 prescale factor to 64
    atmega328::TCCR1B::set(atmega328::TCCR1B::CS11);
    atmega328::TCCR1B::set(atmega328::TCCR1B::CS10);
    // put timer 1 in 8-bit phase correct pwm mode

    atmega328::TCCR1A::set(atmega328::TCCR1A::WGM10);

    // set timer 2 prescale factor to 64

    atmega328::TCCR2B::set(atmega328::TCCR2B::CS22);
    // configure timer 2 for phase correct pwm (8-bit)

    atmega328::TCCR2A::set(atmega328::TCCR2A::WGM20);

    // set a2d prescale factor to 128
    // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
    // XXX: this will not work properly for other clock speeds, and
    // this code should use F_CPU to determine the prescale factor.

    atmega328::ADCSRA::set(atmega328::ADCSRA::ADPS2);
    atmega328::ADCSRA::set(atmega328::ADCSRA::ADPS1);
    atmega328::ADCSRA::set(atmega328::ADCSRA::ADPS0);

    // enable a2d conversions
    atmega328::ADCSRA::set(atmega328::ADCSRA::ADEN);
}

 //1 for atmega328 usb
 const ANALOG_REFERENCE: u8 = 1;

 fn analog_read(mask: u8) -> u16 {
    // set the analog reference (high two bits of ADMUX) and select the
    // channel (low 4 bits).  this also sets ADLAR (left-adjust result)
    // to 0 (the default).
    atmega328::ADMUX::write((ANALOG_REFERENCE << 6) | mask & 0x07);

    // start the conversion
    atmega328::ADCSRA::set(atmega328::ADCSRA::ADSC);

    // ADSC is cleared when the conversion finishes
    while !atmega328::ADCSRA::is_set(atmega328::ADCSRA::ADSC) {}

    // we have to read ADCL first; doing so locks both ADCL
    // and ADCH until ADCH is read.  reading ADCL second would
    // cause the results of each conversion to be discarded,
    // as ADCL and ADCH would be locked when it completed.
    return atmega328::ADC::read();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants