Skip to content
Closed
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
130 changes: 79 additions & 51 deletions targets/TARGET_STM/stm_spi_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -143,23 +143,22 @@ void init_spi(spi_t *obj)
struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle);

__HAL_SPI_DISABLE(handle);

DEBUG_PRINTF("init_spi: instance=0x%8X\r\n", (int)handle->Instance);
if (HAL_SPI_Init(handle) != HAL_OK) {
error("Cannot initialize SPI");
}

/* In some cases after SPI object re-creation SPI overrun flag may not
* be cleared, so clear RX data explicitly to prevent any transmissions errors */
spi_flush_rx(obj);
/* In case of standard 4 wires SPI,PI can be kept enabled all time
* and SCK will only be generated during the write operations. But in case
* of 3 wires, it should be only enabled during rd/wr unitary operations,
* which is handled inside STM32 HAL layer.
*/
if (handle->Init.Direction == SPI_DIRECTION_2LINES) {
__HAL_SPI_ENABLE(handle);

/* in 3-wire case, this avoids starting immediate clock generation */
if (handle->Init.Direction == SPI_DIRECTION_1LINE) {
SPI_1LINE_TX(handle);
//LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_TX);
}

__HAL_SPI_ENABLE(handle);
}

SPIName spi_get_peripheral_name(PinName mosi, PinName miso, PinName sclk)
Expand Down Expand Up @@ -939,6 +938,32 @@ static inline int datasize_to_transfer_bitshift(uint32_t DataSize)
}
}

static inline int spi_get_word_from_buffer(const void *buffer, int bitshift)
{
if (bitshift == 1) {
return *((uint16_t *)buffer);
#ifdef HAS_32BIT_SPI_TRANSFERS
} else if (bitshift == 2) {
return *((uint32_t *)buffer);
#endif /* HAS_32BIT_SPI_TRANSFERS */
} else {
return *((uint8_t *)buffer);
}
}

static inline void spi_put_word_to_buffer(void *buffer, int bitshift, int data)
{
if (bitshift == 1) {
*((uint16_t *)buffer) = data;
#ifdef HAS_32BIT_SPI_TRANSFERS
} else if (bitshift == 2) {
*((uint32_t *)buffer) = data;
#endif /* HAS_32BIT_SPI_TRANSFERS */
} else {
*((uint8_t *)buffer) = data;
}
}

/**
* Check if SPI master interface is writable.
*
Expand Down Expand Up @@ -1057,39 +1082,34 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
SPI_HandleTypeDef *handle = &(spiobj->handle);
const int bitshift = datasize_to_transfer_bitshift(handle->Init.DataSize);
MBED_ASSERT(bitshift >= 0);

/* Ensure that spi is disabled */
LL_SPI_Disable(SPI_INST(obj));

const int word_size = 0x01 << bitshift;

/* Transmit data */
if (tx_length) {
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_TX);
#if defined(SPI_IP_VERSION_V2)
/* Set transaction size */
LL_SPI_SetTransferSize(SPI_INST(obj), tx_length);
#endif /* SPI_IP_VERSION_V2 */
/* TransferDirection and TransferSize can only be set when disabled */
LL_SPI_Disable(SPI_INST(obj));
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_TX);
LL_SPI_SetTransferSize(SPI_INST(obj), tx_length >> bitshift);

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

for (int i = 0; i < tx_length; i++) {
for (int i = 0; i < tx_length; i += word_size) {
msp_wait_writable(obj);
msp_write_data(obj, tx_buffer[i], bitshift);
msp_write_data(obj, spi_get_word_from_buffer(tx_buffer + i, bitshift), bitshift);
}

/* Wait end of transaction */
msp_wait_not_busy(obj);

LL_SPI_Disable(SPI_INST(obj));

#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);
// LL_SPI_SetTransferSize(SPI_INST(obj), 0);
#endif /* SPI_IP_VERSION_V2 */
}

Expand All @@ -1099,17 +1119,14 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
#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));
LL_SPI_StartMasterTransfer(SPI_INST(obj));

