Skip to content

Commit 1443257

Browse files
authored
Merge pull request #15206 from vznncv/iss_stm32_spi_16_bit
STM32: fix SPI 16 bit mode
2 parents d234b35 + 0c9d5b0 commit 1443257

File tree

1 file changed

+73
-12
lines changed

1 file changed

+73
-12
lines changed

targets/TARGET_STM/stm_spi_api.c

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,33 @@ static inline int datasize_to_transfer_bitshift(uint32_t DataSize)
939939
}
940940
}
941941

942+
static inline int spi_get_word_from_buffer(const void *buffer, int bitshift)
943+
{
944+
if (bitshift == 1) {
945+
return *((uint16_t *)buffer);
946+
#ifdef HAS_32BIT_SPI_TRANSFERS
947+
} else if (bitshift == 2) {
948+
return *((uint32_t *)buffer);
949+
#endif /* HAS_32BIT_SPI_TRANSFERS */
950+
} else {
951+
return *((uint8_t *)buffer);
952+
}
953+
}
954+
955+
static inline void spi_put_word_to_buffer(void *buffer, int bitshift, int data)
956+
{
957+
if (bitshift == 1) {
958+
*((uint16_t *)buffer) = data;
959+
#ifdef HAS_32BIT_SPI_TRANSFERS
960+
} else if (bitshift == 2) {
961+
*((uint32_t *)buffer) = data;
962+
#endif /* HAS_32BIT_SPI_TRANSFERS */
963+
} else {
964+
*((uint8_t *)buffer) = data;
965+
}
966+
}
967+
968+
942969
/**
943970
* Check if SPI master interface is writable.
944971
*
@@ -1057,6 +1084,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
10571084
SPI_HandleTypeDef *handle = &(spiobj->handle);
10581085
const int bitshift = datasize_to_transfer_bitshift(handle->Init.DataSize);
10591086
MBED_ASSERT(bitshift >= 0);
1087+
const int word_size = 0x01 << bitshift;
10601088

10611089
/* Ensure that spi is disabled */
10621090
LL_SPI_Disable(SPI_INST(obj));
@@ -1066,17 +1094,17 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
10661094
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_TX);
10671095
#if defined(SPI_IP_VERSION_V2)
10681096
/* Set transaction size */
1069-
LL_SPI_SetTransferSize(SPI_INST(obj), tx_length);
1097+
LL_SPI_SetTransferSize(SPI_INST(obj), tx_length >> bitshift);
10701098
#endif /* SPI_IP_VERSION_V2 */
10711099
LL_SPI_Enable(SPI_INST(obj));
10721100
#if defined(SPI_IP_VERSION_V2)
10731101
/* Master transfer start */
10741102
LL_SPI_StartMasterTransfer(SPI_INST(obj));
10751103
#endif /* SPI_IP_VERSION_V2 */
10761104

