Skip to content

Commit

Permalink
cache lastValue (#6)
Browse files Browse the repository at this point in the history
- change behaviour
  - cache lastValue as calculated by **ready()**
- change **uint16_t value()** signature
- update examples
- update GitHub actions
- minor edits
  • Loading branch information
RobTillaart authored Apr 6, 2024
1 parent 1247671 commit 39e6ed5
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 83 deletions.
3 changes: 2 additions & 1 deletion .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# These are supported funding model platforms

github: RobTillaart
github: RobTillaart
custom: "https://www.paypal.me/robtillaart"

4 changes: 2 additions & 2 deletions .github/workflows/arduino-lint.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@

name: Arduino-lint

on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/arduino_test_runner.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
name: Arduino CI

on: [push, pull_request]

jobs:
runTest:
runs-on: ubuntu-latest
timeout-minutes: 20

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/jsoncheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ on:
jobs:
test:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
uses: limitusus/json-syntax-check@v2
with:
pattern: "\\.json$"

42 changes: 25 additions & 17 deletions AsyncAnalog.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//
// FILE: AsyncAnalog.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.6
// VERSION: 0.2.0
// DATE: 2018-09-05
// PURPOSE: Async version of analogRead, prevent blocking wait
// URL: https://github.com/RobTillaart/AsyncAnalog
Expand All @@ -26,15 +26,15 @@ AsyncAnalog::AsyncAnalog(const uint8_t pin)
void AsyncAnalog::start()
{
#if defined(ADCSRB) && defined(MUX5)
// the MUX5 bit of ADCSRB selects whether we're reading from channels
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
// the MUX5 bit of ADCSRB selects whether we're reading from channels
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((_pin >> 3) & 0x01) << MUX5);
#endif

#if defined(ADMUX)
// set the analogue reference (high two bits of ADMUX) and select the
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
// to 0 (the default).
// set the analogue reference (high two bits of ADMUX) and select the
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
// to 0 (the default).
ADMUX = (DEFAULT << 6) | (_pin & 0x07);
#endif

Expand All @@ -45,23 +45,31 @@ void AsyncAnalog::start()
bool AsyncAnalog::ready()
{
// ADSC is cleared when the conversion finishes
return bit_is_set(ADCSRA, ADSC) == 0;
bool _ready = bit_is_set(ADCSRA, ADSC) == 0;

if (_ready) // calculate the measurement
{
// ADCL has to be read 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.
uint16_t lo = ADCL;
uint16_t hi = ADCH;
// Combine two parts.
_lastValue = (hi * 256) + lo;
}
return _ready;
}


int AsyncAnalog::value()
uint16_t AsyncAnalog::value()
{
// ADCL has to be read 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.
uint16_t lo = ADCL;
uint16_t hi = ADCH;
// Combine two parts.
// _lastValue = (hi * 256) + lo;
return (hi * 256) + lo;
return _lastValue;
}

#else


#endif // ARDUINO_ARCH_AVR


Expand Down
56 changes: 42 additions & 14 deletions AsyncAnalog.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,71 @@
//
// FILE: AsyncAnalog.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.6
// VERSION: 0.2.0
// DATE: 2018-09-05
// PURPOSE: Async version of analogRead for AVR
// URL: https://github.com/RobTillaart/AsyncAnalog


#if !defined(ARDUINO_ARCH_AVR)
#define ASYNCANALOG_LIB_VERSION (F("0.2.0"))

#error “AsyncAnalog library only supports boards with an AVR processor .”

#else

// (ARDUINO_ARCH_SAM) future
// (ARDUINO_ARCH_ESP32) future
// (ARDUINO_ARCH_ESP8266) future
#if defined(ARDUINO_ARCH_AVR)


#include "Arduino.h"
#include "wiring_private.h"
#include "pins_arduino.h"

#define ASYNCANALOG_LIB_VERSION (F("0.1.6"))


class AsyncAnalog
{
public:
AsyncAnalog(const uint8_t pin);

void start();
bool ready();
int value();
void start();
bool ready();
uint16_t value();

private:
uint8_t _pin;
uint16_t _lastValue;
};

// #elif defined(ARDUINO_ARCH_SAM)
// #elif defined(ARDUINO_ARCH_ESP32)
// #elif defined(ARDUINO_ARCH_ESP8266)


#else

#error “AsyncAnalog library only supports boards with an AVR processor .”


/*
#include "Arduino.h"
// fall back for other platforms?
class AsyncAnalog
{
public:
AsyncAnalog(const uint8_t pin)
{
_pin = pin;
_lastValue = 0;
}
void start() { _lastValue = analogRead(_pin); };
bool ready() { return true; };
uint16_t value() { return _lastValue; };
private:
uint8_t _pin;
// uint16_t _lastValue;
uint16_t _lastValue;
};
*/


#endif // defined(ARDUINO_ARCH_AVR)

Expand Down
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).


