mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
523 lines
18 KiB
C
523 lines
18 KiB
C
/*
|
|
* SPDX-License-Identifier: MIT
|
|
*
|
|
* Copyright (C) 2013-2024 OpenMV, LLC.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*
|
|
* OMV SPI port for stm32.
|
|
*/
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include STM32_HAL_H
|
|
#include "py/mphal.h"
|
|
|
|
#include "omv_boardconfig.h"
|
|
#include "irq.h"
|
|
#include "omv_common.h"
|
|
#include "stm_dma.h"
|
|
#include "omv_gpio.h"
|
|
#include "omv_spi.h"
|
|
|
|
// If an SPI handle is already defined in MicroPython, reuse that handle to allow
|
|
// MicroPython to process the SPI IRQ, otherwise define the IRQ handler and its handle.
|
|
#define DEFINE_SPI_INSTANCE(n) \
|
|
static SPI_HandleTypeDef SPIHandle##n; \
|
|
void SPI##n##_IRQHandler(void) { HAL_SPI_IRQHandler(&SPIHandle##n); }
|
|
|
|
#if defined(OMV_SPI1_ID) && defined(MICROPY_HW_SPI1_SCK)
|
|
extern SPI_HandleTypeDef SPIHandle1;
|
|
#elif defined(OMV_SPI1_ID)
|
|
DEFINE_SPI_INSTANCE(1)
|
|
#endif
|
|
|
|
#if defined(OMV_SPI2_ID) && defined(MICROPY_HW_SPI2_SCK)
|
|
extern SPI_HandleTypeDef SPIHandle2;
|
|
#elif defined(OMV_SPI2_ID)
|
|
DEFINE_SPI_INSTANCE(2)
|
|
#endif
|
|
|
|
#if defined(OMV_SPI3_ID) && defined(MICROPY_HW_SPI3_SCK)
|
|
extern SPI_HandleTypeDef SPIHandle3;
|
|
#elif defined(OMV_SPI3_ID)
|
|
DEFINE_SPI_INSTANCE(3)
|
|
#endif
|
|
|
|
#if defined(OMV_SPI4_ID) && defined(MICROPY_HW_SPI4_SCK)
|
|
extern SPI_HandleTypeDef SPIHandle4;
|
|
#elif defined(OMV_SPI4_ID)
|
|
DEFINE_SPI_INSTANCE(4)
|
|
#endif
|
|
|
|
#if defined(OMV_SPI5_ID) && defined(MICROPY_HW_SPI5_SCK)
|
|
extern SPI_HandleTypeDef SPIHandle5;
|
|
#elif defined(OMV_SPI5_ID)
|
|
DEFINE_SPI_INSTANCE(5)
|
|
#endif
|
|
|
|
#if defined(OMV_SPI6_ID) && defined(MICROPY_HW_SPI6_SCK)
|
|
extern SPI_HandleTypeDef SPIHandle6;
|
|
#elif defined(OMV_SPI6_ID)
|
|
DEFINE_SPI_INSTANCE(6)
|
|
#endif
|
|
|
|
#define INITIALIZE_SPI_DESCR(spi, spi_number) \
|
|
do { \
|
|
(spi)->id = spi_number; \
|
|
(spi)->irqn = SPI##spi_number##_IRQn; \
|
|
(spi)->cs = OMV_SPI##spi_number##_SSEL_PIN; \
|
|
(spi)->descr = &SPIHandle##spi_number; \
|
|
(spi)->descr->Instance = SPI##spi_number; \
|
|
(spi)->dma_descr_tx = (DMA_HandleTypeDef) \
|
|
{ OMV_SPI##spi_number##_DMA_TX_CHANNEL, { OMV_SPI##spi_number##_DMA_TX_REQUEST } }; \
|
|
(spi)->dma_descr_rx = (DMA_HandleTypeDef) \
|
|
{ OMV_SPI##spi_number##_DMA_RX_CHANNEL, { OMV_SPI##spi_number##_DMA_RX_REQUEST } }; \
|
|
} while (0)
|
|
|
|
|
|
#ifndef OMV_SPI_DMA_XFER_PORTS
|
|
#define OMV_SPI_DMA_XFER_PORTS (0)
|
|
#endif
|
|
|
|
static omv_spi_t *omv_spi_descr_all[6] = { NULL };
|
|
#if defined(STM32N6)
|
|
static DMA_NodeTypeDef OMV_ATTR_SECTION(OMV_ATTR_ALIGNED(omv_dma_nodes_all[6 * 2], 32), OMV_VOSPI_DMA_BUFFER);
|
|
#endif
|
|
|
|
static uint32_t omv_spi_clocksource(SPI_TypeDef *spi) {
|
|
#if defined(STM32F4) || defined(STM32F7)
|
|
if (spi == SPI2) {
|
|
// SPI2 is on APB1
|
|
return HAL_RCC_GetPCLK1Freq();
|
|
} else if (spi == SPI3) {
|
|
// SPI3 is on APB1
|
|
return HAL_RCC_GetPCLK1Freq();
|
|
} else {
|
|
// SPI1, SPI4, SPI5 and SPI6 are on APB2
|
|
return HAL_RCC_GetPCLK2Freq();
|
|
}
|
|
#elif defined(STM32H7)
|
|
if (spi == SPI1 || spi == SPI2 || spi == SPI3) {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123);
|
|
} else if (spi == SPI4 || spi == SPI5) {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI45);
|
|
} else {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6);
|
|
}
|
|
#elif defined(STM32N6)
|
|
if (spi == SPI1) {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI1);
|
|
} else if (spi == SPI2) {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI2);
|
|
} else if (spi == SPI3) {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI3);
|
|
} else if (spi == SPI4) {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI4);
|
|
} else if (spi == SPI5) {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI5);
|
|
} else {
|
|
return HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI6);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static int omv_spi_prescaler(SPI_TypeDef *spi, uint32_t baudrate) {
|
|
const uint32_t prescalers[] = {
|
|
SPI_BAUDRATEPRESCALER_2,
|
|
SPI_BAUDRATEPRESCALER_4,
|
|
SPI_BAUDRATEPRESCALER_8,
|
|
SPI_BAUDRATEPRESCALER_16,
|
|
SPI_BAUDRATEPRESCALER_32,
|
|
SPI_BAUDRATEPRESCALER_64,
|
|
SPI_BAUDRATEPRESCALER_128,
|
|
SPI_BAUDRATEPRESCALER_256
|
|
};
|
|
|
|
uint32_t clksource = omv_spi_clocksource(spi);
|
|
|
|
for (size_t i = 0; i < OMV_ARRAY_SIZE(prescalers); i++) {
|
|
uint32_t target = clksource / ((2 << i));
|
|
if (target <= baudrate) {
|
|
return prescalers[i];
|
|
}
|
|
}
|
|
|
|
return SPI_BAUDRATEPRESCALER_256;
|
|
}
|
|
|
|
static void omv_spi_callback(SPI_HandleTypeDef *hspi) {
|
|
omv_spi_t *spi = NULL;
|
|
if (0) {
|
|
#if defined(OMV_SPI1_ID)
|
|
} else if (hspi->Instance == SPI1) {
|
|
spi = omv_spi_descr_all[0];
|
|
#endif
|
|
#if defined(OMV_SPI2_ID)
|
|
} else if (hspi->Instance == SPI2) {
|
|
spi = omv_spi_descr_all[1];
|
|
#endif
|
|
#if defined(OMV_SPI3_ID)
|
|
} else if (hspi->Instance == SPI3) {
|
|
spi = omv_spi_descr_all[2];
|
|
#endif
|
|
#if defined(OMV_SPI4_ID)
|
|
} else if (hspi->Instance == SPI4) {
|
|
spi = omv_spi_descr_all[3];
|
|
#endif
|
|
#if defined(OMV_SPI5_ID)
|
|
} else if (hspi->Instance == SPI5) {
|
|
spi = omv_spi_descr_all[4];
|
|
#endif
|
|
#if defined(OMV_SPI6_ID)
|
|
} else if (hspi->Instance == SPI6) {
|
|
spi = omv_spi_descr_all[5];
|
|
#endif
|
|
}
|
|
|
|
if (spi == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (hspi->ErrorCode != HAL_SPI_ERROR_NONE) {
|
|
spi->xfer_flags |= OMV_SPI_XFER_FAILED;
|
|
spi->xfer_error = hspi->ErrorCode;
|
|
omv_spi_transfer_abort(spi);
|
|
} else {
|
|
spi->xfer_flags |= OMV_SPI_XFER_COMPLETE;
|
|
}
|
|
|
|
if (spi->callback) {
|
|
uint8_t *buf = (uint8_t *) (spi->descr->pRxBuffPtr ? spi->descr->pRxBuffPtr : spi->descr->pTxBuffPtr);
|
|
if (spi->dma_flags & OMV_SPI_DMA_DOUBLE) {
|
|
if (spi->xfer_flags & OMV_SPI_XFER_HALF) {
|
|
uint32_t size = spi->descr->RxXferSize ? spi->descr->RxXferSize : spi->descr->TxXferSize;
|
|
buf += (size * ((spi->descr->Init.DataSize == SPI_DATASIZE_8BIT) ? 1 : 2)) / 2;
|
|
}
|
|
spi->xfer_flags ^= OMV_SPI_XFER_HALF;
|
|
}
|
|
spi->callback(spi, spi->userdata, buf);
|
|
}
|
|
}
|
|
|
|
int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer) {
|
|
// No TX transfers in circular or double buffer mode.
|
|
if (xfer->txbuf && (spi->dma_flags & (OMV_SPI_DMA_CIRCULAR | OMV_SPI_DMA_DOUBLE))) {
|
|
return -1;
|
|
}
|
|
|
|
spi->callback = xfer->callback;
|
|
spi->userdata = xfer->userdata;
|
|
spi->xfer_error = 0;
|
|
spi->xfer_flags = xfer->flags;
|
|
|
|
spi->xfer_flags &= ~(OMV_SPI_XFER_FAILED | OMV_SPI_XFER_COMPLETE | OMV_SPI_XFER_HALF);
|
|
|
|
if (spi->xfer_flags & OMV_SPI_XFER_BLOCKING) {
|
|
if (xfer->txbuf && xfer->rxbuf) {
|
|
if (HAL_SPI_TransmitReceive(spi->descr, xfer->txbuf,
|
|
xfer->rxbuf, xfer->size, xfer->timeout) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
} else if (xfer->txbuf) {
|
|
if (HAL_SPI_Transmit(spi->descr, xfer->txbuf, xfer->size, xfer->timeout) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
} else if (xfer->rxbuf) {
|
|
if (HAL_SPI_Receive(spi->descr, xfer->rxbuf, xfer->size, xfer->timeout) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
}
|
|
} else if (spi->xfer_flags & OMV_SPI_XFER_NONBLOCK) {
|
|
if (xfer->txbuf && xfer->rxbuf) {
|
|
if (HAL_SPI_TransmitReceive_IT(spi->descr, xfer->txbuf,
|
|
xfer->rxbuf, xfer->size) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
} else if (xfer->txbuf) {
|
|
if (HAL_SPI_Transmit_IT(spi->descr, xfer->txbuf, xfer->size) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
} else if (xfer->rxbuf) {
|
|
if (HAL_SPI_Receive_IT(spi->descr, xfer->rxbuf, xfer->size) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
}
|
|
} else if (spi->xfer_flags & OMV_SPI_XFER_DMA) {
|
|
if (xfer->txbuf && xfer->rxbuf) {
|
|
if (HAL_SPI_TransmitReceive_DMA(spi->descr, xfer->txbuf,
|
|
xfer->rxbuf, xfer->size) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
} else if (xfer->txbuf) {
|
|
if (HAL_SPI_Transmit_DMA(spi->descr, xfer->txbuf, xfer->size) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
} else if (xfer->rxbuf) {
|
|
if (HAL_SPI_Receive_DMA(spi->descr, xfer->rxbuf, xfer->size) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
}
|
|
} else {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int omv_spi_transfer_abort(omv_spi_t *spi) {
|
|
if (spi && spi->initialized) {
|
|
if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk) {
|
|
HAL_SPI_Abort_IT(spi->descr);
|
|
} else {
|
|
HAL_SPI_Abort(spi->descr);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction, omv_spi_config_t *config) {
|
|
DMA_HandleTypeDef *dma_descr = NULL;
|
|
|
|
if (direction == DMA_MEMORY_TO_PERIPH) {
|
|
dma_descr = &spi->dma_descr_tx;
|
|
} else {
|
|
dma_descr = &spi->dma_descr_rx;
|
|
}
|
|
|
|
#if defined(STM32N6)
|
|
DMA_NodeTypeDef *dma_nodes = NULL;
|
|
DMA_QListTypeDef *dma_queue = NULL;
|
|
|
|
if (direction == DMA_MEMORY_TO_PERIPH) {
|
|
dma_queue = &spi->dma_queue_tx;
|
|
dma_nodes = &omv_dma_nodes_all[(spi->id - 1) * 2 + 0];
|
|
} else {
|
|
dma_queue = &spi->dma_queue_rx;
|
|
dma_nodes = &omv_dma_nodes_all[(spi->id - 1) * 2 + 1];
|
|
}
|
|
#endif
|
|
|
|
uint32_t ssize = 4;
|
|
uint32_t dsize = 4;
|
|
|
|
#if defined(STM32F4) || defined(STM32F7)
|
|
ssize = config->datasize / 8;
|
|
#endif
|
|
|
|
#if defined(STM32H7) || defined(STM32N6)
|
|
uint32_t request = dma_descr->Init.Request;
|
|
#else
|
|
uint32_t request = dma_descr->Init.Channel;
|
|
#endif
|
|
|
|
bool circular = config->dma_flags & OMV_SPI_DMA_CIRCULAR;
|
|
|
|
// Initialize DMA.
|
|
if (stm_dma_init(dma_descr, dma_descr->Instance, request, direction, ssize,
|
|
dsize, OMV_SPI_DMA_XFER_PORTS, &stm_dma_spi_init, circular)) {
|
|
return -1;
|
|
}
|
|
|
|
#if defined(STM32N6)
|
|
if (circular) {
|
|
// Initialize DMA in circular mode.
|
|
if (stm_dma_ll_init(dma_descr, dma_queue, dma_nodes, 1, OMV_SPI_DMA_LIST_PORTS)) {
|
|
return -1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
// Link the DMA handle to SPI handle.
|
|
if (direction == DMA_MEMORY_TO_PERIPH) {
|
|
__HAL_LINKDMA(spi->descr, hdmatx, spi->dma_descr_tx);
|
|
} else {
|
|
__HAL_LINKDMA(spi->descr, hdmarx, spi->dma_descr_rx);
|
|
}
|
|
|
|
// Set the SPI handle used by the DMA channel's IRQ handler.
|
|
stm_dma_set_irq_descr(dma_descr->Instance, dma_descr);
|
|
|
|
// Get DMA channel's IRQ number.
|
|
uint8_t dma_irqn = stm_dma_channel_to_irqn(dma_descr->Instance);
|
|
|
|
// Configure and enable DMA IRQ channel.
|
|
NVIC_SetPriority(dma_irqn, IRQ_PRI_DMA);
|
|
HAL_NVIC_EnableIRQ(dma_irqn);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int omv_spi_bus_init(omv_spi_t *spi, omv_spi_config_t *config) {
|
|
SPI_HandleTypeDef *spi_descr = spi->descr;
|
|
|
|
spi_descr->Init.Mode = config->spi_mode;
|
|
spi_descr->Init.TIMode = SPI_TIMODE_DISABLE;
|
|
spi_descr->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
|
|
spi_descr->Init.NSS = (config->nss_enable == false) ? SPI_NSS_SOFT : SPI_NSS_HARD_OUTPUT;
|
|
spi_descr->Init.DataSize = (config->datasize == 8) ? SPI_DATASIZE_8BIT : SPI_DATASIZE_16BIT;
|
|
spi_descr->Init.FirstBit = config->bit_order;
|
|
spi_descr->Init.CLKPhase = config->clk_pha;
|
|
spi_descr->Init.CLKPolarity = config->clk_pol;
|
|
spi_descr->Init.BaudRatePrescaler = omv_spi_prescaler(spi_descr->Instance, config->baudrate);
|
|
#if defined(STM32F7) || defined(STM32H7) || defined(STM32N6)
|
|
spi_descr->Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
|
|
#if defined(STM32H7) || defined(STM32N6)
|
|
spi_descr->Init.NSSPolarity = (config->nss_pol == 0) ? SPI_NSS_POLARITY_LOW : SPI_NSS_POLARITY_HIGH;
|
|
spi_descr->Init.FifoThreshold = SPI_FIFO_THRESHOLD_04DATA;
|
|
spi_descr->Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
|
|
spi_descr->Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
|
|
spi_descr->Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
|
|
spi_descr->Init.MasterKeepIOState = (config->data_retained == true) ?
|
|
SPI_MASTER_KEEP_IO_STATE_ENABLE : SPI_MASTER_KEEP_IO_STATE_DISABLE;
|
|
spi_descr->Init.IOSwap = SPI_IO_SWAP_DISABLE;
|
|
#endif
|
|
#endif
|
|
|
|
// Configure bus direction.
|
|
if (config->bus_mode == OMV_SPI_BUS_TX_RX) {
|
|
spi_descr->Init.Direction = SPI_DIRECTION_2LINES;
|
|
} else if (config->bus_mode == OMV_SPI_BUS_RX) {
|
|
spi_descr->Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
|
|
} else {
|
|
#if defined(STM32H7) || defined(STM32N6)
|
|
spi_descr->Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
|
|
#else
|
|
spi_descr->Init.Direction = SPI_DIRECTION_1LINE;
|
|
#endif
|
|
}
|
|
|
|
if (HAL_SPI_Init(spi_descr) != HAL_OK) {
|
|
HAL_SPI_DeInit(spi_descr);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config) {
|
|
memset(spi, 0, sizeof(omv_spi_t));
|
|
|
|
if (0) {
|
|
#if defined(OMV_SPI1_ID)
|
|
} else if (config->id == 1) {
|
|
INITIALIZE_SPI_DESCR(spi, 1);
|
|
#endif
|
|
#if defined(OMV_SPI2_ID)
|
|
} else if (config->id == 2) {
|
|
INITIALIZE_SPI_DESCR(spi, 2);
|
|
#endif
|
|
#if defined(OMV_SPI3_ID)
|
|
} else if (config->id == 3) {
|
|
INITIALIZE_SPI_DESCR(spi, 3);
|
|
#endif
|
|
#if defined(OMV_SPI4_ID)
|
|
} else if (config->id == 4) {
|
|
INITIALIZE_SPI_DESCR(spi, 4);
|
|
#endif
|
|
#if defined(OMV_SPI5_ID)
|
|
} else if (config->id == 5) {
|
|
INITIALIZE_SPI_DESCR(spi, 5);
|
|
#endif
|
|
#if defined(OMV_SPI6_ID)
|
|
} else if (config->id == 6) {
|
|
INITIALIZE_SPI_DESCR(spi, 6);
|
|
#endif
|
|
} else {
|
|
return -1;
|
|
}
|
|
|
|
if (omv_spi_bus_init(spi, config) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
if (config->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) {
|
|
int ret = 0;
|
|
if (config->bus_mode & OMV_SPI_BUS_TX) {
|
|
ret |= omv_spi_dma_init(spi, DMA_MEMORY_TO_PERIPH, config);
|
|
}
|
|
if (config->bus_mode & OMV_SPI_BUS_RX) {
|
|
ret |= omv_spi_dma_init(spi, DMA_PERIPH_TO_MEMORY, config);
|
|
}
|
|
if (ret != 0) {
|
|
return -1;
|
|
}
|
|
}
|
|
// Configure and enable SPI IRQ channel.
|
|
NVIC_SetPriority(spi->irqn, IRQ_PRI_SPI);
|
|
HAL_NVIC_EnableIRQ(spi->irqn);
|
|
|
|
// Install TX/RX callbacks even if DMA mode is not enabled for non-blocking transfers.
|
|
HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_RX_COMPLETE_CB_ID, omv_spi_callback);
|
|
HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_COMPLETE_CB_ID, omv_spi_callback);
|
|
HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_COMPLETE_CB_ID, omv_spi_callback);
|
|
if (config->dma_flags & OMV_SPI_DMA_DOUBLE) {
|
|
HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_RX_HALF_COMPLETE_CB_ID, omv_spi_callback);
|
|
HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_HALF_COMPLETE_CB_ID, omv_spi_callback);
|
|
HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_HALF_COMPLETE_CB_ID, omv_spi_callback);
|
|
}
|
|
|
|
spi->initialized = true;
|
|
spi->dma_flags = config->dma_flags;
|
|
omv_spi_descr_all[config->id - 1] = spi;
|
|
return 0;
|
|
}
|
|
|
|
int omv_spi_deinit(omv_spi_t *spi) {
|
|
if (spi && spi->initialized) {
|
|
spi->initialized = false;
|
|
omv_spi_descr_all[spi->id - 1] = NULL;
|
|
omv_spi_transfer_abort(spi);
|
|
if (spi->dma_flags & (OMV_SPI_DMA_NORMAL | OMV_SPI_DMA_CIRCULAR)) {
|
|
if (spi->descr->hdmatx != NULL) {
|
|
HAL_DMA_Abort(spi->descr->hdmatx);
|
|
}
|
|
if (spi->descr->hdmarx != NULL) {
|
|
HAL_DMA_Abort(spi->descr->hdmarx);
|
|
}
|
|
}
|
|
HAL_SPI_DeInit(spi->descr);
|
|
HAL_NVIC_DisableIRQ(spi->irqn);
|
|
// Deinit the CS pin here versus in HAL_SPI_MspDeInit which is shared code.
|
|
omv_gpio_deinit(spi->cs);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// This function is only needed for the py_tv driver on the RT1060 to slow down the SPI bus on reads.
|
|
// The STM32 is capable of reading data on the SPI bus at high speeds without issues...
|
|
int omv_spi_set_baudrate(omv_spi_t *spi, uint32_t baudrate) {
|
|
return 0;
|
|
}
|
|
|
|
int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id) {
|
|
config->id = bus_id;
|
|
config->baudrate = 10000000;
|
|
config->datasize = 8;
|
|
config->spi_mode = OMV_SPI_MODE_MASTER;
|
|
config->bus_mode = OMV_SPI_BUS_TX_RX;
|
|
config->bit_order = OMV_SPI_MSB_FIRST;
|
|
config->clk_pol = OMV_SPI_CPOL_LOW;
|
|
config->clk_pha = OMV_SPI_CPHA_1EDGE;
|
|
config->nss_pol = OMV_SPI_NSS_LOW;
|
|
config->nss_enable = true;
|
|
config->dma_flags = 0;
|
|
config->data_retained = true;
|
|
return 0;
|
|
}
|