cancel
Showing results for 
Search instead for 
Did you mean: 

SPI full duplex slave does not send data

sde c.1
Senior II

Hi all,

I have a setup with Pi and STM board. The Pi acts like an SPI master, the STM is setup as SPI full duplex slave.

The SPI input and outputbuffer are the same size, what i want is that when i receive x bytes from the pi, i send back the first x bytes of the SPI output buffer back .

I can receive data from the Pi with no issue's, but when i put data into the DMA SPI outputbuffer , this data is not send by the slave(STM) the next time the Pi initiate an SPI communication.

I use HAL library and setup the STM like this :

in main(void) ->

uint8_t cnt=0;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
  spi_buf_out[cnt]=cnt++;
 
HAL_SPI_TransmitReceive_DMA(&hspi2,spi_buf_out,spi_buf_in,SPI_SIZE);

At the logic analyser i see correct data at MOSI and MISO lines when the pi sends the first SPI package.

But at the next SPI packages from the master (Pi), there is no data anymore at MISO (spi_buf_out), this line stays 0.

How do i instruct the HAL library to send back the contents of spi_buf_out every time the Pi starts a SPI communication?

Thank you

Steve

15 REPLIES 15

i know, but the number of bytes from the master is variable, so i need to find a way to set the DMA memory pointer back to the first element each communication

reset the fifo and re init the SPI made the whole setup instable.

The code i have now (see my reply at waclawek.jan ), is stable, but i can't figure out why the bytes are 3 bytes shifted.

i'm sure this have something to do with the DMA or FIFI, but i can't find a solution

S.Ma
Principal

In dma cyclic mode, as a slave, the transmit fifo is always filled. When Nss goes high, sck stopped with 3-4 byte ready to shoot out at next exchange.... if you use hal, thing maybe more tricky as a sw state machine is implemented... try deinit, then rcc spi reset, then init again. If the spi version has a flush fifo control bit, test it.

STM32G474RET

The response is shifted by 3 bytes, the first 3 bytes are invalid, the 4th and following bytes are correct every SPI communication.

I cannot figure out how to solve the 3 bytes shift.

This is the code now and a situation sketch.

0693W00000DnUnXQAV.png

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_LPUART1_UART_Init();
  MX_USART1_UART_Init();
  MX_CRC_Init();
  MX_I2C1_Init();
  MX_SPI2_Init();
  RetargetInit(&hlpuart1);
 
  spi_buf_out[0]=1;
    spi_buf_out[1]=2;
    spi_buf_out[2]=3;
    spi_buf_out[3]=4;
HAL_SPI_TransmitReceive_DMA(&hspi2,spi_buf_out,spi_buf_in,SPI_SIZE);
}
 
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
	if(GPIO_Pin == GPIO_PIN_12){
                WritePin(PA10,1); //DE
		memcpy(uart_buf_out,spi_buf_in,SPI_SIZE);
		HAL_UART_Transmit_DMA(&huart1,(uint8_t *)(uart_buf_out+1),*(uint8_t *)(uart_buf_out));
	}
}
 
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
	volatile HAL_StatusTypeDef status;
	if(huart == &huart1){
		WritePin(PA10,0); //DE
                status = HAL_UARTEx_ReceiveToIdle_DMA(&huart1,(uint8_t*)uart_buf_in,UART_SIZE);
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);
		tmr_us_Start(&uart_rx_tmo,1500); //1.5ms
	}
}
 
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
	if(huart == &huart1){
		// process received data
		// copy data to SPI outbuffer for next SPI poll
		//memcpy(spi_buf_out,uart_buf_in,UART_SIZE); // spi_buf_out is now 1234 to test ...
 
		// reset SPI DMA and FIFO
		HAL_SPI_DMAStop(&hspi2);
		__HAL_DMA_DISABLE(&hdma_usart1_rx);
		__HAL_DMA_DISABLE(&hdma_usart1_tx);
		HAL_SPI_TransmitReceive_DMA(&hspi2,spi_buf_out,spi_buf_in,SPI_SIZE);
	}
}

i see my response to weclawek.jan was not sended . Now it is ...

it finally works, your tip lead to the solution. Thank you . I summarize the solution for other people .

The HAL lib is not ideal for this setup, i would recommend other engineers to write their own code to acces the registers , getting this right took at least as much time then starting from 0.

the setup :

The Pi is SPI master , the STM SPI slave , each SPI package is forwarded to the UART, some external device answers. This answer is given back the next SPI packet initiated by the Pi.

0693W00000DnVB5QAN.pngDe code :

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_USART1_UART_Init();
  MX_SPI2_Init();
  
  HAL_SPI_TransmitReceive_DMA(&hspi2,spi_buf_out,spi_buf_in,SPI_SIZE);
}
 
// 1) SPI enable line will have positive flank once the data is transferred from PI to STM, this will be used as interrupt to
// copy the received SPI data into the uart output buffer and initiate a DMA transfer to the uart peripheral
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
	if(GPIO_Pin == GPIO_PIN_12){
                WritePin(PA10,1); //DE
		memcpy(uart_buf_out,spi_buf_in,SPI_SIZE);
		// reset uart to flush FIFO
		HAL_UART_DeInit(&huart1);
		__HAL_RCC_USART1_FORCE_RESET();
		__HAL_RCC_USART1_RELEASE_RESET();
		HAL_UART_Init(&huart1);
 
		HAL_UART_Transmit_DMA(&huart1,(uint8_t *)(uart_buf_out+1),*(uint8_t *)(uart_buf_out));
	}
}
 
// 2) after the DMA transfer at the UART peripheral, this callback will be called
// we use this to clear the RS485 DE line and start the DMA to start receiving data to the uart peripheral
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart){
	if(huart == &huart1){
		WritePin(PA10,0); //DE
		HAL_UARTEx_ReceiveToIdle_DMA(&huart1,(uint8_t*)uart_buf_in,UART_SIZE);
		__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);
	}
}
 
// 3) once data is received this callback is called
// we use this to copy the data in the uart inbuffer to the spi outbuffer, so the data will be available at the SPI bus at the next POLL
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){
	if(huart == &huart1){
		// process received data
		// copy data to SPI outbuffer for next SPI poll
		memcpy(spi_buf_out,uart_buf_in,UART_SIZE);
 
		// reset spi to flush FIFO
		HAL_SPI_DeInit(&hspi2);
		__HAL_RCC_SPI2_FORCE_RESET();
		__HAL_RCC_SPI2_RELEASE_RESET();
		HAL_SPI_Init(&hspi2);
 
		HAL_SPI_TransmitReceive_DMA(&hspi2,spi_buf_out,spi_buf_in,SPI_SIZE);
	}
}