Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

STM32 Interfacing with AD5940

uranyumx

Full Member level 1
Joined
Mar 5, 2011
Messages
96
Helped
1
Reputation
2
Reaction score
0
Trophy points
1,286
Activity points
2,053
Hello,

On my custom designed PCB, there is an AD5940 for impedance measurements with using the STM32F4 processor SPI communication.
My first target is that reading chip ID register to make sure that there is no issue between the processor and AD5940.
There are existing applications in github (https://github.com/analogdevicesinc/ad5940-examples) but when I download it,
I got an error message because I have a custom design board and they do with evaluation boards.

Keil Error.png
 
Hi

SPI is no rocket science.
Just send a couple of bytes ... and receive some at the same time.

I guess it's faster to write these couple of code lines in your own.

Klaus
 
Thank you! @KlausST

Here is my first attempt to control the SPI based on the datasheet:

Code:
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi3;

/* USER CODE BEGIN PV */

uint16_t SPICMD_SETADDR;
uint16_t SPICMD_WRITEREG;
uint16_t SPICMD_READREG;


/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI3_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */



/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI3_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      SPICMD_SETADDR = 0x20;
      HAL_SPI_Transmit(&hspi3,(uint8_t*)&SPICMD_SETADDR,2,100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);

      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      SPICMD_WRITEREG = 0x2D;
      HAL_SPI_Transmit(&hspi3,(uint8_t*)&SPICMD_WRITEREG,2,100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);

      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      SPICMD_READREG = 0x6D;
      HAL_SPI_Transmit(&hspi3,(uint8_t*)&SPICMD_READREG,2,100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);


  }
  /* USER CODE END 3 */
}
 

Attachments

  • AD5940 SPI.png
    AD5940 SPI.png
    765 KB · Views: 63
I think the SPI command would be transmit and receive instead of transmit only. Because in that case, what should I monitor for verification of the codes?
--- Updated ---

When I update my code like at below, I got 32896 which equals to 1000000010000000 from all three variables (SPICMD_SETADDR, SPICMD_WRITEREG, and SPICMD_READREG).

Code:
HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      SPICMD_SETADDR = 0x20;
      HAL_SPI_TransmitReceive(&hspi3,(uint8_t*)&SPICMD_SETADDR,(uint8_t*)&SPICMD_SETADDR, 2,100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);

      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      SPICMD_WRITEREG = 0x2D;
      HAL_SPI_TransmitReceive(&hspi3,(uint8_t*)&SPICMD_WRITEREG,(uint8_t*)&SPICMD_WRITEREG, 2, 100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);

      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      SPICMD_READREG = 0x6D;
      HAL_SPI_TransmitReceive(&hspi3,(uint8_t*)&SPICMD_READREG,(uint8_t*)&SPICMD_READREG, 2,100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);
 
Last edited:
I have another attempt to read chip ID register but I got 0 from chipID variable with this code:
Code:
 uint8_t chipID;
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      uint8_t command = 0x80; // Construct the read command (bit 7: Read, bits 6-0: Address)
      chipID = HAL_SPI_Transmit(&hspi3,(uint8_t*)&command,2,100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);
      return chipID;
 
Hi,

Did you follow the datasheet cgapter: "WRITING TO AND READING FROM REGISTERS"?
Especially "needs two SPI transactions"...2
I can't find them in post#6.
Nor do I find an SPI read.

Just follow the datasheet line by line..

Klaus
 
Read/Write operation is described in data sheet as follows:
1. Write the command byte and configure the registeraddress.
a. Drive CS low.
b. Send 8-bit command byte: SPICMD_SETADDR.
c. Send 16-bit address of register to read to or writefrom.
d. Pull CS high.
2. Write the data to the register.
a. Drive CS low.
b. Send 8-bit command byte:SPICMD_WRITEREG.
c. Write either 16-bit or 32-bit data to the register.d. Bring CS high.
3. Read the data from the register.
a. Drive CS low.
b. Send 8-bit command byte: SPICMD_READREG.
c. Transmit a dummy byte on the SPI bus to initiate aread.
d. Read returning 16-bit or 32-bit data.
e. Bring CS high
I'm seeing several problems in your posted code:
1. no register address send with SETADDR command, e.g. 0x0404 for chip ID
2. SETADDR command is expected to transmit 3 bytes rather than 2
3. WRITEREG/READREG transfers either 3 or 5 bytes (16/32 bit data), 3 bytes for chip ID reg
 
