mirror of
https://github.com/openmv/openmv.git
synced 2025-11-04 14:49:50 +08:00
hal/omv: Add SPI HAL.
This commit is contained in:
parent
57842a7eb4
commit
28f808f54f
79
src/omv/common/omv_spi.h
Normal file
79
src/omv/common/omv_spi.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
*
|
||||
* Copyright (c) 2013-2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||
* Copyright (c) 2013-2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||
*
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* SPI bus abstraction layer.
|
||||
*/
|
||||
#ifndef __OMV_SPI_H__
|
||||
#define __OMV_SPI_H__
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "omv_portconfig.h"
|
||||
|
||||
// Config options are defined in ports so they can be used
|
||||
// directly to initialize peripherals without remapping them.
|
||||
typedef enum {
|
||||
OMV_SPI_XFER_DMA = (1 << 0),
|
||||
OMV_SPI_XFER_BLOCKING = (1 << 1),
|
||||
OMV_SPI_XFER_NONBLOCK = (1 << 2),
|
||||
OMV_SPI_XFER_CIRCULAR = (1 << 3),
|
||||
OMV_SPI_XFER_FAILED = (1 << 4),
|
||||
} omv_spi_xfer_flags_t;
|
||||
|
||||
typedef struct _omv_spi_config {
|
||||
uint8_t id;
|
||||
uint32_t baudrate;
|
||||
uint8_t datasize;
|
||||
uint32_t spi_mode;
|
||||
uint32_t bus_mode;
|
||||
uint32_t bit_order;
|
||||
uint32_t clk_pol;
|
||||
uint32_t clk_pha;
|
||||
uint32_t nss_pol;
|
||||
bool nss_enable;
|
||||
bool dma_enable;
|
||||
bool data_retained;
|
||||
} omv_spi_config_t;
|
||||
|
||||
typedef struct _omv_spi omv_spi_t;
|
||||
|
||||
typedef void (*omv_spi_callback_t)(omv_spi_t *spi, void *data);
|
||||
|
||||
typedef struct _omv_spi_transfer {
|
||||
void *txbuf;
|
||||
void *rxbuf;
|
||||
uint32_t size;
|
||||
uint32_t timeout;
|
||||
omv_spi_xfer_flags_t flags;
|
||||
void *userdata;
|
||||
omv_spi_callback_t callback;
|
||||
} omv_spi_transfer_t;
|
||||
|
||||
typedef struct _omv_spi {
|
||||
uint8_t id;
|
||||
bool initialized;
|
||||
bool dma_enabled;
|
||||
omv_gpio_t cs; // For soft-NSS mode.
|
||||
void *userdata;
|
||||
omv_spi_callback_t callback;
|
||||
uint32_t xfer_error;
|
||||
omv_spi_xfer_flags_t xfer_flags;
|
||||
#ifdef OMV_SPI_PORT_BITS
|
||||
// Additional port-specific fields like device base pointer,
|
||||
// dma handles, more I/Os etc... are included directly here,
|
||||
// so that they can be accessible from this struct.
|
||||
OMV_SPI_PORT_BITS
|
||||
#endif
|
||||
} omv_spi_t;
|
||||
|
||||
int omv_spi_init(omv_spi_t *spi, omv_spi_config_t *config);
|
||||
// Default config: MASTER | FDX | 10MHz | 8 bits | MSB FIRST | NSS HARD | NSS/CPHA/CPOL LOW.
|
||||
int omv_spi_default_config(omv_spi_config_t *config, uint32_t bus_id);
|
||||
int omv_spi_deinit(omv_spi_t *spi);
|
||||
int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer);
|
||||
int omv_spi_transfer_abort(omv_spi_t *spi);
|
||||
#endif // __OMV_SPI_H__
|
||||
@ -62,4 +62,31 @@ typedef const stm32_gpio_t *omv_gpio_t;
|
||||
// IRQ handlers, if this I2C is enabled in Micropython, or defined and handled in stm32fxxx_hal_msp.c.
|
||||
typedef I2C_HandleTypeDef *omv_i2c_dev_t;
|
||||
|
||||
#define OMV_SPI_MODE_SLAVE (SPI_MODE_SLAVE)
|
||||
#define OMV_SPI_MODE_MASTER (SPI_MODE_MASTER)
|
||||
|
||||
#define OMV_SPI_LSB_FIRST (SPI_FIRSTBIT_LSB)
|
||||
#define OMV_SPI_MSB_FIRST (SPI_FIRSTBIT_MSB)
|
||||
|
||||
#define OMV_SPI_BUS_TX (1 << 0)
|
||||
#define OMV_SPI_BUS_RX (1 << 1)
|
||||
#define OMV_SPI_BUS_TX_RX (OMV_SPI_BUS_TX | OMV_SPI_BUS_RX)
|
||||
|
||||
#define OMV_SPI_CPOL_LOW (SPI_POLARITY_LOW)
|
||||
#define OMV_SPI_CPOL_HIGH (SPI_POLARITY_HIGH)
|
||||
|
||||
#define OMV_SPI_CPHA_1EDGE (SPI_PHASE_1EDGE)
|
||||
#define OMV_SPI_CPHA_2EDGE (SPI_PHASE_2EDGE)
|
||||
|
||||
#define OMV_SPI_NSS_LOW (0)
|
||||
#define OMV_SPI_NSS_HIGH (1)
|
||||
|
||||
#define OMV_SPI_PORT_BITS \
|
||||
struct { \
|
||||
IRQn_Type irqn; \
|
||||
SPI_HandleTypeDef *descr; \
|
||||
DMA_HandleTypeDef dma_descr_tx; \
|
||||
DMA_HandleTypeDef dma_descr_rx; \
|
||||
};
|
||||
|
||||
#endif // __OMV_PORTCONFIG_H__
|
||||
|
||||
@ -569,6 +569,7 @@ UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/ports/stm32/,\
|
||||
dma_utils.o \
|
||||
omv_gpio.o \
|
||||
omv_i2c.o \
|
||||
omv_spi.o \
|
||||
)
|
||||
|
||||
UVC_OBJ += $(wildcard $(BUILD)/$(LEPTON_DIR)/src/*.o)
|
||||
|
||||
400
src/omv/ports/stm32/omv_spi.c
Normal file
400
src/omv/ports/stm32/omv_spi.c
Normal file
@ -0,0 +1,400 @@
|
||||
/*
|
||||
* This file is part of the OpenMV project.
|
||||
*
|
||||
* Copyright (c) 2023 Ibrahim Abdelkader <iabdalkader@openmv.io>
|
||||
* Copyright (c) 2023 Kwabena W. Agyeman <kwagyeman@openmv.io>
|
||||
*
|
||||
* This work is licensed under the MIT license, see the file LICENSE for details.
|
||||
*
|
||||
* OMV SPI port for stm32.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include STM32_HAL_H
|
||||
#include "py/mphal.h"
|
||||
|
||||
#include "omv_boardconfig.h"
|
||||
#include "irq.h"
|
||||
#include "common.h"
|
||||
#include "dma_utils.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(SPI1_ID) && defined(MICROPY_HW_SPI1_SCK)
|
||||
extern SPI_HandleTypeDef SPIHandle1;
|
||||
#elif defined(SPI1_ID)
|
||||
DEFINE_SPI_INSTANCE(1)
|
||||
#endif
|
||||
|
||||
#if defined(SPI2_ID) && defined(MICROPY_HW_SPI2_SCK)
|
||||
extern SPI_HandleTypeDef SPIHandle2;
|
||||
#elif defined(SPI2_ID)
|
||||
DEFINE_SPI_INSTANCE(2)
|
||||
#endif
|
||||
|
||||
#if defined(SPI3_ID) && defined(MICROPY_HW_SPI3_SCK)
|
||||
extern SPI_HandleTypeDef SPIHandle3;
|
||||
#elif defined(SPI3_ID)
|
||||
DEFINE_SPI_INSTANCE(3)
|
||||
#endif
|
||||
|
||||
#if defined(SPI4_ID) && defined(MICROPY_HW_SPI4_SCK)
|
||||
extern SPI_HandleTypeDef SPIHandle4;
|
||||
#elif defined(SPI4_ID)
|
||||
DEFINE_SPI_INSTANCE(4)
|
||||
#endif
|
||||
|
||||
#if defined(SPI5_ID) && defined(MICROPY_HW_SPI5_SCK)
|
||||
extern SPI_HandleTypeDef SPIHandle5;
|
||||
#elif defined(SPI5_ID)
|
||||
DEFINE_SPI_INSTANCE(5)
|
||||
#endif
|
||||
|
||||
#if defined(SPI6_ID) && defined(MICROPY_HW_SPI6_SCK)
|
||||
extern SPI_HandleTypeDef SPIHandle6;
|
||||
#elif defined(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 = SPI##spi_number##_SSEL_PIN; \
|
||||
(spi)->descr = &SPIHandle##spi_number; \
|
||||
(spi)->descr->Instance = SPI##spi_number; \
|
||||
(spi)->dma_descr_tx = (DMA_HandleTypeDef) \
|
||||
{SPI##spi_number##_DMA_TX_CHANNEL, {DMA_REQUEST_SPI##spi_number##_TX}};\
|
||||
(spi)->dma_descr_rx = (DMA_HandleTypeDef) \
|
||||
{SPI##spi_number##_DMA_RX_CHANNEL, {DMA_REQUEST_SPI##spi_number##_RX}};\
|
||||
} while(0)
|
||||
|
||||
static omv_spi_t *omv_spi_descr_all[6] = { NULL };
|
||||
|
||||
static uint32_t omv_spi_clocksource(SPI_TypeDef *spi) {
|
||||
#if defined(MCU_SERIES_H7)
|
||||
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);
|
||||
}
|
||||
#else
|
||||
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();
|
||||
}
|
||||
#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(SPI1_ID)
|
||||
} else if (hspi->Instance == SPI1) {
|
||||
spi = omv_spi_descr_all[0];
|
||||
#endif
|
||||
#if defined(SPI2_ID)
|
||||
} else if (hspi->Instance == SPI2) {
|
||||
spi = omv_spi_descr_all[1];
|
||||
#endif
|
||||
#if defined(SPI3_ID)
|
||||
} else if (hspi->Instance == SPI3) {
|
||||
spi = omv_spi_descr_all[2];
|
||||
#endif
|
||||
#if defined(SPI4_ID)
|
||||
} else if (hspi->Instance == SPI4) {
|
||||
spi = omv_spi_descr_all[3];
|
||||
#endif
|
||||
#if defined(SPI5_ID)
|
||||
} else if (hspi->Instance == SPI5) {
|
||||
spi = omv_spi_descr_all[4];
|
||||
#endif
|
||||
#if defined(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);
|
||||
}
|
||||
|
||||
if (spi->callback) {
|
||||
spi->callback(spi, spi->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
int omv_spi_transfer_start(omv_spi_t *spi, omv_spi_transfer_t *xfer)
|
||||
{
|
||||
spi->callback = xfer->callback;
|
||||
spi->userdata = xfer->userdata;
|
||||
spi->xfer_error = 0;
|
||||
spi->xfer_flags = xfer->flags;
|
||||
|
||||
if (spi->xfer_flags & OMV_SPI_XFER_BLOCKING) {
|
||||
if (xfer->txbuf && xfer->rxbuf) {
|
||||
if (HAL_SPI_TransmitReceive(spi->descr,
|
||||
xfer->rxbuf, 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_DMA) {
|
||||
//HAL_NVIC_EnableIRQ(ISC_SPI_DMA_IRQn);
|
||||
HAL_SPI_Receive_DMA(spi->descr, xfer->rxbuf, xfer->size);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omv_spi_transfer_abort(omv_spi_t *spi)
|
||||
{
|
||||
HAL_NVIC_DisableIRQ(spi->irqn);
|
||||
HAL_SPI_Abort(spi->descr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omv_spi_dma_init(omv_spi_t *spi, uint32_t direction)
|
||||
{
|
||||
DMA_HandleTypeDef *dma_descr;
|
||||
|
||||
if (direction == DMA_MEMORY_TO_PERIPH) {
|
||||
dma_descr = &spi->dma_descr_tx;
|
||||
} else {
|
||||
dma_descr = &spi->dma_descr_rx;
|
||||
}
|
||||
|
||||
// Configure the SPI DMA steam.
|
||||
dma_descr->Init.Mode = DMA_CIRCULAR; // TODO FIX
|
||||
dma_descr->Init.Priority = DMA_PRIORITY_HIGH;
|
||||
dma_descr->Init.Direction = direction;
|
||||
// When the DMA is configured in direct mode (the FIFO is disabled), the source and
|
||||
// destination transfer widths are equal, and both defined by PSIZE (MSIZE is ignored).
|
||||
// Additionally, burst transfers are not possible (MBURST and PBURST are both ignored).
|
||||
dma_descr->Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
dma_descr->Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
|
||||
// Note MBURST and PBURST are ignored.
|
||||
dma_descr->Init.MemBurst = DMA_MBURST_INC4;
|
||||
dma_descr->Init.PeriphBurst = DMA_PBURST_INC4;
|
||||
dma_descr->Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
|
||||
dma_descr->Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
|
||||
dma_descr->Init.MemInc = DMA_MINC_ENABLE;
|
||||
dma_descr->Init.PeriphInc = DMA_PINC_DISABLE;
|
||||
|
||||
// Initialize the DMA stream
|
||||
HAL_DMA_DeInit(dma_descr);
|
||||
if (HAL_DMA_Init(dma_descr) != HAL_OK) {
|
||||
// Initialization Error
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 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.
|
||||
dma_utils_set_irq_descr(dma_descr->Instance, dma_descr);
|
||||
|
||||
// Get DMA channel's IRQ number.
|
||||
uint8_t dma_irqn = dma_utils_channel_to_irqn(dma_descr->Instance);
|
||||
|
||||
// Configure and enable DMA IRQ channel.
|
||||
NVIC_SetPriority(dma_irqn, IRQ_PRI_DMA21);
|
||||
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.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(MCU_SERIES_F7) || defined(MCU_SERIES_H7)
|
||||
spi_descr->Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
|
||||
#if defined(MCU_SERIES_H7)
|
||||
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.MasterKeepIOState = (config->data_retained == true) ?
|
||||
SPI_MASTER_KEEP_IO_STATE_ENABLE : SPI_MASTER_KEEP_IO_STATE_ENABLE;
|
||||
#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(MCU_SERIES_H7)
|
||||
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(SPI1_ID)
|
||||
} else if (config->id == 1) {
|
||||
INITIALIZE_SPI_DESCR(spi, 1);
|
||||
#endif
|
||||
#if defined(SPI2_ID)
|
||||
} else if (config->id == 2) {
|
||||
INITIALIZE_SPI_DESCR(spi, 2);
|
||||
#endif
|
||||
#if defined(SPI3_ID)
|
||||
} else if (config->id == 3) {
|
||||
INITIALIZE_SPI_DESCR(spi, 3);
|
||||
#endif
|
||||
#if defined(SPI4_ID)
|
||||
} else if (config->id == 4) {
|
||||
INITIALIZE_SPI_DESCR(spi, 4);
|
||||
#endif
|
||||
#if defined(SPI5_ID)
|
||||
} else if (config->id == 5) {
|
||||
INITIALIZE_SPI_DESCR(spi, 5);
|
||||
#endif
|
||||
#if defined(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_enable) {
|
||||
if (config->bus_mode & OMV_SPI_BUS_TX) {
|
||||
omv_spi_dma_init(spi, DMA_MEMORY_TO_PERIPH);
|
||||
}
|
||||
if (config->bus_mode & OMV_SPI_BUS_RX) {
|
||||
omv_spi_dma_init(spi, DMA_PERIPH_TO_MEMORY);
|
||||
}
|
||||
// Configure and enable SPI IRQ channel.
|
||||
NVIC_SetPriority(spi->irqn, IRQ_PRI_DCMI);// TODO use lower priority
|
||||
HAL_NVIC_EnableIRQ(spi->irqn);
|
||||
}
|
||||
|
||||
// Install TX/RX callbacks even if DMA mode is not enabled for non-blocking transfers.
|
||||
if (config->bus_mode & OMV_SPI_BUS_TX) {
|
||||
HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_TX_COMPLETE_CB_ID, omv_spi_callback);
|
||||
}
|
||||
|
||||
if (config->bus_mode & OMV_SPI_BUS_RX) {
|
||||
HAL_SPI_RegisterCallback(spi->descr, HAL_SPI_RX_COMPLETE_CB_ID, omv_spi_callback);
|
||||
}
|
||||
|
||||
spi->initialized = true;
|
||||
spi->dma_enabled = config->dma_enable;
|
||||
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_enabled) {
|
||||
// TODO: Deinit DMA
|
||||
}
|
||||
HAL_SPI_DeInit(spi->descr);
|
||||
}
|
||||
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_enable = false;
|
||||
config->data_retained = true;
|
||||
return 0;
|
||||
}
|
||||
@ -395,26 +395,65 @@ void HAL_DCMI_MspDeInit(DCMI_HandleTypeDef* hdcmi)
|
||||
|
||||
void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
|
||||
{
|
||||
#if defined(IMU_SPI)
|
||||
if (hspi->Instance == IMU_SPI) {
|
||||
IMU_SPI_CLK_ENABLE();
|
||||
omv_gpio_config(IMU_SPI_SCLK_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_config(IMU_SPI_MISO_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_config(IMU_SPI_MOSI_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_config(IMU_SPI_SSEL_PIN, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_write(IMU_SPI_SSEL_PIN, 1);
|
||||
}
|
||||
#endif
|
||||
typedef struct {
|
||||
omv_gpio_t sclk_pin;
|
||||
omv_gpio_t miso_pin;
|
||||
omv_gpio_t mosi_pin;
|
||||
omv_gpio_t ssel_pin;
|
||||
} spi_pins_t;
|
||||
|
||||
#if defined(ISC_SPI)
|
||||
if (hspi->Instance == ISC_SPI) {
|
||||
ISC_SPI_CLK_ENABLE();
|
||||
omv_gpio_config(ISC_SPI_SCLK_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_config(ISC_SPI_MISO_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_config(ISC_SPI_MOSI_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_config(ISC_SPI_SSEL_PIN, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
}
|
||||
spi_pins_t spi_pins = { NULL, NULL, NULL, NULL };
|
||||
|
||||
if (0) {
|
||||
#if defined(SPI1_ID)
|
||||
} else if (hspi->Instance == SPI1) {
|
||||
__HAL_RCC_SPI1_CLK_ENABLE();
|
||||
spi_pins = (spi_pins_t) { SPI1_SCLK_PIN, SPI1_MISO_PIN, SPI1_MOSI_PIN, SPI1_SSEL_PIN };
|
||||
#endif
|
||||
#if defined(SPI2_ID)
|
||||
} else if (hspi->Instance == SPI2) {
|
||||
__HAL_RCC_SPI2_CLK_ENABLE();
|
||||
spi_pins = (spi_pins_t) { SPI2_SCLK_PIN, SPI2_MISO_PIN, SPI2_MOSI_PIN, SPI2_SSEL_PIN };
|
||||
#endif
|
||||
#if defined(SPI3_ID)
|
||||
} else if (hspi->Instance == SPI3) {
|
||||
__HAL_RCC_SPI3_CLK_ENABLE();
|
||||
spi_pins = (spi_pins_t) { SPI3_SCLK_PIN, SPI3_MISO_PIN, SPI3_MOSI_PIN, SPI3_SSEL_PIN };
|
||||
#endif
|
||||
#if defined(SPI4_ID)
|
||||
} else if (hspi->Instance == SPI4) {
|
||||
__HAL_RCC_SPI4_CLK_ENABLE();
|
||||
spi_pins = (spi_pins_t) { SPI4_SCLK_PIN, SPI4_MISO_PIN, SPI4_MOSI_PIN, SPI4_SSEL_PIN };
|
||||
#endif
|
||||
#if defined(SPI5_ID)
|
||||
} else if (hspi->Instance == SPI5) {
|
||||
__HAL_RCC_SPI5_CLK_ENABLE();
|
||||
spi_pins = (spi_pins_t) { SPI5_SCLK_PIN, SPI5_MISO_PIN, SPI5_MOSI_PIN, SPI5_SSEL_PIN };
|
||||
#endif
|
||||
#if defined(SPI6_ID)
|
||||
} else if (hspi->Instance == SPI6) {
|
||||
__HAL_RCC_SPI6_CLK_ENABLE();
|
||||
spi_pins = (spi_pins_t) { SPI6_SCLK_PIN, SPI6_MISO_PIN, SPI6_MOSI_PIN, SPI6_SSEL_PIN };
|
||||
#endif
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
omv_gpio_config(spi_pins.sclk_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_config(spi_pins.miso_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_HIGH, -1);
|
||||
omv_gpio_config(spi_pins.mosi_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_NONE, OMV_GPIO_SPEED_HIGH, -1);
|
||||
if (hspi->Init.NSS != SPI_NSS_SOFT) {
|
||||
omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_ALT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
} else {
|
||||
omv_gpio_config(spi_pins.ssel_pin, OMV_GPIO_MODE_OUTPUT, OMV_GPIO_PULL_UP, OMV_GPIO_SPEED_HIGH, -1);
|
||||
#if defined(MCU_SERIES_H7)
|
||||
if (hspi->Init.NSSPolarity == SPI_NSS_POLARITY_LOW) {
|
||||
omv_gpio_write(spi_pins.ssel_pin, 1);
|
||||
} else {
|
||||
omv_gpio_write(spi_pins.ssel_pin, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_SPI_MspDeInit(SPI_HandleTypeDef *hspi)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user