diff --git a/.arduino-ci.yml b/.arduino-ci.yml index cecf585..9786d52 100644 --- a/.arduino-ci.yml +++ b/.arduino-ci.yml @@ -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 diff --git a/MCP_DAC.cpp b/MCP_DAC.cpp index a30b45b..17ccc8c 100644 --- a/MCP_DAC.cpp +++ b/MCP_DAC.cpp @@ -70,6 +70,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(); @@ -85,8 +98,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 +108,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 diff --git a/MCP_DAC.h b/MCP_DAC.h index c3f1b42..6f8bb90 100644 --- a/MCP_DAC.h +++ b/MCP_DAC.h @@ -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 @@ class MCP_DAC 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; + 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 + uint8_t _gain; // Programmable Gain Amplifier variable + bool _buffered = false; // Buffer for the Reference Voltage of the MCP49XX Series Chips bool _active = true; 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 @@ class MCP4822 : public MCP_DAC /////////////////////////////////////////////////////////////// // -// 4900 Series +// MCP4900 Series // class MCP4901 : public MCP_DAC { diff --git a/README.md b/README.md index d921cbc..a5d5c1e 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,48 @@ SPI0 and SPI1 are used to access flash memory. SPI2 and SPI3 are "user" SPI cont | not used | MISO = 12 | MISO = 19 | + +### RP2040 specific + +Select 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 bus (Standard, does not need to be called) +- **void selectSPI1()** Select the 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 usd 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 | + + ## Future - test test test and .... diff --git a/examples/MCP4921_wave_generator_RP2040/.arduino-ci.yml b/examples/MCP4921_wave_generator_RP2040/.arduino-ci.yml new file mode 100644 index 0000000..87acfe0 --- /dev/null +++ b/examples/MCP4921_wave_generator_RP2040/.arduino-ci.yml @@ -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 diff --git a/examples/MCP4921_wave_generator_RP2040/MCP4921_wave_generator_RP2040.ino b/examples/MCP4921_wave_generator_RP2040/MCP4921_wave_generator_RP2040.ino new file mode 100644 index 0000000..f677b91 --- /dev/null +++ b/examples/MCP4921_wave_generator_RP2040/MCP4921_wave_generator_RP2040.ino @@ -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 -- diff --git a/examples/readme.md b/examples/readme.md index 1aedf22..3e94ace 100644 --- a/examples/readme.md +++ b/examples/readme.md @@ -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 |