You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/10/18 20:16:18 UTC

[3/5] incubator-mynewt-core git commit: stm32f4 hal spi; hw error counters.

stm32f4 hal spi; hw error counters.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/97bf2867
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/97bf2867
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/97bf2867

Branch: refs/heads/develop
Commit: 97bf286714a9d2c6716d226b92bd98518f4e3bbd
Parents: e238713
Author: Marko Kiiskila <ma...@runtime.io>
Authored: Tue Oct 18 10:10:38 2016 -0700
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Tue Oct 18 13:15:41 2016 -0700

----------------------------------------------------------------------
 hw/mcu/stm/stm32f4xx/src/hal_spi.c          |  29 +-
 hw/mcu/stm/stm32f4xx/src/hal_spi_soft_ssi.c | 847 +++++++++++++++++++++++
 2 files changed, 873 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/97bf2867/hw/mcu/stm/stm32f4xx/src/hal_spi.c
----------------------------------------------------------------------
diff --git a/hw/mcu/stm/stm32f4xx/src/hal_spi.c b/hw/mcu/stm/stm32f4xx/src/hal_spi.c
index c0de992..c52fae9 100644
--- a/hw/mcu/stm/stm32f4xx/src/hal_spi.c
+++ b/hw/mcu/stm/stm32f4xx/src/hal_spi.c
@@ -56,6 +56,9 @@ static struct stm32f4_spi_stat {
     uint32_t irq;
     uint32_t ss_irq;
     uint32_t tx;
+    uint32_t eovf;
+    uint32_t emodf;
+    uint32_t efre;
 } spi_stat;
 
 static void spi_irq_handler(struct stm32f4_hal_spi *spi);