1077-
for (int i = 0; i < tx_length; i++) {
1105+
for (int i = 0; i < tx_length; i += word_size) {
10781106
msp_wait_writable(obj);
1079-
msp_write_data(obj, tx_buffer[i], bitshift);
1107+
msp_write_data(obj, spi_get_word_from_buffer(tx_buffer + i, bitshift), bitshift);
10801108
}
10811109

10821110
/* Wait end of transaction */
@@ -1098,14 +1126,14 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
10981126
LL_SPI_SetTransferDirection(SPI_INST(obj), LL_SPI_HALF_DUPLEX_RX);
10991127
#if defined(SPI_IP_VERSION_V2)
11001128
/* Set transaction size and run SPI */
1101-
LL_SPI_SetTransferSize(SPI_INST(obj), rx_length);
1129+
LL_SPI_SetTransferSize(SPI_INST(obj), rx_length >> bitshift);
11021130
LL_SPI_Enable(SPI_INST(obj));
11031131
LL_SPI_StartMasterTransfer(SPI_INST(obj));
11041132

11051133
/* Receive data */
1106-
for (int i = 0; i < rx_length; i++) {
1134+
for (int i = 0; i < rx_length; i += word_size) {
11071135
msp_wait_readable(obj);
1108-
rx_buffer[i] = msp_read_data(obj, bitshift);
1136+
spi_put_word_to_buffer(rx_buffer + i, bitshift, msp_read_data(obj, bitshift));
11091137
}
11101138

11111139
/* Stop SPI */
@@ -1134,7 +1162,7 @@ static int spi_master_one_wire_transfer(spi_t *obj, const char *tx_buffer, int t
11341162
/* get estimation about one SPI clock cycle */
11351163
uint32_t baudrate_period_ns = 1000000000 / spi_get_baudrate(obj);
11361164

1137-
for (int i = 0; i < rx_length; i++) {
1165+
for (int i = 0; i < rx_length; i += word_size) {
11381166
core_util_critical_section_enter();
11391167
LL_SPI_Enable(SPI_INST(obj));
11401168
/* 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
11431171
core_util_critical_section_exit();
11441172

11451173
msp_wait_readable(obj);
1146-
rx_buffer[i] = msp_read_data(obj, bitshift);
1174+
spi_put_word_to_buffer(rx_buffer + i, bitshift, msp_read_data(obj, bitshift));
11471175
}
11481176

11491177
#endif /* SPI_IP_VERSION_V2 */
@@ -1198,13 +1226,25 @@ int spi_master_block_write(spi_t *obj, const char *tx_buffer, int tx_length,
11981226
{
11991227
struct spi_s *spiobj = SPI_S(obj);
12001228
SPI_HandleTypeDef *handle = &(spiobj->handle);
1229+
const int bitshift = datasize_to_transfer_bitshift(handle->Init.DataSize);
1230+
/* check buffer sizes are multiple of spi word size */
1231+
MBED_ASSERT(tx_length >> bitshift << bitshift == tx_length);
1232+
MBED_ASSERT(rx_length >> bitshift << bitshift == rx_length);
12011233
int total = (tx_length > rx_length) ? tx_length : rx_length;
1234+
12021235
if (handle->Init.Direction == SPI_DIRECTION_2LINES) {
1203-
for (int i = 0; i < total; i++) {
1204-
char out = (i < tx_length) ? tx_buffer[i] : write_fill;
1205-
char in = spi_master_write(obj, out);
1236+
int write_fill_frame = write_fill;
1237+
/* extend fill symbols for 16/32 bit modes */
1238+
for (int i = 0; i < bitshift; i++) {
1239+
write_fill_frame = (write_fill_frame << 8) | write_fill;
1240+
}
1241+
1242+
const int word_size = 0x01 << bitshift;
1243+
for (int i = 0; i < total; i += word_size) {
1244+
int out = (i < tx_length) ? spi_get_word_from_buffer(tx_buffer + i, bitshift) : write_fill_frame;
1245+
int in = spi_master_write(obj, out);
12061246
if (i < rx_length) {
1207-
rx_buffer[i] = in;
1247+
spi_put_word_to_buffer(rx_buffer + i, bitshift, in);
12081248
}
12091249
}
12101250
} else {
@@ -1349,6 +1389,11 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
13491389

13501390
// enable the right hal transfer
13511391
int rc = 0;
1392+
#if defined(SPI_IP_VERSION_V2)
1393+
// HAL SPI API assumes that SPI disabled between transfers and
1394+
// doesn't work properly if SPI is enabled.
1395+
LL_SPI_Disable(SPI_INST(obj));
1396+
#endif
13521397
switch (transfer_type) {
13531398
case SPI_TRANSFER_TYPE_TXRX:
13541399
rc = HAL_SPI_TransmitReceive_IT(handle, (uint8_t *)tx, (uint8_t *)rx, words);
@@ -1367,6 +1412,12 @@ static int spi_master_start_asynch_transfer(spi_t *obj, transfer_type_t transfer
13671412
}
13681413

13691414
if (rc) {
1415+
#if defined(SPI_IP_VERSION_V2)
1416+
// enable SPI back in case of error
1417+
if (handle->Init.Direction != SPI_DIRECTION_1LINE) {
1418+
LL_SPI_Enable(SPI_INST(obj));
1419+
}
1420+
#endif
13701421
DEBUG_PRINTF("SPI: RC=%u\n", rc);
13711422
length = 0;
13721423
}
@@ -1466,6 +1517,16 @@ inline uint32_t spi_irq_handler_asynch(spi_t *obj)
14661517
*/
14671518
spi_flush_rx(obj);
14681519
}
1520+
#else
1521+
// reset transfer size
1522+
LL_SPI_SetTransferSize(SPI_INST(obj), 0);
1523+
1524+
// HAL_SPI_TransmitReceive_IT/HAL_SPI_Transmit_IT/HAL_SPI_Receive_IT
1525+
// function disable SPI after transfer. So we need enabled it back,
1526+
// otherwise spi_master_block_write/spi_master_write won't work in 4-wire mode.
1527+
if (handle->Init.Direction != SPI_DIRECTION_1LINE) {
1528+
LL_SPI_Enable(SPI_INST(obj));
1529+
}
14691530
#endif /* SPI_IP_VERSION_V2 */
14701531
}
14711532

0 commit comments

Comments
 (0)