2021-09-09 01:48 PM
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,®,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,®,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
2021-09-09 03:22 PM
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
2021-09-09 05:02 PM
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
2021-09-09 08:16 PM
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.
2021-09-10 02:57 AM
> 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
2021-09-10 08:28 AM
> 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
2021-09-10 08:43 AM
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.
2021-09-10 01:45 PM
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