Skip to content

Commit 590ab15

Browse files
authored
Merge pull request #97 from maxgerhardt/main
Add OPAMP library for Uno R4 (WiFi, Minima)
2 parents 1231345 + 9f82290 commit 590ab15

File tree

9 files changed

+272
-0
lines changed

9 files changed

+272
-0
lines changed

Diff for: .github/workflows/compile-examples.yml

+5
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,11 @@ jobs:
9494
additional-sketch-paths: |
9595
- libraries/WiFiS3
9696
- libraries/OTAUpdate
97+
- libraries/OPAMP
98+
- board:
99+
fqbn: "arduino-git:renesas:minima"
100+
additional-sketch-paths: |
101+
- libraries/OPAMP
97102
98103
steps:
99104
- name: Checkout repository

Diff for: libraries/OPAMP/README.md

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# OPAMP Libray for Uno R4 Minima & WiFi
2+
3+
## Description
4+
5+
The Arduino UNO R4 Minima and WiFi boards, both a featuring a Renesas R7FA4M1AB3CFM#AA0 microcontroller, do have a built-in OPAMP peripheral.
6+
7+
Operational amplifiers (or "op amp") are very versatile. They can:
8+
* mirror an input voltage to its output ("voltage follower")
9+
* amplify a small analog voltage to its output pin, output voltage range from 0 to ~4.7 V ("non-inverting amplifier")
10+
* compare two input voltages and give a binary "higher" or "lower" output ("comparator")
11+
* integrate and differentiate signals ("integrator", "differentiator")
12+
* many more
13+
14+
Electrical characteristics:
15+
* Input from 0.2 V (low speed) / 0. 3V (highspeed) to AVCC0 - 0.5 V (lowspeed) to AVCC0 - 0.6 V (high-speed)
16+
* Output from 0.1 V to AVCC0 - 0.1 V
17+
* Open gain: 120 dB typical
18+
* Input offset voltage: -10 to 10 mV
19+
* Gain-bandwidth product: 0.04 MHz (low-speed) / 1.7 MHz (high-speed)
20+
* Load current: -100 to 100 µA max.
21+
22+
## Usage
23+
24+
To startup the opamp, simply include the library and call `OPAMP.begin(speed)`. As the optional `speed` argument to this function, can chose either `OPAMP_SPEED_LOWSPEED` as the low-speed (=lower power) mode or `OPAMP_SPEED_HIGHSPEED` as the high-speed, high-power mode.
25+
26+
```cpp
27+
#include <OPAMP.h>
28+
29+
void setup () {
30+
OPAMP.begin(OPAMP_SPEED_HIGHSPEED);
31+
}
32+
33+
void loop() {}
34+
```
35+
36+
## Pinout
37+
38+
Both the Uno R4 Minima and WiFi feature their OPAMP channel 0 output on the same pins:
39+
* Analog A1: Plus
40+
* Analog A2: Minus
41+
* Analog A3: Output
42+
43+
<p align="center">
44+
<img src="amp_symbol.png"></a>
45+
</p>
46+
47+
(Vs+ is fixed to about 5V, Vs- is fixed to GND.)
48+
## Testing
49+
50+
To test the OPAMP in the simplest possible "voltage follower" configuration, connect A2 to A3.
51+
Then, any voltage applied at A1 should be mirrored onto A3. For example, if you connect A1 to GND, the OPAMP output should be GND.
52+
Connect A1 to 3.3V, the output should be 3.3V.
53+
54+
For an amplifier circuit, see https://www.electronics-tutorials.ws/opamp/opamp_3.html. A simple 2x amplifier can be built by using e.g. two 10K resistors: Connect one resistor between "Minus" and GND. Then use the second resistor to connect the output and "Minus" together. Any signal input at the "Plus" will now appear with double the amplitude at the output pin. Of course, the input signal and the Arduino Uno R4 should share the same GND and the amplified output signal should not go above ~4.7V, otherwise clipping will appear.
55+
56+
Below is a capture of an oscilloscope in which a circa 2V square-wave (green, channel 2) is amplified to 4V square-wave (yellow, channel 1) with the aforementioned circuit. The input signal was generated by a function generator (and shared GND was connected).
57+
58+
<p align="center">
59+
<img src="amp_screenshot.png" width="75%"></a>
60+
</p>
61+
62+
<p align="center">
63+
<img src="amp_circuit.png" width="40%"></a>
64+
</p>

Diff for: libraries/OPAMP/amp_circuit.png

56.4 KB
Loading

Diff for: libraries/OPAMP/amp_screenshot.png

26.3 KB
Loading

Diff for: libraries/OPAMP/amp_symbol.png

3.66 KB
Loading

