cancel
Showing results for 
Search instead for 
Did you mean: 

F411 SPI LL example: problem when changing SPI1 to SPI4. Below are the codes for config SPI DMA or SPI.

HDaji.1
Senior

I tried to change SPI1 to SPI4 in the LL example code.

My problem is I cannot detect any signal on the CLK or data pins.

void Configure_SPI4_DMA(void)
{
  /* DMA2 used for SPI4 Transmission
   * DMA2 used for SPI4 Reception
   */
  /* (1) Enable the clock of DMA2 and DMA2 */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA2);
 
 /* (2) Configure NVIC for DMA transfer complete/error interrupts */
  NVIC_SetPriority(DMA2_Stream0_IRQn, 0);
  NVIC_EnableIRQ(DMA2_Stream0_IRQn);
  NVIC_SetPriority(DMA2_Stream1_IRQn, 0);
  NVIC_EnableIRQ(DMA2_Stream1_IRQn);
 
  /* (3) Configure the DMA2_Stream0 functional parameters
   * F411 User Reference pg 170, Table 28. DMA2 request mapping (STM32F411xC/E)
   * */
  LL_DMA_ConfigTransfer(DMA2,
                        LL_DMA_STREAM_0,
                        LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_NORMAL |
                        LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
                        LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
  LL_DMA_ConfigAddresses(DMA2,
                         LL_DMA_STREAM_0,
                         LL_SPI_DMA_GetRegAddr(SPI4), (uint32_t)aSPI4_RxBuf,
                         LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_0));
  LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_0, ubSPI4_NByte2Rx);
 
 
  LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_0, LL_DMA_CHANNEL_4);
 
  /* (4) Configure the DMA2_Stream1 functional parameters */
  LL_DMA_ConfigTransfer(DMA2,
                        LL_DMA_STREAM_1,
                        LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_PRIORITY_HIGH | LL_DMA_MODE_NORMAL |
                        LL_DMA_PERIPH_NOINCREMENT | LL_DMA_MEMORY_INCREMENT |
                        LL_DMA_PDATAALIGN_BYTE | LL_DMA_MDATAALIGN_BYTE);
  LL_DMA_ConfigAddresses(DMA2, LL_DMA_STREAM_1, (uint32_t)aSPI4_TxBuf, LL_SPI_DMA_GetRegAddr(SPI4),
                         LL_DMA_GetDataTransferDirection(DMA2, LL_DMA_STREAM_1));
  LL_DMA_SetDataLength(DMA2, LL_DMA_STREAM_1, ubSPI4_NByte2Tx);
 
  LL_DMA_SetChannelSelection(DMA2, LL_DMA_STREAM_1, LL_DMA_CHANNEL_4);
 
  /* (5) Enable DMA interrupts complete/error */
  LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_1);
  LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_1);
  LL_DMA_EnableIT_TC(DMA2, LL_DMA_STREAM_0);
  LL_DMA_EnableIT_TE(DMA2, LL_DMA_STREAM_0);
}
void Configure_SPI4(void)
{
  /* (1) Enables GPIO clock and configures the SPI4 pins ********************/
 
  /* Enable the peripheral clock of GPIO Port
   * GPIO Port A is enabled in LED_Init, here we ignore.
   * This can easily introduce bug.
   * We should use LL_AHB1_GRP1_IsEnabledClock to check,
   * if 0: not enabled, enable it.
   * */
  if(! LL_AHB1_GRP1_IsEnabledClock(LL_AHB1_GRP1_PERIPH_GPIOB)) {
    LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
  }
 
  /* Configure SCK Pin PB13 */
  LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE);
  LL_GPIO_SetAFPin_0_7(GPIOB, LL_GPIO_PIN_13, LL_GPIO_AF_5);
  LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_13, LL_GPIO_PULL_DOWN);
 
  /* Configure MISO Pin PA11 */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_11, LL_GPIO_MODE_ALTERNATE);
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_11, LL_GPIO_AF_5);
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_11, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_11, LL_GPIO_PULL_DOWN);
 
  /* Configure MOSI Pin PA1 */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_1, LL_GPIO_MODE_ALTERNATE);
  LL_GPIO_SetAFPin_0_7(GPIOA, LL_GPIO_PIN_1, LL_GPIO_AF_5);
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_1, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_1, LL_GPIO_PULL_DOWN);
 
  /* (2) Configure SPI4 functional parameters ********************************/
  /* Enable the peripheral clock of GPIOB */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI4);
  //LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);
 
  /* Configure SPI4 communication */
  LL_SPI_SetBaudRatePrescaler(SPI4, LL_SPI_BAUDRATEPRESCALER_DIV4);
  LL_SPI_SetTransferDirection(SPI4, LL_SPI_FULL_DUPLEX);
  LL_SPI_SetClockPhase(SPI4, LL_SPI_PHASE_1EDGE);
  LL_SPI_SetClockPolarity(SPI4, LL_SPI_POLARITY_LOW);
  /* Reset value is LL_SPI_MSB_FIRST */
  LL_SPI_SetTransferBitOrder(SPI4, LL_SPI_MSB_FIRST);
  LL_SPI_SetDataWidth(SPI4, LL_SPI_DATAWIDTH_8BIT);
  LL_SPI_SetNSSMode(SPI4, LL_SPI_NSS_SOFT);
