cancel
Showing results for 
Search instead for 
Did you mean: 

SPI 3-wire bidirectional master not sending clocks

MRey.1
Associate III

I have an issue with SPI in bidirectional mode (MOSI, CLK and CS). I have a device which I need to write to and from. When I have to write to an adress in the slave device, it works perfectly:

reg=0x04;

CS_DRIVER_LOW

c=HAL_SPI_Transmit_DMA(&hspi2,&reg,1);

while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);

c=HAL_SPI_Transmit_DMA(&hspi2,buff,10);

while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);

CS_DRIVER_HIGH

However, as soon as I run this function, (which sends the address it has to read, then reads it) when writing, it stops sending clocks from that point onwards, even if I use the previous function:

reg=0x84;

CS_DRIVER_LOW

c=HAL_SPI_Transmit_DMA(&hspi2,&reg,1);

//while (HAL_SPI_GetState(&hspi2) != HAL_SPI_STATE_READY);

c=HAL_SPI_Receive_DMA(&hspi2,buff,10);

CS_DRIVER_HIGH

The initialization code is the following:

 hspi2.Instance = SPI2;

 hspi2.Init.Mode = SPI_MODE_MASTER;

 hspi2.Init.Direction = SPI_DIRECTION_1LINE;

 hspi2.Init.DataSize = SPI_DATASIZE_8BIT;

 hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;

 hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;

 hspi2.Init.NSS = SPI_NSS_SOFT;

 hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;

 hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;

 hspi2.Init.TIMode = SPI_TIMODE_DISABLE;

 hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

 hspi2.Init.CRCPolynomial = 7;

 hspi2.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;

 hspi2.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;

 if (HAL_SPI_Init(&hspi2) != HAL_OK)

 {

  Error_Handler();

 }

  /* SPI2 clock enable */

  __HAL_RCC_SPI2_CLK_ENABLE();

  __HAL_RCC_GPIOB_CLK_ENABLE();

  /**SPI2 GPIO Configuration

  PB13   ------> SPI2_SCK

  PB15   ------> SPI2_MOSI

  */

  GPIO_InitStruct.Pin = GPIO_PIN_15;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull = GPIO_NOPULL;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

  GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;

  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = GPIO_PIN_13;

  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

  GPIO_InitStruct.Pull = GPIO_PULLDOWN;

  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

  GPIO_InitStruct.Alternate = GPIO_AF0_SPI2;

  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* SPI2 DMA Init */

  /* SPI2_TX Init */

  hdma_spi2_tx.Instance = DMA1_Channel5;

  hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;

  hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;

  hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;

  hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

  hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

  hdma_spi2_tx.Init.Mode = DMA_NORMAL;

  hdma_spi2_tx.Init.Priority = DMA_PRIORITY_MEDIUM;

  if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)

  {

   Error_Handler();

  }

  __HAL_DMA1_REMAP(HAL_DMA1_CH5_SPI2_TX);

  __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi2_tx);

  /* SPI2_RX Init */

  hdma_spi2_rx.Instance = DMA1_Channel4;

  hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;

  hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE;

  hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE;

  hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

  hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

  hdma_spi2_rx.Init.Mode = DMA_NORMAL;

  hdma_spi2_rx.Init.Priority = DMA_PRIORITY_MEDIUM;

  if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK)

  {

   Error_Handler();

  }

  __HAL_DMA1_REMAP(HAL_DMA1_CH4_SPI2_RX);

  __HAL_LINKDMA(spiHandle,hdmarx,hdma_spi2_rx);

  /* SPI2 interrupt Init */

  HAL_NVIC_SetPriority(SPI2_IRQn, 3, 0);

  HAL_NVIC_EnableIRQ(SPI2_IRQn);

Does anyone know what could be causing this behaviour? I don´t know what else to try

7 REPLIES 7

Which STM32?

> Does anyone know what could be causing this behaviour?

Maybe bug in Cube?

Nonetheless, bidir mode is tricky, relying on Cube users usually find it outputs more clocks than you intended.

Is using bidir mode in your application absolutely necessary?

JW

MRey.1
Associate III

Thanks for answering, the MCU is the STM32F091

I have read that extra clocks is usually the issue, which makes this case even more strange. Are you suggesting I should avoid using HAL functions as much as possible here?

Unfortunately, yes, in this case 3-wire SPI is the only way to communicate, I would definitely avoid it if it was not the case

S.Ma
Principal

I would short miso and mosi outside and disable mosi when needed. For the spi, it is configured with the more rugged bidir mode. In 3 wire mode, as master, you still need to generate clocks by... transmitting dummy data.

> I would short miso and mosi outside and disable mosi when needed

Yes, this is probably the simplest way to work around the SPI's shortcomings.

But if you just want to get the clocks running, and you don't mind there may be more clocks (which may be OK with some slaves), then in the state where you expect clocks running, read out the SPI and relevant DMA registers content and check/post.

JW

MRey.1
Associate III

> But if you just want to get the clocks running, and you don't mind there may be more clocks (which may be OK with some slaves), then in the state where you expect clocks running, read out the SPI and relevant DMA registers content and check/post.

I tried reading without using HAL in the state when the clocks should be, but the result is the same. I'll try seeing if there is a difference in the state of the registers between both functions, since one works and the other one does not.

> I would short miso and mosi outside and disable mosi when needed. For the spi, it is configured with the more rugged bidir mode. In 3 wire mode, as master, you still need to generate clocks by... transmitting dummy data.

I would check this solution, but right now in this board, the MISO pin is used by another peripheral, which would modify the PCB. But I will try it as a last resource

S.Ma
Principal

Some spi version have mosi miso swap control bit, maybe it works....

And remember that completion of the transmission for a master is coming from received data, not transmit one.

MRey.1
Associate III

There I found the problem: a line of code in a separate task was setting the pull up resistor on the clock pin between functions, so when the MOSI sent the bits, the clock got stuck on '1'. Thanks for the help