// Output a sine wave from a TLC5615 10-bitDAC
#include <SPI.h>
const int CS = D0; // Define the Chip Select pin
const unsigned char sine256[] = {
127,130,133,136,139,143,146,149,152,155,158,161,164,167,170,173,
176,178,181,184,187,190,192,195,198,200,203,205,208,210,212,215,
217,219,221,223,225,227,229,231,233,234,236,238,239,240,242,243,
244,245,247,248,249,249,250,251,252,252,253,253,253,254,254,254,
254,254,254,254,253,253,253,252,252,251,250,249,249,248,247,245,
244,243,242,240,239,238,236,234,233,231,229,227,225,223,221,219,
217,215,212,210,208,205,203,200,198,195,192,190,187,184,181,178,
176,173,170,167,164,161,158,155,152,149,146,143,139,136,133,130,
127,124,121,118,115,111,108,105,102,99,96, 93,90,87,84,81,
78,76,73,70,67,64,62,59,56,54,51,49,46,44,42,39,
37,35,33,31,29,27,25,23,21,20,18,16,15,14,12,11,
10,9,7,6,5,5,4,3,2,2,1,1,1,0,0,0,
0,0,0,0,1,1,1,2,2,3,4,5,5,6,7,9,
10,11,12,14,15,16,18,20,21,23,25,27,29,31,33,35,
37,39,42,44,46,49,51,54,56,59,62,64,67,70,73,76,
78,81,84,87,90,93,96,99,102,105,108,111,115,118,121,124 };
void setup() {
Serial.begin(115200); // open the serial port
SPI.begin();
SPI.setBitOrder(MSBFIRST); //We know this from the Data Sheet
// This defines the SPI clock rate.
// The default appears to be 1MHz (1000000). That gives a sine
// with a frequency of about 153Hz (using a NodeMCU with a clock
// of 80MHz - eat your heart out, puny 16MHz Arduinos)
// Raisng the SPI clock to 4MHz gives us a 360Hz sinewave
// 16 525Hz
// 20MHz seems to be about the limit with 555Hz
// Also note that the sine frequency (and by implication, the SPI clock)
// does not change smoothly. For example, at 7.26 and 7.27MHz the sine frequency
// is 428 Hz, but at 7.28MHz it is 447 Hz.
SPI.setFrequency(7280000);
pinMode(CS,OUTPUT);
digitalWrite(CS, HIGH);
}
// Use this data structure to write 16 bits that will be sent down the SPI
// in 2 chunks, most significant byte first.
struct spi_bytes_t {
byte bl;
byte bh;
};
typedef union spidata_t {
spi_bytes_t b;
unsigned int d;
};
spidata_t a;
void loop() {
/* Note, it is important to exit from loop() to let other things happen
* in the background. An example is that staying in the loop forever will
* trigger the WDT and reset the device. It probably does nasty things tp
* the WiFi, too.
*/
for(int i = 0; i < 256; i++) {
digitalWrite(CS, LOW); // select slave. this doesn't get done by the
// SPI code
a.d = sine256[i] << 3; // This level of shifting (3 bits) gives a pk-pk
// of 3.3V without clipping. I.E. 11 data bits.
// of which only the top 10 are used by the D-A
// Going to the full range of the D-A (4 bits shifted)
// Results in clipping of the top, since this exceeds
// the 3.3V reference voltage.
SPI.transfer(a.b.bh); // Although we send 16 bits, the first 4
SPI.transfer(a.b.bl); // appear to gets clocked out and only the
// last 12 bits are retained by the device
digitalWrite(CS, HIGH); // de-select slave
}
}
The output doesn't look too bad. It's a bit noisy, but I put a 10n capacitor across the Vref - 0v which helps.
The DAC is a TLC5615, 8 pin 10 bit device.
On my NodeMCU (there appear to be different varieties, not all of them implement everything the same) the SPI MOSI function is pin D7 and CLK is D5.
I used the NodeMCU 3.3V output as Vref and powered the DAC from the USB power.
CS came from pin D0.