Diff for: libraries/OPAMP/examples/start_opamp/start_opamp.ino

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <OPAMP.h>
2+
3+
void setup () {
4+
Serial.begin(9600);
5+
delay(2000); // serial monitor delay
6+
// activate OPAMP, default channel 0
7+
// Plus: Analog A1
8+
// Minus: Analog A2
9+
// Output: Analog A3
10+
if (!OPAMP.begin(OPAMP_SPEED_HIGHSPEED)) {
11+
Serial.println("Failed to start OPAMP!");
12+
}
13+
bool const isRunning = OPAMP.isRunning(0);
14+
if (isRunning) {
15+
Serial.println("OPAMP running on channel 0!");
16+
} else {
17+
Serial.println("OPAMP channel 0 is not running!");
18+
}
19+
}
20+
21+
void loop() {
22+
delay(1000); // do nothing
23+
}

Diff for: libraries/OPAMP/library.properties

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name=OPAMP
2+
version=1.0.0
3+
author=Maximilian Gerhardt
4+
maintainer=Maximilian Gerhardt <[email protected]>
5+
sentence=Library for using the OPAMP on Arduino UNO R4 boards.
6+
paragraph=Supports OPAMP on Arduino UNO R4 (Minima, WiFi).
7+
category=Signal Input/Output
8+
url=https://github.com/arduino/ArduinoCore-renesas/tree/main/libraries/OPAMP
9+
architectures=renesas,renesas_uno
10+
includes=OPAMP.h

Diff for: libraries/OPAMP/src/OPAMP.cpp

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#include "OPAMP.h"
2+
#include <Arduino.h>
3+
4+
/* Make sure this library fails to compile for unsupported boards. */
5+
#if !defined(ARDUINO_UNOWIFIR4) && !defined(ARDUINO_MINIMA)
6+
#error "Unsupported board for OPAMP library."
7+
#endif
8+
9+
/* pin mode needed to activate OPAMP functionality */
10+
#define OPAMP_IN_PINCFG (IOPORT_CFG_PORT_DIRECTION_INPUT | IOPORT_CFG_PERIPHERAL_PIN | IOPORT_CFG_ANALOG_ENABLE)
11+
#define OPAMP_OUT_PINCFG (IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PERIPHERAL_PIN | IOPORT_CFG_ANALOG_ENABLE)
12+
#define FSP_CHECK(err) do { if( (err) != FSP_SUCCESS) return false; } while(0)
13+
14+
// Compact structure for OPAMP channel pins
15+
struct opamp_channel_pins_t {
16+
bsp_io_port_pin_t plus;
17+
bsp_io_port_pin_t minus;
18+
bsp_io_port_pin_t output;
19+
};
20+
21+
// See Renesas RA4M1 Group Datasheet
22+
// Note: Channel 0 is the only accessible one one the Arduino Minima boards.
23+
static const opamp_channel_pins_t opamp_channels[] = {
24+
{BSP_IO_PORT_00_PIN_00, BSP_IO_PORT_00_PIN_01, BSP_IO_PORT_00_PIN_02}, /* CH0 */
25+
{BSP_IO_PORT_00_PIN_13, BSP_IO_PORT_00_PIN_12, BSP_IO_PORT_00_PIN_03}, /* CH1 */
26+
{BSP_IO_PORT_00_PIN_11, BSP_IO_PORT_00_PIN_10, BSP_IO_PORT_00_PIN_04}, /* CH2 */
27+
{BSP_IO_PORT_00_PIN_05, BSP_IO_PORT_00_PIN_06, BSP_IO_PORT_00_PIN_07}, /* CH3 */
28+
};
29+
30+
bool OpampClass::initPins(uint8_t const channel_mask) {
31+
fsp_err_t err;
32+
ioport_instance_ctrl_t ioport_ctrl {};
33+
// Make sure to return false if nothing was given to initialize
34+
// or a too high channel bit is in there
35+
if (channel_mask == 0 || channel_mask > 0b1111) {
36+
return false;
37+
}
38+
// Check the 4 possible channels
39+
for (uint8_t i = 0; i < 4; i++) {
40+
// was this channel selected?
41+
if (!(channel_mask & (1u << i))) {
42+
continue;
43+
}
44+
opamp_channel_pins_t pins = opamp_channels[i];
45+
err = R_IOPORT_PinCfg(&ioport_ctrl, pins.plus, OPAMP_IN_PINCFG);
46+
FSP_CHECK(err);
47+
err = R_IOPORT_PinCfg(&ioport_ctrl, pins.minus, OPAMP_IN_PINCFG);
48+
FSP_CHECK(err);
49+
err = R_IOPORT_PinCfg(&ioport_ctrl, pins.output, OPAMP_OUT_PINCFG);
50+
FSP_CHECK(err);
51+
}
52+
// if we got here, none of the checks triggered an early return.
53+
return true;
54+
}
55+
56+
void OpampClass::initOpamp(OpampSpeedMode speed, uint8_t const channel_mask) {
57+
uint8_t ampmc_val = 0U;
58+
/* setup amplifier speed mode within amplifier mode control */
59+
/* for all boards, this is at bit position 7 with either 0 (lowspeed) or 1 (highspeed) */
60+
ampmc_val = (uint8_t) ((uint8_t) speed << R_OPAMP_AMPMC_AMPSP_Pos) & R_OPAMP_AMPMC_AMPSP_Msk;
61+
/* reset opamp */
62+
R_OPAMP->AMPC = 0U;
63+
/* write prepared mode control value */
64+
R_OPAMP->AMPMC = ampmc_val;
65+
/* setup activation trigger select register */
66+
/* we only support "Software start & stop" for now, value 0. */
67+
R_OPAMP->AMPTRS = 0;
68+
R_OPAMP->AMPTRM = 0;
69+
/* set the bits for the activated channels */
70+
R_OPAMP->AMPC |= channel_mask;
71+
/* note: we don't have to activate the charge pump (AMPCPC) because here AVCC0 > 2.7V */
72+
/* delay for the wanted init time in microseconds */
73+
if (speed == OPAMP_SPEED_LOWSPEED) {
74+
delayMicroseconds(BSP_FEATURE_OPAMP_MIN_WAIT_TIME_LP_US);
75+
} else if (speed == OPAMP_SPEED_HIGHSPEED) {
76+
delayMicroseconds(BSP_FEATURE_OPAMP_MIN_WAIT_TIME_HS_US);
77+
}
78+
}
79+
80+
bool OpampClass::begin() {
81+
return this->begin(OPAMP_SPEED_HIGHSPEED);
82+
}
83+
84+
bool OpampClass::begin(OpampSpeedMode const speed) {
85+
86+
return this->begin(1u << ARDUINO_UNO_R4_DEFAULT_OPAMP_CHANNEL, speed);
87+
}
88+
89+
bool OpampClass::begin(uint8_t const channel_mask, OpampSpeedMode const speed) {
90+
91+
if (!initPins(channel_mask)) {
92+
return false;
93+
}
94+
initOpamp(speed, channel_mask);
95+
return true;
96+
}
97+
98+
bool OpampClass::isRunning(uint8_t const channel) {
99+
return (R_OPAMP->AMPMON & (1u << channel)) != 0;
100+
}
101+
102+
void OpampClass::end() {
103+
// deactivate all channels.
104+
R_OPAMP->AMPC = 0;
105+
}
106+
107+
void OpampClass::end(uint8_t const channel_mask) {
108+
// deactivate given channels
109+
R_OPAMP->AMPC &= ~channel_mask;
110+
}
111+
112+
/* global instance */
113+
OpampClass OPAMP;

