0.1.7 MCP_DAC

This commit is contained in:
rob tillaart 2022-10-02 17:19:23 +02:00
parent 8e0ab56977
commit c7cc4b04fa
10 changed files with 428 additions and 54 deletions

View File

@ -1,3 +1,18 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
@ -9,3 +24,4 @@ compile:
- esp32
# - esp8266
# - mega2560
# - rpipico

View File

@ -1,7 +1,7 @@
//
// FILE: MCP_DAC.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.6
// VERSION: 0.1.7
// DATE: 2021-02-03
// PURPOSE: Arduino library for MCP_DAC
// URL: https://github.com/RobTillaart/MCP_DAC
@ -20,6 +20,9 @@
// default parameter 0 for getPercentage()
// extended unit tests
// 0.1.6 2021-12-21 update library.json, license, minor edits
// 0.1.7 2022-10-02 support for RP2040 pico (kudos to Intubin)
// update documentation for RP2040 (kudos to Intubin)
// update build-CI to support RP2040
#include "MCP_DAC.h"
@ -70,6 +73,19 @@ void MCP_DAC::begin(uint8_t select)
mySPI->end();
mySPI->begin(18, 19, 23, select); // CLK=18 MISO=19 MOSI=23
}
#elif defined(ARDUINO_ARCH_RP2040)
if (_useSPI1 == true) {
mySPI = &SPI1;
}else{
mySPI = &SPI;
}
mySPI->end();
mySPI->begin();
#else // generic hardware SPI
mySPI = &SPI;
mySPI->end();
@ -86,7 +102,7 @@ void MCP_DAC::begin(uint8_t select)
}
#if defined(ESP32)
#if defined(ESP32) or defined(ARDUINO_ARCH_RP2040)
void MCP_DAC::setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select)
{
_clock = clk;
@ -96,7 +112,20 @@ void MCP_DAC::setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t selec
digitalWrite(_select, HIGH);
mySPI->end(); // disable SPI
#if defined(ESP32)
mySPI->begin(clk, miso, mosi, select);
#elif defined(ARDUINO_ARCH_RP2040)
mySPI->setCS(select);
mySPI->setSCK(clk);
mySPI->setTX(mosi);
mySPI->begin();
#endif
}
#endif

View File

