diff --git a/targets/TARGET_STM/stm_spi_api.c b/targets/TARGET_STM/stm_spi_api.c index 63572659b83..5377e6ed46e 100644 --- a/targets/TARGET_STM/stm_spi_api.c +++ b/targets/TARGET_STM/stm_spi_api.c @@ -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) @@ -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. * @@ -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 */ } @@ -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)); @@ -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. */ @@ -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 */ @@ -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) { @@ -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 { @@ -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; @@ -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) { @@ -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