Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions targets/TARGET_STM/TARGET_STM32H7/spi_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "stm32h7xx_ll_rcc.h"
#include "stm32h7xx_ll_spi.h"

#define SPI_IP_VERSION_V2

// Defines the word legnth capability of the device where Nth bit allows for N window size
#define STM32_SPI_CAPABILITY_WORD_LENGTH (0xFFFFFFF8)

Expand Down
181 changes: 141 additions & 40 deletions targets/TARGET_STM/stm_spi_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,58 +197,135 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
spiobj->spi = (SPIName)pinmap->peripheral;
MBED_ASSERT(spiobj->spi != (SPIName)NC);

#if defined(SPI_IP_VERSION_V2)
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
#endif /* SPI_IP_VERSION_V2 */

#if defined SPI1_BASE
// Enable SPI clock
if (spiobj->spi == SPI_1) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI1;
#if defined (RCC_SPI123CLKSOURCE_PLL)
PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
#else
PeriphClkInit.Spi1ClockSelection = RCC_SPI1CLKSOURCE_SYSCLK;
#endif
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */

__HAL_RCC_SPI1_FORCE_RESET();
__HAL_RCC_SPI1_RELEASE_RESET();
__HAL_RCC_SPI1_CLK_ENABLE();
spiobj->spiIRQ = SPI1_IRQn;
}
#endif

#if defined SPI2_BASE
if (spiobj->spi == SPI_2) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI2;
#if defined (RCC_SPI123CLKSOURCE_PLL)
PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
#else
PeriphClkInit.Spi2ClockSelection = RCC_SPI2CLKSOURCE_SYSCLK;
#endif
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */

__HAL_RCC_SPI2_FORCE_RESET();
__HAL_RCC_SPI2_RELEASE_RESET();
__HAL_RCC_SPI2_CLK_ENABLE();
spiobj->spiIRQ = SPI2_IRQn;
}
#endif

#if defined SPI3_BASE
if (spiobj->spi == SPI_3) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI3;
#if defined (RCC_SPI123CLKSOURCE_PLL)
PeriphClkInit.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
#else
PeriphClkInit.Spi3ClockSelection = RCC_SPI3CLKSOURCE_SYSCLK;
#endif
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */

__HAL_RCC_SPI3_FORCE_RESET();
__HAL_RCC_SPI3_RELEASE_RESET();
__HAL_RCC_SPI3_CLK_ENABLE();
spiobj->spiIRQ = SPI3_IRQn;
}
#endif

#if defined SPI4_BASE
if (spiobj->spi == SPI_4) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI4;
PeriphClkInit.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */

__HAL_RCC_SPI4_FORCE_RESET();
__HAL_RCC_SPI4_RELEASE_RESET();
__HAL_RCC_SPI4_CLK_ENABLE();
spiobj->spiIRQ = SPI4_IRQn;
}
#endif

#if defined SPI5_BASE
if (spiobj->spi == SPI_5) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI5;
PeriphClkInit.Spi45ClockSelection = RCC_SPI45CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */

__HAL_RCC_SPI5_FORCE_RESET();
__HAL_RCC_SPI5_RELEASE_RESET();
__HAL_RCC_SPI5_CLK_ENABLE();
spiobj->spiIRQ = SPI5_IRQn;
}
#endif

#if defined SPI6_BASE
if (spiobj->spi == SPI_6) {
#if defined(SPI_IP_VERSION_V2)
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_SPI6;
PeriphClkInit.Spi6ClockSelection = RCC_SPI6CLKSOURCE_PCLK4;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
error("HAL_RCCEx_PeriphCLKConfig\n");
}
#endif /* SPI_IP_VERSION_V2 */

__HAL_RCC_SPI6_FORCE_RESET();
__HAL_RCC_SPI6_RELEASE_RESET();
__HAL_RCC_SPI6_CLK_ENABLE();
spiobj->spiIRQ = SPI6_IRQn;
}
#endif

// Configure the SPI pins
pin_function(pinmap->mosi_pin, pinmap->mosi_function);
pin_mode(pinmap->mosi_pin, PullNone);
pin_mode(pinmap->mosi_pin, PullDown); // Pull Down is set for output line

pin_function(pinmap->miso_pin, pinmap->miso_function);
pin_mode(pinmap->miso_pin, PullNone);

pin_function(pinmap->sclk_pin, pinmap->sclk_function);
pin_mode(pinmap->sclk_pin, PullNone);

