Fix STM32 SPI 16-bit logic

Update SPI logic to process 16 bit words in the same way by sync/async,
3/4 wires modes:
- fix 3-wire synchronous transmission to move 2 or more bytes between buffer and
  SPI register per word tarnsmission
- fix 4-wire synchronous transmission to move 2 or more bytes between buffer and
  SPI register per word tarnsmission
pull/15206/head
Konstantin Kochin 2022-01-11 20:32:51 +03:00
parent c02e10bcdc
commit 756f6f5199
1 changed files with 52 additions and 12 deletions

View File

@ -939,6 +939,33 @@ 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,6 +1084,7 @@ 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);
const int word_size = 0x01 << bitshift;
/* Ensure that spi is disabled */
LL_SPI_Disable(SPI_INST(obj));
@ -1066,7 +1094,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
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);
LL_SPI_SetTransferSize(SPI_INST(obj), tx_length >> bitshift);
#endif /* SPI_IP_VERSION_V2 */
LL_SPI_Enable(SPI_INST(obj));
#if defined(SPI_IP_VERSION_V2)
@ -1074,9 +1102,9 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
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 */
@ -1098,14 +1126,14 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_RX);
#if defined(SPI_IP_VERSION_V2)
/* Set transaction size and run SPI */
LL_SPI_SetTransferSize(SPI_INST(obj), rx_length);
LL_SPI_SetTransferSize(SPI_INST(obj), rx_length >> bitshift);
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 */
@ -1134,7 +1162,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 +1171,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 */
@ -1198,13 +1226,25 @@ 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);
/* check buffer sizes are multiple of spi word size */
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;
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);
int write_fill_frame = write_fill;
/* extend fill symbols for 16/32 bit modes */
for (int i = 0; i < bitshift; i++) {
write_fill_frame = (write_fill_frame << 8) | write_fill;
}
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 {