mbed-os

Dependents:   cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more

Committer:
be_bryan
Date:
Mon Dec 11 17:54:04 2017 +0000
Revision:
0:b74591d5ab33
motor ++

Who changed what in which revision?

UserRevisionLine numberNew contents of line
be_bryan 0:b74591d5ab33 1 /* mbed Microcontroller Library
be_bryan 0:b74591d5ab33 2 *******************************************************************************
be_bryan 0:b74591d5ab33 3 * Copyright (c) 2015, STMicroelectronics
be_bryan 0:b74591d5ab33 4 * All rights reserved.
be_bryan 0:b74591d5ab33 5 *
be_bryan 0:b74591d5ab33 6 * Redistribution and use in source and binary forms, with or without
be_bryan 0:b74591d5ab33 7 * modification, are permitted provided that the following conditions are met:
be_bryan 0:b74591d5ab33 8 *
be_bryan 0:b74591d5ab33 9 * 1. Redistributions of source code must retain the above copyright notice,
be_bryan 0:b74591d5ab33 10 * this list of conditions and the following disclaimer.
be_bryan 0:b74591d5ab33 11 * 2. Redistributions in binary form must reproduce the above copyright notice,
be_bryan 0:b74591d5ab33 12 * this list of conditions and the following disclaimer in the documentation
be_bryan 0:b74591d5ab33 13 * and/or other materials provided with the distribution.
be_bryan 0:b74591d5ab33 14 * 3. Neither the name of STMicroelectronics nor the names of its contributors
be_bryan 0:b74591d5ab33 15 * may be used to endorse or promote products derived from this software
be_bryan 0:b74591d5ab33 16 * without specific prior written permission.
be_bryan 0:b74591d5ab33 17 *
be_bryan 0:b74591d5ab33 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
be_bryan 0:b74591d5ab33 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
be_bryan 0:b74591d5ab33 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
be_bryan 0:b74591d5ab33 21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
be_bryan 0:b74591d5ab33 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
be_bryan 0:b74591d5ab33 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
be_bryan 0:b74591d5ab33 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
be_bryan 0:b74591d5ab33 25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
be_bryan 0:b74591d5ab33 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
be_bryan 0:b74591d5ab33 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
be_bryan 0:b74591d5ab33 28 *******************************************************************************
be_bryan 0:b74591d5ab33 29 */
be_bryan 0:b74591d5ab33 30 #include "mbed_assert.h"
be_bryan 0:b74591d5ab33 31 #include "mbed_error.h"
be_bryan 0:b74591d5ab33 32 #include "mbed_debug.h"
be_bryan 0:b74591d5ab33 33 #include "spi_api.h"
be_bryan 0:b74591d5ab33 34
be_bryan 0:b74591d5ab33 35 #if DEVICE_SPI
be_bryan 0:b74591d5ab33 36 #include <stdbool.h>
be_bryan 0:b74591d5ab33 37 #include <math.h>
be_bryan 0:b74591d5ab33 38 #include <string.h>
be_bryan 0:b74591d5ab33 39 #include "cmsis.h"
be_bryan 0:b74591d5ab33 40 #include "pinmap.h"
be_bryan 0:b74591d5ab33 41 #include "PeripheralPins.h"
be_bryan 0:b74591d5ab33 42 #include "spi_device.h"
be_bryan 0:b74591d5ab33 43
be_bryan 0:b74591d5ab33 44 #if DEVICE_SPI_ASYNCH
be_bryan 0:b74591d5ab33 45 #define SPI_INST(obj) ((SPI_TypeDef *)(obj->spi.spi))
be_bryan 0:b74591d5ab33 46 #else
be_bryan 0:b74591d5ab33 47 #define SPI_INST(obj) ((SPI_TypeDef *)(obj->spi))
be_bryan 0:b74591d5ab33 48 #endif
be_bryan 0:b74591d5ab33 49
be_bryan 0:b74591d5ab33 50 #if DEVICE_SPI_ASYNCH
be_bryan 0:b74591d5ab33 51 #define SPI_S(obj) (( struct spi_s *)(&(obj->spi)))
be_bryan 0:b74591d5ab33 52 #else
be_bryan 0:b74591d5ab33 53 #define SPI_S(obj) (( struct spi_s *)(obj))
be_bryan 0:b74591d5ab33 54 #endif
be_bryan 0:b74591d5ab33 55
be_bryan 0:b74591d5ab33 56 #ifndef DEBUG_STDIO
be_bryan 0:b74591d5ab33 57 # define DEBUG_STDIO 0
be_bryan 0:b74591d5ab33 58 #endif
be_bryan 0:b74591d5ab33 59
be_bryan 0:b74591d5ab33 60 #if DEBUG_STDIO
be_bryan 0:b74591d5ab33 61 # include <stdio.h>
be_bryan 0:b74591d5ab33 62 # define DEBUG_PRINTF(...) do { printf(__VA_ARGS__); } while(0)
be_bryan 0:b74591d5ab33 63 #else
be_bryan 0:b74591d5ab33 64 # define DEBUG_PRINTF(...) {}
be_bryan 0:b74591d5ab33 65 #endif
be_bryan 0:b74591d5ab33 66
be_bryan 0:b74591d5ab33 67 /* Consider 10ms as the default timeout for sending/receving 1 byte */
be_bryan 0:b74591d5ab33 68 #define TIMEOUT_1_BYTE 10
be_bryan 0:b74591d5ab33 69
be_bryan 0:b74591d5ab33 70 void init_spi(spi_t *obj)
be_bryan 0:b74591d5ab33 71 {
be_bryan 0:b74591d5ab33 72 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 73 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 74
be_bryan 0:b74591d5ab33 75 __HAL_SPI_DISABLE(handle);
be_bryan 0:b74591d5ab33 76
be_bryan 0:b74591d5ab33 77 DEBUG_PRINTF("init_spi: instance=0x%8X\r\n", (int)handle->Instance);
be_bryan 0:b74591d5ab33 78 if (HAL_SPI_Init(handle) != HAL_OK) {
be_bryan 0:b74591d5ab33 79 error("Cannot initialize SPI");
be_bryan 0:b74591d5ab33 80 }
be_bryan 0:b74591d5ab33 81
be_bryan 0:b74591d5ab33 82 /* In case of standard 4 wires SPI,PI can be kept enabled all time
be_bryan 0:b74591d5ab33 83 * and SCK will only be generated during the write operations. But in case
be_bryan 0:b74591d5ab33 84 * of 3 wires, it should be only enabled during rd/wr unitary operations,
be_bryan 0:b74591d5ab33 85 * which is handled inside STM32 HAL layer.
be_bryan 0:b74591d5ab33 86 */
be_bryan 0:b74591d5ab33 87 if (handle->Init.Direction == SPI_DIRECTION_2LINES) {
be_bryan 0:b74591d5ab33 88 __HAL_SPI_ENABLE(handle);
be_bryan 0:b74591d5ab33 89 }
be_bryan 0:b74591d5ab33 90 }
be_bryan 0:b74591d5ab33 91
be_bryan 0:b74591d5ab33 92 void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel)
be_bryan 0:b74591d5ab33 93 {
be_bryan 0:b74591d5ab33 94 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 95 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 96
be_bryan 0:b74591d5ab33 97 // Determine the SPI to use
be_bryan 0:b74591d5ab33 98 SPIName spi_mosi = (SPIName)pinmap_peripheral(mosi, PinMap_SPI_MOSI);
be_bryan 0:b74591d5ab33 99 SPIName spi_miso = (SPIName)pinmap_peripheral(miso, PinMap_SPI_MISO);
be_bryan 0:b74591d5ab33 100 SPIName spi_sclk = (SPIName)pinmap_peripheral(sclk, PinMap_SPI_SCLK);
be_bryan 0:b74591d5ab33 101 SPIName spi_ssel = (SPIName)pinmap_peripheral(ssel, PinMap_SPI_SSEL);
be_bryan 0:b74591d5ab33 102
be_bryan 0:b74591d5ab33 103 SPIName spi_data = (SPIName)pinmap_merge(spi_mosi, spi_miso);
be_bryan 0:b74591d5ab33 104 SPIName spi_cntl = (SPIName)pinmap_merge(spi_sclk, spi_ssel);
be_bryan 0:b74591d5ab33 105
be_bryan 0:b74591d5ab33 106 spiobj->spi = (SPIName)pinmap_merge(spi_data, spi_cntl);
be_bryan 0:b74591d5ab33 107 MBED_ASSERT(spiobj->spi != (SPIName)NC);
be_bryan 0:b74591d5ab33 108
be_bryan 0:b74591d5ab33 109 #if defined SPI1_BASE
be_bryan 0:b74591d5ab33 110 // Enable SPI clock
be_bryan 0:b74591d5ab33 111 if (spiobj->spi == SPI_1) {
be_bryan 0:b74591d5ab33 112 __HAL_RCC_SPI1_CLK_ENABLE();
be_bryan 0:b74591d5ab33 113 spiobj->spiIRQ = SPI1_IRQn;
be_bryan 0:b74591d5ab33 114 }
be_bryan 0:b74591d5ab33 115 #endif
be_bryan 0:b74591d5ab33 116
be_bryan 0:b74591d5ab33 117 #if defined SPI2_BASE
be_bryan 0:b74591d5ab33 118 if (spiobj->spi == SPI_2) {
be_bryan 0:b74591d5ab33 119 __HAL_RCC_SPI2_CLK_ENABLE();
be_bryan 0:b74591d5ab33 120 spiobj->spiIRQ = SPI2_IRQn;
be_bryan 0:b74591d5ab33 121 }
be_bryan 0:b74591d5ab33 122 #endif
be_bryan 0:b74591d5ab33 123
be_bryan 0:b74591d5ab33 124 #if defined SPI3_BASE
be_bryan 0:b74591d5ab33 125 if (spiobj->spi == SPI_3) {
be_bryan 0:b74591d5ab33 126 __HAL_RCC_SPI3_CLK_ENABLE();
be_bryan 0:b74591d5ab33 127 spiobj->spiIRQ = SPI3_IRQn;
be_bryan 0:b74591d5ab33 128 }
be_bryan 0:b74591d5ab33 129 #endif
be_bryan 0:b74591d5ab33 130
be_bryan 0:b74591d5ab33 131 #if defined SPI4_BASE
be_bryan 0:b74591d5ab33 132 if (spiobj->spi == SPI_4) {
be_bryan 0:b74591d5ab33 133 __HAL_RCC_SPI4_CLK_ENABLE();
be_bryan 0:b74591d5ab33 134 spiobj->spiIRQ = SPI4_IRQn;
be_bryan 0:b74591d5ab33 135 }
be_bryan 0:b74591d5ab33 136 #endif
be_bryan 0:b74591d5ab33 137
be_bryan 0:b74591d5ab33 138 #if defined SPI5_BASE
be_bryan 0:b74591d5ab33 139 if (spiobj->spi == SPI_5) {
be_bryan 0:b74591d5ab33 140 __HAL_RCC_SPI5_CLK_ENABLE();
be_bryan 0:b74591d5ab33 141 spiobj->spiIRQ = SPI5_IRQn;
be_bryan 0:b74591d5ab33 142 }
be_bryan 0:b74591d5ab33 143 #endif
be_bryan 0:b74591d5ab33 144
be_bryan 0:b74591d5ab33 145 #if defined SPI6_BASE
be_bryan 0:b74591d5ab33 146 if (spiobj->spi == SPI_6) {
be_bryan 0:b74591d5ab33 147 __HAL_RCC_SPI6_CLK_ENABLE();
be_bryan 0:b74591d5ab33 148 spiobj->spiIRQ = SPI6_IRQn;
be_bryan 0:b74591d5ab33 149 }
be_bryan 0:b74591d5ab33 150 #endif
be_bryan 0:b74591d5ab33 151
be_bryan 0:b74591d5ab33 152 // Configure the SPI pins
be_bryan 0:b74591d5ab33 153 pinmap_pinout(mosi, PinMap_SPI_MOSI);
be_bryan 0:b74591d5ab33 154 pinmap_pinout(miso, PinMap_SPI_MISO);
be_bryan 0:b74591d5ab33 155 pinmap_pinout(sclk, PinMap_SPI_SCLK);
be_bryan 0:b74591d5ab33 156 spiobj->pin_miso = miso;
be_bryan 0:b74591d5ab33 157 spiobj->pin_mosi = mosi;
be_bryan 0:b74591d5ab33 158 spiobj->pin_sclk = sclk;
be_bryan 0:b74591d5ab33 159 spiobj->pin_ssel = ssel;
be_bryan 0:b74591d5ab33 160 if (ssel != NC) {
be_bryan 0:b74591d5ab33 161 pinmap_pinout(ssel, PinMap_SPI_SSEL);
be_bryan 0:b74591d5ab33 162 } else {
be_bryan 0:b74591d5ab33 163 handle->Init.NSS = SPI_NSS_SOFT;
be_bryan 0:b74591d5ab33 164 }
be_bryan 0:b74591d5ab33 165
be_bryan 0:b74591d5ab33 166 /* Fill default value */
be_bryan 0:b74591d5ab33 167 handle->Instance = SPI_INST(obj);
be_bryan 0:b74591d5ab33 168 handle->Init.Mode = SPI_MODE_MASTER;
be_bryan 0:b74591d5ab33 169 handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
be_bryan 0:b74591d5ab33 170
be_bryan 0:b74591d5ab33 171 if (miso != NC) {
be_bryan 0:b74591d5ab33 172 handle->Init.Direction = SPI_DIRECTION_2LINES;
be_bryan 0:b74591d5ab33 173 } else {
be_bryan 0:b74591d5ab33 174 handle->Init.Direction = SPI_DIRECTION_1LINE;
be_bryan 0:b74591d5ab33 175 }
be_bryan 0:b74591d5ab33 176
be_bryan 0:b74591d5ab33 177 handle->Init.CLKPhase = SPI_PHASE_1EDGE;
be_bryan 0:b74591d5ab33 178 handle->Init.CLKPolarity = SPI_POLARITY_LOW;
be_bryan 0:b74591d5ab33 179 handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
be_bryan 0:b74591d5ab33 180 handle->Init.CRCPolynomial = 7;
be_bryan 0:b74591d5ab33 181 handle->Init.DataSize = SPI_DATASIZE_8BIT;
be_bryan 0:b74591d5ab33 182 handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
be_bryan 0:b74591d5ab33 183 handle->Init.TIMode = SPI_TIMODE_DISABLE;
be_bryan 0:b74591d5ab33 184
be_bryan 0:b74591d5ab33 185 init_spi(obj);
be_bryan 0:b74591d5ab33 186 }
be_bryan 0:b74591d5ab33 187
be_bryan 0:b74591d5ab33 188 void spi_free(spi_t *obj)
be_bryan 0:b74591d5ab33 189 {
be_bryan 0:b74591d5ab33 190 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 191 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 192
be_bryan 0:b74591d5ab33 193 DEBUG_PRINTF("spi_free\r\n");
be_bryan 0:b74591d5ab33 194
be_bryan 0:b74591d5ab33 195 __HAL_SPI_DISABLE(handle);
be_bryan 0:b74591d5ab33 196 HAL_SPI_DeInit(handle);
be_bryan 0:b74591d5ab33 197
be_bryan 0:b74591d5ab33 198 #if defined SPI1_BASE
be_bryan 0:b74591d5ab33 199 // Reset SPI and disable clock
be_bryan 0:b74591d5ab33 200 if (spiobj->spi == SPI_1) {
be_bryan 0:b74591d5ab33 201 __HAL_RCC_SPI1_FORCE_RESET();
be_bryan 0:b74591d5ab33 202 __HAL_RCC_SPI1_RELEASE_RESET();
be_bryan 0:b74591d5ab33 203 __HAL_RCC_SPI1_CLK_DISABLE();
be_bryan 0:b74591d5ab33 204 }
be_bryan 0:b74591d5ab33 205 #endif
be_bryan 0:b74591d5ab33 206 #if defined SPI2_BASE
be_bryan 0:b74591d5ab33 207 if (spiobj->spi == SPI_2) {
be_bryan 0:b74591d5ab33 208 __HAL_RCC_SPI2_FORCE_RESET();
be_bryan 0:b74591d5ab33 209 __HAL_RCC_SPI2_RELEASE_RESET();
be_bryan 0:b74591d5ab33 210 __HAL_RCC_SPI2_CLK_DISABLE();
be_bryan 0:b74591d5ab33 211 }
be_bryan 0:b74591d5ab33 212 #endif
be_bryan 0:b74591d5ab33 213
be_bryan 0:b74591d5ab33 214 #if defined SPI3_BASE
be_bryan 0:b74591d5ab33 215 if (spiobj->spi == SPI_3) {
be_bryan 0:b74591d5ab33 216 __HAL_RCC_SPI3_FORCE_RESET();
be_bryan 0:b74591d5ab33 217 __HAL_RCC_SPI3_RELEASE_RESET();
be_bryan 0:b74591d5ab33 218 __HAL_RCC_SPI3_CLK_DISABLE();
be_bryan 0:b74591d5ab33 219 }
be_bryan 0:b74591d5ab33 220 #endif
be_bryan 0:b74591d5ab33 221
be_bryan 0:b74591d5ab33 222 #if defined SPI4_BASE
be_bryan 0:b74591d5ab33 223 if (spiobj->spi == SPI_4) {
be_bryan 0:b74591d5ab33 224 __HAL_RCC_SPI4_FORCE_RESET();
be_bryan 0:b74591d5ab33 225 __HAL_RCC_SPI4_RELEASE_RESET();
be_bryan 0:b74591d5ab33 226 __HAL_RCC_SPI4_CLK_DISABLE();
be_bryan 0:b74591d5ab33 227 }
be_bryan 0:b74591d5ab33 228 #endif
be_bryan 0:b74591d5ab33 229
be_bryan 0:b74591d5ab33 230 #if defined SPI5_BASE
be_bryan 0:b74591d5ab33 231 if (spiobj->spi == SPI_5) {
be_bryan 0:b74591d5ab33 232 __HAL_RCC_SPI5_FORCE_RESET();
be_bryan 0:b74591d5ab33 233 __HAL_RCC_SPI5_RELEASE_RESET();
be_bryan 0:b74591d5ab33 234 __HAL_RCC_SPI5_CLK_DISABLE();
be_bryan 0:b74591d5ab33 235 }
be_bryan 0:b74591d5ab33 236 #endif
be_bryan 0:b74591d5ab33 237
be_bryan 0:b74591d5ab33 238 #if defined SPI6_BASE
be_bryan 0:b74591d5ab33 239 if (spiobj->spi == SPI_6) {
be_bryan 0:b74591d5ab33 240 __HAL_RCC_SPI6_FORCE_RESET();
be_bryan 0:b74591d5ab33 241 __HAL_RCC_SPI6_RELEASE_RESET();
be_bryan 0:b74591d5ab33 242 __HAL_RCC_SPI6_CLK_DISABLE();
be_bryan 0:b74591d5ab33 243 }
be_bryan 0:b74591d5ab33 244 #endif
be_bryan 0:b74591d5ab33 245
be_bryan 0:b74591d5ab33 246 // Configure GPIOs
be_bryan 0:b74591d5ab33 247 pin_function(spiobj->pin_miso, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
be_bryan 0:b74591d5ab33 248 pin_function(spiobj->pin_mosi, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
be_bryan 0:b74591d5ab33 249 pin_function(spiobj->pin_sclk, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
be_bryan 0:b74591d5ab33 250 if (handle->Init.NSS != SPI_NSS_SOFT) {
be_bryan 0:b74591d5ab33 251 pin_function(spiobj->pin_ssel, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0));
be_bryan 0:b74591d5ab33 252 }
be_bryan 0:b74591d5ab33 253 }
be_bryan 0:b74591d5ab33 254
be_bryan 0:b74591d5ab33 255 void spi_format(spi_t *obj, int bits, int mode, int slave)
be_bryan 0:b74591d5ab33 256 {
be_bryan 0:b74591d5ab33 257 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 258 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 259
be_bryan 0:b74591d5ab33 260 DEBUG_PRINTF("spi_format, bits:%d, mode:%d, slave?:%d\r\n", bits, mode, slave);
be_bryan 0:b74591d5ab33 261
be_bryan 0:b74591d5ab33 262 // Save new values
be_bryan 0:b74591d5ab33 263 handle->Init.DataSize = (bits == 16) ? SPI_DATASIZE_16BIT : SPI_DATASIZE_8BIT;
be_bryan 0:b74591d5ab33 264
be_bryan 0:b74591d5ab33 265 switch (mode) {
be_bryan 0:b74591d5ab33 266 case 0:
be_bryan 0:b74591d5ab33 267 handle->Init.CLKPolarity = SPI_POLARITY_LOW;
be_bryan 0:b74591d5ab33 268 handle->Init.CLKPhase = SPI_PHASE_1EDGE;
be_bryan 0:b74591d5ab33 269 break;
be_bryan 0:b74591d5ab33 270 case 1:
be_bryan 0:b74591d5ab33 271 handle->Init.CLKPolarity = SPI_POLARITY_LOW;
be_bryan 0:b74591d5ab33 272 handle->Init.CLKPhase = SPI_PHASE_2EDGE;
be_bryan 0:b74591d5ab33 273 break;
be_bryan 0:b74591d5ab33 274 case 2:
be_bryan 0:b74591d5ab33 275 handle->Init.CLKPolarity = SPI_POLARITY_HIGH;
be_bryan 0:b74591d5ab33 276 handle->Init.CLKPhase = SPI_PHASE_1EDGE;
be_bryan 0:b74591d5ab33 277 break;
be_bryan 0:b74591d5ab33 278 default:
be_bryan 0:b74591d5ab33 279 handle->Init.CLKPolarity = SPI_POLARITY_HIGH;
be_bryan 0:b74591d5ab33 280 handle->Init.CLKPhase = SPI_PHASE_2EDGE;
be_bryan 0:b74591d5ab33 281 break;
be_bryan 0:b74591d5ab33 282 }
be_bryan 0:b74591d5ab33 283
be_bryan 0:b74591d5ab33 284 if (handle->Init.NSS != SPI_NSS_SOFT) {
be_bryan 0:b74591d5ab33 285 handle->Init.NSS = (slave) ? SPI_NSS_HARD_INPUT : SPI_NSS_HARD_OUTPUT;
be_bryan 0:b74591d5ab33 286 }
be_bryan 0:b74591d5ab33 287
be_bryan 0:b74591d5ab33 288 handle->Init.Mode = (slave) ? SPI_MODE_SLAVE : SPI_MODE_MASTER;
be_bryan 0:b74591d5ab33 289
be_bryan 0:b74591d5ab33 290 if (slave && (handle->Init.Direction == SPI_DIRECTION_1LINE)) {
be_bryan 0:b74591d5ab33 291 /* SPI slave implemtation in MBED does not support the 3 wires SPI.
be_bryan 0:b74591d5ab33 292 * (e.g. when MISO is not connected). So we're forcing slave in
be_bryan 0:b74591d5ab33 293 * 2LINES mode. As MISO is not connected, slave will only read
be_bryan 0:b74591d5ab33 294 * from master, and cannot write to it. Inform user.
be_bryan 0:b74591d5ab33 295 */
be_bryan 0:b74591d5ab33 296 debug("3 wires SPI slave not supported - slave will only read\r\n");
be_bryan 0:b74591d5ab33 297 handle->Init.Direction = SPI_DIRECTION_2LINES;
be_bryan 0:b74591d5ab33 298 }
be_bryan 0:b74591d5ab33 299
be_bryan 0:b74591d5ab33 300 init_spi(obj);
be_bryan 0:b74591d5ab33 301 }
be_bryan 0:b74591d5ab33 302
be_bryan 0:b74591d5ab33 303 /*
be_bryan 0:b74591d5ab33 304 * Only the IP clock input is family dependant so it computed
be_bryan 0:b74591d5ab33 305 * separately in spi_get_clock_freq
be_bryan 0:b74591d5ab33 306 */
be_bryan 0:b74591d5ab33 307 extern int spi_get_clock_freq(spi_t *obj);
be_bryan 0:b74591d5ab33 308
be_bryan 0:b74591d5ab33 309 static const uint16_t baudrate_prescaler_table[] = {SPI_BAUDRATEPRESCALER_2,
be_bryan 0:b74591d5ab33 310 SPI_BAUDRATEPRESCALER_4,
be_bryan 0:b74591d5ab33 311 SPI_BAUDRATEPRESCALER_8,
be_bryan 0:b74591d5ab33 312 SPI_BAUDRATEPRESCALER_16,
be_bryan 0:b74591d5ab33 313 SPI_BAUDRATEPRESCALER_32,
be_bryan 0:b74591d5ab33 314 SPI_BAUDRATEPRESCALER_64,
be_bryan 0:b74591d5ab33 315 SPI_BAUDRATEPRESCALER_128,
be_bryan 0:b74591d5ab33 316 SPI_BAUDRATEPRESCALER_256};
be_bryan 0:b74591d5ab33 317
be_bryan 0:b74591d5ab33 318 void spi_frequency(spi_t *obj, int hz) {
be_bryan 0:b74591d5ab33 319 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 320 int spi_hz = 0;
be_bryan 0:b74591d5ab33 321 uint8_t prescaler_rank = 0;
be_bryan 0:b74591d5ab33 322 uint8_t last_index = (sizeof(baudrate_prescaler_table)/sizeof(baudrate_prescaler_table[0])) - 1;
be_bryan 0:b74591d5ab33 323 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 324
be_bryan 0:b74591d5ab33 325 /* Calculate the spi clock for prescaler_rank 0: SPI_BAUDRATEPRESCALER_2 */
be_bryan 0:b74591d5ab33 326 spi_hz = spi_get_clock_freq(obj) / 2;
be_bryan 0:b74591d5ab33 327
be_bryan 0:b74591d5ab33 328 /* Define pre-scaler in order to get highest available frequency below requested frequency */
be_bryan 0:b74591d5ab33 329 while ((spi_hz > hz) && (prescaler_rank < last_index)) {
be_bryan 0:b74591d5ab33 330 spi_hz = spi_hz / 2;
be_bryan 0:b74591d5ab33 331 prescaler_rank++;
be_bryan 0:b74591d5ab33 332 }
be_bryan 0:b74591d5ab33 333
be_bryan 0:b74591d5ab33 334 /* Use the best fit pre-scaler */
be_bryan 0:b74591d5ab33 335 handle->Init.BaudRatePrescaler = baudrate_prescaler_table[prescaler_rank];
be_bryan 0:b74591d5ab33 336
be_bryan 0:b74591d5ab33 337 /* In case maximum pre-scaler still gives too high freq, raise an error */
be_bryan 0:b74591d5ab33 338 if (spi_hz > hz) {
be_bryan 0:b74591d5ab33 339 DEBUG_PRINTF("WARNING: lowest SPI freq (%d) higher than requested (%d)\r\n", spi_hz, hz);
be_bryan 0:b74591d5ab33 340 }
be_bryan 0:b74591d5ab33 341
be_bryan 0:b74591d5ab33 342 DEBUG_PRINTF("spi_frequency, request:%d, select:%d\r\n", hz, spi_hz);
be_bryan 0:b74591d5ab33 343
be_bryan 0:b74591d5ab33 344 init_spi(obj);
be_bryan 0:b74591d5ab33 345 }
be_bryan 0:b74591d5ab33 346
be_bryan 0:b74591d5ab33 347 static inline int ssp_readable(spi_t *obj)
be_bryan 0:b74591d5ab33 348 {
be_bryan 0:b74591d5ab33 349 int status;
be_bryan 0:b74591d5ab33 350 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 351 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 352
be_bryan 0:b74591d5ab33 353 // Check if data is received
be_bryan 0:b74591d5ab33 354 status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_RXNE) != RESET) ? 1 : 0);
be_bryan 0:b74591d5ab33 355 return status;
be_bryan 0:b74591d5ab33 356 }
be_bryan 0:b74591d5ab33 357
be_bryan 0:b74591d5ab33 358 static inline int ssp_writeable(spi_t *obj)
be_bryan 0:b74591d5ab33 359 {
be_bryan 0:b74591d5ab33 360 int status;
be_bryan 0:b74591d5ab33 361 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 362 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 363
be_bryan 0:b74591d5ab33 364 // Check if data is transmitted
be_bryan 0:b74591d5ab33 365 status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_TXE) != RESET) ? 1 : 0);
be_bryan 0:b74591d5ab33 366 return status;
be_bryan 0:b74591d5ab33 367 }
be_bryan 0:b74591d5ab33 368
be_bryan 0:b74591d5ab33 369 static inline int ssp_busy(spi_t *obj)
be_bryan 0:b74591d5ab33 370 {
be_bryan 0:b74591d5ab33 371 int status;
be_bryan 0:b74591d5ab33 372 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 373 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 374 status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_BSY) != RESET) ? 1 : 0);
be_bryan 0:b74591d5ab33 375 return status;
be_bryan 0:b74591d5ab33 376 }
be_bryan 0:b74591d5ab33 377
be_bryan 0:b74591d5ab33 378 int spi_master_write(spi_t *obj, int value)
be_bryan 0:b74591d5ab33 379 {
be_bryan 0:b74591d5ab33 380 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 381 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 382
be_bryan 0:b74591d5ab33 383 if (handle->Init.Direction == SPI_DIRECTION_1LINE) {
be_bryan 0:b74591d5ab33 384 return HAL_SPI_Transmit(handle, (uint8_t*)&value, 1, TIMEOUT_1_BYTE);
be_bryan 0:b74591d5ab33 385 }
be_bryan 0:b74591d5ab33 386
be_bryan 0:b74591d5ab33 387 #if defined(LL_SPI_RX_FIFO_TH_HALF)
be_bryan 0:b74591d5ab33 388 /* Configure the default data size */
be_bryan 0:b74591d5ab33 389 if (handle->Init.DataSize == SPI_DATASIZE_16BIT) {
be_bryan 0:b74591d5ab33 390 LL_SPI_SetRxFIFOThreshold(SPI_INST(obj), LL_SPI_RX_FIFO_TH_HALF);
be_bryan 0:b74591d5ab33 391 } else {
be_bryan 0:b74591d5ab33 392 LL_SPI_SetRxFIFOThreshold(SPI_INST(obj), LL_SPI_RX_FIFO_TH_QUARTER);
be_bryan 0:b74591d5ab33 393 }
be_bryan 0:b74591d5ab33 394 #endif
be_bryan 0:b74591d5ab33 395
be_bryan 0:b74591d5ab33 396 /* Here we're using LL which means direct registers access
be_bryan 0:b74591d5ab33 397 * There is no error management, so we may end up looping
be_bryan 0:b74591d5ab33 398 * infinitely here in case of faulty device for insatnce,
be_bryan 0:b74591d5ab33 399 * but this will increase performances significantly
be_bryan 0:b74591d5ab33 400 */
be_bryan 0:b74591d5ab33 401
be_bryan 0:b74591d5ab33 402 /* Wait TXE flag to transmit data */
be_bryan 0:b74591d5ab33 403 while (!LL_SPI_IsActiveFlag_TXE(SPI_INST(obj)));
be_bryan 0:b74591d5ab33 404
be_bryan 0:b74591d5ab33 405 if (handle->Init.DataSize == SPI_DATASIZE_16BIT) {
be_bryan 0:b74591d5ab33 406 LL_SPI_TransmitData16(SPI_INST(obj), value);
be_bryan 0:b74591d5ab33 407 } else {
be_bryan 0:b74591d5ab33 408 LL_SPI_TransmitData8(SPI_INST(obj), (uint8_t) value);
be_bryan 0:b74591d5ab33 409 }
be_bryan 0:b74591d5ab33 410
be_bryan 0:b74591d5ab33 411 /* Then wait RXE flag before reading */
be_bryan 0:b74591d5ab33 412 while (!LL_SPI_IsActiveFlag_RXNE(SPI_INST(obj)));
be_bryan 0:b74591d5ab33 413
be_bryan 0:b74591d5ab33 414 if (handle->Init.DataSize == SPI_DATASIZE_16BIT) {
be_bryan 0:b74591d5ab33 415 return LL_SPI_ReceiveData16(SPI_INST(obj));
be_bryan 0:b74591d5ab33 416 } else {
be_bryan 0:b74591d5ab33 417 return LL_SPI_ReceiveData8(SPI_INST(obj));
be_bryan 0:b74591d5ab33 418 }
be_bryan 0:b74591d5ab33 419 }
be_bryan 0:b74591d5ab33 420
be_bryan 0:b74591d5ab33 421 int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
be_bryan 0:b74591d5ab33 422 char *rx_buffer, int rx_length, char write_fill)
be_bryan 0:b74591d5ab33 423 {
be_bryan 0:b74591d5ab33 424 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 425 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 426 int total = (tx_length > rx_length) ? tx_length : rx_length;
be_bryan 0:b74591d5ab33 427 int i = 0;
be_bryan 0:b74591d5ab33 428 if (handle->Init.Direction == SPI_DIRECTION_2LINES) {
be_bryan 0:b74591d5ab33 429 for (i = 0; i < total; i++) {
be_bryan 0:b74591d5ab33 430 char out = (i < tx_length) ? tx_buffer[i] : write_fill;
be_bryan 0:b74591d5ab33 431 char in = spi_master_write(obj, out);
be_bryan 0:b74591d5ab33 432 if (i < rx_length) {
be_bryan 0:b74591d5ab33 433 rx_buffer[i] = in;
be_bryan 0:b74591d5ab33 434 }
be_bryan 0:b74591d5ab33 435 }
be_bryan 0:b74591d5ab33 436 } else {
be_bryan 0:b74591d5ab33 437 /* In case of 1 WIRE only, first handle TX, then Rx */
be_bryan 0:b74591d5ab33 438 if (tx_length != 0) {
be_bryan 0:b74591d5ab33 439 if (HAL_OK != HAL_SPI_Transmit(handle, (uint8_t*)tx_buffer, tx_length, tx_length*TIMEOUT_1_BYTE)) {
be_bryan 0:b74591d5ab33 440 /* report an error */
be_bryan 0:b74591d5ab33 441 total = 0;
be_bryan 0:b74591d5ab33 442 }
be_bryan 0:b74591d5ab33 443 }
be_bryan 0:b74591d5ab33 444 if (rx_length != 0) {
be_bryan 0:b74591d5ab33 445 if (HAL_OK != HAL_SPI_Receive(handle, (uint8_t*)rx_buffer, rx_length, rx_length*TIMEOUT_1_BYTE)) {
be_bryan 0:b74591d5ab33 446 /* report an error */
be_bryan 0:b74591d5ab33 447 total = 0;
be_bryan 0:b74591d5ab33 448 }
be_bryan 0:b74591d5ab33 449 }
be_bryan 0:b74591d5ab33 450 }
be_bryan 0:b74591d5ab33 451
be_bryan 0:b74591d5ab33 452 return total;
be_bryan 0:b74591d5ab33 453 }
be_bryan 0:b74591d5ab33 454
be_bryan 0:b74591d5ab33 455 int spi_slave_receive(spi_t *obj)
be_bryan 0:b74591d5ab33 456 {
be_bryan 0:b74591d5ab33 457 return ((ssp_readable(obj) && !ssp_busy(obj)) ? 1 : 0);
be_bryan 0:b74591d5ab33 458 };
be_bryan 0:b74591d5ab33 459
be_bryan 0:b74591d5ab33 460 int spi_slave_read(spi_t *obj)
be_bryan 0:b74591d5ab33 461 {
be_bryan 0:b74591d5ab33 462 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 463 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 464 while (!ssp_readable(obj));
be_bryan 0:b74591d5ab33 465 if (handle->Init.DataSize == SPI_DATASIZE_16BIT) {
be_bryan 0:b74591d5ab33 466 return LL_SPI_ReceiveData16(SPI_INST(obj));
be_bryan 0:b74591d5ab33 467 } else {
be_bryan 0:b74591d5ab33 468 return LL_SPI_ReceiveData8(SPI_INST(obj));
be_bryan 0:b74591d5ab33 469 }
be_bryan 0:b74591d5ab33 470 }
be_bryan 0:b74591d5ab33 471
be_bryan 0:b74591d5ab33 472 void spi_slave_write(spi_t *obj, int value)
be_bryan 0:b74591d5ab33 473 {
be_bryan 0:b74591d5ab33 474 SPI_TypeDef *spi = SPI_INST(obj);
be_bryan 0:b74591d5ab33 475 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 476 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 477 while (!ssp_writeable(obj));
be_bryan 0:b74591d5ab33 478 if (handle->Init.DataSize == SPI_DATASIZE_8BIT) {
be_bryan 0:b74591d5ab33 479 // Force 8-bit access to the data register
be_bryan 0:b74591d5ab33 480 uint8_t *p_spi_dr = 0;
be_bryan 0:b74591d5ab33 481 p_spi_dr = (uint8_t *) & (spi->DR);
be_bryan 0:b74591d5ab33 482 *p_spi_dr = (uint8_t)value;
be_bryan 0:b74591d5ab33 483 } else { // SPI_DATASIZE_16BIT
be_bryan 0:b74591d5ab33 484 spi->DR = (uint16_t)value;
be_bryan 0:b74591d5ab33 485 }
be_bryan 0:b74591d5ab33 486 }
be_bryan 0:b74591d5ab33 487
be_bryan 0:b74591d5ab33 488 int spi_busy(spi_t *obj)
be_bryan 0:b74591d5ab33 489 {
be_bryan 0:b74591d5ab33 490 return ssp_busy(obj);
be_bryan 0:b74591d5ab33 491 }
be_bryan 0:b74591d5ab33 492
be_bryan 0:b74591d5ab33 493 #ifdef DEVICE_SPI_ASYNCH
be_bryan 0:b74591d5ab33 494 typedef enum {
be_bryan 0:b74591d5ab33 495 SPI_TRANSFER_TYPE_NONE = 0,
be_bryan 0:b74591d5ab33 496 SPI_TRANSFER_TYPE_TX = 1,
be_bryan 0:b74591d5ab33 497 SPI_TRANSFER_TYPE_RX = 2,
be_bryan 0:b74591d5ab33 498 SPI_TRANSFER_TYPE_TXRX = 3,
be_bryan 0:b74591d5ab33 499 } transfer_type_t;
be_bryan 0:b74591d5ab33 500
be_bryan 0:b74591d5ab33 501
be_bryan 0:b74591d5ab33 502 /// @returns the number of bytes transferred, or `0` if nothing transferred
be_bryan 0:b74591d5ab33 503 static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer_type, const void *tx, void *rx, size_t length)
be_bryan 0:b74591d5ab33 504 {
be_bryan 0:b74591d5ab33 505 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 506 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 507 bool is16bit = (handle->Init.DataSize == SPI_DATASIZE_16BIT);
be_bryan 0:b74591d5ab33 508 // the HAL expects number of transfers instead of number of bytes
be_bryan 0:b74591d5ab33 509 // so for 16 bit transfer width the count needs to be halved
be_bryan 0:b74591d5ab33 510 size_t words;
be_bryan 0:b74591d5ab33 511
be_bryan 0:b74591d5ab33 512 DEBUG_PRINTF("SPI inst=0x%8X Start: %u, %u\r\n", (int)handle->Instance, transfer_type, length);
be_bryan 0:b74591d5ab33 513
be_bryan 0:b74591d5ab33 514 obj->spi.transfer_type = transfer_type;
be_bryan 0:b74591d5ab33 515
be_bryan 0:b74591d5ab33 516 if (is16bit) {
be_bryan 0:b74591d5ab33 517 words = length / 2;
be_bryan 0:b74591d5ab33 518 } else {
be_bryan 0:b74591d5ab33 519 words = length;
be_bryan 0:b74591d5ab33 520 }
be_bryan 0:b74591d5ab33 521
be_bryan 0:b74591d5ab33 522 // enable the interrupt
be_bryan 0:b74591d5ab33 523 IRQn_Type irq_n = spiobj->spiIRQ;
be_bryan 0:b74591d5ab33 524 NVIC_DisableIRQ(irq_n);
be_bryan 0:b74591d5ab33 525 NVIC_ClearPendingIRQ(irq_n);
be_bryan 0:b74591d5ab33 526 NVIC_SetPriority(irq_n, 1);
be_bryan 0:b74591d5ab33 527 NVIC_EnableIRQ(irq_n);
be_bryan 0:b74591d5ab33 528
be_bryan 0:b74591d5ab33 529 // enable the right hal transfer
be_bryan 0:b74591d5ab33 530 int rc = 0;
be_bryan 0:b74591d5ab33 531 switch(transfer_type) {
be_bryan 0:b74591d5ab33 532 case SPI_TRANSFER_TYPE_TXRX:
be_bryan 0:b74591d5ab33 533 rc = HAL_SPI_TransmitReceive_IT(handle, (uint8_t*)tx, (uint8_t*)rx, words);
be_bryan 0:b74591d5ab33 534 break;
be_bryan 0:b74591d5ab33 535 case SPI_TRANSFER_TYPE_TX:
be_bryan 0:b74591d5ab33 536 rc = HAL_SPI_Transmit_IT(handle, (uint8_t*)tx, words);
be_bryan 0:b74591d5ab33 537 break;
be_bryan 0:b74591d5ab33 538 case SPI_TRANSFER_TYPE_RX:
be_bryan 0:b74591d5ab33 539 // the receive function also "transmits" the receive buffer so in order
be_bryan 0:b74591d5ab33 540 // to guarantee that 0xff is on the line, we explicitly memset it here
be_bryan 0:b74591d5ab33 541 memset(rx, SPI_FILL_WORD, length);
be_bryan 0:b74591d5ab33 542 rc = HAL_SPI_Receive_IT(handle, (uint8_t*)rx, words);
be_bryan 0:b74591d5ab33 543 break;
be_bryan 0:b74591d5ab33 544 default:
be_bryan 0:b74591d5ab33 545 length = 0;
be_bryan 0:b74591d5ab33 546 }
be_bryan 0:b74591d5ab33 547
be_bryan 0:b74591d5ab33 548 if (rc) {
be_bryan 0:b74591d5ab33 549 DEBUG_PRINTF("SPI: RC=%u\n", rc);
be_bryan 0:b74591d5ab33 550 length = 0;
be_bryan 0:b74591d5ab33 551 }
be_bryan 0:b74591d5ab33 552
be_bryan 0:b74591d5ab33 553 return length;
be_bryan 0:b74591d5ab33 554 }
be_bryan 0:b74591d5ab33 555
be_bryan 0:b74591d5ab33 556 // asynchronous API
be_bryan 0:b74591d5ab33 557 void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint8_t bit_width, uint32_t handler, uint32_t event, DMAUsage hint)
be_bryan 0:b74591d5ab33 558 {
be_bryan 0:b74591d5ab33 559 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 560 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 561
be_bryan 0:b74591d5ab33 562 // TODO: DMA usage is currently ignored
be_bryan 0:b74591d5ab33 563 (void) hint;
be_bryan 0:b74591d5ab33 564
be_bryan 0:b74591d5ab33 565 // check which use-case we have
be_bryan 0:b74591d5ab33 566 bool use_tx = (tx != NULL && tx_length > 0);
be_bryan 0:b74591d5ab33 567 bool use_rx = (rx != NULL && rx_length > 0);
be_bryan 0:b74591d5ab33 568 bool is16bit = (handle->Init.DataSize == SPI_DATASIZE_16BIT);
be_bryan 0:b74591d5ab33 569
be_bryan 0:b74591d5ab33 570 // don't do anything, if the buffers aren't valid
be_bryan 0:b74591d5ab33 571 if (!use_tx && !use_rx)
be_bryan 0:b74591d5ab33 572 return;
be_bryan 0:b74591d5ab33 573
be_bryan 0:b74591d5ab33 574 // copy the buffers to the SPI object
be_bryan 0:b74591d5ab33 575 obj->tx_buff.buffer = (void *) tx;
be_bryan 0:b74591d5ab33 576 obj->tx_buff.length = tx_length;
be_bryan 0:b74591d5ab33 577 obj->tx_buff.pos = 0;
be_bryan 0:b74591d5ab33 578 obj->tx_buff.width = is16bit ? 16 : 8;
be_bryan 0:b74591d5ab33 579
be_bryan 0:b74591d5ab33 580 obj->rx_buff.buffer = rx;
be_bryan 0:b74591d5ab33 581 obj->rx_buff.length = rx_length;
be_bryan 0:b74591d5ab33 582 obj->rx_buff.pos = 0;
be_bryan 0:b74591d5ab33 583 obj->rx_buff.width = obj->tx_buff.width;
be_bryan 0:b74591d5ab33 584
be_bryan 0:b74591d5ab33 585 obj->spi.event = event;
be_bryan 0:b74591d5ab33 586
be_bryan 0:b74591d5ab33 587 DEBUG_PRINTF("SPI: Transfer: %u, %u\n", tx_length, rx_length);
be_bryan 0:b74591d5ab33 588
be_bryan 0:b74591d5ab33 589 // register the thunking handler
be_bryan 0:b74591d5ab33 590 IRQn_Type irq_n = spiobj->spiIRQ;
be_bryan 0:b74591d5ab33 591 NVIC_SetVector(irq_n, (uint32_t)handler);
be_bryan 0:b74591d5ab33 592
be_bryan 0:b74591d5ab33 593 // enable the right hal transfer
be_bryan 0:b74591d5ab33 594 if (use_tx && use_rx) {
be_bryan 0:b74591d5ab33 595 // we cannot manage different rx / tx sizes, let's use smaller one
be_bryan 0:b74591d5ab33 596 size_t size = (tx_length < rx_length)? tx_length : rx_length;
be_bryan 0:b74591d5ab33 597 if(tx_length != rx_length) {
be_bryan 0:b74591d5ab33 598 DEBUG_PRINTF("SPI: Full duplex transfer only 1 size: %d\n", size);
be_bryan 0:b74591d5ab33 599 obj->tx_buff.length = size;
be_bryan 0:b74591d5ab33 600 obj->rx_buff.length = size;
be_bryan 0:b74591d5ab33 601 }
be_bryan 0:b74591d5ab33 602 spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TXRX, tx, rx, size);
be_bryan 0:b74591d5ab33 603 } else if (use_tx) {
be_bryan 0:b74591d5ab33 604 spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_TX, tx, NULL, tx_length);
be_bryan 0:b74591d5ab33 605 } else if (use_rx) {
be_bryan 0:b74591d5ab33 606 spi_master_start_asynch_transfer(obj, SPI_TRANSFER_TYPE_RX, NULL, rx, rx_length);
be_bryan 0:b74591d5ab33 607 }
be_bryan 0:b74591d5ab33 608 }
be_bryan 0:b74591d5ab33 609
be_bryan 0:b74591d5ab33 610 inline uint32_t spi_irq_handler_asynch(spi_t *obj)
be_bryan 0:b74591d5ab33 611 {
be_bryan 0:b74591d5ab33 612 int event = 0;
be_bryan 0:b74591d5ab33 613
be_bryan 0:b74591d5ab33 614 // call the CubeF4 handler, this will update the handle
be_bryan 0:b74591d5ab33 615 HAL_SPI_IRQHandler(&obj->spi.handle);
be_bryan 0:b74591d5ab33 616
be_bryan 0:b74591d5ab33 617 if (obj->spi.handle.State == HAL_SPI_STATE_READY) {
be_bryan 0:b74591d5ab33 618 // When HAL SPI is back to READY state, check if there was an error
be_bryan 0:b74591d5ab33 619 int error = obj->spi.handle.ErrorCode;
be_bryan 0:b74591d5ab33 620 if(error != HAL_SPI_ERROR_NONE) {
be_bryan 0:b74591d5ab33 621 // something went wrong and the transfer has definitely completed
be_bryan 0:b74591d5ab33 622 event = SPI_EVENT_ERROR | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
be_bryan 0:b74591d5ab33 623
be_bryan 0:b74591d5ab33 624 if (error & HAL_SPI_ERROR_OVR) {
be_bryan 0:b74591d5ab33 625 // buffer overrun
be_bryan 0:b74591d5ab33 626 event |= SPI_EVENT_RX_OVERFLOW;
be_bryan 0:b74591d5ab33 627 }
be_bryan 0:b74591d5ab33 628 } else {
be_bryan 0:b74591d5ab33 629 // else we're done
be_bryan 0:b74591d5ab33 630 event = SPI_EVENT_COMPLETE | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE;
be_bryan 0:b74591d5ab33 631 }
be_bryan 0:b74591d5ab33 632 // enable the interrupt
be_bryan 0:b74591d5ab33 633 NVIC_DisableIRQ(obj->spi.spiIRQ);
be_bryan 0:b74591d5ab33 634 NVIC_ClearPendingIRQ(obj->spi.spiIRQ);
be_bryan 0:b74591d5ab33 635 }
be_bryan 0:b74591d5ab33 636
be_bryan 0:b74591d5ab33 637
be_bryan 0:b74591d5ab33 638 return (event & (obj->spi.event | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE));
be_bryan 0:b74591d5ab33 639 }
be_bryan 0:b74591d5ab33 640
be_bryan 0:b74591d5ab33 641 uint8_t spi_active(spi_t *obj)
be_bryan 0:b74591d5ab33 642 {
be_bryan 0:b74591d5ab33 643 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 644 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 645 HAL_SPI_StateTypeDef state = HAL_SPI_GetState(handle);
be_bryan 0:b74591d5ab33 646
be_bryan 0:b74591d5ab33 647 switch(state) {
be_bryan 0:b74591d5ab33 648 case HAL_SPI_STATE_RESET:
be_bryan 0:b74591d5ab33 649 case HAL_SPI_STATE_READY:
be_bryan 0:b74591d5ab33 650 case HAL_SPI_STATE_ERROR:
be_bryan 0:b74591d5ab33 651 return 0;
be_bryan 0:b74591d5ab33 652 default:
be_bryan 0:b74591d5ab33 653 return 1;
be_bryan 0:b74591d5ab33 654 }
be_bryan 0:b74591d5ab33 655 }
be_bryan 0:b74591d5ab33 656
be_bryan 0:b74591d5ab33 657 void spi_abort_asynch(spi_t *obj)
be_bryan 0:b74591d5ab33 658 {
be_bryan 0:b74591d5ab33 659 struct spi_s *spiobj = SPI_S(obj);
be_bryan 0:b74591d5ab33 660 SPI_HandleTypeDef *handle = &(spiobj->handle);
be_bryan 0:b74591d5ab33 661
be_bryan 0:b74591d5ab33 662 // disable interrupt
be_bryan 0:b74591d5ab33 663 IRQn_Type irq_n = spiobj->spiIRQ;
be_bryan 0:b74591d5ab33 664 NVIC_ClearPendingIRQ(irq_n);
be_bryan 0:b74591d5ab33 665 NVIC_DisableIRQ(irq_n);
be_bryan 0:b74591d5ab33 666
be_bryan 0:b74591d5ab33 667 // clean-up
be_bryan 0:b74591d5ab33 668 __HAL_SPI_DISABLE(handle);
be_bryan 0:b74591d5ab33 669 HAL_SPI_DeInit(handle);
be_bryan 0:b74591d5ab33 670 HAL_SPI_Init(handle);
be_bryan 0:b74591d5ab33 671 __HAL_SPI_ENABLE(handle);
be_bryan 0:b74591d5ab33 672 }
be_bryan 0:b74591d5ab33 673
be_bryan 0:b74591d5ab33 674 #endif //DEVICE_SPI_ASYNCH
be_bryan 0:b74591d5ab33 675
be_bryan 0:b74591d5ab33 676 #endif