diff options
Diffstat (limited to 'Projects/NUCLEO-WB35CE/Examples_LL/SPI/SPI_TwoBoards_FullDuplex_DMA_Slave_Init/Src/main.c')
-rw-r--r-- | Projects/NUCLEO-WB35CE/Examples_LL/SPI/SPI_TwoBoards_FullDuplex_DMA_Slave_Init/Src/main.c | 572 |
1 files changed, 572 insertions, 0 deletions
diff --git a/Projects/NUCLEO-WB35CE/Examples_LL/SPI/SPI_TwoBoards_FullDuplex_DMA_Slave_Init/Src/main.c b/Projects/NUCLEO-WB35CE/Examples_LL/SPI/SPI_TwoBoards_FullDuplex_DMA_Slave_Init/Src/main.c new file mode 100644 index 000000000..0a3de9762 --- /dev/null +++ b/Projects/NUCLEO-WB35CE/Examples_LL/SPI/SPI_TwoBoards_FullDuplex_DMA_Slave_Init/Src/main.c @@ -0,0 +1,572 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file Examples_LL/SPI/SPI_TwoBoards_FullDuplex_DMA_Slave_Init/Src/main.c + * @author MCD Application Team + * @brief This example describes how to send/receive bytes over SPI IP using + * the STM32WBxx SPI LL API. + * Peripheral initialization done using LL unitary services functions. + ****************************************************************************** + * @attention + * + * <h2><center>© Copyright (c) 2019 STMicroelectronics. + * All rights reserved.</center></h2> + * + * This software component is licensed by ST under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ****************************************************************************** + */ +/* USER CODE END Header */ + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* Private includes ----------------------------------------------------------*/ +/* USER CODE BEGIN Includes */ + +/* USER CODE END Includes */ + +/* Private typedef -----------------------------------------------------------*/ +/* USER CODE BEGIN PTD */ + +/* USER CODE END PTD */ + +/* Private define ------------------------------------------------------------*/ +/* USER CODE BEGIN PD */ + +/* USER CODE END PD */ + +/* Private macro -------------------------------------------------------------*/ +/* USER CODE BEGIN PM */ + +/* USER CODE END PM */ + +/* Private variables ---------------------------------------------------------*/ + +/* USER CODE BEGIN PV */ + +__IO uint8_t ubButtonPress = 0; + +/* Buffer used for transmission */ +uint8_t aTxBuffer[] = "**** SPI_TwoBoards_FullDuplex_DMA communication **** SPI_TwoBoards_FullDuplex_DMA communication **** SPI_TwoBoards_FullDuplex_DMA communication ****"; +uint8_t ubNbDataToTransmit = sizeof(aTxBuffer); +__IO uint8_t ubTransmissionComplete = 0; + +/* Buffer used for reception */ +uint8_t aRxBuffer[sizeof(aTxBuffer)]; +uint8_t ubNbDataToReceive = sizeof(aTxBuffer); +__IO uint8_t ubReceptionComplete = 0; + +/* USER CODE END PV */ + +/* Private function prototypes -----------------------------------------------*/ +void SystemClock_Config(void); +static void MX_GPIO_Init(void); +static void MX_DMA_Init(void); +static void MX_SPI1_Init(void); +/* USER CODE BEGIN PFP */ + +void SystemClock_Config(void); +void Activate_SPI(void); +void LED_On(void); +void LED_Blinking(uint32_t Period); +void WaitAndCheckEndOfTransfer(void); +uint8_t Buffercmp8(uint8_t *pBuffer1, uint8_t *pBuffer2, uint8_t BufferLength); + +/* USER CODE END PFP */ + +/* Private user code ---------------------------------------------------------*/ +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +/** + * @brief The application entry point. + * @retval int + */ +int main(void) +{ + /* USER CODE BEGIN 1 */ + /* USER CODE END 1 */ + + /* MCU Configuration--------------------------------------------------------*/ + + /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ + + + NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + + /* System interrupt 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_SPI1_Init(); + /* USER CODE BEGIN 2 */ + + /* Configure the DMA1_Channel3 functional parameters */ + LL_DMA_ConfigTransfer(DMA1, + LL_DMA_CHANNEL_3, + 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(DMA1, + LL_DMA_CHANNEL_3, + (uint32_t)aTxBuffer, LL_SPI_DMA_GetRegAddr(SPI1), + LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3)); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_3, ubNbDataToReceive); + + LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_3, LL_DMAMUX_REQ_SPI1_TX); + + + /* Configure the DMA1_Channel1 functional parameters */ + LL_DMA_ConfigTransfer(DMA1, + LL_DMA_CHANNEL_1, + 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(DMA1, LL_DMA_CHANNEL_1, LL_SPI_DMA_GetRegAddr(SPI1), (uint32_t)aRxBuffer, + LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1)); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, ubNbDataToTransmit); + LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_SPI1_RX); + + + /* Enable DMA interrupts complete/error */ + LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_3); + LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_3); + LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1); + LL_DMA_EnableIT_TE(DMA1, LL_DMA_CHANNEL_1); + + /* Initialize FFIFO Threshold */ + LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER); + + /* Configure SPI1 DMA transfer interrupts */ + /* Enable DMA TX Interrupt */ + LL_SPI_EnableDMAReq_TX(SPI1); + + /* Configure SPI1 DMA transfer interrupts */ + /* Enable DMA RX Interrupt */ + LL_SPI_EnableDMAReq_RX(SPI1); + + /* Enable the SPI1 peripheral */ + Activate_SPI(); + + /* Wait for the end of the transfer and check received data */ + /* LED blinking FAST during waiting time */ + WaitAndCheckEndOfTransfer(); + /* USER CODE END 2 */ + + /* Infinite loop */ + /* USER CODE BEGIN WHILE */ + while (1) + { + /* USER CODE END WHILE */ + + /* USER CODE BEGIN 3 */ + } + /* USER CODE END 3 */ +} + +/** + * @brief System Clock Configuration + * @retval None + */ +void SystemClock_Config(void) +{ + LL_FLASH_SetLatency(LL_FLASH_LATENCY_3); + + /* MSI configuration and activation */ + LL_RCC_MSI_Enable(); + while(LL_RCC_MSI_IsReady() != 1) + { + }; + + /* Main PLL configuration and activation */ + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_MSI, LL_RCC_PLLM_DIV_1, 32, LL_RCC_PLLR_DIV_2); + LL_RCC_PLL_Enable(); + LL_RCC_PLL_EnableDomain_SYS(); + while(LL_RCC_PLL_IsReady() != 1) + { + }; + + /* Sysclk activation on the main PLL */ + /* Set CPU1 prescaler*/ + LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1); + + /* Set CPU2 prescaler*/ + LL_C2_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2); + + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) + { + }; + + /* Set AHB SHARED prescaler*/ + LL_RCC_SetAHB4Prescaler(LL_RCC_SYSCLK_DIV_1); + + /* Set APB1 prescaler*/ + LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1); + + /* Set APB2 prescaler*/ + LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1); + + LL_Init1msTick(64000000); + + /* Update CMSIS variable (which can be updated also through SystemCoreClockUpdate function) */ + LL_SetSystemCoreClock(64000000); + /* USER CODE BEGIN Smps */ + + /* USER CODE END Smps */ +} + +/** + * @brief SPI1 Initialization Function + * @param None + * @retval None + */ +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}; + + /* Peripheral clock enable */ + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1); + + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + /**SPI1 GPIO Configuration + PA5 ------> SPI1_SCK + PA6 ------> SPI1_MISO + PA7 ------> SPI1_MOSI + */ + GPIO_InitStruct.Pin = LL_GPIO_PIN_5|LL_GPIO_PIN_7; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_HIGH; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStruct.Pull = LL_GPIO_PULL_DOWN; + GPIO_InitStruct.Alternate = LL_GPIO_AF_5; + LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = LL_GPIO_PIN_6; + GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; + 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); + + /* SPI1 DMA Init */ + + /* SPI1_TX Init */ + LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_3, LL_DMAMUX_REQ_SPI1_TX); + + LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_3, LL_DMA_DIRECTION_MEMORY_TO_PERIPH); + + LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PRIORITY_LOW); + + LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MODE_NORMAL); + + LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PERIPH_NOINCREMENT); + + LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MEMORY_INCREMENT); + + LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_PDATAALIGN_BYTE); + + LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_3, LL_DMA_MDATAALIGN_BYTE); + + /* SPI1_RX Init */ + LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_SPI1_RX); + + LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY); + + LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW); + + LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL); + + LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT); + + LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT); + + LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE); + + LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE); + + /* 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_SLAVE; + SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT; + SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH; + SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE; + SPI_InitStruct.NSS = LL_SPI_NSS_SOFT; + SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST; + SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE; + SPI_InitStruct.CRCPoly = 7; + LL_SPI_Init(SPI1, &SPI_InitStruct); + LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA); + LL_SPI_DisableNSSPulseMgt(SPI1); + /* USER CODE BEGIN SPI1_Init 2 */ + + /* USER CODE END SPI1_Init 2 */ + +} + +/** + * Enable DMA controller clock + */ +static void MX_DMA_Init(void) +{ + + /* Init with LL driver */ + /* DMA controller clock enable */ + LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMAMUX1); + LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1); + + /* DMA interrupt init */ + /* DMA1_Channel1_IRQn interrupt configuration */ + NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); + NVIC_EnableIRQ(DMA1_Channel1_IRQn); + /* DMA1_Channel3_IRQn interrupt configuration */ + NVIC_SetPriority(DMA1_Channel3_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0)); + NVIC_EnableIRQ(DMA1_Channel3_IRQn); + +} + +/** + * @brief GPIO Initialization Function + * @param None + * @retval None + */ +static void MX_GPIO_Init(void) +{ + LL_GPIO_InitTypeDef GPIO_InitStruct = {0}; + + /* GPIO Ports Clock Enable */ + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA); + LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB); + + /**/ + LL_GPIO_ResetOutputPin(LED2_GPIO_Port, LED2_Pin); + + /**/ + GPIO_InitStruct.Pin = LED2_Pin; + GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT; + GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW; + GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; + GPIO_InitStruct.Pull = LL_GPIO_PULL_NO; + LL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct); + +} + +/* USER CODE BEGIN 4 */ + +/** + * @brief This function Activate SPI1 + * @param None + * @retval None + */ +void Activate_SPI(void) +{ + /* Enable SPI1 */ + LL_SPI_Enable(SPI1); + + /* Enable DMA Channels */ + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_3); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1); +} + +/** + * @brief Turn-on LED2. + * @param None + * @retval None + */ +void LED_On(void) +{ + /* Turn LED2 on */ + LL_GPIO_SetOutputPin(LED2_GPIO_PORT, LED2_PIN); +} + + +/** + * @brief Set LED2 to Blinking mode for an infinite loop (toggle period based on value provided as input parameter). + * @param Period : Period of time (in ms) between each toggling of LED + * This parameter can be user defined values. Pre-defined values used in that example are : + * @arg LED_BLINK_FAST : Fast Blinking + * @arg LED_BLINK_SLOW : Slow Blinking + * @arg LED_BLINK_ERROR : Error specific Blinking + * @retval None + */ +void LED_Blinking(uint32_t Period) +{ + /* Toggle LED2 in an infinite loop */ + while (1) + { + LL_GPIO_TogglePin(LED2_GPIO_PORT, LED2_PIN); + LL_mDelay(Period); + } +} + + +/** + * @brief Wait end of transfer and check if received Data are well. + * @param None + * @retval None + */ +void WaitAndCheckEndOfTransfer(void) +{ + /* 1 - Wait end of transmission */ + while (ubTransmissionComplete != 1) + { + } + /* Disable DMA1 Tx Channel */ + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + /* 2 - Wait end of reception */ + while (ubReceptionComplete != 1) + { + } + /* Disable DMA1 Rx Channel */ + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_3); + /* 3 - Compare Transmit data to receive data */ + if (Buffercmp8((uint8_t *)aTxBuffer, (uint8_t *)aRxBuffer, ubNbDataToTransmit)) + { + /* Processing Error */ + LED_Blinking(LED_BLINK_ERROR); + } + else + { + /* Turn On Led if data are well received */ + LED_On(); + } +} + +/** +* @brief Compares two 8-bit buffers and returns the comparison result. +* @param pBuffer1: pointer to the source buffer to be compared to. +* @param pBuffer2: pointer to the second source buffer to be compared to the first. +* @param BufferLength: buffer's length. +* @retval 0: Comparison is OK (the two Buffers are identical) +* Value different from 0: Comparison is NOK (Buffers are different) +*/ +uint8_t Buffercmp8(uint8_t *pBuffer1, uint8_t *pBuffer2, uint8_t BufferLength) +{ + while (BufferLength--) + { + if (*pBuffer1 != *pBuffer2) + { + return 1; + } + + pBuffer1++; + pBuffer2++; + } + + return 0; +} + + +/******************************************************************************/ +/* USER IRQ HANDLER TREATMENT Functions */ +/******************************************************************************/ +/** + * @brief Function to manage User push-button (SW1) + * @param None + * @retval None + */ +void UserButton_Callback(void) +{ + /* Update User push-button (SW1) variable : to be checked in waiting loop in main program */ + ubButtonPress = 1; +} + +/** + * @brief Function called from DMA1 IRQ Handler when Rx transfer is completed + * @param None + * @retval None + */ +void DMA1_ReceiveComplete_Callback(void) +{ + /* DMA Rx transfer completed */ + ubReceptionComplete = 1; +} + +/** + * @brief Function called from DMA1 IRQ Handler when Tx transfer is completed + * @param None + * @retval None + */ +void DMA1_TransmitComplete_Callback(void) +{ + /* DMA Tx transfer completed */ + ubTransmissionComplete = 1; +} + +/** + * @brief Function called in case of error detected in SPI IT Handler + * @param None + * @retval None + */ +void SPI1_TransferError_Callback(void) +{ + /* Disable DMA1 Rx Channel */ + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_3); + + /* Disable DMA1 Tx Channel */ + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1); + /* Set LED2 to Blinking mode to indicate error occurs */ + LED_Blinking(LED_BLINK_ERROR); +} + + +/* USER CODE END 4 */ + +/** + * @brief This function is executed in case of error occurrence. + * @retval None + */ +void Error_Handler(void) +{ + /* USER CODE BEGIN Error_Handler_Debug */ + /* User can add his own implementation to report the HAL error return state */ + + /* USER CODE END Error_Handler_Debug */ +} + +#ifdef USE_FULL_ASSERT +/** + * @brief Reports the name of the source file and the source line number + * where the assert_param error has occurred. + * @param file: pointer to the source file name + * @param line: assert_param error line source number + * @retval None + */ +void assert_failed(uint8_t *file, uint32_t line) +{ + /* USER CODE BEGIN 6 */ + /* User can add his own implementation to report the file name and line number, + tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ + /* USER CODE END 6 */ +} +#endif /* USE_FULL_ASSERT */ + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |