HAL library 08- SPI for STM32Fxxx
Next library in ported libs is SPI for HAL based drivers for STM32F4xx and STM32F7xx based devices.
Library
Features
- Operate with up to 6 SPI peripherals
- Send single or multiple bytes at time
- Automatic SPI prescaler selection based on maximum clock selected for your external device
- Software based Chip Select pin
- Support for custom GPIO pins combination for SPI
Dependencies
- HAL
- TM
- STM32Fxxx HAL
- defines.h
- GPIO
Pinouts
Table with SPI pins for different pinspack. Pinspack is selected on library initialization.
Pins pack 1 | Pins pack 2 | Pins pack 3 | Pins pack 4 | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
SPIx | MOSI | MISO | SCK | MOSI | MISO | SCK | MOSI | MISO | SCK | MOSI | MISO | SCK |
SPI1 | PA7 | PA6 | PA5 | PB5 | PB4 | PB3 | ||||||
SPI2 | PC3 | PC2 | PB10 | PB15 | PB14 | PB13 | PI3 | PI2 | PI0 | PB15 | PB14 | PI1 |
SPI3 | PB5 | PB4 | PB3 | PC12 | PC11 | PC10 | ||||||
SPI4 | PE6 | PE5 | PE2 | PE14 | PE13 | PE12 | ||||||
SPI5 | PF9 | PF8 | PF7 | PF11 | PH7 | PH6 | ||||||
SPI6 | PG14 | PG12 | PG13 |
Functions and enumerations
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
/** * @defgroup TM_SPI_Typedefs * @brief Library Typedefs * @{ */ /** * @brief SPI modes selection */ typedef enum { TM_SPI_Mode_0 = 0x00, /*!< Clock polarity low, clock phase 1st edge */ TM_SPI_Mode_1, /*!< Clock polarity low, clock phase 2nd edge */ TM_SPI_Mode_2, /*!< Clock polarity high, clock phase 1st edge */ TM_SPI_Mode_3 /*!< Clock polarity high, clock phase 2nd edge */ } TM_SPI_Mode_t; /** * @brief USART PinsPack enumeration to select pins combination for USART */ typedef enum { TM_SPI_PinsPack_1 = 0x00, /*!< Select PinsPack1 from Pinout table for specific SPI */ TM_SPI_PinsPack_2, /*!< Select PinsPack2 from Pinout table for specific SPI */ TM_SPI_PinsPack_3, /*!< Select PinsPack3 from Pinout table for specific SPI */ TM_SPI_PinsPack_4, /*!< Select PinsPack4 from Pinout table for specific SPI */ TM_SPI_PinsPack_Custom /*!< Select custom pins for specific SPI, callback will be called, look @ref TM_SPI_InitCustomPinsCallback */ } TM_SPI_PinsPack_t; /** * @brief Daza size enumeration */ typedef enum { TM_SPI_DataSize_8b = 0x00, /*!< SPI in 8-bits mode */ TM_SPI_DataSize_16b /*!< SPI in 16-bits mode */ } TM_SPI_DataSize_t; /** * @} */ /** * @defgroup TM_SPI_Functions * @brief Library Functions * @{ */ /** * @brief Initializes SPIx peripheral with custom pinspack and default other settings * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param pinspack: Pinspack you will use from default SPI table. This parameter can be a value of @ref TM_SPI_PinsPack_t enumeration * @retval None */ void TM_SPI_Init(SPI_TypeDef* SPIx, TM_SPI_PinsPack_t pinspack); /** * @brief Initializes SPIx peripheral with custom pinspack and SPI mode and default other settings * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param pinspack: Pinspack you will use from default SPI table. This parameter can be a value of @ref TM_SPI_PinsPack_t enumeration * @param SPI_Mode: SPI mode you will use. This parameter can be a value of @ref TM_SPI_Mode_t enumeration * @retval None */ void TM_SPI_InitWithMode(SPI_TypeDef* SPIx, TM_SPI_PinsPack_t pinspack, TM_SPI_Mode_t SPI_Mode); /** * @brief Initializes SPIx peripheral with custom settings * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param pinspack: Pinspack you will use from default SPI table. This parameter can be a value of @ref TM_SPI_PinsPack_t enumeration * @param SPI_BaudRatePrescaler: SPI baudrate prescaler. This parameter can be a value of @ref SPI_BaudRatePrescaler * @param SPI_Mode_t: SPI mode you will use. This parameter can be a value of @ref TM_SPI_Mode_t enumeration * @param SPI_Mode: SPI mode you will use: * - SPI_MODE_MASTER: SPI in master mode (default) * - SPI_MODE_SLAVE: SPI in slave mode * @param SPI_FirstBit: select first bit for SPI * - SPI_FIRSTBIT_MSB: MSB is first bit (default) * - SPI_FIRSTBIT_LSB: LSB is first bit * @retval None */ void TM_SPI_InitFull(SPI_TypeDef* SPIx, TM_SPI_PinsPack_t pinspack, uint16_t SPI_BaudRatePrescaler, TM_SPI_Mode_t SPI_Mode_t, uint16_t SPI_Mode, uint16_t SPI_FirstBit); /** * @brief Calculates bits for SPI prescaler register to get minimal prescaler value for SPI peripheral * @note SPI has 8 prescalers available, 2,4,8,...,128,256 * @note This function will return you a bits you must set in your CR1 register. * * @note Imagine, you can use 20MHz max clock in your system, your system is running on 168MHz, and you use SPI on APB2 bus. * On 168 and 180MHz devices, APB2 works on Fclk/2, so 84 and 90MHz. * So, if you calculate this, prescaler will need to be 84MHz / 20MHz = 4.xx, but if you use 4 prescaler, then you will be over 20MHz. * You need 8 prescaler then. This function will calculate this. * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6. * Different SPIx works on different clock and is important to know for which SPI you need prescaler. * @param MAX_SPI_Frequency: Max SPI frequency you can use. Function will calculate the minimum prescaler you need for that. * * @retval Bits combination for SPI_CR1 register, with aligned location already, prepared to set parameter for @ref TM_SPI_InitFull() function. */ uint16_t TM_SPI_GetPrescalerFromMaxFrequency(SPI_TypeDef* SPIx, uint32_t MAX_SPI_Frequency); /** * @brief Sets data size for SPI at runtime * @note You can select either 8 or 16 bits data array. * @param *SPIx: Pointer to SPIx peripheral where data size will be set * @param DataSize: Datasize which will be used. This parameter can be a value of @ref TM_SPI_DataSize_t enumeration * @retval Status of data size before changes happen */ TM_SPI_DataSize_t TM_SPI_SetDataSize(SPI_TypeDef* SPIx, TM_SPI_DataSize_t DataSize); /** * @brief Sends single byte over SPI * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param data: 8-bit data size to send over SPI * @retval Received byte from slave device */ static __INLINE uint8_t TM_SPI_Send(SPI_TypeDef* SPIx, uint8_t data) { /* Check if SPI is enabled */ SPI_CHECK_ENABLED_RESP(SPIx, 0); /* Wait for previous transmissions to complete if DMA TX enabled for SPI */ SPI_WAIT_TX(SPIx); /* Fill output buffer with data */ *(__IO uint8_t *)&SPIx->DR = data; /* Wait for transmission to complete */ SPI_WAIT_RX(SPIx); /* Return data from buffer */ return SPIx->DR; } /** * @brief Sends and receives multiple bytes over SPIx * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param *dataOut: Pointer to array with data to send over SPI * @param *dataIn: Pointer to array to to save incoming data * @param count: Number of bytes to send/receive over SPI * @retval None */ void TM_SPI_SendMulti(SPI_TypeDef* SPIx, uint8_t* dataOut, uint8_t* dataIn, uint32_t count); /** * @brief Writes multiple bytes over SPI * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param *dataOut: Pointer to array with data to send over SPI * @param count: Number of elements to send over SPI * @retval None */ void TM_SPI_WriteMulti(SPI_TypeDef* SPIx, uint8_t* dataOut, uint32_t count); /** * @brief Receives multiple data bytes over SPI * @note Selected SPI must be set in 16-bit mode * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param *dataIn: Pointer to 8-bit array to save data into * @param dummy: Dummy byte to be sent over SPI, to receive data back. In most cases 0x00 or 0xFF * @param count: Number of bytes you want read from device * @retval None */ void TM_SPI_ReadMulti(SPI_TypeDef* SPIx, uint8_t *dataIn, uint8_t dummy, uint32_t count); /** * @brief Sends single byte over SPI * @note Selected SPI must be set in 16-bit mode * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param data: 16-bit data size to send over SPI * @retval Received 16-bit value from slave device */ static __INLINE uint16_t TM_SPI_Send16(SPI_TypeDef* SPIx, uint8_t data) { /* Check if SPI is enabled */ SPI_CHECK_ENABLED_RESP(SPIx, 0); /* Wait for previous transmissions to complete if DMA TX enabled for SPI */ SPI_WAIT_TX(SPIx); /* Fill output buffer with data */ SPIx->DR = data; /* Wait for transmission to complete */ SPI_WAIT_RX(SPIx); /* Return data from buffer */ return SPIx->DR; } /** * @brief Sends and receives multiple bytes over SPIx in 16-bit SPI mode * @note Selected SPI must be set in 16-bit mode * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param *dataOut: Pointer to array with data to send over SPI * @param *dataIn: Pointer to array to to save incoming data * @param count: Number of 16-bit values to send/receive over SPI * @retval None */ void TM_SPI_SendMulti16(SPI_TypeDef* SPIx, uint16_t* dataOut, uint16_t* dataIn, uint32_t count); /** * @brief Writes multiple data via SPI in 16-bit SPI mode * @note Selected SPI must be set in 16-bit mode * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param *dataOut: Pointer to 16-bit array with data to send over SPI * @param count: Number of elements to send over SPI * @retval None */ void TM_SPI_WriteMulti16(SPI_TypeDef* SPIx, uint16_t* dataOut, uint32_t count); /** * @brief Receives multiple data bytes over SPI in 16-bit SPI mode * @note Selected SPI must be set in 16-bit mode * @param *SPIx: Pointer to SPIx peripheral you will use, where x is between 1 to 6 * @param *dataIn: Pointer to 16-bit array to save data into * @param dummy: Dummy 16-bit value to be sent over SPI, to receive data back. In most cases 0x00 or 0xFF * @param count: Number of 16-bit values you want read from device * @retval None */ void TM_SPI_ReadMulti16(SPI_TypeDef* SPIx, uint16_t* dataIn, uint16_t dummy, uint32_t count); /** * @brief Init custom SPI pins for your SPIx. This is callback function and will be called from my library if needed. * @note When you call TM_SPI_Init() function, and if you pass TM_SPI_PinsPack_Custom to function, * then this function will be called where you can initialize custom pins for SPI peripheral * * @note You have to initialize MOSI, MISO and SCK pin * * @param *SPIx: Pointer to SPIx peripheral for which you have to set your custom pin settings * @param AlternateFunction: Alternate function number which should be used for GPIO pins * @retval None * @note With __weak parameter to prevent link errors if not defined by user */ void TM_SPI_InitCustomPinsCallback(SPI_TypeDef* SPIx, uint16_t AlternateFunction); /** * @} */ |
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
/** * Keil project example for SPI communication * * Before you start, select your target, on the right of the "Load" button * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 * @conf PLL parameters are set in "Options for Target" -> "C/C++" -> "Defines" * @packs STM32F4xx/STM32F7xx Keil packs are requred with HAL driver support * @stdperiph STM32F4xx/STM32F7xx HAL drivers required */ /* Include core modules */ #include "stm32fxxx_hal.h" /* Include my libraries here */ #include "defines.h" #include "tm_stm32_disco.h" #include "tm_stm32_spi.h" #include "string.h" /* Data for send and receive */ uint8_t Transmit[15], Receive[15]; int main(void) { uint8_t i; /* Init system clock for maximum system speed */ TM_RCC_InitSystem(); /* Init HAL layer */ HAL_Init(); /* Init leds */ TM_DISCO_LedInit(); /* Init SPI */ #if defined(STM32F7_DISCOVERY) /* Use custom for STM32F7-Discovery, callback function will be called for SPI GPIO initialization */ TM_SPI_Init(SPI2, TM_SPI_PinsPack_Custom); #else /* Use PB13,14,15 pins for SPI */ TM_SPI_Init(SPI2, TM_SPI_PinsPack_2); #endif /* Connect MOSI and MISO pins together! */ /* Send multi bytes */ for (i = 0; i < 15; i++) { Transmit[i] = i; /* Check for receive */ Receive[i] = TM_SPI_Send(SPI2, Transmit[i]); } /* Memory compare */ if (memcmp(Transmit, Receive, 15) == 0) { /* Turn on GREEN LED = Everything OK */ TM_DISCO_LedOn(LED_GREEN); } else { /* Turn on RED LED = SPI error */ TM_DISCO_LedOn(LED_RED); } while (1) { /* Do nothing */ } } /* Custom SPI initialization */ void TM_SPI_InitCustomPinsCallback(SPI_TypeDef* SPIx, uint16_t AlternateFunction) { /* SPI callback */ if (SPIx == SPI2) { /* Pins on STM32F7-Discovery on Arduino header */ TM_GPIO_InitAlternate(GPIOB, GPIO_PIN_14 | GPIO_PIN_15, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, AlternateFunction); TM_GPIO_InitAlternate(GPIOI, GPIO_PIN_1, TM_GPIO_OType_PP, TM_GPIO_PuPd_NOPULL, TM_GPIO_Speed_High, AlternateFunction); } } |
Project is available on Github, download all libraries below.
STM32 libraries based on STM32Fxxx HAL drivers.
Recent comments