@@ -155,8 +158,6 @@ stm32f4_resolve_spi_irq(SPI_HandleTypeDef *hspi)
 static void
 spim_irq_handler(struct stm32f4_hal_spi *spi)
 {
-    HAL_SPI_IRQHandler(&spi->handle);
-
     if (spi->handle.TxXferCount == 0 && spi->handle.RxXferCount == 0) {
         if (spi->txrx_cb_func) {
             spi->txrx_cb_func(spi->txrx_cb_arg, spi->handle.TxXferSize);
@@ -167,7 +168,6 @@ spim_irq_handler(struct stm32f4_hal_spi *spi)
 static void
 spis_irq_handler(struct stm32f4_hal_spi *spi)
 {
-    HAL_SPI_IRQHandler(&spi->handle);
     if (spi->tx_in_prog) {
         if (spi->handle.TxXferCount == 0 && spi->handle.RxXferCount == 0) {
             spi->tx_in_prog = 0;
@@ -187,7 +187,24 @@ spis_irq_handler(struct stm32f4_hal_spi *spi)
 static void
 spi_irq_handler(struct stm32f4_hal_spi *spi)
 {
+    uint32_t err;
+
     spi_stat.irq++;
+
+    HAL_SPI_IRQHandler(&spi->handle);
+    err = spi->handle.ErrorCode;
+    if (err) {
+        if (err & HAL_SPI_ERROR_OVR) {
+            spi_stat.eovf++;
+        }
+        if (err & HAL_SPI_ERROR_MODF) {
+            spi_stat.emodf++;
+        }
+        if (err & HAL_SPI_ERROR_FRE) {
+            spi_stat.efre++;
+        }
+        spi->handle.ErrorCode = 0;
+    }
     if (!spi->slave) {
         spim_irq_handler(spi);
     } else {
@@ -221,9 +238,15 @@ spi_ss_isr(void *arg)
         spi->selected = 1;
     }
     if (ss == 1 && spi->selected) {
+        if (spi->handle.Instance->SR & SPI_SR_RXNE && spi->handle.RxISR) {
+            spi->handle.RxISR(&spi->handle);
+        }
         reg = spi->handle.Instance->CR1;
         reg &= ~SPI_CR1_SPE;
         reg |= SPI_CR1_SSI;
+
+        __HAL_SPI_DISABLE_IT(&spi->handle, SPI_IT_RXNE|SPI_IT_TXE|SPI_IT_ERR);
+
         spi->handle.Instance->CR1 = reg;
         len = spi->handle.RxXferSize - spi->handle.RxXferCount;
         if (spi->tx_in_prog && len) {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/97bf2867/hw/mcu/stm/stm32f4xx/src/hal_spi_soft_ssi.c
----------------------------------------------------------------------
diff --git a/hw/mcu/stm/stm32f4xx/src/hal_spi_soft_ssi.c b/hw/mcu/stm/stm32f4xx/src/hal_spi_soft_ssi.c
new file mode 100644
index 0000000..71bea92
--- /dev/null
+++ b/hw/mcu/stm/stm32f4xx/src/hal_spi_soft_ssi.c
@@ -0,0 +1,847 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <hal/hal_spi.h>
+#include <hal/hal_gpio.h>
+
+#include <string.h>
+
+#include <assert.h>
+
+#include <syscfg/syscfg.h>
+
+#include "stm32f4xx.h"
+#include "stm32f4xx_hal_dma.h"
+#include "stm32f4xx_hal_spi.h"
+#include "stm32f4xx_hal_gpio.h"
+#include "stm32f4xx_hal_gpio_ex.h"
+#include "stm32f4xx_hal_rcc.h"
+#include "mcu/stm32f4xx_mynewt_hal.h"
+#include "mcu/stm32f4_bsp.h"
+#include "bsp/cmsis_nvic.h"
+
+#define STM32F4_HAL_SPI_TIMEOUT (1000)
+
+#define STM32F4_HAL_SPI_MAX (6)
+
+struct stm32f4_hal_spi {
+    SPI_HandleTypeDef handle;
+    uint8_t slave:1;
+    uint8_t tx_in_prog:1;
+    uint8_t selected:1;
+    uint8_t def_char[4];
+    struct stm32f4_hal_spi_cfg *cfg;
+    /* Callback and arguments */
+    hal_spi_txrx_cb txrx_cb_func;
+    void            *txrx_cb_arg;
+};
+
+static struct stm32f4_spi_stat {
+    uint32_t irq;
+    uint32_t ss_irq;
+} spi_stat;
+
+static void spi_irq_handler(struct stm32f4_hal_spi *spi);
+
+#if MYNEWT_VAL(SPI_0)
+struct stm32f4_hal_spi stm32f4_hal_spi0;
+#endif
+#if MYNEWT_VAL(SPI_1)
+struct stm32f4_hal_spi stm32f4_hal_spi1;
+#endif
+#if MYNEWT_VAL(SPI_2)
+struct stm32f4_hal_spi stm32f4_hal_spi2;
+#endif
+#if MYNEWT_VAL(SPI_3)
+struct stm32f4_hal_spi stm32f4_hal_spi3;
+#endif
+#if MYNEWT_VAL(SPI_4)
+struct stm32f4_hal_spi stm32f4_hal_spi4;
+#endif
+#if MYNEWT_VAL(SPI_5)
+struct stm32f4_hal_spi stm32f4_hal_spi5;
+#endif
+
+static struct stm32f4_hal_spi *stm32f4_hal_spis[STM32F4_HAL_SPI_MAX] = {
+#if MYNEWT_VAL(SPI_0)
+    &stm32f4_hal_spi0,
+#else
+    NULL,
+#endif
+#if MYNEWT_VAL(SPI_1)
+    &stm32f4_hal_spi1,
+#else
+    NULL,
+#endif
+#if MYNEWT_VAL(SPI_2)
+    &stm32f4_hal_spi2,
+#else
+    NULL,
+#endif
+#if MYNEWT_VAL(SPI_3)
+    &stm32f4_hal_spi3,
+#else
+    NULL,
+#endif
+#if MYNEWT_VAL(SPI_4)
+    &stm32f4_hal_spi4,
+#else
+    NULL,
+#endif
+#if MYNEWT_VAL(SPI_5)
+    &stm32f4_hal_spi5,
+#else
+    NULL,
+#endif
+};
+
+#define STM32F4_HAL_SPI_RESOLVE(__n, __v)                        \
+    if ((__n) >= STM32F4_HAL_SPI_MAX) {                          \
+        rc = -1;                                                 \
+        goto err;                                                \
+    }                                                            \
+    (__v) = (struct stm32f4_hal_spi *) stm32f4_hal_spis[(__n)];  \
+    if ((__v) == NULL) {                                         \
+        rc = -1;                                                 \
+        goto err;                                                \
+    }
+
+static IRQn_Type
+stm32f4_resolve_spi_irq(SPI_HandleTypeDef *hspi)
+{
+    uintptr_t spi = (uintptr_t)hspi->Instance;
+
+    switch(spi) {
+        case (uintptr_t)SPI1:
+            return SPI1_IRQn;
+        case (uintptr_t)SPI2:
+            return SPI2_IRQn;
+        case (uintptr_t)SPI3:
+            return SPI3_IRQn;
+#ifdef SPI4
+        case (uintptr_t)SPI4:
+            return SPI4_IRQn;
+#endif
+#ifdef SPI5
+        case (uintptr_t)SPI5:
+            return SPI5_IRQn;
+#endif
+#ifdef SPI6
+        case (uintptr_t)SPI6:
+            return SPI6_IRQn;
+#endif
+        default:
+            assert(0);
+    }
+}
+
+static void
+spim_irq_handler(struct stm32f4_hal_spi *spi)
+{
+    HAL_SPI_IRQHandler(&spi->handle);
+
+    if (spi->handle.TxXferCount == 0 && spi->handle.RxXferCount == 0) {
+        spi->handle.Instance->CR1 |= SPI_CR1_SSI;
+        if (spi->txrx_cb_func) {
+            spi->txrx_cb_func(spi->txrx_cb_arg, spi->handle.TxXferSize);
+        }
+    }
+}
+
+static void
+spis_irq_handler(struct stm32f4_hal_spi *spi)
+{
+    HAL_SPI_IRQHandler(&spi->handle);
+    if (spi->tx_in_prog) {
+        if (spi->handle.TxXferCount == 0 && spi->handle.RxXferCount == 0) {
+            spi->tx_in_prog = 0;
+
+            HAL_SPI_Transmit_IT(&spi->handle, spi->def_char, 2);
+
+            if (spi->txrx_cb_func) {
+                spi->txrx_cb_func(spi->txrx_cb_arg, spi->handle.TxXferSize);
+            }
+        }
+    } else {
+        spi->handle.pTxBuffPtr = spi->def_char;
+        spi->handle.TxXferCount = 2;
+    }
+}
+
+static void
+spi_irq_handler(struct stm32f4_hal_spi *spi)
+{
+    spi_stat.irq++;
+    if (!spi->slave) {
+        spim_irq_handler(spi);
+    } else {
+        spis_irq_handler(spi);
+    }
+}
+
+static void
+spi_ss_isr(void *arg)
+{
+    struct stm32f4_hal_spi *spi = (struct stm32f4_hal_spi *)arg;
+    int ss;
+    int len;
+    int rc;
+    uint16_t reg;
+
+    spi_stat.ss_irq++;
+    ss = hal_gpio_read(spi->cfg->ss_pin);
+    if (ss == 0 && !spi->selected) {
+        reg = spi->handle.Instance->CR1;
+        reg |= SPI_CR1_SPE;
+        reg &= ~SPI_CR1_SSI;
+        spi->handle.Instance->CR1 = reg;
+        if (spi->tx_in_prog) {
+            rc = HAL_SPI_TransmitReceive_IT(&spi->handle,
+              spi->handle.pTxBuffPtr, spi->handle.pRxBuffPtr,
+              spi->handle.TxXferSize);
+        } else {
+            rc = HAL_SPI_Transmit_IT(&spi->handle, spi->def_char, 2);
+        }
+        assert(rc == 0);
+        spi->selected = 1;
+    }
+    if (ss == 1 && spi->selected) {
+        reg = spi->handle.Instance->CR1;
+        reg &= ~SPI_CR1_SPE;
+        reg |= SPI_CR1_SSI;
+        spi->handle.Instance->CR1 = reg;
+        len = spi->handle.RxXferSize - spi->handle.RxXferCount;
+        if (spi->tx_in_prog && len) {
+            spi->tx_in_prog = 0;
+
+            if (spi->txrx_cb_func) {
+                spi->txrx_cb_func(spi->txrx_cb_arg, len);
+            }
+        }
+        spi->handle.State = HAL_SPI_STATE_READY;
+        spi->selected = 0;
+    }
+}
+
+static void
+spi1_irq_handler(void)
+{
+    spi_irq_handler(stm32f4_hal_spis[0]);
+}
+
+static void
+spi2_irq_handler(void)
+{
+    spi_irq_handler(stm32f4_hal_spis[1]);
+}
+
+static void
+spi3_irq_handler(void)
+{
+    spi_irq_handler(stm32f4_hal_spis[2]);
+}
+
+#ifdef SPI4
+static void
+spi4_irq_handler(void)
+{
+    spi_irq_handler(stm32f4_hal_spis[3]);
+}
+#endif
+
+#ifdef SPI5
+static void
+spi5_irq_handler(void)
+{
+    spi_irq_handler(stm32f4_hal_spis[4]);
+}
+#endif
+
+
+#ifdef SPI6
+static void
+spi6_irq_handler(void)
+{
+    spi_irq_handler(stm32f4_hal_spis[5]);
+}
+#endif
+
+uint32_t
+stm32f4_resolve_spi_irq_handler(SPI_HandleTypeDef *hspi)
+{
+    switch((uintptr_t)hspi->Instance) {
+        case (uintptr_t)SPI1:
+            return (uint32_t)&spi1_irq_handler;
+        case (uintptr_t)SPI2:
+            return (uint32_t)&spi2_irq_handler;
+        case (uintptr_t)SPI3:
+            return (uint32_t)&spi3_irq_handler;
+#ifdef SPI4
+        case (uintptr_t)SPI4:
+            return (uint32_t)&spi4_irq_handler;
+#endif
+#ifdef SPI5
+        case (uintptr_t)SPI5:
+            return (uint32_t)&spi5_irq_handler;
+#endif
+#ifdef SPI6
+        case (uintptr_t)SPI6:
+            return (uint32_t)&spi6_irq_handler;
+#endif
+        default:
+            assert(0);
+    }
+}
+
+int
+hal_spi_init(int spi_num, void *usercfg, uint8_t spi_type)
+{
+    struct stm32f4_hal_spi *spi;
+    int rc;
+
+    /* Check for valid arguments */
+    rc = -1;
+    if (usercfg == NULL) {
+        goto err;
+    }
+
+    if ((spi_type != HAL_SPI_TYPE_MASTER) && (spi_type != HAL_SPI_TYPE_SLAVE)) {
+        goto err;
+    }
+
+    /* Allow user to specify default init settings for the SPI.
+     * This can be done in BSP, so that only the generic SPI settings
+     * are passed to the user configure() call.
+     */
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+
+    spi->cfg = usercfg;
+    spi->slave = (spi_type == HAL_SPI_TYPE_SLAVE);
+
+    return (0);
+err:
+    return (rc);
+}
+
+static int
+stm32f4_spi_resolve_prescaler(uint8_t spi_num, uint32_t baudrate, uint32_t *prescaler)
+{
+    uint32_t candidate_br;
+    uint32_t apbfreq;
+    int i;
+
+    /* SPIx {1,4,5,6} use PCLK2 on the STM32F4, otherwise use PCKL1.
+     * The numbers in the switch below are offset by 1, because the HALs index
+     * SPI ports from 0.
+     */
+    switch (spi_num) {
+        case 0:
+        case 3:
+        case 4:
+        case 5:
+            apbfreq = HAL_RCC_GetPCLK2Freq();
+            break;
+        default:
+            apbfreq = HAL_RCC_GetPCLK1Freq();
+            break;
+    }
+
+    if (baudrate == 0) {
+        *prescaler = 0;
+        return 0;
+    }
+
+    /* Calculate best-fit prescaler: divide the clock by each subsequent
+     * prescalar until we reach the highest prescalar that generates at
+     * _most_ the baudrate.
+     */
+    *prescaler = SPI_BAUDRATEPRESCALER_256;
+    for (i = 0; i < 8; i++) {
+        candidate_br = apbfreq >> (i + 1);
+        if (candidate_br <= baudrate) {
+            *prescaler = i << 3;
+            break;
+        }
+    }
+
+    return (0);
+}
+
+/**
+ * Sets the txrx callback (executed at interrupt context) when the
+ * buffer is transferred by the master or the slave using the non-blocking API.
+ * Cannot be called when the spi is enabled. This callback will also be called
+ * when chip select is de-asserted on the slave.
+ *
+ * NOTE: This callback is only used for the non-blocking interface and must
+ * be called prior to using the non-blocking API.
+ *
+ * @param spi_num   SPI interface on which to set callback
+ * @param txrx      Callback function
+ * @param arg       Argument to be passed to callback function
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_set_txrx_cb(int spi_num, hal_spi_txrx_cb txrx_cb, void *arg)
+{
+    struct stm32f4_hal_spi *spi;
+    int rc = 0;
+    int sr;
+
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+
+    __HAL_DISABLE_INTERRUPTS(sr);
+    spi->txrx_cb_func = txrx_cb;
+    spi->txrx_cb_arg = arg;
+    __HAL_ENABLE_INTERRUPTS(sr);
+err:
+    return rc;
+}
+
+/**
+ * Enables the SPI. This does not start a transmit or receive operation;
+ * it is used for power mgmt. Cannot be called when a SPI transfer is in
+ * progress.
+ *
+ * @param spi_num
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_enable(int spi_num)
+{
+    struct stm32f4_hal_spi *spi;
+    int rc;
+
+    rc = 0;
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+
+    /* XXX power up */
+err:
+    return rc;
+}
+
+/**
+ * Disables the SPI. Used for power mgmt. It will halt any current SPI transfers
+ * in progress.
+ *
+ * @param spi_num
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_disable(int spi_num)
+{
+    struct stm32f4_hal_spi *spi;
+    int rc;
+
+    rc = 0;
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+
+    if (!spi->slave) {
+        spi->handle.Instance->CR1 |= SPI_CR1_SSI;
+    }
+    /* XXX power down */
+err:
+    return rc;
+}
+
+int
+hal_spi_config(int spi_num, struct hal_spi_settings *settings)
+{
+    struct stm32f4_hal_spi *spi;
+    struct stm32f4_hal_spi_cfg *cfg;
+    SPI_InitTypeDef *init;
+    GPIO_InitTypeDef gpio;
+    IRQn_Type irq;
+    uint32_t prescaler;
+    int rc;
+    int sr;
+
+    __HAL_DISABLE_INTERRUPTS(sr);
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+
+    init = &spi->handle.Init;
+
+    cfg = spi->cfg;
+
+    if (!spi->slave) {
+        spi->handle.Init.NSS = SPI_NSS_SOFT;
+        spi->handle.Init.Mode = SPI_MODE_MASTER;
+    } else {
+        spi->handle.Init.NSS = SPI_NSS_SOFT;
+        spi->handle.Init.Mode = SPI_MODE_SLAVE;
+    }
+
+    gpio.Mode = GPIO_MODE_AF_PP;
+    gpio.Pull = GPIO_NOPULL;
+    gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+
+    /* Enable the clocks for this SPI */
+    switch (spi_num) {
+        case 0:
+            __HAL_RCC_SPI1_CLK_ENABLE();
+            gpio.Alternate = GPIO_AF5_SPI1;
+            spi->handle.Instance = SPI1;
+            break;
+        case 1:
+            __HAL_RCC_SPI2_CLK_ENABLE();
+            gpio.Alternate = GPIO_AF5_SPI2;
+            spi->handle.Instance = SPI2;
+            break;
+        case 2:
+            __HAL_RCC_SPI3_CLK_ENABLE();
+            gpio.Alternate = GPIO_AF6_SPI3;
+            spi->handle.Instance = SPI3;
+            break;
+#ifdef SPI4
+        case 3:
+            __HAL_RCC_SPI4_CLK_ENABLE();
+            gpio.Alternate = GPIO_AF5_SPI4;
+            spi->handle.Instance = SPI4;
+            break;
+#endif
+#ifdef SPI5
+        case 4:
+            __HAL_RCC_SPI5_CLK_ENABLE();
+            gpio.Alternate = GPIO_AF5_SPI5;
+            spi->handle.Instance = SPI5;
+            break;
+#endif
+#ifdef SPI6
+        case 5:
+            __HAL_RCC_SPI6_CLK_ENABLE();
+            gpio.Alternate = GPIO_AF5_SPI6;
+            spi->handle.Instance = SPI6;
+            break;
+#endif
+       default:
+            assert(0);
+            rc = -1;
+            goto err;
+    }
+
+    if (!spi->slave) {
+        if (settings->data_mode == HAL_SPI_MODE2 ||
+          settings->data_mode == HAL_SPI_MODE3) {
+            gpio.Pull = GPIO_PULLUP;
+        } else {
+            gpio.Pull = GPIO_PULLDOWN;
+        }
+    }
+    rc = hal_gpio_init_stm(cfg->sck_pin, &gpio);
+    if (rc != 0) {
+        goto err;
+    }
+    if (!spi->slave) {
+        gpio.Pull = GPIO_NOPULL;
+    } else {
+        gpio.Mode = GPIO_MODE_AF_OD;
+    }
+
+    rc = hal_gpio_init_stm(cfg->mosi_pin, &gpio);
+    if (rc != 0) {
+        goto err;
+    }
+    if (!spi->slave) {
+        gpio.Mode = GPIO_MODE_AF_OD;
+    } else {
+        gpio.Mode = GPIO_MODE_AF_PP;
+    }
+    rc = hal_gpio_init_stm(cfg->miso_pin, &gpio);
+    if (rc != 0) {
+        goto err;
+    }
+
+    switch (settings->data_mode) {
+        case HAL_SPI_MODE0:
+            init->CLKPolarity = SPI_POLARITY_LOW;
+            init->CLKPhase = SPI_PHASE_1EDGE;
+            break;
+        case HAL_SPI_MODE1:
+            init->CLKPolarity = SPI_POLARITY_LOW;
+            init->CLKPhase = SPI_PHASE_2EDGE;
+            break;
+        case HAL_SPI_MODE2:
+            init->CLKPolarity = SPI_POLARITY_HIGH;
+            init->CLKPhase = SPI_PHASE_1EDGE;
+            break;
+        case HAL_SPI_MODE3:
+            init->CLKPolarity = SPI_POLARITY_HIGH;
+            init->CLKPhase = SPI_PHASE_2EDGE;
+            break;
+        default:
+            rc = -1;
+            goto err;
+    }
+
+    switch (settings->data_order) {
+        case HAL_SPI_MSB_FIRST:
+            init->FirstBit = SPI_FIRSTBIT_MSB;
+            break;
+        case HAL_SPI_LSB_FIRST:
+            init->FirstBit = SPI_FIRSTBIT_LSB;
+            break;
+        default:
+            rc = -1;
+            goto err;
+    }
+
+    switch (settings->word_size) {
+        case HAL_SPI_WORD_SIZE_8BIT:
+            init->DataSize = SPI_DATASIZE_8BIT;
+            break;
+        case HAL_SPI_WORD_SIZE_9BIT:
+            init->DataSize = SPI_DATASIZE_16BIT;
+            break;
+        default:
+            rc = -1;
+            goto err;
+    }
+
+    rc = stm32f4_spi_resolve_prescaler(spi_num, settings->baudrate * 1000,
+      &prescaler);
+    if (rc != 0) {
+        goto err;
+    }
+
+    init->BaudRatePrescaler = prescaler;
+
+    irq = stm32f4_resolve_spi_irq(&spi->handle);
+    NVIC_SetPriority(irq, cfg->irq_prio);
+    NVIC_SetVector(irq, stm32f4_resolve_spi_irq_handler(&spi->handle));
+    NVIC_EnableIRQ(irq);
+
+    /* Init, Enable */
+    rc = HAL_SPI_Init(&spi->handle);
+    if (rc != 0) {
+        goto err;
+    }
+    if (!spi->slave) {
+        spi->handle.Instance->CR1 |= SPI_CR1_SSI;
+    } else {
+        rc = hal_gpio_irq_init(cfg->ss_pin, spi_ss_isr, spi, GPIO_TRIG_BOTH,
+          GPIO_PULL_UP);
+        spi_ss_isr(spi);
+    }
+    __HAL_ENABLE_INTERRUPTS(sr);
+    return (0);
+err:
+    __HAL_ENABLE_INTERRUPTS(sr);
+    return (rc);
+}
+
+int
+hal_spi_txrx_noblock(int spi_num, void *txbuf, void *rxbuf, int len)
+{
+    struct stm32f4_hal_spi *spi;
+    int rc;
+    int sr;
+
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+
+    __HAL_DISABLE_INTERRUPTS(sr);
+    rc = -1;
+    if (!spi->slave) {
+        spi->handle.Instance->CR1 |= (SPI_CR1_SSI | SPI_CR1_SPE);
+        rc = HAL_SPI_TransmitReceive_IT(&spi->handle, txbuf, rxbuf, len);
+    } else {
+        spi->tx_in_prog = 1;
+        if (spi->selected) {
+            rc = HAL_SPI_TransmitReceive_IT(&spi->handle, txbuf, rxbuf, len);
+        } else {
+            rc = 0;
+            spi->handle.pTxBuffPtr = txbuf;
+            spi->handle.TxXferSize = len;
+            spi->handle.pRxBuffPtr = rxbuf;
+            spi->handle.RxXferSize  = len;
+        }
+    }
+    __HAL_ENABLE_INTERRUPTS(sr);
+err:
+    return (rc);
+}
+
+/**
+ * Sets the default value transferred by the slave. Not valid for master
+ *
+ * @param spi_num SPI interface to use
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_slave_set_def_tx_val(int spi_num, uint16_t val)
+{
+    struct stm32f4_hal_spi *spi;
+    int rc;
+    int sr;
+    int i;
+
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+
+    if (spi->slave) {
+        __HAL_DISABLE_INTERRUPTS(sr);
+        if (spi->handle.Init.DataSize == SPI_DATASIZE_8BIT) {
+            for (i = 0; i < 4; i++) {
+                ((uint8_t *)spi->def_char)[i] = val;
+            }
+        } else {
+            for (i = 0; i < 2; i++) {
+                ((uint16_t *)spi->def_char)[i] = val;
+            }
+        }
+        if (!spi->tx_in_prog && spi->selected) {
+            spi->handle.Instance->DR = val;
+        }
+        __HAL_ENABLE_INTERRUPTS(sr);
+    } else {
+        rc = -1;
+    }
+err:
+    return rc;
+}
+
+/**
+ * Blocking call to send a value on the SPI. Returns the value received from the
+ * SPI slave.
+ *
+ * MASTER: Sends the value and returns the received value from the slave.
+ * SLAVE: Invalid API. Returns 0xFFFF
+ *
+ * @param spi_num   Spi interface to use
+ * @param val       Value to send
+ *
+ * @return uint16_t Value received on SPI interface from slave. Returns 0xFFFF
+ * if called when the SPI is configured to be a slave
+ */
+uint16_t hal_spi_tx_val(int spi_num, uint16_t val)
+{
+    int rc;
+    struct stm32f4_hal_spi *spi;
+    uint16_t retval;
+    uint16_t reg;
+    int len;
+    int sr;
+
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+    if (spi->slave) {
+        retval = -1;
+        goto err;
+    }
+    if (spi->handle.Init.DataSize == SPI_DATASIZE_8BIT) {
+        len = sizeof(uint8_t);
+    } else {
+        len = sizeof(uint16_t);
+    }
+    __HAL_DISABLE_INTERRUPTS(sr);
+    reg = spi->handle.Instance->CR1;
+    reg &= ~SPI_CR1_SSI;
+    reg |= SPI_CR1_SPE;
+    spi->handle.Instance->CR1 = reg;
+    rc = HAL_SPI_TransmitReceive(&spi->handle,(uint8_t *)&val,
+                                 (uint8_t *)&retval, len,
+                                 STM32F4_HAL_SPI_TIMEOUT);
+    reg = spi->handle.Instance->CR1;
+    reg |= SPI_CR1_SSI;
+    reg &= ~SPI_CR1_SPE;
+    spi->handle.Instance->CR1 = reg;
+    __HAL_ENABLE_INTERRUPTS(sr);
+    if (rc != HAL_OK) {
+        retval = 0xFFFF;
+    }
+
+err:
+    return retval;
+}
+
+/**
+ * Blocking interface to send a buffer and store the received values from the
+ * slave. The transmit and receive buffers are either arrays of 8-bit (uint8_t)
+ * values or 16-bit values depending on whether the spi is configured for 8 bit
+ * data or more than 8 bits per value. The 'cnt' parameter is the number of
+ * 8-bit or 16-bit values. Thus, if 'cnt' is 10, txbuf/rxbuf would point to an
+ * array of size 10 (in bytes) if the SPI is using 8-bit data; otherwise
+ * txbuf/rxbuf would point to an array of size 20 bytes (ten, uint16_t values).
+ *
+ * NOTE: these buffers are in the native endian-ness of the platform.
+ *
+ *     MASTER: master sends all the values in the buffer and stores the
+ *             stores the values in the receive buffer if rxbuf is not NULL.
+ *             The txbuf parameter cannot be NULL.
+ *     SLAVE: cannot be called for a slave; returns -1
+ *
+ * @param spi_num   SPI interface to use
+ * @param txbuf     Pointer to buffer where values to transmit are stored.
+ * @param rxbuf     Pointer to buffer to store values received from peer.
+ * @param cnt       Number of 8-bit or 16-bit values to be transferred.
+ *
+ * @return int 0 on success, non-zero error code on failure.
+ */
+int
+hal_spi_txrx(int spi_num, void *txbuf, void *rxbuf, int len)
+{
+    int rc;
+    struct stm32f4_hal_spi *spi;
+    int sr;
+
+    rc = -1;
+    if (!len) {
+        goto err;
+    }
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+    if (spi->slave) {
+        goto err;
+    }
+    __HAL_DISABLE_INTERRUPTS(sr);
+    spi->handle.Instance->CR1 |= (SPI_CR1_SSI | SPI_CR1_SPE);
+    rc = HAL_SPI_TransmitReceive(&spi->handle, (uint8_t *)txbuf,
+                                 (uint8_t *)rxbuf, len,
+                                 STM32F4_HAL_SPI_TIMEOUT);
+    spi->handle.Instance->CR1 &= ~(SPI_CR1_SSI | SPI_CR1_SPE);
+    __HAL_ENABLE_INTERRUPTS(sr);
+    if (rc != HAL_OK) {
+        rc = -1;
+        goto err;
+    }
+    rc = 0;
+err:
+    return rc;
+}
+
+int
+hal_spi_abort(int spi_num)
+{
+    int rc;
+    struct stm32f4_hal_spi *spi;
+    int sr;
+
+    rc = 0;
+    STM32F4_HAL_SPI_RESOLVE(spi_num, spi);
+    if (spi->slave) {
+        goto err;
+    }
+    __HAL_DISABLE_INTERRUPTS(sr);
+    spi->handle.State = HAL_SPI_STATE_READY;
+    __HAL_SPI_DISABLE_IT(&spi->handle, SPI_IT_TXE | SPI_IT_RXNE | SPI_IT_ERR);
+    spi->handle.Instance->CR1 &= ~(SPI_CR1_SSI | SPI_CR1_SPE);
+    __HAL_ENABLE_INTERRUPTS(sr);
+err:
+    return rc;
+}