Hello!

Have you tried to use CubeMX to generate the code? The advantage is that you have something that works
at once, and you just have to fill the blanks, the "holes" in the code. Therefore if you call the generated "TransmitReceive" function (please check the real name), then you're absolutely sure it will work.

Before generating the code, you can model your board using a very handy, yet powerful graphical interface, which allows you to easily find the position of your pins, and at the end you can generate a working code frame.

The learning curve is not that steep, and anyway you can ask. I'm sure I'm not the only one here using it.

Dora

Hello,

On my custom designed PCB, there is an AD5940 for impedance measurements with using the STM32F4 processor SPI communication. My first target is that reading chip ID register to make sure that there is no issue between the processor and AD5940. There are existing applications in github (https://github.com/analogdevicesinc/ad5940-examples) but when I download it, I got an error message because I have a custom design board and they do with evaluation boards.
 
Hello, thank you for your comments. These are my attempts based on the datasheet commands. If you advise me in the missing steps, I would be appreciate with that. @doraemon ; @FvM ; @KlausST

1st Step for the SPI control of AD5940
1. Write the command byte and configure the register address.
a. Drive CS low.
b. Send 8-bit command byte: SPICMD_SETADDR.
c. Send 16-bit address of register to read to or write
from.
d. Pull CS high.

Code:
HAL_GPIO_WritePin(INTAN_CS_GPIO_Port, Intan_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2, (uint8_t*)&SPICMD_SETADDR, 1, 100);
//I don't know that step
HAL_GPIO_WritePin(INTAN_CS_GPIO_Port, Intan_CS_Pin, GPIO_PIN_SET);


2nd Step for the SPI control of AD5940
2. Write the data to the register.
a. Drive CS low.
b. Send 8-bit command byte: SPICMD_WRITEREG.
c. Write either 16-bit or 32-bit data to the register.
d. Bring CS high

Code:
HAL_GPIO_WritePin(INTAN_CS_GPIO_Port, Intan_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2, (uint8_t*)&SPICMD_WRITEREG, 1, 100);
//I don't know that step
HAL_GPIO_WritePin(INTAN_CS_GPIO_Port, Intan_CS_Pin, GPIO_PIN_SET);

3rd Step for the SPI control of AD5940
3. Read the data from the register.
a. Drive CS low.
b. Send 8-bit command byte: SPICMD_READREG.
c. Transmit a dummy byte on the SPI bus to initiate a read.
d. Read returning 16-bit or 32-bit data.
e. Bring CS high.

Code:
HAL_GPIO_WritePin(INTAN_CS_GPIO_Port, Intan_CS_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi2, (uint8_t*)&SPICMD_READREG, 1, 100);
//I don't know that step
HAL_GPIO_WritePin(INTAN_CS_GPIO_Port, Intan_CS_Pin, GPIO_PIN_SET);
 
Hello!

Again, you wrote this, and... what happens?
What do you mean by "I don't know that step"? Obviously you know this step because
you wrote it.
Beside this: you write (therefore send a signal to MOSI). What happens on MISO?
Can you hook a scope and see what happens? Is the MISO alive or is it constant?
If you don't have a scope, can you use TransmitReceive instead of Transmit, just
to check if something happens on MISO?

Beside this, there are many things we cannot check.
What is your SPI clock frequency?
Did you generate the code using CubeMX for SPI initialization, or did you write it yourself?
In that latter case, use generated code just to make sure it's done properly.

But again, if you don't describe accurately what happens, nobody can help you.
Example:
- The SPI command is sent, and then
(1) It's filled with 0s.
(2) It's filled with FFs
(3) It's filled with garbage, but constant. The contents is the same after power cycling.
(4) It's filled with garbage, but it changes after power cycling.
(5) It's filled with garbage, but it changes at every command...
Just to make you aware of how wide the problems can be even on a single command.
So to summarize: DESCRIBE THE PROBLEM ACCURATELY!!!

Dora
 
Last edited:
//I don't know that step
You can add HAL_SPI_Transmit of length 2 with the address word respectively HAL_SPI_Receive of length 2 to receive the data. Or Transmit command and address in one 3 byte transfer, similarly use TransmitReceive to transfer ReadReg command and read data in one call.
 
I updated the code:

Code:
/* USER CODE BEGIN PV */

uint8_t SPICMD_SETADDR = 0x20;
uint8_t SPICMD_WRITEREG = 0x2D;
uint8_t SPICMD_READREG = 0X6D;


/* USER CODE END PV */

int main()

while(1)
{
HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      HAL_SPI_TransmitReceive(&hspi3, (uint8_t*)&SPICMD_SETADDR, (uint8_t*)&SPICMD_SETADDR, 1, 100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);

      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      HAL_SPI_TransmitReceive(&hspi3, (uint8_t*)&SPICMD_WRITEREG, (uint8_t*)&SPICMD_WRITEREG, 1, 100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);

      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
      HAL_SPI_TransmitReceive(&hspi3, (uint8_t*)&SPICMD_READREG, (uint8_t*)&SPICMD_READREG, 1, 100);
      HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);


}

