/** ************************************************************************** * @file general_spi.c * @brief Модуль для инициализации SPI. ************************************************************************** Реализация функций для работы с SPI: - Инициализация SPI и его линий CLK/MISO/MOSI - Настройка GPIO для SPI - Настройка NVIC и тактирования SPI **************************************************************************/ #include "general_spi.h" #include "general_gpio.h" //------------------------------------------------------------------- //------------------------SPI INIT FUNCTIONS------------------------ /** * @brief Инициализация SPI с помощью структуры SPI_SettingsTypeDef. * @param sspi Указатель на структуру с настройками SPI. * @return HAL status. * @details * Инициализирует SPI и его GPIO. * Настройка аналогична HAL_SPI_Init * @code * suart.hspi.Init... * @endcode * но дополнительно надо прописать пины CLK/MISO/MOSI @ref SPI_SettingsTypeDef */ HAL_StatusTypeDef SPI_Base_Init(SPI_SettingsTypeDef *sspi) { // function takes setting structure for init // check is settings are valid if(SPI_Check_Init_Struct(sspi) != HAL_OK) return HAL_ERROR; SPI_MspInit(&sspi->hspi); if (HAL_SPI_Init(&sspi->hspi) != HAL_OK) { MyLibs_Error_Handler(); return HAL_ERROR; } // init gpio from SPISettings structure SPI_GPIO_Init(sspi); // // init dma from SPISettings structure if need // if (sspi->DMAChannel != 0) // SPI_DMA_Init(&sspi->hspi, sspi->hspi.hdmarx, sspi->DMAChannel, sspi->DMA_CHANNEL_X); return HAL_OK; } /** * @brief Инициализация GPIO для SPI. * @param sspi Указатель на структуру с настройками SPI. */ void SPI_GPIO_Init(SPI_SettingsTypeDef *sspi) { GPIO_InitTypeDef GPIO_InitStruct = {0}; // GPIO INIT GPIO_Clock_Enable(sspi->CLK_GPIOx); GPIO_Clock_Enable(sspi->MISO_GPIOx); GPIO_Clock_Enable(sspi->MOSI_GPIOx); // CLK PIN INIT GPIO_InitStruct.Pin = sspi->CLK_PIN; GPIO_InitStruct.Alternate = sspi->CLK_GPIO_AlternageFunc; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(sspi->CLK_GPIOx, &GPIO_InitStruct); // MISO PIN INIT GPIO_InitStruct.Pin = sspi->MISO_PIN; GPIO_InitStruct.Alternate = sspi->MISO_GPIO_AlternageFunc; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(sspi->MISO_GPIOx, &GPIO_InitStruct); // MOSI PIN INIT GPIO_InitStruct.Pin = sspi->MOSI_PIN; GPIO_InitStruct.Alternate = sspi->MOSI_GPIO_AlternageFunc; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(sspi->MOSI_GPIOx, &GPIO_InitStruct); } void SPI_DMA_Init(SPI_HandleTypeDef *hspi, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X) { // function takes spi and dma handlers and dmachannel for spi // // for now only dma rx is supported, tx maybe later if needed // // calc defines on boot_project_setup.h // /* SPI3 DMA Init */ // /* SPI3_RX Init */ // // hdma_rx->Instance = DMAChannel; //#if defined(STM32F4xx) // dma channel choose for 407 // hdma_rx->Init.Channel = DMA_CHANNEL_X; //#endif // hdma_rx->Init.Direction = DMA_PERIPH_TO_MEMORY; // hdma_rx->Init.PeriphInc = DMA_PINC_DISABLE; // hdma_rx->Init.MemInc = DMA_MINC_ENABLE; // hdma_rx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // hdma_rx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; // hdma_rx->Init.Mode = DMA_CIRCULAR; // hdma_rx->Init.Priority = DMA_PRIORITY_LOW; // if (HAL_DMA_Init(hdma_rx) != HAL_OK) // { // MyLibs_Error_Handler(); // } // __USER_LINKDMA(hspi,hdmarx,hdma_rx); // // // __USER_LINKDMA is need because __HAL_LINKDMA is written for global defined hdma_rx // // so you get error because hal uses . insted of -> } /** * @brief Настройка тактирования и прерываний SPI. * @param hspi Указатель на хендл SPI. * @note Чтобы не генерировать функцию с иницилизацией неиспользуемых SPI, дефайнами @ref SPI_INIT в @ref general_spi.h определяются используемые SPI. */ void SPI_MspInit(SPI_HandleTypeDef *hspi) // analog for hal function { // rcc, dma and interrupt init for SPIs // GPIO init was moved to own functions SPI_GPIO_Init if(0); #ifdef USE_SPI1 else if(hspi->Instance==SPI1) { // /* DMA2 clock enable */ // __HAL_RCC_DMA2_CLK_ENABLE(); // /* DMA interrupt init */ // HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0); // HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); /* SPI1 clock enable */ __HAL_RCC_SPI1_CLK_ENABLE(); /* SPI1 interrupt Init */ HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(SPI1_IRQn); } #endif // USE_SPI1 #ifdef USE_SPI2 else if(hspi->Instance==SPI2) { // /* DMA1 clock enable */ // __HAL_RCC_DMA1_CLK_ENABLE(); // /* DMA interrupt init */ // HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0); // HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); /* SPI2 clock enable */ __HAL_RCC_SPI2_CLK_ENABLE(); /* SPI2 interrupt Init */ HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(SPI2_IRQn); } #endif // USE_SPI2 #ifdef USE_SPI3 else if(hspi->Instance==SPI3) { // /* DMA1 clock enable */ // __HAL_RCC_DMA1_CLK_ENABLE(); // /* DMA interrupt init */ // HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0); // HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); /* SPI3 clock enable */ __HAL_RCC_SPI3_CLK_ENABLE(); /* SPI3 interrupt Init */ HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0); HAL_NVIC_EnableIRQ(SPI3_IRQn); } #endif // USE_SPI3 } /** * @brief Деинициализация тактирования и прерываний SPI. * @param hspi Указатель на хендл SPI. * @note Чтобы не генерировать функцию с иницилизацией неиспользуемых SPI, дефайнами @ref SPI_INIT в @ref general_spi.h определяются используемые SPI. */ void SPI_MspDeInit(SPI_HandleTypeDef *hspi) // analog for hal function { // rcc, dma and interrupt init for SPIs // GPIO init was moved to own functions SPI_GPIO_Init if(0); #ifdef USE_SPI1 else if(hspi->Instance==SPI1) { // /* DMA2 clock enable */ // __HAL_RCC_DMA2_CLK_ENABLE(); // /* DMA interrupt init */ // HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0); // HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); /* SPI1 clock reset */ __HAL_RCC_SPI1_FORCE_RESET(); __HAL_RCC_SPI1_RELEASE_RESET(); } #endif // USE_SPI1 #ifdef USE_SPI2 else if(hspi->Instance==SPI2) { // /* DMA1 clock enable */ // __HAL_RCC_DMA1_CLK_ENABLE(); // /* DMA interrupt init */ // HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0); // HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); /* SPI2 clock reset */ __HAL_RCC_SPI2_FORCE_RESET(); __HAL_RCC_SPI2_RELEASE_RESET(); } #endif // USE_SPI2 #ifdef USE_SPI3 else if(hspi->Instance==SPI3) { // /* DMA1 clock enable */ // __HAL_RCC_DMA1_CLK_ENABLE(); // /* DMA interrupt init */ // HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0); // HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); /* SPI3 clock reset */ __HAL_RCC_SPI3_FORCE_RESET(); __HAL_RCC_SPI3_RELEASE_RESET(); } #endif // USE_SPI3 } /** * @brief Проверка корректности структуры инициализации SPI. * @param sspi Указатель на структуру с настройками SPI. * @return HAL status. */ HAL_StatusTypeDef SPI_Check_Init_Struct(SPI_SettingsTypeDef *sspi) { // check is settings are valid if (!IS_SPI_ALL_INSTANCE(sspi->hspi.Instance)) return HAL_ERROR; // check init settings if (!IS_SPI_MODE(sspi->hspi.Init.Mode)) return HAL_ERROR; if (!IS_SPI_DIRECTION(sspi->hspi.Init.Direction)) return HAL_ERROR; if (!IS_SPI_DATASIZE(sspi->hspi.Init.DataSize)) return HAL_ERROR; if (!IS_SPI_BAUDRATE_PRESCALER(sspi->hspi.Init.BaudRatePrescaler)) return HAL_ERROR; if (!IS_SPI_CPOL(sspi->hspi.Init.CLKPolarity)) return HAL_ERROR; if (!IS_SPI_CPHA(sspi->hspi.Init.CLKPhase)) return HAL_ERROR; if (!IS_SPI_NSS(sspi->hspi.Init.NSS)) return HAL_ERROR; if (!IS_SPI_FIRST_BIT(sspi->hspi.Init.FirstBit)) return HAL_ERROR; if (!IS_SPI_CRC_CALCULATION(sspi->hspi.Init.CRCCalculation)) return HAL_ERROR; if (!IS_SPI_CRC_POLYNOMIAL(sspi->hspi.Init.NSS) && (sspi->hspi.Init.CRCCalculation != SPI_CRCCALCULATION_DISABLE)) return HAL_ERROR; if (!IS_SPI_TIMODE(sspi->hspi.Init.TIMode)) return HAL_ERROR; // check gpio if (!IS_GPIO_ALL_INSTANCE(sspi->CLK_GPIOx) || !IS_GPIO_ALL_INSTANCE(sspi->MISO_GPIOx) || !IS_GPIO_ALL_INSTANCE(sspi->MOSI_GPIOx)) return HAL_ERROR; if (!IS_GPIO_PIN(sspi->CLK_PIN) && !IS_GPIO_PIN(sspi->MISO_PIN) && !IS_GPIO_PIN(sspi->MOSI_PIN)) // if both pins arent set up return HAL_ERROR; return HAL_OK; }