Exemplo n.º 1
0
/**
 * 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 stm32_hal_spi *spi;
    uint16_t retval;
    int len;
    int sr;

    STM32_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);
    spi_stat.tx++;
    rc = HAL_SPI_TransmitReceive(&spi->handle,(uint8_t *)&val,
                                 (uint8_t *)&retval, len,
                                 STM32_HAL_SPI_TIMEOUT);
    __HAL_ENABLE_INTERRUPTS(sr);
    if (rc != HAL_OK) {
        retval = 0xFFFF;
    }

err:
    return retval;
}
Exemplo n.º 2
0
int
hal_spi_txrx_noblock(int spi_num, void *txbuf, void *rxbuf, int len)
{
    struct stm32_hal_spi *spi;
    int rc;
    int sr;

    STM32_HAL_SPI_RESOLVE(spi_num, spi);

    spi_stat.tx++;
    rc = -1;
    __HAL_DISABLE_INTERRUPTS(sr);
    if (!spi->slave) {
        rc = HAL_SPI_TransmitReceive_IT_Custom(&spi->handle, txbuf, rxbuf, len);
    } else {
        /*
         * Slave: if selected, start transmitting new data.
         * If not selected, queue it for transmission.
         */
        spi->handle.State = HAL_SPI_STATE_READY;
        if (spi->selected) {
            rc = HAL_SPI_TransmitReceive_IT_Custom(&spi->handle, txbuf, rxbuf, len);
        } else {
            rc = HAL_SPI_Slave_Queue_TransmitReceive(&spi->handle, txbuf, rxbuf,
              len);
        }
        if (rc == 0) {
            spi->tx_in_prog = 1;
        }
    }
    __HAL_ENABLE_INTERRUPTS(sr);
err:
    return (rc);
}
Exemplo n.º 3
0
/**
 * 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 stm32_hal_spi *spi;
    int sr;

    rc = -1;
    if (!len) {
        goto err;
    }
    STM32_HAL_SPI_RESOLVE(spi_num, spi);
    if (spi->slave) {
        goto err;
    }
    __HAL_DISABLE_INTERRUPTS(sr);
    spi_stat.tx++;
    __HAL_SPI_ENABLE(&spi->handle);
    rc = HAL_SPI_TransmitReceive(&spi->handle, (uint8_t *)txbuf,
                                 (uint8_t *)rxbuf, len,
                                 STM32_HAL_SPI_TIMEOUT);
    __HAL_ENABLE_INTERRUPTS(sr);
    if (rc != HAL_OK) {
        rc = -1;
        goto err;
    }
    rc = 0;
err:
    return rc;
}
Exemplo n.º 4
0
static int
nrf52k_flash_erase_sector(uint32_t sector_address)
{
    int sr;
    int rc = -1;

    if (nrf52k_flash_wait_ready()) {
        return -1;
    }
    __HAL_DISABLE_INTERRUPTS(sr);
    NRF_NVMC->CONFIG |= NVMC_CONFIG_WEN_Een; /* Enable erase OP */
    if (nrf52k_flash_wait_ready()) {
        goto out;
    }

    NRF_NVMC->ERASEPAGE = sector_address;
    if (nrf52k_flash_wait_ready()) {
        goto out;
    }
    rc = 0;
out:
    NRF_NVMC->CONFIG &= ~NVMC_CONFIG_WEN_Een; /* Disable erase OP */
    __HAL_ENABLE_INTERRUPTS(sr);
    return rc;
}
Exemplo n.º 5
0
/**
 * gpio irq disable
 *
 *
 * @param pin
 */
void
gpio_irq_disable(int pin)
{
    uint32_t ctx;
    uint32_t mask;

    mask = GPIO_MASK(pin);
    __HAL_DISABLE_INTERRUPTS(ctx);
    EXTI->IMR &= ~mask;
    __HAL_ENABLE_INTERRUPTS(ctx);
}
Exemplo n.º 6
0
/**
 * gpio irq enable
 *
 * Enable the irq on the specified pin
 *
 * @param pin
 */