/* Receive data */
for (int i = 0; i < rx_length; i++) {
for (int i = 0; i < rx_length; i += word_size) {
msp_wait_readable(obj);
rx_buffer[i] = msp_read_data(obj, bitshift);
spi_put_word_to_buffer(rx_buffer + i, bitshift, msp_read_data(obj, bitshift));
}

/* Stop SPI */
LL_SPI_Disable(SPI_INST(obj));
/* Clear transaction flags */
LL_SPI_ClearFlag_EOT(SPI_INST(obj));
LL_SPI_ClearFlag_TXTF(SPI_INST(obj));
Expand All @@ -1134,7 +1151,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
/* get estimation about one SPI clock cycle */
uint32_t baudrate_period_ns = 1000000000 / spi_get_baudrate(obj);

for (int i = 0; i < rx_length; i++) {
for (int i = 0; i < rx_length; i += word_size) {
core_util_critical_section_enter();
LL_SPI_Enable(SPI_INST(obj));
/* Wait single SPI clock cycle. */
Expand All @@ -1143,7 +1160,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
core_util_critical_section_exit();

msp_wait_readable(obj);
rx_buffer[i] = msp_read_data(obj, bitshift);
spi_put_word_to_buffer(rx_buffer + i, bitshift, msp_read_data(obj, bitshift));
}

#endif /* SPI_IP_VERSION_V2 */
Expand All @@ -1157,13 +1174,18 @@ int spi_master_write(spi_t *obj, int value)
struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle);

if (handle->Init.Direction == SPI_DIRECTION_1LINE) {
int result = spi_master_one_wire_transfer(obj, (const char *)&value, 1, NULL, 0);
return result == 1 ? HAL_OK : HAL_ERROR;
}
// HAL_SPI_Transmit(handle, (uint8_t*)&value, 1, 5);
// while(HAL_SPI_GetState(handle) != HAL_SPI_STATE_READY);
// return 0;

const int bitshift = datasize_to_transfer_bitshift(handle->Init.DataSize);
MBED_ASSERT(bitshift >= 0);

if (handle->Init.Direction == SPI_DIRECTION_1LINE) {
int result = spi_master_one_wire_transfer(obj, (const char *)&value, 1 << bitshift, NULL, 0);
return result == 1 ? HAL_OK : HAL_ERROR;
}

#if defined(LL_SPI_RX_FIFO_TH_HALF)
/* Configure the default data size */
if (bitshift == 0) {
Expand Down Expand Up @@ -1198,13 +1220,23 @@ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
{
struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle);

const int bitshift = datasize_to_transfer_bitshift(handle->Init.DataSize);
MBED_ASSERT(tx_length >> bitshift << bitshift == tx_length);
MBED_ASSERT(rx_length >> bitshift << bitshift == rx_length);
int total = (tx_length > rx_length) ? tx_length : rx_length;
int write_fill_frame = write_fill;
for (int i = 0; i < bitshift; i++) {
write_fill_frame = (write_fill_frame << 8) | write_fill;
}

if (handle->Init.Direction == SPI_DIRECTION_2LINES) {
for (int i = 0; i < total; i++) {
char out = (i < tx_length) ? tx_buffer[i] : write_fill;
char in = spi_master_write(obj, out);
const int word_size = 0x01 << bitshift;
for (int i = 0; i < total; i += word_size) {
int out = (i < tx_length) ? spi_get_word_from_buffer(tx_buffer + i, bitshift) : write_fill_frame;
int in = spi_master_write(obj, out);
if (i < rx_length) {
rx_buffer[i] = in;
spi_put_word_to_buffer(rx_buffer + i, bitshift, in);
}
}
} else {
Expand Down Expand Up @@ -1322,18 +1354,14 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
{
struct spi_s *spiobj = SPI_S(obj);
SPI_HandleTypeDef *handle = &(spiobj->handle);
// bool is16bit = (handle->Init.DataSize == SPI_DATASIZE_16BIT);
const int bitshift = datasize_to_transfer_bitshift(handle->Init.DataSize);
MBED_ASSERT(bitshift >= 0);
// the HAL expects number of transfers instead of number of bytes
// so the number of transfers depends on the container size
size_t words;

DEBUG_PRINTF("SPI inst=0x%8X Start: %u, %u\r\n", (int)handle->Instance, transfer_type, length);

obj->spi.transfer_type = transfer_type;
DEBUG_PRINTF("SPI inst=0x%8X Start: %u, %u\r\n", (int)handle->Instance, transfer_type, length);

words = length >> bitshift;
// the HAL expects number of transfers instead of number of bytes
// so the number of transfers depends on the container size
size_t words = length >> bitshift;

// enable the interrupt
IRQn_Type irq_n = spiobj->spiIRQ;
Expand All @@ -1347,6 +1375,7 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
HAL_SPIEx_FlushRxFifo(handle);
#endif

__HAL_SPI_DISABLE(handle);
// enable the right hal transfer
int rc = 0;
switch (transfer_type) {
Expand Down Expand Up @@ -1504,10 +1533,9 @@ void spi_abort_asynch(spi_t *obj)
HAL_SPI_Init(handle);
// cleanup input buffer
spi_flush_rx(obj);
// enable SPI back if it isn't 3-wire mode
if (handle->Init.Direction != SPI_DIRECTION_1LINE) {
LL_SPI_Enable(SPI_INST(obj));
}

// enable SPI back
LL_SPI_Enable(SPI_INST(obj));
}

#endif //DEVICE_SPI_ASYNCH
Expand Down