Diff for: libraries/OPAMP/src/OPAMP.h

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#ifndef _OPAMP_H_
2+
#define _OPAMP_H_
3+
4+
#include <stdint.h>
5+
6+
/* Available speed modes */
7+
/* Note: No middle speed mode on the Uno R4 boards */
8+
enum OpampSpeedMode {
9+
OPAMP_SPEED_LOWSPEED = 0,
10+
OPAMP_SPEED_HIGHSPEED = 1,
11+
};
12+
13+
/* The supported boards have 4 OPAMP channels, however, only channel 0 is accessible. */
14+
/* All other channels are connected to the LED matrix or not exposed. */
15+
#define ARDUINO_UNO_R4_DEFAULT_OPAMP_CHANNEL 0
16+
17+
/**
18+
* Pin Mapping for OPAMP
19+
* Arduino UNO R4 (Minima, WiFi):
20+
* ~Channel 0~
21+
* Plus: Analog A1 (Renesas P0.00)
22+
* Minus: Analog A2 (Renesas P0.01)
23+
* Output: Analog A3 (Renesas P0.02)
24+
* ~Channel 1~ (Inaccessible)
25+
* +: P0.13, -: Renesas P0.12, Out: Renesas P0.03
26+
* ~Channel 2~ (Inaccessible)
27+
* +: P0.11, -: Renesas P0.10, Out: Renesas P0.04
28+
* ~Channel 3~ (Inaccessible)
29+
* +: P0.05, -: Renesas P0.06, Out: Renesas P0.07
30+
*/
31+
class OpampClass {
32+
public:
33+
/* startup the OPAMP on channel 0 in high-speed mode */
34+
bool begin();
35+
/* startup the OPAMP on channel 0 with specific mode */
36+
bool begin(OpampSpeedMode const speed);
37+
38+
/* startup the OPAMP with arbitrary channel mask */
39+
bool begin(uint8_t const channel_mask, OpampSpeedMode const speed);
40+
41+
/* stop all OPAMP channels */
42+
void end();
43+
/* stop specific OPAMP channel(s) */
44+
void end(uint8_t const channel_mask);
45+
/* returns true if the specified OPAMP channel number is running */
46+
bool isRunning(uint8_t const channel);
47+
private:
48+
/* initializes OPAMP pins for given channel(s) */
49+
bool initPins(uint8_t const channel_mask);
50+
/* activates OPAMP for given speed and channel(s) */
51+
void initOpamp(OpampSpeedMode const speed, uint8_t const channel_mask);
52+
53+
};
54+
55+
extern OpampClass OPAMP;
56+
57+
#endif /* _OPAMP_H_ */

0 commit comments

Comments
 (0)