2019-03-06 05:47 AM
Hi,
I am working on SPI bus communication between IMX6dl MPU and STM32L476 MCU.
MPU work as a master device and MCU work as a slave device.
Configuration of MPU is:
pinctrl_ecspi3: ecspi3grp {
fsl,pins = <
MX6QDL_PAD_DISP0_DAT2__ECSPI3_MISO 0x100b1
MX6QDL_PAD_DISP0_DAT1__ECSPI3_MOSI 0x100b1
MX6QDL_PAD_DISP0_DAT0__ECSPI3_SCLK 0x000b1
#define GP_ECSPI3_NOR_CS <&gpio4 24 GPIO_ACTIVE_HIGH>
MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x0b0b1
>;
};
&ecspi3 {
fsl,spi-num-chipselects = <1>;
cs-gpios = GP_ECSPI3_NOR_CS;
/*spi-slave;*/
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
status = "okay";
spidev2: spi@0 {
compatible = "spidev";
reg = <0>;
spi-cpha;
spi-max-frequency = <34000000>;
};
};
Master clock frequency: 312500
Master Mode: CPOL = 0, CPOH = 1 (i.e. Mode 1)
Datasize = 8 bit
Configuration of MCU is:
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_SLAVE;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi3.Init.NSS = SPI_NSS_SOFT;
hspi3.Init.FirstBit = SPI_FIRSTBIT_LSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 7;
hspi3.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
My queries are:
1. Is master and slave configuration is ok??
2. How can i check loop back mode in MCU??
First of all i have checked Loop back mode in Master.
Master loop back communication is working fine.
When i am testing master to slave SPI communication, master is sending dataframe "10101010" at slave end receiving dataframe is "01010101".
Please let me know what could be the reason for above point.
Thank you.
2019-03-06 07:57 AM
My advice:
Use DMA in slave receive mode. Use DMA in Circular mode with an SRAM buffer.
Use EXTI interrupt on NSS to reset the DMA to the beginning of the buffer (falling edge) and process the received data on NSS rising edge. (NSS would be a GPIO)
Make sure the master wait few microsecond after changing NSS level for the slave interrupt to have the time to react and init DMA. Then you'll be ready to go, No DMA interrupt needed here.
Program the SPI in 8 bit mode. And remember you have to program both DMA TX and RX. Use SPI 4 wire interface mode to get started.
2019-03-12 07:56 AM
Thanks for input. I have enable RX/TX DMA and global interrupt as per your suggestion and I see there is 2 bits shifting most of the time during Tx/RX operation.
i.e.
Below is configuration in MCU-STM32l4:
File: main.c
static void MX_SPI3_Init(void)
{
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_SLAVE;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi3.Init.NSS = SPI_NSS_SOFT;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 7;
hspi3.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi3) != HAL_OK)
{
Error_Handler();
}
}
===
/**
* Enable DMA controller clock
*/
static void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Channel1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);
/* DMA2_Channel2_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Channel2_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel2_IRQn);
}
===
uint8_t spi_RX_data;
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART3_UART_Init();
MX_QUADSPI_Init();
MX_I2C2_Init();
MX_UART4_Init();
MX_USART1_UART_Init();
MX_UART5_Init();
MX_SPI3_Init();
MX_I2C1_Init();
MX_I2C3_Init();
MX_CRC_Init();
/* USER CODE BEGIN 2 */
HAL_SPI_Receive_DMA(&hspi3, &spi_RX_data, 1);
}
===========
File: stm32l4xx_hal_msp.c
/**
* @brief SPI MSP Initialization
* This function configures the hardware resources used in this example
* @param hspi: SPI handle pointer
* @retval None
*/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hspi->Instance==SPI3)
{
/* USER CODE BEGIN SPI3_MspInit 0 */
/* USER CODE END SPI3_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SPI3_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
HAL_PWREx_EnableVddIO2();
/**SPI3 GPIO Configuration
PG9 ------> SPI3_SCK
PG10 ------> SPI3_MISO
PG11 ------> SPI3_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
/* SPI3 DMA Init */
/* SPI3_RX Init */
hdma_spi3_rx.Instance = DMA2_Channel1;
hdma_spi3_rx.Init.Request = DMA_REQUEST_3;
hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi3_rx.Init.Mode = DMA_CIRCULAR;
hdma_spi3_rx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi3_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmarx,hdma_spi3_rx);
/* SPI3_TX Init */
hdma_spi3_tx.Instance = DMA2_Channel2;
hdma_spi3_tx.Init.Request = DMA_REQUEST_3;
hdma_spi3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi3_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi3_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi3_tx.Init.Mode = DMA_CIRCULAR;
hdma_spi3_tx.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_spi3_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmatx,hdma_spi3_tx);
/* SPI3 interrupt Init */
HAL_NVIC_SetPriority(SPI3_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(SPI3_IRQn);
/* USER CODE BEGIN SPI3_MspInit 1 */
/* USER CODE END SPI3_MspInit 1 */
}
}
2019-03-12 09:49 AM
Before optimizing do the following:
Depending when the MPU and MCU start to listen to SPI lines, there might be dummy glitches where the bit counters in slave might be shifted. Easy to spot with oscilloscope, not so easy with logic analyser.
Also make sure the levels are same both sides.
2019-03-12 11:56 AM
Thank you for your quick response.
Below are few observations during my expirmints:
I used the oscilloscope and found that the data coming on MISO / MOSI are same which I received during Tx and RX.
RX Path (MPU to MCU)
Also note that as I was getting the 2 bits shift issue while receiving data on MCU ( MP to MCU [master to slave line] ) - for testing purpose I tried following and except the 1st byte ( as I did some runtime bits configuration changes to play with shift register) all bytes (with different burst size) received correctly .
hspi3.Init.DataSize = SPI_DATASIZE_10BIT;
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
static int i = 0;
if(i == 0)
{
i = 1;
LOG_Print("Chaning Configuration to 8 bits\n");
if (HAL_SPI_DeInit(&hspi3) != HAL_OK)
{
Error_Handler();
}
MX_SPI3_Init_8bits();
}
}
==
static void MX_SPI3_Init_8bits(void)
{
LOG_Print("In 8 Bits config\n");
/* USER CODE BEGIN SPI3_Init 0 */
/* USER CODE END SPI3_Init 0 */
/* USER CODE BEGIN SPI3_Init 1 */
/* USER CODE END SPI3_Init 1 */
/* SPI3 parameter configuration*/
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_SLAVE;
hspi3.Init.Direction = SPI_DIRECTION_2LINES;
hspi3.Init.DataSize = SPI_DATASIZE_8BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi3.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi3.Init.NSS = SPI_NSS_SOFT;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 7;
hspi3.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
hspi3.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
if (HAL_SPI_Init(&hspi3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI3_Init 2 */
/* USER CODE END SPI3_Init 2 */
}
============================
After this all the byte received correctly. note that I sent one byte and than I tried with different amount of bytes sending and all were received correctly.
Tx Path: (MCU to MPU)
I tried to find same kind of shift register ( data register) combination on Tx side and there is no luck !
Is there any API which we do have to use to flush /clear the Data register ( shift register) before we do start communicating over the SPI line ?
Am I missing anything here... As this looks like workaround (rx path) - how should I fix it in correct way.
Thank you again for your continuous help.
2019-03-12 12:12 PM
If the MPU is controlling NSS and sends 8 bit data SPI, then it seems to be the rootcause hasn't been found. Can you take a scope snapshot of NSS / MISO / MOSI / SCK ?
In slave mode, the MCU doesn't control the SCK clock so the callback might not happen when the SCK is idle. The only way to reset the SPI and its FIFO is to run a RCC/CFG Reset of the peripheral when NSS goes high.
In DMA cyclic mode, the SPI TX FIFO will always be filled by DMA. Once NSS goes up, the SCK stops and the TX FIFO is filled while the transmission ended. Next NSS going low, the first 3 old bytes in the FIFO will be sent wrongly. The refman warning for RX FIFO also applies to TX FIFO. If you properly "reset the SPI and flush its FIFO" at least the conditions will improve without the lucky and probably full of side-effect 10 bit SPI mode.
Some of my code extract for SPI Slave in STM32L4R, in case it give clues:
void SPIP_SlaveReStart(SPIP_t* pSPIP) {
HAL_SPI_DeInit(pSPIP->hspi); // back to original state
// first, we reset the cell (yes!)
/*RCC->AHB1RSTR |= 1<<0; // DMA1
NOPs(2);
RCC->AHB1RSTR &= ~(1<<0);*/
NOPs(2);
RCC->APB1RSTR1 |= (1<<14);// SPI2
NOPs(2);
RCC->APB1RSTR1 &= ~(1<<14);
SPIP_SlaveConfigureSpi(pSPIP->hspi);
SPIP_SlaveConfigureDma(pSPIP->hspi);
}
2023-10-08 11:46 PM
Hi @SPare.9
Could you please share the details on how you are able establish communication between mcu and mpu. We are aslo in a same situation where we need establish an spi communicaiton between imx6 solo and MCU.