Then I got responses from three variables:

1687193550535.png



The SPI settings (Baudrate: 10 Mbits/s based on the processor clock frequency):

Code:
static void MX_SPI3_Init(void)
{

  /* USER CODE BEGIN SPI3_Init 0 */

  /* USER CODE END SPI3_Init 0 */

  /* USER CODE BEGIN SPI3_Init 1 */

  /* USER CODE END SPI3_Init 1 */
  /* SPI3 parameter configuration*/
  hspi3.Instance = SPI3;
  hspi3.Init.Mode = SPI_MODE_MASTER;
  hspi3.Init.Direction = SPI_DIRECTION_2LINES;
  hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi3.Init.NSS = SPI_NSS_SOFT;
  hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi3.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi3) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI3_Init 2 */

  /* USER CODE END SPI3_Init 2 */

}

I cannot probe SPI command lines because the processor and AD5940 BGA type so I cannot reach their pins.
 
Hi,

you show uncommented code. Thus I don´t know what you want to achieve.

Focus on one AD5940 command:
Example: (referred to post#19)

1st Step for the SPI control of AD5940
1. Write the command byte and configure the register address.
a. Drive CS low.
b. Send 8-bit command byte: SPICMD_SETADDR.
c. Send 16-bit address of register to read to or write
from.
d. Pull CS high.

Info: 8 bits are one byte. So sending an 8 bit command and an 16 bit address means you need to send 3 bytes in total (before pulling CS HIGH).
You could do this with
* one 1 byte transfer followed by a 2 byte transfer, or you can do it
* with a single 3 byte transfer.(shown below)
In either case you need to declare byte arrays for transmit buffer (and receive buffer)... accessed by pointer.
It doesn´t hurt if the array size is 8 bytes (shown below)

I´m not familiar with writing C code, thus see this as "pseudo code"
Code:
#define SPICMD_SETADDR  0x20;
...
uint8_t WBuf[8]; // decalare a byte array with size 8 (3 minimum for this example) Write buffer
uint8_t RBuf[8]; // same for read buffer
...
WBuf[0] = SPICMD_SETADDR; // set the values in the array
WBuf[1] = myAddrH; // high byte of 16 bit address
WBuf[2] = myAddrL; // low byte of 16 bit address
...
   HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET); // Drive CS low. (Assuming your port setup was correct as totem pole output.)
   HAL_SPI_TransmitReceive(&hspi3, WBuf, RBuf, 3, 100); // transmit 3 bits of WBuf to SPI; Receive 3 bytes from SPI to RBuf ... contents of RBuf are useless here.
   HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET); // Pull CS high.
...
For sure there are many other ways.
Here I did it as universal code .. may be used for all three steps of communication. Read and write AD5940 registers

Klaus
 
Last edited:
Hi.

