cancel
Showing results for 
Search instead for 
Did you mean: 

why receiving shifted data in SPI communication

NMurr.2
Associate II

Hi all,

I want to make communicate two nucleo l432kc (slaves) with a raspberry pi (master) through the SPI protocol. On the raspberry I'm using the spidev API, while on the nucleo I'm using the HAL SPI interface with DMA.

The only configuration that permits a stable transmission is the SPI_MODE_2 of spidev that corresponds to the SPI_POLARITY_HIGH and SPI_PHASE_2EDGE configuration of the HAL.

With the above configuration I have a problem: The messages sent by the master to the slaves arrive always correctly, but all the messages sent by the slaves to the master always arrive shifted by 1 bit on the right (e.g. if I send two bytes 0b00000011 0b00000001 I receive 0b00000001 0b10000000). It seems that the sampling of the MISO signal is delayed but I can't figure out why.

This are the configurations of the slaves:

// SPI
__HAL_RCC_SPI1_CLK_ENABLE();
 
/* SPI1 parameter configuration*/
hspi.Instance = SPI1; 
hspi.Init.Mode = SPI_MODE_SLAVE;
hspi.Init.Direction = SPI_DIRECTION_2LINES;   // full duplex mode 
hspi.Init.DataSize = SPI_DATASIZE_8BIT;       // dimension of 1 byte
hspi.Init.CLKPolarity = SPI_POLARITY_HIGH;    // start and idle clk value
hspi.Init.CLKPhase = SPI_PHASE_2EDGE;         // edge of sampling of data both on miso and mosi        
hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;        // bit order
hspi.Init.TIMode = SPI_TIMODE_DISABLE;        // disabling the TI mode
hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; // disable crc calc
hspi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;           // disable NSS puls value
 
if (HAL_SPI_Init(&hspi) != HAL_OK)
  return false;
 
  /* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
 
// GPIO 
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/**SPI1 GPIO Configuration    
PA1     ------> SPI1_SCK
PA11     ------> SPI1_MISO
PA12     ------> SPI1_MOSI 
PB0     ------> SPI1_NSS 
*/
GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_11|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
 
// DMA 
/* DMA controller clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
 
    /* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi_rx.Instance = DMA1_Channel2;
hdma_spi_rx.Init.Request = DMA_REQUEST_1;
hdma_spi_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi_rx.Init.Mode = DMA_NORMAL;
hdma_spi_rx.Init.Priority = DMA_PRIORITY_LOW;
  
if (HAL_DMA_Init(&hdma_spi_rx) != HAL_OK) return false;
 
 __HAL_LINKDMA(&hspi,hdmarx,hdma_spi_rx);
/* DMA interrupt init */
/* DMA1_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel2_IRQn);
 
/* SPI1 DMA Init */
/* SPI1_TX Init */
hdma_spi_tx.Instance = DMA1_Channel3;
hdma_spi_tx.Init.Request = DMA_REQUEST_1;
hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi_tx.Init.Mode = DMA_NORMAL;
hdma_spi_tx.Init.Priority = DMA_PRIORITY_LOW;
    
if (HAL_DMA_Init(&hdma_spi_tx) != HAL_OK) return false;
 
__HAL_LINKDMA(&hspi,hdmatx,hdma_spi_tx);
 
/* DMA interrupt init */
/* DMA1_Channel3_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);

Why is this happening?

EDIT 0

This is the code that I use for the configuration of the spidev interface on the raspberry:

unsigned int bitsPerByte = 8u;
unsigned int delay =  0u; 
unsigned int speed = 100; // hz
unsigned int cs_change   = 0u;  // false in C
 
// initialization
fd = ::open("/dev/spidev0.0", O_RDWR);
auto mode = SPI_MODE_2;  // clock polarity low, clock phase second edge
 
if (fd == -1)
    throw std::runtime_error("Can't open the spi device");
 
if (::ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) 
    throw std::runtime_error("Can't set the spi mode"); 
 
 /*
 * bits per word
 */
auto bits = bitsPerByte;
auto ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
	throw std::runtime_error("can't set bits per word");
 
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
	throw std::runtime_error("can't get bits per word");
 
/*
 * max speed hz
 */
auto maxSpeed = speed;
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &maxSpeed);
if (ret == -1)
	throw std::runtime_error("can't set max speed hz");
 
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &maxSpeed);
if (ret == -1)
	throw std::runtime_error("can't get max speed hz");
 
// code used for sending messages
void transfer(uint8_t *tx, uint8_t *rx, size_t size) {
    struct spi_ioc_transfer tr = {	
        (unsigned long)tx,  // .tx_buf 
        (unsigned long)rx,  // .rx_buf        
        size, // .len  
        speed,  // .speed_hz
        delay, // .delay_usecs
        bitsPerByte, // .bits_per_word
        cs_change, // .cs_change
        0,  // .tx_nbits
	0,  // .rx_nbits
	0,  // .pad
    };
 
    if (::ioctl(fd, SPI_IOC_MESSAGE(1), &tr) == -1)
        throw std::runtime_error("Can't send data throught the spi");
}

EDIT 1

Another problem that I have noticed is that I receive the data in the slaves even if the NSS is set to HIGH, this happens even if I use the class SPISlave of the mbed framework.

If I use the SPISlave I can receive corretly the bytes.

2 REPLIES 2

Perhaps look at how the Master is configured and the signalling expectations there.​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
NMurr.2
Associate II

the spidev interface is not so configurable in the user space. There are 4 modes (that are used to set the clock polarity and phase) the maximum speed, the actual speed, a delay in usec to wait before deactivate the CS and the amount of bits per byte (8 or 9) .

I've already tried all the possible configurations and I'm checking for errors in each function that I call.