0
\$\begingroup\$

I have STM32L052K8T6 (master) and I am trying to communicate with AD7124-4 ADC (slave) via SPI. My problem is that STM stops transmiting clock pulses on SCLK immediately after it transfers all data from tx buffer (checked on external oscilloscope) and ignores request to wait for answer till timeout expire. Slave has no chance to answer when it has no clock to synchronise.

My init:

void initSPI (void)
{
GPIO_InitTypeDef GPIO_InitStructure;

__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_SPI1_CLK_ENABLE();

//GPIO - MOSI, MISO, CLK
GPIO_InitStructure.Pin = GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = GPIO_AF0_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);

HAL_NVIC_SetPriority(SPI1_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(SPI1_IRQn);

hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi1.Init.NSS = SPI_NSS_HARD_OUTPUT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 7;

if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
    ErrorHandler();
}

HAL_SPI_MspInit(&hspi1);

__HAL_SPI_ENABLE(&hspi1);
}

I am calling this function:

void SendReceiveData ()
{
    uint8_t tx = 64;
    while (hspi1.State != HAL_SPI_STATE_READY);
    HAL_SPI_TransmitReceive(&hspi1, &tx, &rx, 1, 10000);
}

Even when I have a long timeout it is ignored.

HAL_SPI_TransmitReceive() returns HAL_OK.

Is there a problem in my initialization?

\$\endgroup\$
4
\$\begingroup\$

I think you misunderstood the functionality of HAL_SPI_TransmitReceive function. It doesn't first transmit tx buffer then receive to rx buffer. It does both at the same time. After all SPI is a full duplex protocol. It can transmit (from MOSI) and receive (MISO) at the same time.

To achieve what you want in a single function call you should use buffers of size 2. Like this:

    HAL_SPI_TransmitReceive(&hspi1, &tx, &rx, 2, 10000);

It doesn't matter what is in the second byte of TX buffer (tx[1]) or what you read in the first byte of RX buffer (rx[0]). Just make sure you put correct data to tx[0] and take received data from rx[1] and ignore the rest.

PS: I haven't checked the datasheet of the slave device you mentioned. Some devices start sending data at the very first clock cycle. Make sure you understand protocol correctly.

\$\endgroup\$
3
\$\begingroup\$

It is standard for the SCLK to stop when a device is not transmitting, because SCLK generally forces communication in both directions. In this case, the ADC really only has communication in one direction at a time, either the device received a command or sends data, and they illustrated that poorly.

You need to send some null data after your command to force the clock to be active. It looks like the datasheet recommends sending 0, but it is not clear if the device even pays attention to the data.

If the ADC wants a specific time between your command bytes and the data, you may need to take manual control of the CS line so that you can hold it low while you delay.

\$\endgroup\$
  • 1
    \$\begingroup\$ I find it useful to describe SPI as a circular shift register, where master and slave are simply two connected parts of the overall shift register. \$\endgroup\$ – Peter Smith Dec 28 '17 at 17:28
  • \$\begingroup\$ @PeterSmith yes, circular shift register is a perfect description \$\endgroup\$ – pscheidler Dec 28 '17 at 17:32
0
\$\begingroup\$

Thanks guys.

I combined both your answers to working solution. Because the ADC (slave) waits for command and it answers after, I had to force SCLK to keep "ticking". Communication isn't working both ways at the same time in this case. I send 0xFF character (slave ignores it) after a valid command to keep MOSI in logic high and clock working. I send as much 0xFF characters as I expect as answer and it works. Not the nicest a solution but the working one.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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