@ -2,7 +2,7 @@
//
// FILE: MCP_DAC.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.6
// VERSION: 0.1.7
// DATE: 2021-02-03
// PURPOSE: Arduino library for MCP_DAC
// URL: https://github.com/RobTillaart/MCP_DAC
@ -13,7 +13,7 @@
#include "SPI.h"
#define MCP_DAC_LIB_VERSION (F("0.1.6"))
#define MCP_DAC_LIB_VERSION (F("0.1.7"))
@ -74,47 +74,77 @@ public:
void reset();
bool usesHWSPI() { return _hwSPI; };
// ESP32 specific
#if defined(ESP32)
#if defined(ESP32) // ESP32 specific
void selectHSPI() { _useHSPI = true; };
void selectVSPI() { _useHSPI = false; };
bool usesHSPI() { return _useHSPI; };
bool usesVSPI() { return !_useHSPI; };
// to overrule ESP32 default hardware pins
// to overrule the ESP32s default hardware pins
void setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select);
#elif defined(ARDUINO_ARCH_RP2040) // RP2040 specific
// check which SPI-Bus (SPI or SPI1) is used
void selectSPI() { _useSPI1 = false; };
void selectSPI1() { _useSPI1 = true; };
bool usesSPI() { return !_useSPI1; };
bool usesSPI1() { return _useSPI1; };
// to overrule the RP2040s default hardware pins
void setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select);
#endif
protected:
uint8_t _dataOut;
uint8_t _clock;
uint8_t _select;
uint8_t _latchPin = 255;
bool _hwSPI;
uint32_t _SPIspeed = 16000000;
uint8_t _channels;
uint16_t _maxValue;
uint16_t _value[2];
uint8_t _gain;
bool _buffered = false;
bool _active = true;
protected:
uint8_t _dataOut; // Data out Pin (MOSI)
uint8_t _clock; // Clock Pin (SCK)
uint8_t _select; // Chip Select Pin (CS)
uint8_t _latchPin = 255; // Latch-DAC Pin (LDAC)
bool _hwSPI; // Hardware SPI (true) or Software SPI (false)
uint32_t _SPIspeed = 16000000; // SPI-Bus Frequency
uint8_t _channels; // Number of DAC-Channels of a given Chip
uint16_t _maxValue; // Maximum value of a given Chip
uint16_t _value[2]; // Current value (cache for performance)
uint8_t _gain; // Programmable Gain Amplifier variable
bool _buffered = false; // Buffer for the Reference Voltage of the MCP49XX Series Chips
bool _active = true; // Indicates shutDown mode.
void transfer(uint16_t data);
uint8_t swSPI_transfer(uint8_t d);
#if defined(ARDUINO_ARCH_RP2040)
SPIClassRP2040 * mySPI;
#else
SPIClass * mySPI;
#endif
SPISettings _spi_settings;
#if defined(ESP32)
bool _useHSPI = true;
#elif defined(ARDUINO_ARCH_RP2040)
bool _useSPI1 = false;
#endif
};
///////////////////////////////////////////////////////////////
//
// 4800 Series
// MCP4800 Series
//
class MCP4801 : public MCP_DAC
{
@ -160,7 +190,7 @@ public:
///////////////////////////////////////////////////////////////
//
// 4900 Series
// MCP4900 Series
//
class MCP4901 : public MCP_DAC
{

View File

@ -113,7 +113,9 @@ MCP49xxx series only, see page 20 ==> not functional for MCP48xx series.
- **bool usesHWSPI()** returns true if HW SPI is used.
### ESP32 specific
## ESP32 specific
### SPI port selection
This functionality is new in 0.1.2 and it is expected that the interface will change
in the future.
@ -127,7 +129,7 @@ The **selectVSPI()** or the **selectHSPI()** needs to be called
BEFORE the **begin()** function.
#### experimental
### Experimental
- **void setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select)** overrule GPIO pins of ESP32 for hardware SPI. needs to be called
AFTER the **begin()** function.
@ -145,7 +147,7 @@ This interface can change in the future as the **select** pin is known
in the code.
#### ESP32 connections to MCP4922 (example)
### ESP32 connections to MCP4922 (example)
ESP32 has **four** SPI peripherals from which two can be used.
@ -159,15 +161,80 @@ SPI0 and SPI1 are used to access flash memory. SPI2 and SPI3 are "user" SPI cont
| SDI | MOSI = 13 | MOSI = 23 |
| not used | MISO = 12 | MISO = 19 |
By using different **SELECT** pins multiple DAC's can be controlled over
one SPI bus.
## Future
- test test test and ....
- refactor the API
- improve documentation
- ...
## RP2040 specific
### SPI port selection
Select the SPI bus on which the device is on. Both need to be called before the **begin()** function. If the function is called after the **begin()** function, changes will only apply if the **end()** and then the **begin()** functions are called.
- **void selectSPI()** Select the SPI (SPI0) bus. This is the default and does not need to be called.
- **void selectSPI1()** Select the (second) SPI1 bus.
- **bool usesSPI()** returns true if SPI is used
- **bool usesSPI1()** returns true if SPI1 is used
### Experimental
- **void setGPIOpins(uint8_t clk, uint8_t miso, uint8_t mosi, uint8_t select)** overrule GPIO pins of RP2040 for different SPI pins. needs to be called
AFTER the **begin()** function. Selcted pins must match the RP2040 pinout!
```cpp
void setup()
{
MCP.selectSPI(); //use for SPI / SPI0
MCP.selectSPI1(); //use for SPI1
MCP.begin(17);
MCP.setGPIOpins(CLK, MISO, MOSI, SELECT); // SELECT should match the param of begin()
}
```
### Pico connections to MCP4922 (example)
The RP2040 has **two** SPI peripherals from which two can be used.
SPI (SPI0) and SPI1 can both be used to connect devices.
| MCP4922 | SPI / SPI0 | SPI1 |
|:--------:|:-------------:|:-------------:|
| CS | SELECT = 17 | SELECT = 13 |
| SCK | SCLK = 18 | SCLK = 14 |
| SDI | MOSI = 19 | MOSI = 15 |
| not used | MISO = 16 | MISO = 12 |
By using different **SELECT** pins multiple DAC's can be controlled over
one SPI bus.
## Operation
See examples
## Future
#### Must
- test test test and ....
- improve documentation.
#### Should
- **useSPI1** and **useHSPI** are functional identical indicators.
- how to refactor to a generic model? Should work for all libraries.
- int8_t HWSPIport = 0, 1, 2, 3, 4, .... (-1 == SW SPI ?).
- numbers are not self-documenting.
- **selectSPIport(int)** ?
- would reduce conditional code.
#### Could
- refactor the API (how).
- minimize conditional in code if possible.

View File

@ -0,0 +1,27 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
# - uno
# - due
# - zero
# - leonardo
# - m4
# - esp32
# - esp8266
# - mega2560
- rpipico

View File

@ -0,0 +1,198 @@
//
// FILE: MCP4921_wave_generator_RP2040.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo function generators
// DATE: 2021-02-03
// URL: https://github.com/RobTillaart/FunctionGenerator
//
// depending on the platform, the range of "smooth" sinus is limited.
// other signals are less difficult so have a slightly larger range.
//
// PLATFORM SINUS SQUARE SAWTOOTH TRIANGLE
// UNO -100 Hz
// ESP32 -200 Hz -1000 -250 -100
//
/*
SPI Connections:
MOSI: GP 19
SCK: GP 18
CS: GP 17
LDAC: GP 2
SPI1 Connections:
MOSI: GP 15
SCK: GP 14
CS: GP 13
LDAC: GP 3
(Experimental) The Pins can be changed at any time via the setGPIO() command, view the Pico Pinout for compatible Pins
*/
#include "MCP_DAC.h"
uint16_t freq = 10;
uint32_t period = 0;
uint32_t halvePeriod = 0;
// q = square
// s = sinus
// w = sawtooth
// t = triangle
// r = random
char mode = 'q';
MCP4921 MCP;
uint16_t count;
uint32_t lastTime = 0;
// LOOKUP TABLE SINE
uint16_t sine[361];
void setup()
{
Serial.begin(115200);
// fill table with sinus values for fast lookup
for (int i = 0; i < 361; i++)
{
sine[i] = 2047 + round(2047 * sin(i * PI / 180));
}
MCP.selectSPI(); //select SPI
//MCP.selectSPI1(); //select SPI1
MCP.begin(17); // select pin = 17, SPI
//MCP.begin(13); // select pin = 13, SPI1
MCP.fastWriteA(0);
period = 1e6 / freq;
halvePeriod = period / 2;
while (1)
{
// Serial.println(analogRead(A0)); // read output back via A0.
yield();
uint32_t now = micros();
count++;
if (now - lastTime > 100000)
{
lastTime = now;
// Serial.println(count); // show # updates per 0.1 second
count = 0;
if (Serial.available())
{
int c = Serial.read();
switch (c)
{
case '+':
freq++;
break;
case '-':
freq--;
break;
case '*':
freq *= 10;
break;
case '/':
freq /= 10;
break;
case '0' ... '9':
freq *= 10;
freq += (c - '0');
break;
case 'c':
freq = 0;
break;
case 'A':
break;
case 'a':
break;
case 'q':
case 's':
case 'w':
case 't':
case 'r':
case 'z':
case 'm':
case 'h':
mode = c;
break;
default:
break;
}
period = 1e6 / freq;
halvePeriod = period / 2;
Serial.print(freq);
// Serial.print('\t');
// Serial.print(period);
// Serial.print('\t');
// Serial.print(halvePeriod);
Serial.println();
}
}
uint32_t t = now % period;
switch (mode)
{
case 'q':
if (t < halvePeriod ) MCP.fastWriteA(4095);
else MCP.fastWriteA(0);
break;
case 'w':
MCP.fastWriteA(t * 4095 / period );
break;
case 't':
if (t < halvePeriod) MCP.fastWriteA(t * 4095 / halvePeriod);
else MCP.fastWriteA( (period - t) * 4095 / halvePeriod );
break;
case 'r':
MCP.fastWriteA(random(4096));
break;
case 'z': // zero
MCP.fastWriteA(0);
break;
case 'h': // high
MCP.fastWriteA(4095);
break;
case 'm': // mid
MCP.fastWriteA(2047);
break;
default:
case 's':
// reference
// float f = ((PI * 2) * t)/period;
// MCP.setValue(2047 + 2047 * sin(f));
//
int idx = (360 * t) / period;
MCP.fastWriteA(sine[idx]); // lookuptable
break;
}
}
}
void loop()
{
}
// -- END OF FILE --

View File

@ -2,11 +2,13 @@
Note that some examples are ESP32 specific as they use e.g. VSPI()
| example | UNO | ESP32 |
|:-----------------------|:-----:|:-----:|
| MCP4911_test | Y | Y |
| MCP4921_standalone | Y | Y |
| MCP4921_test | Y | Y |
| MCP4921_VSPI | N | Y |
| MCP4921_wave_generator | N | Y |
| example | UNO | ESP32 | RP2040 |
|:-----------------------------:|:-----:|:-----:|:------:|
| MCP4911_test | Y | Y | Y |
| MCP4921_standalone | Y | Y | Y |
| MCP4921_test | Y | Y | Y |
| MCP4921_VSPI | N | Y | N |
| MCP4921_wave_generator | Y | Y | Y |
| MCP4921_wave_generator_ESP32 | N | Y | N |
| MCP4921_wave_generator_RP2040 | N | N | Y |

View File

@ -52,6 +52,11 @@ setGPIOpins KEYWORD2
increment KEYWORD2
decrement KEYWORD2
selectSPI KEYWORD2
selectSPI1 KEYWORD2
usesSPI KEYWORD2
usesSPI1 KEYWORD2
# Instances (KEYWORD2)
# Constants (LITERAL1)

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/MCP_DAC"
},
"version": "0.1.6",
"version": "0.1.7",
"license": "MIT",
"frameworks": "arduino",
"platforms": "*",

View File

@ -1,9 +1,9 @@
name=MCP_DAC
version=0.1.6
version=0.1.7
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for Microchip SPI DAC, 8, 10, 12 bit; 1 or 2 channel.
paragraph= MCP4801, MCP4802, MCP4811,MCP4812, MCP4821, MCP4822, MCP4901, MCP4902, MCP4911, MCP4912, MCP4921, MCP4922
paragraph= MCP4801, MCP4802, MCP4811,MCP4812, MCP4821, MCP4822, MCP4901, MCP4902, MCP4911, MCP4912, MCP4921, MCP4922.
category=Sensors
url=https://github.com/RobTillaart/MCP_DAC
architectures=*