## [0.2.0] - 2024-04-06
- change behaviour
- cache lastValue as calculated by **ready()**
- change **uint16_t value()** signature
- update examples
- update GitHub actions
- minor edits

----

## [0.1.6] - 2023-10-17
- update readme.md
- add changelog.md
- minor edits


## [0.1.5] - 2021-12-13
- update library.json
- update license
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018-2023 Rob Tillaart
Copyright (c) 2018-2024 Rob Tillaart

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
34 changes: 24 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,41 @@ Arduino Library for async reading of an analogue pin. **\[AVR ONLY\]**.
## Description

AsyncAnalog is a library to read the analogue port of an **AVR** in an asynchronous way.
This means that the user must explicitly **start** the ADC, check if it is **ready**
and read out its **value**.
This means that the user must explicitly **start()** the ADC, check if it is **ready()**
and read its **value()**.

By using this class, the user prevents the (~112 uSec) blocking of the
**analogRead()** call, and gives the user the ability to do some processing.

The library works only for AVR boards now, other platforms might be supported in the future.
(PR's are welcome).

**WARNING**
As the UNO has only one ADC that is multiplexed, one can only read one analogue pin
in async way simultaneously.
As the UNO has only one ADC that is multiplexed, one can only read one analog pin
in async way simultaneously. Still it offers to about 100 micros to do something!

**Use with care**


#### Related

- https://github.com/RobTillaart/AnalogPin


## Interface

```cpp
#include "AsynAnalog,h"
```

- **AsyncAnalog(uint8_t pin)** constructor, defines the analogue pin to use.
- **void start()** triggers a new ADC reading.
- **bool ready()** returns true if sample is complete.
- **int value()** returns the value.
- **void start()** triggers a new ADC measurement.
- **bool ready()** Checks if the measurement is completed.
If so the value is calculated and cached for **value()**.
As long as ready() is not called the old value will not change!
- **uint16_t value()** returns the value of the ADC from cache.
So it will return the same value even if the internal ADC is used to sample
another analog port.


## Operation
Expand All @@ -54,18 +64,22 @@ over Serial at 115200 baud.

#### Must

- improve documentation.

#### Should

- improve documentation.
- create examples
- real world examples preferred.
- multi ADC, e.g. A0..A4


#### Could

- investigate the performance gain.
- asyncAnalogTest2.ino is not a good test.
- create examples
- real world examples preferred.
- investigate other platforms
- fall back to normal analogRead for non AVR platforms ?
- start would be analogRead() and it would immediately be ready and the value is cached.
- better have specific code per platform.

#### Wont
Expand Down
34 changes: 20 additions & 14 deletions examples/asyncAnalogTest/asyncAnalogTest.ino
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//
// FILE: asyncAnalogTest.ino
// AUTHOR: Rob Tillaart
// VERSION: 0.1.1
// DATE: 2018-09-05
// PURPOSE: demo


#include "AsyncAnalog.h"
Expand All @@ -18,9 +17,14 @@ uint16_t count = 0;
void setup()
{
Serial.begin(115200);
Serial.println("start: ");
Serial.println(__FILE__);
Serial.print("ASYNCANALOG_LIB_VERSION: ");
Serial.println(ASYNCANALOG_LIB_VERSION);

Serial.print("\nstart: ");
Serial.println(analogRead(0));

// request initial measurement
AA.start();
start = micros();
}
Expand All @@ -29,29 +33,31 @@ void setup()
void loop()
{

// if sample ready
// if measurement ready
if (AA.ready())
{
// process sample
// get data
duration = micros() - start;
uint16_t val = AA.value();

// process measurement
Serial.print(duration);
Serial.print("\t");
Serial.print(AA.value());
Serial.print("\t");
Serial.print(count);
Serial.println();
Serial.print('\t');
Serial.print(val);
Serial.print('\t');
Serial.println(count);

// request a new sample
// request a new measurement
AA.start();
start = micros();


count = 0;
}

// do other stuff here
// do other stuff here
count++;
}


// -- END OF FILE --

// -- END OF FILE --
Loading

0 comments on commit 39e6ed5

Please sign in to comment.