0
\$\begingroup\$

Referencing ATmega328p manual, I only can send 1 byte at time. However MCP4802 specs say that MCP4802 wish to get 2 bytes (4 info bits + 8 data bits + 4 don't care bits).

I have written Arduino code that should send this data to MCP4802, however it doesn't work - output on oscilloscope is noise :(

What is wrong with my SPI interfacing with MCP4802?? How do I send data to it?

Code:

byte counter = 0;

void setup() {
  DDRB |= (1 << DDB5) | (1 << DDB3) | (1 << DDB2); // SPI.begin();
  PORTB |= (1 << PORTB2); // CS goes ON
  SPCR = (1 << SPE) | (1 << MSTR) | (0 << CPOL) | (0 << CPHA) | (8 << SPR0); // SPI init
}

void loop() {
  PORTB &= ~(1 << PORTB2); // CS LOW
  SPDR = 0b00010000;
  SPDR = sine_wave[counter];
  SPDR = 0b00000000;
  while (!(SPSR & (1<<SPIF)));
  PORTB |= (1 << PORTB2); // CS BACK HIGH
  counter++;
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

As you have guessed, you just send the bytes one after the next. The MCP4802 won't know whether you sent them as two 8 bit numbers, or one 16 bit number. This is in fact one of the purposes of the chip select signal - it's used by the slave device to correct align itself so that it knows when the first byte is being sent.

The problem is with the way you are loading the data register. For each 8-bit byte you load into the register, you must wait for the ATMega to finish sending it before you can load another byte. By loading another byte before the first one is sent, you will end up with a write collision (sets WCOL flag is SPSR), in which case the second data byte is lost.

The following psuedo code explains how it's done:

Chip select low
...
SPDR = firstByte;
while (!(SPSR & (1<<SPIF)));
SPDR = secondByte;
while (!(SPSR & (1<<SPIF)));
...
Chip select back high
\$\endgroup\$
3
  • \$\begingroup\$ You are the best! Thank you very much! Btw have you an idea why my signal is ca 1 V at the output? I have set my MCP4802 SPI to 0b0001000, which means USE GAIN of 2? So first byte is 0b0001000, second is 8 byte data and last is 8 bytes don't care \$\endgroup\$ Commented Nov 30, 2022 at 0:15
  • 2
    \$\begingroup\$ @ojacomarket According to the datasheet (page 23), you should be sending only two 8-bit bytes, not three. The first byte contains the four control bits plus the upper four bits of the DAC output, and the second byte contains the lower four bits of the data. For the 8-bit DAC, you would send (config << 4) | (data >> 4) for the first byte, and (data << 4) for the second byte, where data is a uint8_t containing your waveform, and config is a uint8_t containing the four config bits, e.g. 0b0001 would be gain of 2. \$\endgroup\$ Commented Nov 30, 2022 at 0:31
  • \$\begingroup\$ perfect! Works like charm! Have a good day and thanks again for your time! \$\endgroup\$ Commented Nov 30, 2022 at 0:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.