void
hal_gpio_irq_enable(int pin)
{
    uint32_t ctx;
    uint32_t mask;

    mask = HAL_GPIO_PIN(pin);

    __HAL_DISABLE_INTERRUPTS(ctx);
    EXTI->IMR |= mask;
    __HAL_ENABLE_INTERRUPTS(ctx);
}
Exemplo n.º 7
0
void
hal_uart_start_tx(int port)
{
    struct hal_uart *u;
    int sr;

    u = &uarts[port];
    __HAL_DISABLE_INTERRUPTS(sr);
    u->u_regs->CR1 &= ~USART_CR1_TCIE;
    u->u_regs->CR1 |= USART_CR1_TXEIE;
    u->u_tx_end = 0;
    __HAL_ENABLE_INTERRUPTS(sr);
}
Exemplo n.º 8
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 stm32_hal_spi *spi;
    int rc = 0;
    int sr;

    STM32_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;
}
Exemplo n.º 9
0
void
os_bsp_systick_init(uint32_t os_ticks_per_sec, int prio)
{
    uint32_t ctx;
    uint32_t mask;
    uint32_t pre_scaler;

    /* Turn on the LFCLK */
    NRF_CLOCK->XTALFREQ = CLOCK_XTALFREQ_XTALFREQ_16MHz;
    NRF_CLOCK->TASKS_LFCLKSTOP = 1;
    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    NRF_CLOCK->LFCLKSRC = CLOCK_LFCLKSRC_SRC_Xtal;
    NRF_CLOCK->TASKS_LFCLKSTART = 1;

    /* Wait here till started! */
    mask = CLOCK_LFCLKSTAT_STATE_Msk | CLOCK_LFCLKSTAT_SRC_Xtal;
    while (1) {
        if (NRF_CLOCK->EVENTS_LFCLKSTARTED) {
            if ((NRF_CLOCK->LFCLKSTAT & mask) == mask) {
                break;
            }
        }
    }

    /* Is this exact frequency obtainable? */
    pre_scaler = (32768 / os_ticks_per_sec) - 1;

    /* disable interrupts */
    __HAL_DISABLE_INTERRUPTS(ctx);

    NRF_RTC0->TASKS_STOP = 1;
    NRF_RTC0->EVENTS_TICK = 0;
    NRF_RTC0->PRESCALER = pre_scaler;
    NRF_RTC0->INTENCLR = 0xffffffff;
    NRF_RTC0->TASKS_CLEAR = 1;

    /* Set isr in vector table and enable interrupt */
    NVIC_SetPriority(RTC0_IRQn, prio);
    NVIC_SetVector(RTC0_IRQn, (uint32_t)rtc0_timer_handler);
    NVIC_EnableIRQ(RTC0_IRQn);

    NRF_RTC0->INTENSET = RTC_INTENSET_TICK_Msk;
    NRF_RTC0->TASKS_START = 1;

    __HAL_ENABLE_INTERRUPTS(ctx);
}
Exemplo n.º 10
0
void
hal_uart_start_rx(int port)
{
    struct hal_uart *u;
    int sr;
    int rc;

    u = &uarts[port];
    if (u->u_rx_stall) {
        __HAL_DISABLE_INTERRUPTS(sr);
        rc = u->u_rx_func(u->u_func_arg, u->u_rx_data);
        if (rc == 0) {
            u->u_rx_stall = 0;
            u->u_regs->CR1 |= USART_CR1_RXNEIE;
        }
        __HAL_ENABLE_INTERRUPTS(sr);
    }
}
Exemplo n.º 11
0
int
hal_spi_abort(int spi_num)
{
    int rc;
    struct stm32_hal_spi *spi;
    int sr;

    rc = 0;
    STM32_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_SPE;
    __HAL_ENABLE_INTERRUPTS(sr);
err:
    return rc;
}
Exemplo n.º 12
0
uint64_t
cputime_get64(void)
{
    uint32_t ctx;
    uint32_t high;
    uint32_t low;
    uint64_t cpu_time;

    __HAL_DISABLE_INTERRUPTS(ctx);
    high = g_cputime.cputime_high;
    low = cputime_get32();
    if (CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_OVERFLOW]) {
        ++high;
        low = cputime_get32();
    }
    __HAL_ENABLE_INTERRUPTS(ctx);

    cpu_time = ((uint64_t)high << 32) | low;

    return cpu_time;
}
Exemplo n.º 13
0
/**
 * 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 stm32_hal_spi *spi;
    int rc;
    int sr;
    int i;

    STM32_HAL_SPI_RESOLVE(spi_num, spi);

    if (spi->slave) {
        rc = 0;
        __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) {
            /*
             * Replaces the current default char in tx buffer register.
             */
            spi->handle.State = HAL_SPI_STATE_READY;
            rc = HAL_SPI_QueueTransmit(&spi->handle, spi->def_char, 2);
            assert(rc == 0);
        }
        __HAL_ENABLE_INTERRUPTS(sr);
    } else {
        rc = -1;
    }
