Search code examples
c++raspberry-pispidacwiringpi

How to correctly use wiringPiSPISetupMode for MAX5144 DAC IC on SPI1, CS1?


I am working on interfacing the MAX5144 DAC using SPI communication on a Raspberry Pi (SPI1, CS1). Below is my main program and my SPI testing program.

The main program initializes the DAC and sets the output value, but I encounter the following error:

wiringPiSPI: Invalid SPI number/channel (need wiringPiSPIxSetupMode before read/write)

The SPI test program runs successfully, confirming that SPI1 and CS1 are correctly set up.

Cmake:

cmake_minimum_required(VERSION 3.10)
project(TemperatureControlProject)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_FLAGS "-g") 

# Add custom module path for FindWiringPi.cmake
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")

include_directories(include)

# Main project executable
add_executable(TemperatureControlProject src/main.cpp src/MAX5144.cpp)
find_package(WiringPi REQUIRED)
target_link_libraries(TemperatureControlProject ${WIRINGPI_LIBRARY})

# SPI test executable
add_executable(SPITest src/spi_test.cpp)
target_link_libraries(SPITest -lwiringPi)

Main Program Code (Error Occurs Here):

#include "MAX5144.h"
#include <iostream>

int main() {
    try {
        MAX5144 dac(1, 17);  // SPI channel 1, CS pin GPIO17
        dac.setDacOutput(4854);  // Set DAC output value
        std::cout << "DAC output successfully set." << std::endl;
    } catch (const std::exception &e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
    return 0;
}

MAX5144.cpp:

#include "MAX5144.h"
#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <iostream>
#include <stdexcept>

MAX5144::MAX5144(int spiChannel, int csPin) : csPin(csPin) {
    wiringPiSetup();
    pinMode(csPin, OUTPUT);
    digitalWrite(csPin, HIGH);

    if (wiringPiSPISetupMode(spiChannel, 500000, 0) < 0) {
        throw std::runtime_error("SPI initialization failed!");
    }
}

void MAX5144::setDacOutput(int value) {
    if (value < 0 || value >= 16384) {
        throw std::invalid_argument("DAC value out of range!");
    }

    int dataWord = value << 2;
    unsigned char msb = (dataWord >> 8) & 0xFF;
    unsigned char lsb = dataWord & 0xFF;

    digitalWrite(csPin, LOW);
    unsigned char buffer[2] = {msb, lsb};
    wiringPiSPIDataRW(1, buffer, 2);  // SPI channel 1
    digitalWrite(csPin, HIGH);

    std::cout << "DAC output set to: " << value << std::endl;
}

MAX5144::~MAX5144() {}

SPI Testing Program (Works Correctly):

#include <wiringPiSPI.h>
#include <iostream>
#include <stdexcept>

int main() {
    int spiChannel = 1;  // Using SPI1
    int speed = 500000;  // SPI speed
    int mode = 0;        // SPI mode 0

    if (wiringPiSPISetupMode(spiChannel, speed, mode) < 0) {
        throw std::runtime_error("SPI1 initialization failed!");
    }
    std::cout << "SPI1 initialized successfully!" << std::endl;

    unsigned char buffer[2] = {0xFF, 0x00};  // Test data
    if (wiringPiSPIDataRW(spiChannel, buffer, 2) < 0) {
        throw std::runtime_error("SPI1 data transfer failed!");
    }
    std::cout << "SPI1 data sent successfully!" << std::endl;

    return 0;
}

Additional Information:

  1. Hardware Test Results: The DAC works perfectly when controlled using Python, so there are no hardware-related issues with the SPI setup or the MAX5144 IC.

  2. Observed Error: The error in the main program suggests a problem with SPI channel initialization (wiringPiSPISetupMode), but the SPI test program verifies that SPI1 and CS1 are functioning as expected.

Questions:

  1. Why does the main program fail with the error regarding wiringPiSPI?
  2. The SPI test program works fine, so is there an issue with how I configure the MAX5144 class?
  3. Is the use of wiringPiSPIDataRW(1, ...) in the MAX5144::setDacOutput method correct for SPI1?

Solution

  • MAX5144 Driver Code

    #include "MAX5144.h"
    #include <wiringPi.h>
    #include <wiringPiSPI.h>
    #include <stdexcept>
    #include <iostream>
    
    // Constructor
    MAX5144::MAX5144(int spiNumber, int spiChannel, int csPin, int speed, int mode)
        : spiNumber(spiNumber), spiChannel(spiChannel), csPin(csPin) {
        // Initialize GPIO for CS
        if (wiringPiSetup() < 0) {
            throw std::runtime_error("Failed to initialize WiringPi!");
        }
        pinMode(csPin, OUTPUT);
        digitalWrite(csPin, HIGH); // Default to deselected state
    
        // Initialize SPI
        if (wiringPiSPIxSetupMode(spiNumber, spiChannel, speed, mode) < 0) {
            throw std::runtime_error("SPI initialization failed for SPI" + std::to_string(spiNumber) +
                                     ", Channel " + std::to_string(spiChannel));
        }
        std::cout << "SPI initialized on SPI" << spiNumber << ", Channel " << spiChannel << std::endl;
    }
    
    // Set DAC Output
    void MAX5144::setDacOutput(int value) {
        if (value < 0 || value > 16383) {
            throw std::invalid_argument("DAC value out of range! Must be between 0 and 16383.");
        }
    
        // Prepare data
        int dataWord = value << 2; // Align 14-bit value
        unsigned char buffer[2] = {
            static_cast<unsigned char>((dataWord >> 8) & 0xFF), // MSB
            static_cast<unsigned char>(dataWord & 0xFF)         // LSB
        };
    
        // SPI Transfer
        digitalWrite(csPin, LOW); // Select chip
        if (wiringPiSPIxDataRW(spiNumber, spiChannel, buffer, 2) < 0) {
            throw std::runtime_error("SPI data transfer failed!");
        }
        digitalWrite(csPin, HIGH); // Deselect chip
    
        std::cout << "DAC output set to: " << value << std::endl;
    }
    
    // Destructor
    MAX5144::~MAX5144() {
        wiringPiSPIClose(spiChannel); // Close SPI channel
    }
    

    mic drop :)

    welcome to visits my github https://github.com/dcl920108/MAX5144-SPI-Driver/blob/main/MAX5144.cpp