spiobj->pin_miso = pinmap->miso_pin;
spiobj->pin_mosi = pinmap->mosi_pin;
spiobj->pin_sclk = pinmap->sclk_pin;
Expand Down Expand Up @@ -289,10 +366,21 @@ static void _spi_init_direct(spi_t *obj, const spi_pinmap_t *pinmap)
handle->Init.FirstBit = SPI_FIRSTBIT_MSB;
handle->Init.TIMode = SPI_TIMODE_DISABLE;

#if TARGET_STM32H7
#if defined (SPI_IP_VERSION_V2)
handle->Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
handle->Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;
handle->Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
#endif
handle->Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
handle->Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
handle->Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
handle->Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
handle->Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
handle->Init.IOSwap = SPI_IO_SWAP_DISABLE;
#if defined(SPI_RDY_MASTER_MANAGEMENT_INTERNALLY)
handle->Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
handle->Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;
#endif
#endif /* SPI_IP_VERSION_V2 */

/*
* According the STM32 Datasheet for SPI peripheral we need to PULLDOWN
Expand Down Expand Up @@ -580,16 +668,21 @@ void spi_format(spi_t *obj, int bits, int mode, int slave)
handle->Init.NSS = (slave) ? SPI_NSS_HARD_INPUT : SPI_NSS_HARD_OUTPUT;
}

handle->Init.Mode = (slave) ? SPI_MODE_SLAVE : SPI_MODE_MASTER;
if (slave) {
handle->Init.Mode = SPI_MODE_SLAVE;

if (slave && (handle->Init.Direction == SPI_DIRECTION_1LINE)) {
/* SPI slave implemtation in MBED does not support the 3 wires SPI.
* (e.g. when MISO is not connected). So we're forcing slave in
* 2LINES mode. As MISO is not connected, slave will only read
* from master, and cannot write to it. Inform user.
*/
debug("3 wires SPI slave not supported - slave will only read\r\n");
handle->Init.Direction = SPI_DIRECTION_2LINES;
if (handle->Init.Direction == SPI_DIRECTION_1LINE) {
/* SPI slave implemtation in MBED does not support the 3 wires SPI.
* (e.g. when MISO is not connected). So we're forcing slave in
* 2LINES mode. As MISO is not connected, slave will only read
* from master, and cannot write to it. Inform user.
*/
debug("3 wires SPI slave not supported - slave will only read\r\n");
handle->Init.Direction = SPI_DIRECTION_2LINES;
}

pin_mode(spiobj->pin_mosi, PullNone);
pin_mode(spiobj->pin_miso, PullDown); // Pull Down is set for output line
}

/*
Expand Down Expand Up @@ -699,7 +792,11 @@ static inline int ssp_readable(spi_t *obj)
SPI_HandleTypeDef *handle = &(spiobj->handle);

// Check if data is received
#if defined(SPI_IP_VERSION_V2)
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_RXP) != RESET) ? 1 : 0);
#else /* SPI_IP_VERSION_V2 */
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_RXNE) != RESET) ? 1 : 0);
#endif /* SPI_IP_VERSION_V2 */
return status;
}

Expand All @@ -710,7 +807,12 @@ static inline int ssp_writeable(spi_t *obj)
SPI_HandleTypeDef *handle = &(spiobj->handle);

// Check if data is transmitted
#if defined(SPI_IP_VERSION_V2)
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_TXP) != RESET) ? 1 : 0);
#else /* SPI_IP_VERSION_V2 */
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_TXE) != RESET) ? 1 : 0);
#endif /* SPI_IP_VERSION_V2 */

return status;
}

Expand All @@ -719,11 +821,11 @@ static inline int ssp_busy(spi_t *obj)
int status;
struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle);
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_RXWNE) != RESET) ? 1 : 0);
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
status = ((__HAL_SPI_GET_FLAG(handle, SPI_FLAG_BSY) != RESET) ? 1 : 0);
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
return status;
}

Expand Down Expand Up @@ -845,11 +947,11 @@ static inline int datasize_to_transfer_bitshift(uint32_t DataSize)
*/
static inline int msp_writable(spi_t *obj)
{
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
return (int)LL_SPI_IsActiveFlag_TXP(SPI_INST(obj));
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
return (int)LL_SPI_IsActiveFlag_TXE(SPI_INST(obj));
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}

/**
Expand All @@ -860,11 +962,11 @@ static inline int msp_writable(spi_t *obj)
*/
static inline int msp_readable(spi_t *obj)
{
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
return (int)LL_SPI_IsActiveFlag_RXP(SPI_INST(obj));
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
return (int)LL_SPI_IsActiveFlag_RXNE(SPI_INST(obj));
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}

