cancel
Showing results for 
Search instead for 
Did you mean: 

Switching from HAL to LL complications

Igneous
Associate III

Good day,

I recently made a post about getting my SPI to a certain speed. Ive managed to get the core down but found out that HAL is way too slow for what I need. I thus switched to low-level drivers. Now using LL instead of hal, Im trying to do a simple transmit receive to my 24 bit SPI. While HAL used to work, I'm doing something wrong. me and my collegue can't put our fniger on it. Anyone here think they might be able to help figure it out? Code is added below. many thanks in advance!

Board is the STM32 H755ZIQ. 
Also before this comes up, yes I will likely have to do this through DMA eventually. This will have to do for now though.

static void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  LL_SPI_InitTypeDef SPI_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};

  /** Initializes the peripherals clock
  */
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI1;
  PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);

  LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOA);
  LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOG);
  /**SPI1 GPIO Configuration
  PA6   ------> SPI1_MISO
  PA7   ------> SPI1_MOSI
  PG11   ------> SPI1_SCK
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_11;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(GPIOG, &GPIO_InitStruct);

  /* SPI1 interrupt Init */
  NVIC_SetPriority(SPI1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(SPI1_IRQn);

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_24BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 0x0;
  LL_SPI_Init(SPI1, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_SetFIFOThreshold(SPI1, LL_SPI_FIFO_TH_01DATA);
  LL_SPI_DisableNSSPulseMgt(SPI1);

  LL_SPI_Enable(SPI1);
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

void SPI1_TransmitReceive() {
		 while (LL_SPI_IsActiveFlag_TXP(SPI1) == 0); // Wait until the TX FIFO is not full (TXP)
         LL_SPI_TransmitData8(SPI1, (TxData >> 16) & 0xFF);  // MSB
         while (LL_SPI_IsActiveFlag_TXP(SPI1) == 0); // Wait until the TX FIFO is not full (TXP)
         LL_SPI_TransmitData8(SPI1, (TxData >>  & 0xFF);   // Middle byte
         while (LL_SPI_IsActiveFlag_TXP(SPI1) == 0); // Wait until the TX FIFO is not full (TXP)
         LL_SPI_TransmitData8(SPI1, TxData & 0xFF);          // LSB

         // Ensure all bytes are transmitted before reading RX
         while (!LL_SPI_IsActiveFlag_EOT(SPI1));  // End Of Transfer flag
         // Wait until we have three bytes in RX FIFO
         while (LL_SPI_GetRxFIFOPackingLevel(SPI1) < 3);

         uint32_t receivedData = 0;

         while (LL_SPI_GetRxFIFOPackingLevel(SPI1) == 0);
         receivedData |= (LL_SPI_ReceiveData8(SPI1) << 16);  // MSB
         while (LL_SPI_GetRxFIFOPackingLevel(SPI1) == 0);
         receivedData |= (LL_SPI_ReceiveData8(SPI1) << 8);   // Middle byte
         while (LL_SPI_GetRxFIFOPackingLevel(SPI1) == 0);
         receivedData |= LL_SPI_ReceiveData8(SPI1);          // LSB

         RxData = receivedData;

         HAL_Delay(10);  // Remove this delay in real-time applications
}

/* Stop TIM1 */
void Stop_TIM1(void)
{
    /* Stop TIM1 base timer */
    if (HAL_TIM_Base_Stop_IT(&htim1) != HAL_OK)
    {
        /* Error Handling */
        Error_Handler();
    }
}

/* Start TIM1 in interrupt mode */
void Start_TIM1(void)
{
	HAL_NVIC_SetPriority(TIM1_UP_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(TIM1_UP_IRQn);
	sampling = 1;
    /* Start TIM1 base timer with interrupt */
    if (HAL_TIM_Base_Start_IT(&htim1) != HAL_OK)
    {
        /* Error Handling */
        Error_Handler();
    }
}

void TIM1_UP_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&htim1);
}

///* Timer Interrupt Handler */
//void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
//{
//    if (htim->Instance == TIM1)  // Check if TIM1 triggered the interrupt
//    {
//        /* Code to execute on every timer interrupt */
//    	// This code should be executed every time TIM2 period elapses
//    	countertest++;
//    	four = 4;  // This should set 'four' to 4 every time the timer triggers
//    }
//}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
	countertest++;
	four = 4;
    if (htim->Instance == TIM1) {
        if (sampleIterator >= maxIterator) {
            sampleIterator = 0;
        }

        currentSample++;

        // Select SPI transfer data
        TxData = txDataList[sampleIterator];

        // Toggle CNV to trigger ADC conversion
        GPIOC->BSRR = GPIO_BSRR_BS10; // Set CNV (pin 10 high)
        GPIOC->BSRR = GPIO_BSRR_BR10; // Reset CNV (pin 10 low)

        // Wait until C11 is low (ADC ready)
        while (GPIOC->IDR & GPIO_IDR_ID11);

        // Pull CS low
        GPIOC->BSRR = GPIO_BSRR_BR12;

        // Perform SPI transfer
        //HAL_SPI_TransmitReceive(&hspi1, (uint32_t*) &TxData, (uint32_t*) &RxData, 1, HAL_MAX_DELAY);
        SPI1_TransmitReceive();

        // Pull CS high
        GPIOC->BSRR = GPIO_BSRR_BS12;

        // Extract 18-bit ADC value
        adc_value = (RxData >> 6) & 0x3FFFF;

        // Store data in active buffer
        currentBuffer[bufferIndex++] = adc_value & 0xFF;        // LSB
        currentBuffer[bufferIndex++] = (adc_value >> 8) & 0xFF; // Middle byte
        currentBuffer[bufferIndex++] = (adc_value >> 16) & 0xFF;// MSB

        // When buffer is full, switch buffers and send data
        if (bufferIndex >= BUFFER_SIZE) {
            bufferIndex = 0;

            if (!sendingInProgress) {
                sendingInProgress = 1;
                uint8_t* temp = currentBuffer;
                currentBuffer = sendingBuffer;
                sendingBuffer = temp;

                CDC_Transmit_HS((uint8_t*)sendingBuffer, BUFFER_SIZE);
            }
        }

        if (currentSample >= totalSamples) {
            sampling = 0;
        }

        sampleIterator++;
    }
}

 

 

 

 

5 REPLIES 5
mƎALLEm
ST Employee

Hello @Igneous ,

Please, instead of sharing screenshots of your code, please use </> button and past it here.

See this link.

Thank you for your understanding.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Please see How to insert source code - not as images.

 

What problem(s) are you having with your LL code?

The code seems to get stuck in the transmitreceive method Ive written. For some reason it appears that, once it gets to the RX section of this code, it hangs on the RX flags and never passes them.

Thanks for the note, ill keep it in mind for next time and ill edit it in the post

Igneous
Associate III

Update:
I've changed some of the code. I now have a responce in my logic analyser that I can see. Problem is that it's not being read as rxdata for some reason and still getting stuck in the loop on [while (!LL_SPI_IsActiveFlag_EOT(SPI1));]

Logic analyser:

Igneous_0-1743080461150.png

 

Current method:

void SPI1_TransmitReceive() {
	three = 1;
	if (LL_GPIO_IsInputPinSet(GPIOA, LL_GPIO_PIN_6)){
		// Ensure SPI is enabled
		if (!LL_SPI_IsEnabled(SPI1)) {
			LL_SPI_Enable(SPI1);
		}

		// Pull NSS (PC12) LOW to start transaction
		LL_GPIO_ResetOutputPin(GPIOC, LL_GPIO_PIN_12);
		LL_SPI_StartMasterTransfer(SPI1);

		// Start Master Transfer (Needed for STM32H7)
		LL_SPI_StartMasterTransfer(SPI1);
		three = 2;
		// Wait until TX is ready
		while (!LL_SPI_IsActiveFlag_TXP(SPI1));

		// Send 24-bit data
		LL_SPI_TransmitData32(SPI1, TxData);
		three = 3;
		rx_fifo_level = LL_SPI_ReceiveData32(SPI1);
		// Wait for End of Transfer
		while (!LL_SPI_IsActiveFlag_EOT(SPI1));
		three = 4;
		// Clear EOT flag
		LL_SPI_ClearFlag_EOT(SPI1);

		// Wait for RX data
		while (!LL_SPI_IsActiveFlag_RXP(SPI1));

		// Read received 24-bit data
		RxData = LL_SPI_ReceiveData32(SPI1);

		// Pull NSS (PC12) HIGH to end transaction
		LL_GPIO_SetOutputPin(GPIOC, LL_GPIO_PIN_12);
	}
}