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; +}