/**
Expand All @@ -891,11 +993,11 @@ static inline void msp_wait_readable(spi_t *obj)
*/
static inline int msp_busy(spi_t *obj)
{
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
return !(int)LL_SPI_IsActiveFlag_TXC(SPI_INST(obj));
#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
return (int)LL_SPI_IsActiveFlag_BSY(SPI_INST(obj));
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}

/**
Expand Down Expand Up @@ -962,15 +1064,15 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
/* Transmit data */
if (tx_length) {
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_TX);
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Set transaction size */
LL_SPI_SetTransferSize(SPI_INST(obj), tx_length);
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
LL_SPI_Enable(SPI_INST(obj));
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Master transfer start */
LL_SPI_StartMasterTransfer(SPI_INST(obj));
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */

for (int i = 0; i < tx_length; i++) {
msp_wait_writable(obj);
Expand All @@ -982,19 +1084,19 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t

LL_SPI_Disable(SPI_INST(obj));

#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Clear transaction flags */
LL_SPI_ClearFlag_EOT(SPI_INST(obj));
LL_SPI_ClearFlag_TXTF(SPI_INST(obj));
/* Reset transaction size */
LL_SPI_SetTransferSize(SPI_INST(obj), 0);
#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}

/* Receive data */
if (rx_length) {
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_RX);
#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Set transaction size and run SPI */
LL_SPI_SetTransferSize(SPI_INST(obj), rx_length);
LL_SPI_Enable(SPI_INST(obj));
Expand All @@ -1014,7 +1116,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
/* Reset transaction size */
LL_SPI_SetTransferSize(SPI_INST(obj), 0);

#else /* TARGET_STM32H7 */
#else /* SPI_IP_VERSION_V2 */
/* Unlike STM32H7 other STM32 families generates SPI Clock signal continuously in half-duplex receive mode
* till SPI is enabled. To stop clock generation a SPI should be disabled during last frame receiving,
* after generation at least one SPI clock cycle. It causes necessity of critical section usage.
Expand Down Expand Up @@ -1044,7 +1146,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
rx_buffer[i] = msp_read_data(obj, bitshift);
}

#endif /* TARGET_STM32H7 */
#endif /* SPI_IP_VERSION_V2 */
}

return rx_length + tx_length;
Expand Down Expand Up @@ -1077,10 +1179,10 @@ int spi_master_write(spi_t *obj, int value)
* but this will increase performances significantly
*/

#if TARGET_STM32H7
#if defined(SPI_IP_VERSION_V2)
/* Master transfer start */
LL_SPI_StartMasterTransfer(SPI_INST(obj));
#endif
#endif /* SPI_IP_VERSION_V2 */

/* Transmit data */
msp_wait_writable(obj);
Expand Down Expand Up @@ -1241,7 +1343,7 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
NVIC_EnableIRQ(irq_n);

// flush FIFO
#if defined(SPI_FLAG_FRLVL) // STM32F0 STM32F3 STM32F7 STM32L4
#if defined(SPI_FLAG_FRLVL)
HAL_SPIEx_FlushRxFifo(handle);
#endif

Expand Down Expand Up @@ -1306,11 +1408,10 @@ void spi_master_transfer(spi_t *obj, const void *tx, size_t tx_length, void *rx,

obj->spi.event = event;

DEBUG_PRINTF("SPI: Transfer: %u, %u\n", tx_length, rx_length);

// register the thunking handler
IRQn_Type irq_n = spiobj->spiIRQ;
NVIC_SetVector(irq_n, (uint32_t)handler);
DEBUG_PRINTF("SPI: Transfer: tx %u (%u), rx %u (%u), IRQ %u\n", use_tx, tx_length, use_rx, rx_length, irq_n);

// enable the right hal transfer
if (use_tx && use_rx) {
Expand Down Expand Up @@ -1355,7 +1456,7 @@ inline uint32_t spi_irq_handler_asynch(spi_t *obj)
// disable the interrupt
NVIC_DisableIRQ(obj->spi.spiIRQ);
NVIC_ClearPendingIRQ(obj->spi.spiIRQ);
#ifndef TARGET_STM32H7
#if !defined(SPI_IP_VERSION_V2)
if (handle->Init.Direction == SPI_DIRECTION_1LINE && obj->rx_buff.buffer != NULL) {
/**
* In case of 3-wire SPI data receiving we usually get dummy reads.
Expand All @@ -1365,7 +1466,7 @@ inline uint32_t spi_irq_handler_asynch(spi_t *obj)
*/
spi_flush_rx(obj);
}
#endif
#endif /* SPI_IP_VERSION_V2 */
}

return (event & (obj->spi.event | SPI_EVENT_INTERNAL_TRANSFER_COMPLETE));
Expand Down