err:
    return rc;
}
Exemplo n.º 14
0
void
os_tick_init(uint32_t os_ticks_per_sec, int prio)
{
    uint32_t ctx;
    uint32_t prescaler_reg;

    /* Make os ticks per sec divides evenly into frequency */
    timer_ticks_per_ostick = MKW41Z_LPTMR_FREQ / os_ticks_per_sec;
    assert((timer_ticks_per_ostick * os_ticks_per_sec) == MKW41Z_LPTMR_FREQ);

    /* disable interrupts */
    __HAL_DISABLE_INTERRUPTS(ctx);

    /* Enable access to LPTMR module. LPTMR is bit 0 */
    SIM->SCGC5 |= 1;

    /* Make sure timer is disabled */
    LPTMR0->CSR = 0;

    /* Set isr in vector table and enable interrupt */
    NVIC_SetPriority(LPTMR0_IRQn, prio);
    NVIC_SetVector(LPTMR0_IRQn, (uint32_t)mkw41z_os_tick_handler);
    NVIC_EnableIRQ(LPTMR0_IRQn);

    /* Set prescaler register. Bypass prescalar and use LPO (clock 1) */
    prescaler_reg = LPTMR_PSR_PBYP_MASK | 1;
    LPTMR0->PSR = prescaler_reg;

    /* Write output compare while disabled */
    LPTMR0->CMR = timer_ticks_per_ostick - 1;

    /* Enable the timer: note you cannot alter bits 5 to 1 (inclusive) */
    LPTMR0->CSR = LPTMR_CSR_TIE_MASK | LPTMR_CSR_TEN_MASK;

    __HAL_ENABLE_INTERRUPTS(ctx);
}
Exemplo n.º 15
0
/*
 * Flash write is done by writing 4 bytes at a time at a word boundary.
 */
static int
nrf52k_flash_write(uint32_t address, const void *src, uint32_t num_bytes)
{
    int sr;
    int rc = -1;
    uint32_t val;
    int cnt;
    uint32_t tmp;

    if (nrf52k_flash_wait_ready()) {
        return -1;
    }
    __HAL_DISABLE_INTERRUPTS(sr);
    NRF_NVMC->CONFIG |= NVMC_CONFIG_WEN_Wen; /* Enable erase OP */
    tmp = address & 0x3;
    if (tmp) {
        if (nrf52k_flash_wait_ready()) {
            goto out;
        }
        /*
         * Starts at a non-word boundary. Read 4 bytes which were there
         * before, update with new data, and write back.
         */
        val = *(uint32_t *)(address & ~0x3);
        cnt = 4 - tmp;
        if (cnt > num_bytes) {
            cnt = num_bytes;
        }
        memcpy((uint8_t *)&val + tmp, src, cnt);
        *(uint32_t *)(address & ~0x3) = val;
        address += cnt;
        num_bytes -= cnt;
        src += cnt;
    }

    while (num_bytes >= sizeof(uint32_t)) {
        /*
         * Write data 4 bytes at a time.
         */
        if (nrf52k_flash_wait_ready()) {
            goto out;
        }
        *(uint32_t *)address = *(uint32_t *)src;
        address += sizeof(uint32_t);
        src += sizeof(uint32_t);
        num_bytes -= sizeof(uint32_t);
    }
    if (num_bytes) {
        /*
         * Deal with the trailing bytes.
         */
        val = *(uint32_t *)address;
        memcpy(&val, src, num_bytes);
        if (nrf52k_flash_wait_ready()) {
            goto out;
        }
        *(uint32_t *)address = val;
    }
    rc = 0;
    if (nrf52k_flash_wait_ready()) {
        goto out;
    }
out:
    NRF_NVMC->CONFIG &= ~NVMC_CONFIG_WEN_Wen;
    __HAL_ENABLE_INTERRUPTS(sr);
    return rc;
}
Exemplo n.º 16
0
/**
 * cputime init
 *
 * Initialize the cputime module. This must be called after os_init is called
 * and before any other timer API are used. This should be called only once
 * and should be called before the hardware timer is used.
 *
 * @param clock_freq The desired cputime frequency, in hertz (Hz).
 *
 * @return int 0 on success; -1 on error.
 */
