2024-01-09 10:51 AM
Hi, I am writing a driver for the AD5262 digital potentiometer, which uses SPI type serial but requires a 9 bit data format. I would much rather use the HAL SPI library (which has worked on similar AD family pots) and not use bitbanging. However the pot is not responsive to my messages, when I've tried a variety of methods to format this data.
Here is my driver code:
extern SPI_HandleTypeDef hspi2;
static void delay(void) {
static volatile int x = 0;
for (int i = 0; i < 100; i++) {
x += 1;
}
}
void ad5262_init(void) {
HAL_GPIO_WritePin(CS_DP_GPIO_Port, CS_DP_Pin, GPIO_PIN_SET);
}
static uint8_t pot_targets[2];
static uint8_t pot_vals[2];
static void ad5262_write_spi(uint8_t pot, uint8_t val){
uint8_t spi_block[2];
spi_block[0] = (pot << 7) | (val >> 1);
spi_block[1] = val << 7;
// spi_block[0] = pot;
// spi_block[1] = val;
HAL_StatusTypeDef res;
delay();
HAL_GPIO_WritePin(CS_DP_GPIO_Port, CS_DP_Pin, GPIO_PIN_RESET);
delay();
res = HAL_SPI_Transmit(&hspi2, (uint8_t*) spi_block, sizeof(spi_block), 5);
if(res != HAL_OK){
delay();
}
delay();
HAL_GPIO_WritePin(CS_DP_GPIO_Port, CS_DP_Pin, GPIO_PIN_SET);
delay();
}
void ad5262_set(uint8_t pot, uint8_t val) {
assert(pot < 2);
pot_targets[pot & 0x1] = val;
}
void ad5262_set_both(uint8_t val1, uint8_t val2) {
pot_targets[0] = val1;
pot_targets[1] = val2;
}
void ad5262_service(void) {
static uint64_t last = 0;
if (now() < last + 1) {
return;
}
last = now();
static uint8_t pot = 0;
bool changed = false;
for (int i = 0; i < 2; i++) {
if(i == pot){
if (pot_targets[i] > pot_vals[i]) {
pot_vals[i]++;
changed = true;
} else if (pot_targets[i] < pot_vals[i]) {
pot_vals[i]--;
changed = true;
}
}
}
if (changed) {
ad5262_write_spi(pot, pot_vals[pot]);
}
pot = (pot + 1) % 2;
}
The SPI write returns HAL_OK every time. Is there anything else I could be missing?
The one weird thing I notice is that the MX config for this project doesn't have options for the SPI data format like normal (motorola, MSB first). Is there anything that could be going on in that regard?
Please advise! I found this other post on using this pot as well but neither way I formatted the data into 2 8 bit writes worked for me: https://community.st.com/t5/stm32cubemx-mcus/idea-needed-for-9-bit-spi-transfer-using-hal-library/td-p/459375
2024-01-09 11:21 AM - edited 2024-01-09 11:22 AM
What chip are you using?
Not all chips support 9-bit SPI word size.
2024-01-09 03:01 PM
This project is using STM32L152. As shown in the code above we are not using a 9-bit SPI word size, but rather breaking the 9-bit word into two 8-bit SPI packets.
One thing we have found however is that the clock signal looks strange on our oscilloscope. It appears to be written fully high with small blips above 3.3V during write periods:
Is there anything in MX setup that might account for this?
We have tested the board for shorts and found none. Data and Chip Select Signals look normal:
This is our schematic for the digital pot:
This is our MX config:
2024-01-09 05:00 PM - edited 2024-01-09 05:13 PM
Analog Devices is a serious company, they don't employ ****s. Of course they considered SPI controllers that can only send whole bytes.
The document says clearly: "For the AD5262, the last nine bits of the data word entered into the
serial register are held when CS returns high. Any extra bits are ignored. " (page 15). The MSBit goes out first. So, just output 16 bits where your 9-bit data is aligned to the right (LSB goes out last).
void ad5262_write_spi(uint8_t pot, uint8_t val){
uint8_t spi_block[2];
spi_block[0] = val; // LSbyte = value
spi_block[1] = pot & 1; // MSbyte = channel 0/1
...............
}
2024-01-09 05:16 PM
If SCK is always high, even when it should be sending clocks, yeah that's the problem, or at least one of the problems. There's no CubeMX setting to do this, it's likely a hardware fault.
I wouldn't worry too much about the noise, at least not if SCK is otherwise behaving normally. Is something happening in your system at ~200 kHz?
2024-01-09 05:28 PM
Thanks for confirming this is likely hardware, that will be very helpful in tracking the bug down. We are going to further hardware tests
2024-01-09 05:36 PM - edited 2024-01-09 05:38 PM
@Pavel A. wrote:Analog Devices is a serious company, they don't employ ****s. Of course they considered SPI controllers that can only send whole bytes.
The document says clearly: "For the AD5262, the last nine bits of the data word entered into the
serial register are held when CS returns high. Any extra bits are ignored. " (page 15). The MSBit goes out first. So, just output 16 bits where your 9-bit data is aligned to the right (LSB goes out last).
void ad5262_write_spi(uint8_t pot, uint8_t val){
uint8_t spi_block[2];
spi_block[0] = val; // LSbyte = value
spi_block[1] = pot & 1; // MSbyte = channel 0/1
...............
}
Hmmm... could you explain how the code example you sent matches up with what's described in the datasheet?
Your example appears that is would send out the wiper value then the address bit, whereas the datasheet clearly shows the address bit coming first:
I think the main question here is whether the extra zeros should come before or after the 9 bit word. Can you clarify that?
spi_block[0] = (pot << 7) | (val >> 1); //zeros after data
spi_block[1] = val << 7;
// spi_block[0] = pot; //zeros before data
// spi_block[1] = val;
It sounds like maybe you are saying the zeros go before the data, but have the order of the SPI blocks reversed in your example?
2024-01-10 01:13 PM - edited 2024-01-10 01:15 PM
Yes , the zeros go before the data. I can be wrong with the bytes/bits order. The STM32 Ref. Manual shows that bits on SPI interface go out from MSB (first) to LSB (last). The last 9 bits of 16 do matter. Thus I defined the array so that the significant bits are LOW - assuming that the SPI data size is 16 bit. You've got the idea. You can set the SPI data size to 8 bits as well. Please use a logic analyzer to check what actually goes onto the wires.