#ifdef MASTER_BOARD
  LL_SPI_SetMode(SPI4, LL_SPI_MODE_MASTER);
#else
  /* Reset value is LL_SPI_MODE_SLAVE */
  //LL_SPI_SetMode(SPI4, LL_SPI_MODE_SLAVE);
#endif /* MASTER_BOARD */
 
  /* Configure SPI4 DMA transfer interrupts */
  /* Enable DMA RX Interrupt */
  LL_SPI_EnableDMAReq_RX(SPI4);
  /* Enable DMA TX Interrupt */
  LL_SPI_EnableDMAReq_TX(SPI4);
}

12 REPLIES 12
TDK
Guru

> LL_GPIO_SetAFPin_0_7(GPIOB, LL_GPIO_PIN_13, LL_GPIO_AF_5);

That won't work with pin 13. You need LL_GPIO_SetAFPin_8_15. Same mistake multiple times.

Examine registers. Does the DMA's NDTR register go to zero? If so, data is getting transferred.

If you feel a post has answered your question, please click "Accept as Solution".

thank you, @TDK​

What is Alternate LL_GPIO_AF_5 there doing?

The definition of the function tells you what it's doing as well as valid parameters. LL_GPIO_AF_5 is there to set the pin to AF5.

Note that LL_GPIO_PIN_13 is not a valid parameter here.

/**
  * @brief  Configure gpio alternate function of a dedicated pin from 0 to 7 for a dedicated port.
  * @note   Possible values are from AF0 to AF15 depending on target.
  * @note   Warning: only one pin can be passed as parameter.
  * @rmtoll AFRL         AFSELy        LL_GPIO_SetAFPin_0_7
  * @param  GPIOx GPIO Port
  * @param  Pin This parameter can be one of the following values:
  *         @arg @ref LL_GPIO_PIN_0
  *         @arg @ref LL_GPIO_PIN_1
  *         @arg @ref LL_GPIO_PIN_2
  *         @arg @ref LL_GPIO_PIN_3
  *         @arg @ref LL_GPIO_PIN_4
  *         @arg @ref LL_GPIO_PIN_5
  *         @arg @ref LL_GPIO_PIN_6
  *         @arg @ref LL_GPIO_PIN_7
  * @param  Alternate This parameter can be one of the following values:
  *         @arg @ref LL_GPIO_AF_0
  *         @arg @ref LL_GPIO_AF_1
  *         @arg @ref LL_GPIO_AF_2
  *         @arg @ref LL_GPIO_AF_3
  *         @arg @ref LL_GPIO_AF_4
  *         @arg @ref LL_GPIO_AF_5
  *         @arg @ref LL_GPIO_AF_6
  *         @arg @ref LL_GPIO_AF_7
  *         @arg @ref LL_GPIO_AF_8
  *         @arg @ref LL_GPIO_AF_9
  *         @arg @ref LL_GPIO_AF_10
  *         @arg @ref LL_GPIO_AF_11
  *         @arg @ref LL_GPIO_AF_12
  *         @arg @ref LL_GPIO_AF_13
  *         @arg @ref LL_GPIO_AF_14
  *         @arg @ref LL_GPIO_AF_15
  * @retval None
  */