WBuf[1] = myAddrH; // high byte of 16 bit address

Since WBuf is an array of bytes ... myAddrH also is a byte.
It also says "byte" in the comment.

Klaus
 
I got these errors:

../Core/Src/main.c:66:1: warning: data definition has no type or storage class
66 | WBuf[0] = SPICMD_SETADDR;
| ^~~~
../Core/Src/main.c:66:1: warning: type defaults to 'int' in declaration of 'WBuf' [-Wimplicit-int]
../Core/Src/main.c:66:1: error: conflicting types for 'WBuf'
../Core/Src/main.c:50:9: note: previous declaration of 'WBuf' was here
50 | uint8_t WBuf[8];
| ^~~~
../Core/Src/main.c:24:25: error: invalid initializer
24 | #define SPICMD_SETADDR 0x20
| ^~~~
../Core/Src/main.c:66:11: note: in expansion of macro 'SPICMD_SETADDR'
66 | WBuf[0] = SPICMD_SETADDR;
| ^~~~~~~~~~~~~~
../Core/Src/main.c:67:1: warning: data definition has no type or storage class
67 | WBuf [1] = myAddrH;
| ^~~~
../Core/Src/main.c:67:1: warning: type defaults to 'int' in declaration of 'WBuf' [-Wimplicit-int]
../Core/Src/main.c:67:1: error: conflicting types for 'WBuf'
../Core/Src/main.c:50:9: note: previous declaration of 'WBuf' was here
50 | uint8_t WBuf[8];
| ^~~~
../Core/Src/main.c:67:12: error: 'myAddrH' undeclared here (not in a function)
67 | WBuf [1] = myAddrH;
| ^~~~~~~
../Core/Src/main.c:68:1: warning: data definition has no type or storage class
68 | WBuf [2] = myAddrL;
| ^~~~
../Core/Src/main.c:68:1: warning: type defaults to 'int' in declaration of 'WBuf' [-Wimplicit-int]
../Core/Src/main.c:68:1: error: conflicting types for 'WBuf'
../Core/Src/main.c:50:9: note: previous declaration of 'WBuf' was here
50 | uint8_t WBuf[8];
| ^~~~
../Core/Src/main.c:68:12: error: 'myAddrL' undeclared here (not in a function)
68 | WBuf [2] = myAddrL;
 
Now I minimized the errors with declaring Wbuf and Rbuf as char type. Now I got errors from myAddrH. What should be its declaration?
../Core/Src/main.c:78:13: error: 'myAddrH' undeclared (first use in this function)
78 | WBuf [1] = myAddrH;
| ^~~~~~~
../Core/Src/main.c:78:13: note: each undeclared identifier is reported only once for each function it appears in
../Core/Src/main.c:79:13: error: 'myAddrL' undeclared (first use in this function)
79 | WBuf [2] = myAddrL;
 
I modified a little more with declaring myAddrH with random values,
Code:
...
/* USER CODE BEGIN PV */

const uint8_t SPICMD_SETADDR =  0x20;
const uint8_t SPICMD_READREG = 0x6D;
const uint8_t SPICMD_WRITEREG = 0x2D;

/* USER CODE END PV */
...

int main(void)
{
  /* USER CODE BEGIN 1 */
    char write_buf[8]; // Send data
    char read_buf[8]; // Receive data
    ...
     /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_SPI3_Init();
  /* USER CODE BEGIN 2 */

  // CS pin should default high
  HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);

  write_buf[0] = SPICMD_SETADDR;
  write_buf[1] = 0xCD; // myAddrH
  write_buf[2] = 0xEF; // myAddrL

  HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
  HAL_SPI_Transmit(&hspi3, (uint8_t *)write_buf, 3, 100);
  HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);

  HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_RESET);
  HAL_SPI_Receive(&hspi3, (uint8_t *)read_buf, 3, 100);
  HAL_GPIO_WritePin(SPI3_CS_GPIO_Port, SPI3_CS_Pin, GPIO_PIN_SET);


  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  ...

Then, I got this response,

1687813042194.png
 

LaTeX Commands Quick-Menu:

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top