int
cputime_hw_init(uint32_t clock_freq)
{
    uint32_t ctx;
    uint32_t max_freq;
    uint32_t pre_scaler;

#if defined(HAL_CPUTIME_1MHZ)
    if (clock_freq != 1000000) {
        return -1;
    }
#endif

    /* Clock frequency must be at least 1 MHz */
    if (clock_freq < 1000000U) {
        return -1;
    }

    /* Check if clock frequency exceeds max. range */
    max_freq = NRF51_MAX_TIMER_FREQ;
    if (clock_freq > max_freq) {
        return -1;
    }

    /* Is this exact frequency obtainable? */
    pre_scaler = max_freq / clock_freq;
    if ((pre_scaler * clock_freq) != max_freq) {
        return -1;
    }

    /*
     * Pre-scaler is 4 bits and is a 2^n, so the only possible values that
     * work are 1, 2, 4, 8 and 16, which gives a valid pre-scaler of 0, 1, 2,
     * 3 or 4.
     */
    switch (pre_scaler) {
    case 1:
        pre_scaler = 0;
        break;
    case 2:
        pre_scaler = 1;
        break;
    case 4:
        pre_scaler = 2;
        break;
    case 8:
        pre_scaler = 3;
        break;
    case 16:
        pre_scaler = 4;
        break;
    default:
        pre_scaler = 0xFFFFFFFF;
        break;
    }

    if (pre_scaler == 0xFFFFFFFF) {
        return -1;
    }

    /* disable interrupts */
    __HAL_DISABLE_INTERRUPTS(ctx);

    /* Set the clock frequency */
    g_cputime.ticks_per_usec = clock_freq / 1000000U;

    /* XXX: no way to halt the timer in debug mode that I can see */

    /* Stop the timer first */
    CPUTIMER->TASKS_STOP = 1;

    /* Put the timer in timer mode using 32 bits. */
    CPUTIMER->MODE = TIMER_MODE_MODE_Timer;
    CPUTIMER->BITMODE = TIMER_BITMODE_BITMODE_32Bit;

    /* Set the pre-scaler*/
    CPUTIMER->PRESCALER = pre_scaler;

    /* Start the timer */
    CPUTIMER->TASKS_START = 1;

    /*  Use an output compare to generate an overflow */
#ifdef HAL_CPUTIME_USE_OVERFLOW
    CPUTIMER->CC[CPUTIMER_CC_OVERFLOW] = 0;
    CPUTIMER->EVENTS_COMPARE[CPUTIMER_CC_OVERFLOW] = 0;
    CPUTIMER->INTENSET = CPUTIMER_INT_MASK(CPUTIMER_CC_OVERFLOW);
#endif

    /* Set isr in vector table and enable interrupt */
    NVIC_SetVector(CPUTIMER_IRQ, (uint32_t)cputime_isr);
    NVIC_EnableIRQ(CPUTIMER_IRQ);

    __HAL_ENABLE_INTERRUPTS(ctx);

    return 0;
}
Exemplo n.º 17
0
int
hal_spi_config(int spi_num, struct hal_spi_settings *settings)
{
    struct stm32_hal_spi *spi;
    struct stm32_hal_spi_cfg *cfg;
    SPI_InitTypeDef *init;
    GPIO_InitTypeDef gpio;
    uint32_t gpio_speed;
    IRQn_Type irq;
    uint32_t prescaler;
    int rc;
    int sr;

    __HAL_DISABLE_INTERRUPTS(sr);
    STM32_HAL_SPI_RESOLVE(spi_num, spi);

    init = &spi->handle.Init;

    cfg = spi->cfg;

    if (!spi->slave) {
        spi->handle.Init.NSS = SPI_NSS_HARD_OUTPUT;
        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;

    /* TODO: also VERY_HIGH for STM32L1x */
    if (settings->baudrate <= 2000) {
        gpio_speed = GPIO_SPEED_FREQ_LOW;
    } else if (settings->baudrate <= 12500) {
        gpio_speed = GPIO_SPEED_FREQ_MEDIUM;
    } else {
        gpio_speed = GPIO_SPEED_FREQ_HIGH;
    }

    /* Enable the clocks for this SPI */
    switch (spi_num) {
#if SPI_0_ENABLED
    case 0:
        __HAL_RCC_SPI1_CLK_ENABLE();
#if !defined(STM32F1)
        gpio.Alternate = GPIO_AF5_SPI1;
#endif
        spi->handle.Instance = SPI1;
        break;
#endif
#if SPI_1_ENABLED
    case 1:
        __HAL_RCC_SPI2_CLK_ENABLE();
#if !defined(STM32F1)
        gpio.Alternate = GPIO_AF5_SPI2;
#endif
        spi->handle.Instance = SPI2;
        break;
#endif
#if SPI_2_ENABLED
    case 2:
        __HAL_RCC_SPI3_CLK_ENABLE();
#if !defined(STM32F1)
        gpio.Alternate = GPIO_AF6_SPI3;
#endif
        spi->handle.Instance = SPI3;
        break;
#endif
#if SPI_3_ENABLED
    case 3:
        __HAL_RCC_SPI4_CLK_ENABLE();
#if !defined(STM32F1)
        gpio.Alternate = GPIO_AF5_SPI4;
#endif
        spi->handle.Instance = SPI4;
        break;
#endif
#if SPI_4_ENABLED
    case 4:
        __HAL_RCC_SPI5_CLK_ENABLE();
#if !defined(STM32F1)
        gpio.Alternate = GPIO_AF5_SPI5;
#endif
        spi->handle.Instance = SPI5;
        break;
#endif
#if SPI_5_ENABLED
    case 5:
        __HAL_RCC_SPI6_CLK_ENABLE();
#if !defined(STM32F1)
        gpio.Alternate = GPIO_AF5_SPI6;
#endif
        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;
        }
    }

    /* NOTE: Errata ES0125: STM32L100x6/8/B, STM32L151x6/8/B and
     * STM32L152x6/8/B ultra-low-power device limitations.
     *
     * 2.6.6 - Corrupted last bit of data and or CRC, received in Master
     * mode with delayed SCK feedback
     *
     * This driver is always using very high speed for SCK on STM32L1x
     */

#if defined(STM32L152xC)
    if (!spi->slave) {
        gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    } else {
        gpio.Speed = gpio_speed;
    }
#else
    gpio.Speed = gpio_speed;
#endif

    rc = hal_gpio_init_stm(cfg->sck_pin, &gpio);
    if (rc != 0) {
        goto err;
    }

#if defined(STM32L152xC)
    if (!spi->slave) {
        gpio.Speed = gpio_speed;
    }
#endif

    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 = stm32_spi_resolve_prescaler(spi_num, settings->baudrate * 1000, &prescaler);
    if (rc != 0) {
        goto err;
    }

    init->BaudRatePrescaler = prescaler;

    /* Add default values */
    init->Direction = SPI_DIRECTION_2LINES;
    init->TIMode = SPI_TIMODE_DISABLE;
    init->CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    init->CRCPolynomial = 1;
#ifdef SPI_NSS_PULSE_DISABLE
    init->NSSPMode = SPI_NSS_PULSE_DISABLE;
#endif

    irq = stm32_resolve_spi_irq(&spi->handle);
    NVIC_SetPriority(irq, cfg->irq_prio);
    NVIC_SetVector(irq, stm32_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) {
        hal_spi_slave_set_def_tx_val(spi_num, 0);
        rc = hal_gpio_irq_init(cfg->ss_pin, spi_ss_isr, spi, HAL_GPIO_TRIG_BOTH,
                               HAL_GPIO_PULL_UP);
        spi_ss_isr(spi);
    }
    __HAL_ENABLE_INTERRUPTS(sr);
    return (0);
err:
    __HAL_ENABLE_INTERRUPTS(sr);
    return (rc);
}