Proper use of SPI functions in RP2040 C/C++ SDK with PGA2310 volume control IC

May 2024 ยท 4 minute read

I've been working on a project where I use a PGA2310 volume control IC to set the volume of an audio signal. The chip's interface is supposedly SPI, but no matter how much I try, I just can't seem to get it right. The chip takes a 16 bit word over SPI that contains the left and right channel volume information.

I'm wondering if I am using the sdk all wrong and my code is whacked.

I guess my question is: Am I setting up and using the SPI functions correctly?

Here is my code

 /** * SPI interface for PGA2310 volume control ic */ #include "pico/stdlib.h" #include "hardware/spi.h" #include "pico/time.h" const int CS = 0; const int SDI = 1; const int SCLK = 2; const int LED_PIN16 = 16; const int LED_PIN25 = 25; uint16_t PGA2310(); uint16_t PGA2310() { int baud = 1600000; // SPI inistalization spi_init(spi0, baud); spi_set_format(spi0, 16, SPI_CPOL_0 , SPI_CPHA_0, SPI_MSB_FIRST); // Sets SPI pins gpio_set_function(CS, GPIO_FUNC_SPI); gpio_set_function(SDI, GPIO_FUNC_SPI); gpio_set_function(SCLK, GPIO_FUNC_SPI); // Sets LED pins gpio_init(LED_PIN16); gpio_set_dir(LED_PIN16, GPIO_OUT); gpio_init(LED_PIN25); gpio_set_dir(LED_PIN25, GPIO_OUT); // Data to send to chip. only sending first 8 bits for right channel. // This is because I am currently just testing the output of the right channel uint16_t high = 255; uint16_t low = 100; // Test by toggling between high and low volume states with LED indicators while (true) { gpio_put(LED_PIN25, 1); spi_write16_blocking(spi0, &high, 1); sleep_ms(2000); gpio_put(LED_PIN25, 0); spi_write16_blocking(spi0, &low, 1); sleep_ms(2000); } } 

I've tried a bunch of different methods that I found online for using SPI with the pico SDK. I've tried just sending 8 bits.

Let me know if more info is needed.

7

2 Answers

As explained in comments, SPI normally consists of 4 signals: /SS, SCLK, MOSI and MISO.

In this case the MCU is the master so you should be using MOSI/SDO. A MCU is almost always the master, except when communicating with other MCUs.

Additionally, always double check which CPOL and CPHA settings that the slave expects. Getting these wrong is a classic problem and can lead to subtle "clock skew" problems where everything works fine most of the time, then fail and give corrupt data intermittently.

2

The names you pick for variables/constants in C code do not have any effect on the hardware and they disappear as soon as the code is compiled. The most important thing is that you understand how the hardware works, read the documentation for the RP2040 SDK functions you are calling, and then pass the correct values to the RP2040 SDK functions.

The biggest problem is that you need to rethink every pin assignment. The RP2040 hardware SPI pin functions are defined in column F1 of the "GPIO Functions" section of the RP2040 datasheet. Here is an excerpt from that table:

Excerpt of RP2040 GPIO functions table

This table tells us, for example, you cannot use pin 0 as the SPI0 CS function. If you assign that pin to be an SPI pin, it will be the SPI0 RX (data receiving) pin.

At a minimum, you need to pick one pin to be the SPI0 SCK pin and another to be the SPI0 TX pin, and you must connect those pins from the RP2040 to the equivalent pins on your device. Then you might also need to pick an RP2040 pin to control the CS pin on your device, if it has one. On the RP2040 side, this pin would be configured as a GPIO output pin and you would drive it low or high to enable your device. Refer to your device's datasheet for details about what signals it expects on its inputs and then use an oscilloscope to make sure you are generating compliant signals.

Another problem is that the spi_write16_blocking is probably modifying your high and low variables, so you will probably need to set those to the right values before each time that you use them. (So there is no point in having two different variables like that, just have one.)

1

ncG1vNJzZmirpJawrLvVnqmfpJ%2Bse6S7zGiorp2jqbawutJobm1wZ2h%2Bdn%2BOqamoqJWnera%2FxGamn2WjpbZustSnmq2hn6PAbrXNZqmpamBpfW6vjJxkrJybYsSqwMdmp6CZYmh%2BcXnVqKOupZVisLC606umpWWZmA%3D%3D