__STATIC_INLINE void LL_GPIO_SetAFPin_0_7(GPIO_TypeDef *GPIOx, uint32_t Pin, uint32_t Alternate)
{
  MODIFY_REG(GPIOx->AFR[0], (GPIO_AFRL_AFSEL0 << (POSITION_VAL(Pin) * 4U)),
             (Alternate << (POSITION_VAL(Pin) * 4U)));
}

If you feel a post has answered your question, please click "Accept as Solution".

Yes, now I know I need to use LL_GPIO_SetAFPin_8_15. In LL_GPIO_SetAFPin_8_15, LL_GPIO_AF_5 is still valid.

  /* Configure SCK Pin PB13 */
  LL_GPIO_SetPinMode(GPIOB, LL_GPIO_PIN_13, LL_GPIO_MODE_ALTERNATE);
  LL_GPIO_SetAFPin_8_15(GPIOB, LL_GPIO_PIN_13, LL_GPIO_AF_5);
  LL_GPIO_SetPinSpeed(GPIOB, LL_GPIO_PIN_13, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinPull(GPIOB, LL_GPIO_PIN_13, LL_GPIO_PULL_DOWN);
 
  /* Configure MISO Pin PA11 */
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_11, LL_GPIO_MODE_ALTERNATE);
  LL_GPIO_SetAFPin_8_15(GPIOA, LL_GPIO_PIN_11, LL_GPIO_AF_5);
  LL_GPIO_SetPinSpeed(GPIOA, LL_GPIO_PIN_11, LL_GPIO_SPEED_FREQ_HIGH);
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_11, LL_GPIO_PULL_DOWN);

But I still cannot detect any signals. However, the SPI Tx/Rx callback functions are successfully triggered when I do step-by-step debugging.

Please bear with me: not so familiar with these deep low level stuff.

TDK
Guru

Set up PB13/PA11 as GPIO outputs and toggle them to verify that whatever you're measuring is connected to those pins and that those pins are free to be toggled.

I don't see you enable GPIOA clock anywhere. Should still see SCK signal though.

If callbacks are getting called, it suggests SPI is set up and functioning, but not connected to what you're measuring and/or there is contention on those pins.

If you feel a post has answered your question, please click "Accept as Solution".
TDK
Guru

> Please bear with me: not so familiar with these deep low level stuff.

I don't know how invested you are in the LL library, but if you are not very invested, I would strongly suggest you either use direct register access (which is not much different than LL, but requires you to learn less and is more readable), or use HAL.

LL is a needless obfuscation of the register access interface. I don't understand what benefits it offers.

If you feel a post has answered your question, please click "Accept as Solution".

My app needs speed as fast as hardware can reach.

I tried HAL before, there is too much time wasted between CS pin low/high to SPI transmission.

I use LL api, because there is existing example for me to quickly make my prototype work.

The original code works well, although I don't know much of the tech details.

Now I need one more SPI, but run into problems.

If I try to use direct register access, there is only reference manual, which maybe has all the information, but lacks a clear guide on how to use them.

I did GPIO output for all the 3 pins and toggled them periodically. There is no issue.

I just found out that In my code, there are errors in alternate function mapping.

Now I changed according to Table 9 in data sheet, but still does not work.

I must miss sth?