2 * Copyright (c) 2020-2021 Arm Limited. All rights reserved.
4 * SPDX-License-Identifier: Apache-2.0
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * -----------------------------------------------------------------------------
21 * Title: SPI Server application
23 * -----------------------------------------------------------------------------
32 #include "SPI_Server_Config.h"
33 #include "SPI_Server.h"
35 #include "cmsis_os2.h"
36 #include "cmsis_compiler.h"
37 #include "cmsis_vio.h"
39 #include "Driver_SPI.h" // ::CMSIS Driver:SPI
41 #ifndef SPI_SERVER_DEBUG
42 #define SPI_SERVER_DEBUG 0
45 // Fixed SPI Server settings (not available through SPI_Server_Config.h)
46 #define SPI_SERVER_SS_MODE 2 // Slave Select Hardware monitored
47 #define SPI_SERVER_FORMAT 0 // Clock Polarity 0 / Clock Phase 0
48 #define SPI_SERVER_DATA_BITS 8 // 8 data bits
49 #define SPI_SERVER_BIT_ORDER 0 // MSB to LSB bit order
51 #define SPI_EVENTS_MASK (ARM_SPI_EVENT_TRANSFER_COMPLETE | \
52 ARM_SPI_EVENT_DATA_LOST | \
53 ARM_SPI_EVENT_MODE_FAULT)
55 #define DATA_BITS_TO_BYTES(data_bits) (((data_bits) > 16) ? (4U) : (((data_bits) > 8) ? (2U) : (1U)))
56 #define BYTES_TO_ITEMS(bytes,data_bits) ((bytes + DATA_BITS_TO_BYTES(data_bits) - 1U) / DATA_BITS_TO_BYTES(data_bits))
58 /* Access to Driver_SPI# */
59 #define SPI_Driver_Aux(n) Driver_SPI##n
60 #define SPI_Driver_Name(n) SPI_Driver_Aux(n)
61 extern ARM_DRIVER_SPI SPI_Driver_Name(SPI_SERVER_DRV_NUM);
62 #define drvSPI (&SPI_Driver_Name(SPI_SERVER_DRV_NUM))
64 typedef struct { // SPI Interface settings structure
73 // Structure containing command string and pointer to command handling function
76 int32_t (*Command_Func) (const char *command);
81 // Main thread (reception and execution of command)
83 static void SPI_Server_Thread (void *argument);
85 // SPI Interface communication functions
86 static void SPI_Com_Event (uint32_t event);
87 static int32_t SPI_Com_Initialize (void);
88 static int32_t SPI_Com_Uninitialize (void);
89 static int32_t SPI_Com_PowerOn (void);
90 static int32_t SPI_Com_PowerOff (void);
91 static int32_t SPI_Com_Configure (const SPI_COM_CONFIG_t *config);
92 static uint32_t SPI_Com_SS (uint32_t active);
93 static int32_t SPI_Com_Receive ( void *data_in, uint32_t num, uint32_t timeout);
94 static int32_t SPI_Com_Send (const void *data_out, uint32_t num, uint32_t timeout);
95 static int32_t SPI_Com_Transfer (const void *data_out, void *data_in, uint32_t num, uint32_t timeout);
96 static int32_t SPI_Com_Abort (void);
97 static uint32_t SPI_Com_GetCnt (void);
99 // Command handling functions
100 static int32_t SPI_Cmd_GetVer (const char *cmd);
101 static int32_t SPI_Cmd_GetCap (const char *cmd);
102 static int32_t SPI_Cmd_SetBuf (const char *cmd);
103 static int32_t SPI_Cmd_GetBuf (const char *cmd);
104 static int32_t SPI_Cmd_SetCom (const char *cmd);
105 static int32_t SPI_Cmd_Xfer (const char *cmd);
106 static int32_t SPI_Cmd_GetCnt (const char *cmd);
110 // Command specification (command string, command handling function)
111 static const SPI_CMD_DESC_t spi_cmd_desc[] = {
112 { "GET VER" , SPI_Cmd_GetVer },
113 { "GET CAP" , SPI_Cmd_GetCap },
114 { "SET BUF" , SPI_Cmd_SetBuf },
115 { "GET BUF" , SPI_Cmd_GetBuf },
116 { "SET COM" , SPI_Cmd_SetCom },
117 { "XFER" , SPI_Cmd_Xfer },
118 { "GET CNT" , SPI_Cmd_GetCnt }
121 static osThreadId_t spi_server_thread_id = NULL;
122 static osThreadAttr_t thread_attr = {
123 .name = "SPI_Server_Thread",
127 static uint8_t spi_server_state = SPI_SERVER_STATE_RECEPTION;
128 static uint32_t spi_cmd_timeout = SPI_SERVER_CMD_TIMEOUT;
129 static uint32_t spi_xfer_timeout = SPI_SERVER_CMD_TIMEOUT;
130 static uint32_t spi_xfer_cnt = 0U;
131 static uint32_t spi_xfer_buf_size = SPI_SERVER_BUF_SIZE;
132 static const SPI_COM_CONFIG_t spi_com_config_default = { ARM_SPI_MODE_SLAVE,
133 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk),
134 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk),
135 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk),
137 0U // Bus speed for Slave mode is unused
139 static const SPI_COM_CONFIG_t spi_com_config_inactive= { ARM_SPI_MODE_INACTIVE, 0U, 0U, 0U, 0U, 0U };
140 static SPI_COM_CONFIG_t spi_com_config_xfer;
141 static uint8_t spi_bytes_per_item = 1U;
142 static uint8_t spi_cmd_buf_rx[32] __ALIGNED(4);
143 static uint8_t spi_cmd_buf_tx[32] __ALIGNED(4);
144 static uint8_t *ptr_spi_xfer_buf_rx = NULL;
145 static uint8_t *ptr_spi_xfer_buf_tx = NULL;
146 static void *ptr_spi_xfer_buf_rx_alloc = NULL;
147 static void *ptr_spi_xfer_buf_tx_alloc = NULL;
152 \fn int32_t SPI_Server_Start (void)
153 \brief Initialize, power up, configure SPI interface and start SPI Server thread.
154 \return execution status
155 - EXIT_SUCCESS: Operation successful
156 - EXIT_FAILURE: Operation failed
158 int32_t SPI_Server_Start (void) {
162 (void)vioPrint(vioLevelHeading, "SPI Server v%s", SPI_SERVER_VER);
164 // Initialize local variables
165 spi_server_state = SPI_SERVER_STATE_RECEPTION;
166 spi_cmd_timeout = SPI_SERVER_CMD_TIMEOUT;
167 spi_xfer_timeout = SPI_SERVER_CMD_TIMEOUT;
169 spi_xfer_buf_size = SPI_SERVER_BUF_SIZE;
170 spi_bytes_per_item = DATA_BITS_TO_BYTES(SPI_SERVER_DATA_BITS);
171 memset(spi_cmd_buf_rx, 0, sizeof(spi_cmd_buf_rx));
172 memset(spi_cmd_buf_tx, 0, sizeof(spi_cmd_buf_tx));
173 memcpy(&spi_com_config_xfer, &spi_com_config_default, sizeof(SPI_COM_CONFIG_t));
175 // Allocate buffers for data transmission and reception
176 // (maximum size is incremented by 4 bytes to ensure that buffer can be aligned to 4 bytes)
178 ptr_spi_xfer_buf_rx_alloc = malloc(SPI_SERVER_BUF_SIZE + 4U);
179 if (((uint32_t)ptr_spi_xfer_buf_rx_alloc & 3U) != 0U) {
180 // If allocated memory is not 4 byte aligned, use next 4 byte aligned address for ptr_tx_buf
181 ptr_spi_xfer_buf_rx = (uint8_t *)((((uint32_t)ptr_spi_xfer_buf_rx_alloc) + 3U) & (~3U));
183 // If allocated memory is 4 byte aligned, use it directly
184 ptr_spi_xfer_buf_rx = (uint8_t *)ptr_spi_xfer_buf_rx_alloc;
186 ptr_spi_xfer_buf_tx_alloc = malloc(SPI_SERVER_BUF_SIZE + 4U);
187 if (((uint32_t)ptr_spi_xfer_buf_tx_alloc & 3U) != 0U) {
188 // If allocated memory is not 4 byte aligned, use next 4 byte aligned address for ptr_tx_buf
189 ptr_spi_xfer_buf_tx = (uint8_t *)((((uint32_t)ptr_spi_xfer_buf_tx_alloc) + 3U) & (~3U));
191 // If allocated memory is 4 byte aligned, use it directly
192 ptr_spi_xfer_buf_tx = (uint8_t *)ptr_spi_xfer_buf_tx_alloc;
195 if ((ptr_spi_xfer_buf_rx != NULL) || (ptr_spi_xfer_buf_tx != NULL)) {
196 memset(ptr_spi_xfer_buf_rx, 0, SPI_SERVER_BUF_SIZE);
197 memset(ptr_spi_xfer_buf_rx, 0, SPI_SERVER_BUF_SIZE);
203 if (ret == EXIT_SUCCESS) {
204 ret = SPI_Com_Initialize();
207 if (ret == EXIT_SUCCESS) {
208 ret = SPI_Com_PowerOn();
211 if (ret == EXIT_SUCCESS) {
212 ret = SPI_Com_Configure(&spi_com_config_default);
215 if ((ret == EXIT_SUCCESS) && (spi_server_thread_id == NULL)) {
216 // Create SPI_Server_Thread thread
217 spi_server_thread_id = osThreadNew(SPI_Server_Thread, NULL, &thread_attr);
218 if (spi_server_thread_id == NULL) {
223 if (ret != EXIT_SUCCESS) {
224 vioPrint(vioLevelError, "Server Start failed!");
231 \fn int32_t SPI_Server_Stop (void)
232 \brief Terminate SPI Server thread, power down and uninitialize SPI interface.
233 \return execution status
234 - EXIT_SUCCESS: Operation successful
235 - EXIT_FAILURE: Operation failed
237 int32_t SPI_Server_Stop (void) {
243 if (spi_server_thread_id != NULL) {
244 spi_server_state = SPI_SERVER_STATE_TERMINATE;
245 for (i = 0U; i < 10U; i++) {
246 if (osThreadGetState(spi_server_thread_id) == osThreadTerminated) {
247 spi_server_thread_id = NULL;
255 if (ret == EXIT_SUCCESS) {
256 ret = SPI_Com_PowerOff();
259 if (ret == EXIT_SUCCESS) {
260 ret = SPI_Com_Uninitialize();
263 if (ptr_spi_xfer_buf_rx_alloc != NULL) {
264 free(ptr_spi_xfer_buf_rx_alloc);
265 ptr_spi_xfer_buf_rx = NULL;
266 ptr_spi_xfer_buf_rx_alloc = NULL;
268 if (ptr_spi_xfer_buf_tx_alloc != NULL) {
269 free(ptr_spi_xfer_buf_tx_alloc);
270 ptr_spi_xfer_buf_tx = NULL;
271 ptr_spi_xfer_buf_tx_alloc = NULL;
274 if (ret != EXIT_SUCCESS) {
275 vioPrint(vioLevelError, "Server Stop failed! ");
285 \fn static void SPI_Server_Thread (void *argument)
286 \brief SPI Server thread function.
287 \detail This is a thread function that waits to receive a command from SPI Client
288 (Driver Validation suite), and after command is received it is executed
289 and the process starts again by waiting to receive next command.
290 \param[in] argument Not used
293 static void SPI_Server_Thread (void *argument) {
299 switch (spi_server_state) {
301 case SPI_SERVER_STATE_RECEPTION: // Receive a command
302 if (SPI_Com_Receive(spi_cmd_buf_rx, BYTES_TO_ITEMS(sizeof(spi_cmd_buf_rx),SPI_SERVER_DATA_BITS), osWaitForever) == EXIT_SUCCESS) {
303 spi_server_state = SPI_SERVER_STATE_EXECUTION;
305 // If 32 byte command was not received restart the reception of 32 byte command
308 case SPI_SERVER_STATE_EXECUTION: // Execute a command
309 // Find the command and call handling function
310 for (i = 0U; i < (sizeof(spi_cmd_desc) / sizeof(SPI_CMD_DESC_t)); i++) {
311 if (memcmp(spi_cmd_buf_rx, spi_cmd_desc[i].command, strlen(spi_cmd_desc[i].command)) == 0) {
312 (void)spi_cmd_desc[i].Command_Func((const char *)spi_cmd_buf_rx);
316 vioPrint(vioLevelMessage, "%.20s ", spi_cmd_buf_rx);
317 spi_server_state = SPI_SERVER_STATE_RECEPTION;
320 case SPI_SERVER_STATE_TERMINATE: // Self-terminate the thread
321 default: // Should never happen, processed as terminate request
322 vioPrint(vioLevelError, "Server stopped! ");
323 (void)SPI_Com_Abort();
324 (void)osThreadTerminate(osThreadGetId());
331 \fn static void SPI_Com_Event (uint32_t event)
332 \brief SPI communication event callback (called from SPI driver from IRQ context).
333 \detail This function dispatches event (flag) to SPI Server thread.
334 \param[in] event SPI event
335 - ARM_SPI_EVENT_TRANSFER_COMPLETE: Data Transfer completed
336 - ARM_SPI_EVENT_DATA_LOST: Data lost: Receive overflow / Transmit underflow
337 - ARM_SPI_EVENT_MODE_FAULT: Master Mode Fault (SS deactivated when Master)
340 static void SPI_Com_Event (uint32_t event) {
342 if (spi_server_thread_id != NULL) {
343 (void)osThreadFlagsSet(spi_server_thread_id, event);
348 \fn static int32_t SPI_Com_Initialize (void)
349 \brief Initialize SPI interface.
350 \return execution status
351 - EXIT_SUCCESS: Operation successful
352 - EXIT_FAILURE: Operation failed
354 static int32_t SPI_Com_Initialize (void) {
359 if (drvSPI->Initialize(SPI_Com_Event) == ARM_DRIVER_OK) {
367 \fn static int32_t SPI_Com_Uninitialize (void)
368 \brief Uninitialize SPI interface.
369 \return execution status
370 - EXIT_SUCCESS: Operation successful
371 - EXIT_FAILURE: Operation failed
373 static int32_t SPI_Com_Uninitialize (void) {
378 if (drvSPI->Uninitialize() == ARM_DRIVER_OK) {
386 \fn static int32_t SPI_Com_PowerOn (void)
387 \brief Power-up SPI interface.
388 \return execution status
389 - EXIT_SUCCESS: Operation successful
390 - EXIT_FAILURE: Operation failed
392 static int32_t SPI_Com_PowerOn (void) {
397 if (drvSPI->PowerControl(ARM_POWER_FULL) == ARM_DRIVER_OK) {
405 \fn static int32_t SPI_Com_PowerOff (void)
406 \brief Power-down SPI interface.
407 \return execution status
408 - EXIT_SUCCESS: Operation successful
409 - EXIT_FAILURE: Operation failed
411 static int32_t SPI_Com_PowerOff (void) {
416 if (drvSPI->PowerControl(ARM_POWER_OFF) == ARM_DRIVER_OK) {
424 \fn static int32_t SPI_Com_Configure (const SPI_COM_CONFIG_t *config)
425 \brief Configure SPI interface.
426 \param[in] config Pointer to structure containing SPI interface configuration settings
427 \return execution status
428 - EXIT_SUCCESS: Operation successful
429 - EXIT_FAILURE: Operation failed
431 static int32_t SPI_Com_Configure (const SPI_COM_CONFIG_t *config) {
436 if (drvSPI->Control(config->mode |
441 config->bus_speed ) == ARM_DRIVER_OK) {
442 spi_bytes_per_item = DATA_BITS_TO_BYTES((config->bit_num & ARM_SPI_DATA_BITS_Msk) >> ARM_SPI_DATA_BITS_Pos);
450 \fn static uint32_t SPI_Com_SS (void)
451 \brief Drive Slave Select line with Control function.
452 \return number of data items transferred
454 static uint32_t SPI_Com_SS (uint32_t active) {
461 arg = ARM_SPI_SS_ACTIVE;
463 arg = ARM_SPI_SS_INACTIVE;
466 if (drvSPI->Control(ARM_SPI_CONTROL_SS, arg) == ARM_DRIVER_OK) {
474 \fn static int32_t SPI_Com_Receive (void *data_in, uint32_t num, uint32_t timeout)
475 \brief Receive data (command) over SPI interface.
476 \param[out] data_in Pointer to memory where data will be received
477 \param[in] num Number of data items to be received
478 \param[in] timeout Timeout for reception (in ms)
479 \return execution status
480 - EXIT_SUCCESS: Operation successful
481 - EXIT_FAILURE: Operation failed
483 static int32_t SPI_Com_Receive (void *data_in, uint32_t num, uint32_t timeout) {
485 uint32_t flags, tmo, time, cnt;
489 if (spi_server_thread_id != NULL) {
490 memset(data_in, (int32_t)'?', spi_bytes_per_item * num);
491 vioSetSignal (vioLED0, vioLEDon);
494 if (drvSPI->Receive(data_in, num) == ARM_DRIVER_OK) {
501 flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, tmo);
502 if (flags == osFlagsErrorTimeout) { // If timeout
503 if (time != osWaitForever) {
506 if (drvSPI->GetDataCount() != 0U) {
507 while (cnt != drvSPI->GetDataCount()) { // While count is changing
508 cnt = drvSPI->GetDataCount();
509 flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, 10U);
510 if (flags == osFlagsErrorTimeout) { // If timeout
511 if (time != osWaitForever) {
519 } else if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
520 // If completed event was signaled
524 // In all other cases exit with failed status
529 // If something was received but not of expected size then terminate the reception
533 } else if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
534 // If completed event was signaled
538 // In all other cases exit with failed status
542 if (ret != EXIT_SUCCESS) {
543 // If receive was activated but failed to receive expected data then abort the transfer
544 (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
546 vioSetSignal (vioLED0, vioLEDoff);
554 \fn static int32_t SPI_Com_Send (const void *data_out, uint32_t num, uint32_t timeout)
555 \brief Send data (response) over SPI interface.
556 \param[out] data_out Pointer to memory containing data to be sent
557 \param[in] num Number of data items to be sent
558 \param[in] timeout Timeout for send (in ms)
559 \return execution status
560 - EXIT_SUCCESS: Operation successful
561 - EXIT_FAILURE: Operation failed
563 static int32_t SPI_Com_Send (const void *data_out, uint32_t num, uint32_t timeout) {
569 if (spi_server_thread_id != NULL) {
570 vioSetSignal (vioLED1, vioLEDon);
571 if (drvSPI->Send(data_out, num) == ARM_DRIVER_OK) {
572 flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, timeout);
573 if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
574 // If completed event was signaled
577 if (ret != EXIT_SUCCESS) {
578 // If send was activated but failed to send all of the expected data then abort the transfer
579 (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
581 vioSetSignal (vioLED1, vioLEDoff);
589 \fn static int32_t SPI_Com_Transfer (const void *data_out, void *data_in, uint32_t num, uint32_t timeout)
590 \brief Transfer (send/receive) data over SPI interface.
591 \param[in] data_out Pointer to memory containing data to be sent
592 \param[out] data_in Pointer to memory where data will be received
593 \param[in] num Number of data items to be transferred
594 \param[in] timeout Timeout for transfer (in ms)
595 \return execution status
596 - EXIT_SUCCESS: Operation successful
597 - EXIT_FAILURE: Operation failed
599 static int32_t SPI_Com_Transfer (const void *data_out, void *data_in, uint32_t num, uint32_t timeout) {
605 if (spi_server_thread_id != NULL) {
606 vioSetSignal (vioLED2, vioLEDon);
607 if (drvSPI->Transfer(data_out, data_in, num) == ARM_DRIVER_OK) {
608 flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, timeout);
609 spi_xfer_cnt = drvSPI->GetDataCount();
610 if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
611 // If completed event was signaled
614 // If error or timeout
615 (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
617 vioSetSignal (vioLED2, vioLEDoff);
625 \fn static int32_t SPI_Com_Abort (void)
626 \brief Abort current transfer on SPI interface.
627 \return execution status
628 - EXIT_SUCCESS: Operation successful
629 - EXIT_FAILURE: Operation failed
631 static int32_t SPI_Com_Abort (void) {
636 if (drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U) == ARM_DRIVER_OK) {
644 \fn static uint32_t SPI_Com_GetCnt (void)
645 \brief Get number of data items transferred over SPI interface in last transfer.
646 \return number of data items transferred
648 static uint32_t SPI_Com_GetCnt (void) {
653 // Command handling functions
656 \fn static int32_t SPI_Cmd_GetVer (const char *cmd)
657 \brief Handle command "GET VER".
658 \detail Return SPI Server version over SPI interface (16 bytes).
659 \param[in] cmd Pointer to null-terminated command string
660 \return execution status
661 - EXIT_SUCCESS: Operation successful
662 - EXIT_FAILURE: Operation failed
664 static int32_t SPI_Cmd_GetVer (const char *cmd) {
668 memset(spi_cmd_buf_tx, 0, 16);
669 memcpy(spi_cmd_buf_tx, SPI_SERVER_VER, sizeof(SPI_SERVER_VER));
671 return (SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(16U, SPI_SERVER_DATA_BITS), spi_cmd_timeout));
675 \fn static int32_t SPI_Cmd_GetCap (const char *cmd)
676 \brief Handle command "GET CAP".
677 \detail Return SPI Server capabilities over SPI interface (32 bytes).
678 \param[in] cmd Pointer to null-terminated command string
679 \return execution status
680 - EXIT_SUCCESS: Operation successful
681 - EXIT_FAILURE: Operation failed
683 static int32_t SPI_Cmd_GetCap (const char *cmd) {
685 uint32_t mode_mask, format_mask, data_bits_mask, bit_order_mask, bus_speed_min, bus_speed_max;
693 // Determine supported minimum bus speed
694 // Find minimum speed setting at which Control function succeeds
697 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
698 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
699 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
700 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
701 ARM_SPI_SS_MASTER_HW_OUTPUT ,
702 bs ) == ARM_DRIVER_OK) {
705 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
706 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
707 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
708 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
709 ARM_SPI_SS_MASTER_HW_OUTPUT ,
710 bs * 2U) == ARM_DRIVER_OK) {
714 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
715 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
716 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
717 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
718 ARM_SPI_SS_MASTER_HW_OUTPUT ,
719 bs * 5U) == ARM_DRIVER_OK) {
723 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
724 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
725 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
726 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
727 ARM_SPI_SS_MASTER_HW_OUTPUT ,
728 bs * 10U) == ARM_DRIVER_OK) {
733 } while (bs < 1000000U);
736 // Determine supported maximum bus speed
737 // Find maximum speed setting at which Control function succeeds
740 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
741 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
742 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
743 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
744 ARM_SPI_SS_MASTER_HW_OUTPUT ,
745 bs ) == ARM_DRIVER_OK) {
748 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
749 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
750 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
751 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
752 ARM_SPI_SS_MASTER_HW_OUTPUT ,
753 bs / 2U) == ARM_DRIVER_OK) {
757 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
758 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
759 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
760 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
761 ARM_SPI_SS_MASTER_HW_OUTPUT ,
762 bs / 5U) == ARM_DRIVER_OK) {
766 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
767 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
768 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
769 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
770 ARM_SPI_SS_MASTER_HW_OUTPUT ,
771 bs / 10U) == ARM_DRIVER_OK) {
776 } while (bs > 1000000U);
779 // Determine supported modes
781 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
782 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
783 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
784 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
785 ARM_SPI_SS_MASTER_HW_OUTPUT ,
786 bus_speed_min ) == ARM_DRIVER_OK) {
790 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
791 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
792 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
793 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
794 ARM_SPI_SS_SLAVE_HW ,
795 0U ) == ARM_DRIVER_OK) {
796 mode_mask |= 1U << 1;
799 // Determine supported clock / frame format
801 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
802 ARM_SPI_CPOL0_CPHA0 |
803 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
804 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
805 ARM_SPI_SS_SLAVE_HW ,
806 0U ) == ARM_DRIVER_OK) {
809 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
810 ARM_SPI_CPOL0_CPHA1 |
811 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
812 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
813 ARM_SPI_SS_SLAVE_HW ,
814 0U ) == ARM_DRIVER_OK) {
815 format_mask |= 1U << 1;
817 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
818 ARM_SPI_CPOL1_CPHA0 |
819 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
820 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
821 ARM_SPI_SS_SLAVE_HW ,
822 0U ) == ARM_DRIVER_OK) {
823 format_mask |= 1U << 2;
825 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
826 ARM_SPI_CPOL1_CPHA1 |
827 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
828 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
829 ARM_SPI_SS_SLAVE_HW ,
830 0U ) == ARM_DRIVER_OK) {
831 format_mask |= 1U << 3;
833 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
835 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
836 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
837 ARM_SPI_SS_SLAVE_HW ,
838 0U ) == ARM_DRIVER_OK) {
839 format_mask |= 1U << 4;
841 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
843 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
844 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
845 ARM_SPI_SS_SLAVE_HW ,
846 0U ) == ARM_DRIVER_OK) {
847 format_mask |= 1U << 5;
850 // Determine supported data bits
852 for (i = 1U; i <= 32U; i++) {
853 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
854 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
855 ((i << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
856 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
857 ARM_SPI_SS_SLAVE_HW ,
858 0U ) == ARM_DRIVER_OK) {
859 data_bits_mask |= 1UL << (i - 1U);
863 // Determine bit order
865 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
866 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
867 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
869 ARM_SPI_SS_SLAVE_HW ,
870 0U ) == ARM_DRIVER_OK) {
871 bit_order_mask |= 1U;
873 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
874 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
875 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
877 ARM_SPI_SS_SLAVE_HW ,
878 0U ) == ARM_DRIVER_OK) {
879 bit_order_mask |= 1U << 1;
882 // Revert communication settings to default because they were changed during auto-detection of capabilities
883 (void)SPI_Com_Configure(&spi_com_config_default);
885 memset(spi_cmd_buf_tx, 0, 32);
886 if (snprintf((char *)spi_cmd_buf_tx, 32, "%02X,%02X,%08X,%02X,%i,%i",
891 (bus_speed_min / 1000U),
892 (bus_speed_max / 1000U)) <= 32) {
893 ret = SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(32U, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
900 \fn static int32_t SPI_Cmd_SetBuf (const char *cmd)
901 \brief Handle command "SET BUF RX/TX,len[,pattern]".
902 \detail Initialize content of the buffer in the following way:
903 - fill whole buffer with 'pattern' value if it is specified, and 'len' is 0
904 - fill whole buffer with 0 if 'pattern' is not provided and 'len' is 0
905 - load 'len' bytes from start of the buffer with content
906 received in IN data phase
907 \param[in] cmd Pointer to null-terminated command string
908 \return execution status
909 - EXIT_SUCCESS: Operation successful
910 - EXIT_FAILURE: Operation failed
912 static int32_t SPI_Cmd_SetBuf (const char *cmd) {
926 // Parse 'RX' or 'TX' selection
927 if (strstr(cmd, "RX") != NULL) {
928 ptr_buf = ptr_spi_xfer_buf_rx;
929 } else if (strstr(cmd, "TX") != NULL) {
930 ptr_buf = ptr_spi_xfer_buf_tx;
935 if (ret == EXIT_SUCCESS) {
937 ptr_str = strstr(cmd, ","); // Find ','
938 if (ptr_str != NULL) { // If ',' was found
939 ptr_str++; // Skip ','
940 while (*ptr_str == ' ') { // Skip whitespaces after ','
943 if (sscanf(ptr_str, "%u", &val) == 1) {
944 if (val <= spi_xfer_buf_size) {
957 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
958 // Parse optional 'pattern'
959 ptr_str = strstr(ptr_str, ","); // Find ','
960 if (ptr_str != NULL) { // If ',' was found
961 ptr_str++; // Skip ','
962 while (*ptr_str == ' ') { // Skip whitespaces after ','
965 if (sscanf(ptr_str, "%x", &val) == 1) {
966 pattern = (uint8_t)val;
973 if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL)) {
974 // Fill the whole buffer with 'pattern', if 'pattern' was not specified
975 // in the command then the whole buffer will be filled with 0
976 memset(ptr_buf, (int32_t)pattern, spi_xfer_buf_size);
979 if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL) && (len != 0U)) {
980 // Load 'len' bytes from start of buffer with content received in IN data phase
981 ret = SPI_Com_Receive(ptr_buf, BYTES_TO_ITEMS(len, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
988 \fn static int32_t SPI_Cmd_GetBuf (const char *cmd)
989 \brief Handle command "GET BUF RX/TX,len".
990 \detail Send content of buffer over SPI interface.
991 \param[in] cmd Pointer to null-terminated command string
992 \return execution status
993 - EXIT_SUCCESS: Operation successful
994 - EXIT_FAILURE: Operation failed
996 static int32_t SPI_Cmd_GetBuf (const char *cmd) {
998 const uint8_t *ptr_buf;
1008 // Parse 'RX' or 'TX' selection
1009 if (strstr(cmd, "RX") != NULL) {
1010 ptr_buf = ptr_spi_xfer_buf_rx;
1011 } else if (strstr(cmd, "TX") != NULL) {
1012 ptr_buf = ptr_spi_xfer_buf_tx;
1017 if (ret == EXIT_SUCCESS) {
1019 ptr_str = strstr(cmd, ","); // Find ','
1020 if (ptr_str != NULL) { // If ',' was found
1021 ptr_str++; // Skip ','
1022 while (*ptr_str == ' ') { // Skip whitespaces after ','
1025 if (sscanf(ptr_str, "%u", &val) == 1) {
1026 if ((val > 0U) && (val <= spi_xfer_buf_size)) {
1039 if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL) && (len != 0U)) {
1040 ret = SPI_Com_Send(ptr_buf, BYTES_TO_ITEMS(len, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
1047 \fn static int32_t SPI_Cmd_SetCom (const char *cmd)
1048 \brief Handle command "SET COM mode,format,bit_num,bit_order,ss_mode,bus_speed".
1049 \detail Set communication configuration settings used for transfers (XFER commands).
1050 \param[in] cmd Pointer to null-terminated command string
1051 \return execution status
1052 - EXIT_SUCCESS: Operation successful
1053 - EXIT_FAILURE: Operation failed
1055 static int32_t SPI_Cmd_SetCom (const char *cmd) {
1056 const char *ptr_str;
1063 ptr_str = &cmd[7]; // Skip "SET COM"
1064 while (*ptr_str == ' ') { // Skip whitespaces
1069 if (sscanf(ptr_str, "%u", &val) == 1) {
1071 case 0U: // Master mode
1072 spi_com_config_xfer.mode = ARM_SPI_MODE_MASTER;
1074 case 1U: // Slave mode
1075 spi_com_config_xfer.mode = ARM_SPI_MODE_SLAVE;
1085 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1086 // Parse 'format' (clock polarity/phase or frame format)
1087 ptr_str = strstr(ptr_str, ","); // Find ','
1088 if (ptr_str != NULL) { // If ',' was found
1089 ptr_str++; // Skip ','
1090 while (*ptr_str == ' ') { // Skip whitespaces after ','
1093 if (sscanf(ptr_str, "%u", &val) == 1) {
1095 case 0: // Clock polarity 0, clock phase 0
1096 spi_com_config_xfer.format = ARM_SPI_CPOL0_CPHA0;
1098 case 1: // Clock polarity 0, clock phase 1
1099 spi_com_config_xfer.format = ARM_SPI_CPOL0_CPHA1;
1101 case 2: // Clock polarity 1, clock phase 0
1102 spi_com_config_xfer.format = ARM_SPI_CPOL1_CPHA0;
1104 case 3: // Clock polarity 1, clock phase 1
1105 spi_com_config_xfer.format = ARM_SPI_CPOL1_CPHA1;
1107 case 4: // Texas Instruments Frame Format
1108 spi_com_config_xfer.format = ARM_SPI_TI_SSI;
1110 case 5: // National Microwire Frame Format
1111 spi_com_config_xfer.format = ARM_SPI_MICROWIRE;
1123 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1125 ptr_str = strstr(ptr_str, ","); // Find ','
1126 if (ptr_str != NULL) { // If ',' was found
1127 ptr_str++; // Skip ','
1128 while (*ptr_str == ' ') { // Skip whitespaces after ','
1131 if (sscanf(ptr_str, "%u", &val) == 1) {
1132 if ((val > 0U) && (val <= 32U)) {
1133 spi_com_config_xfer.bit_num = ARM_SPI_DATA_BITS(val);
1143 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1144 // Parse 'bit_order'
1145 ptr_str = strstr(ptr_str, ","); // Find ','
1146 if (ptr_str != NULL) { // If ',' was found
1147 ptr_str++; // Skip ','
1148 while (*ptr_str == ' ') { // Skip whitespaces after ','
1151 if (sscanf(ptr_str, "%u", &val) == 1) {
1153 spi_com_config_xfer.bit_order = ARM_SPI_MSB_LSB;
1154 } else if (val == 1U) {
1155 spi_com_config_xfer.bit_order = ARM_SPI_LSB_MSB;
1165 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1167 ptr_str = strstr(ptr_str, ","); // Find ','
1168 if (ptr_str != NULL) { // If ',' was found
1169 ptr_str++; // Skip ','
1170 while (*ptr_str == ' ') { // Skip whitespaces after ','
1173 if (sscanf(ptr_str, "%u", &val) == 1) {
1174 if (spi_com_config_xfer.mode == ARM_SPI_MODE_MASTER) {
1175 // Slave Select modes for Master mode
1178 spi_com_config_xfer.ss_mode = ARM_SPI_SS_MASTER_UNUSED;
1181 spi_com_config_xfer.ss_mode = ARM_SPI_SS_MASTER_HW_OUTPUT;
1188 // Slave Select modes for Slave mode
1191 spi_com_config_xfer.ss_mode = ARM_SPI_SS_SLAVE_SW;
1194 spi_com_config_xfer.ss_mode = ARM_SPI_SS_SLAVE_HW;
1207 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1208 // Parse 'bus_speed'
1209 ptr_str = strstr(ptr_str, ","); // Find ','
1210 if (ptr_str != NULL) { // If ',' was found
1211 ptr_str++; // Skip ','
1212 while (*ptr_str == ' ') { // Skip whitespaces after ','
1215 if (sscanf(ptr_str, "%u", &val) == 1) {
1216 spi_com_config_xfer.bus_speed = val;
1227 \fn static int32_t SPI_Cmd_Xfer (const char *cmd)
1228 \brief Handle command "XFER num[,delay_c][,delay_t][,timeout]".
1229 \detail Send data from SPI TX buffer and receive data to SPI RX buffer
1230 (buffers must be set with "SET BUF" command before this command).
1231 Control function is delayed by optional parameter 'delay_c' in milliseconds.
1232 Transfer function is delayed by optional parameter 'delay_t' in milliseconds,
1233 starting after delay specified with 'delay_c' parameter.
1234 \param[in] cmd Pointer to null-terminated command string
1235 \return execution status
1236 - EXIT_SUCCESS: Operation successful
1237 - EXIT_FAILURE: Operation failed
1239 static int32_t SPI_Cmd_Xfer (const char *cmd) {
1240 const char *ptr_str;
1241 uint32_t val, num, delay_c, delay_t, start_tick, curr_tick;
1250 ptr_str = &cmd[4]; // Skip "XFER"
1251 while (*ptr_str == ' ') { // Skip whitespaces
1256 if (sscanf(ptr_str, "%u", &val) == 1) {
1257 if ((val > 0U) && (val <= spi_xfer_buf_size)) {
1266 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1267 // Parse optional 'delay_c'
1268 ptr_str = strstr(ptr_str, ","); // Find ','
1269 if (ptr_str != NULL) { // If ',' was found
1270 ptr_str++; // Skip ','
1271 while (*ptr_str == ' ') { // Skip whitespaces after ','
1274 if (sscanf(ptr_str, "%u", &val) == 1) {
1275 if (val != osWaitForever) {
1286 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1287 // Parse optional 'delay_t'
1288 ptr_str = strstr(ptr_str, ","); // Find ','
1289 if (ptr_str != NULL) { // If ',' was found
1290 ptr_str++; // Skip ','
1291 while (*ptr_str == ' ') { // Skip whitespaces after ','
1294 if (sscanf(ptr_str, "%u", &val) == 1) {
1295 if (val != osWaitForever) {
1306 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1307 // Parse optional 'timeout'
1308 ptr_str = strstr(ptr_str, ","); // Find ','
1309 if (ptr_str != NULL) { // If ',' was found
1310 ptr_str++; // Skip ','
1311 while (*ptr_str == ' ') { // Skip whitespaces after ','
1314 if (sscanf(ptr_str, "%u", &val) == 1) {
1315 if (val != osWaitForever) {
1316 spi_xfer_timeout = val;
1326 start_tick = osKernelGetTickCount();
1328 if (ret == EXIT_SUCCESS) {
1330 ret = SPI_Com_Configure(&spi_com_config_inactive);
1333 if ((ret == EXIT_SUCCESS) && (delay_c != 0U)) {
1334 // Delay before Control function is called
1335 (void)osDelay(delay_c);
1338 if (ret == EXIT_SUCCESS) {
1339 // Configure communication settings before transfer
1340 ret = SPI_Com_Configure(&spi_com_config_xfer);
1343 if ((ret == EXIT_SUCCESS) && (delay_t != 0U)) {
1344 // Delay before Transfer function is called
1345 (void)osDelay(delay_t);
1348 if ((ret == EXIT_SUCCESS) &&
1349 (spi_com_config_xfer.mode == ARM_SPI_MODE_SLAVE) &&
1350 (spi_com_config_xfer.ss_mode == ARM_SPI_SS_SLAVE_SW)) {
1351 // Only for Slave transfer with Slave Select unused,
1352 // use Software Slave Select and drive it to active state
1353 ret = SPI_Com_SS(1U);
1356 if (ret == EXIT_SUCCESS) {
1358 ret = SPI_Com_Transfer(ptr_spi_xfer_buf_tx, ptr_spi_xfer_buf_rx, num, spi_xfer_timeout);
1361 if ((ret == EXIT_SUCCESS) &&
1362 (spi_com_config_xfer.mode == ARM_SPI_MODE_SLAVE) &&
1363 (spi_com_config_xfer.ss_mode == ARM_SPI_SS_SLAVE_SW)) {
1364 // Only for Slave transfer with Slave Select unused,
1365 // use Software Slave Select and drive it to inactive state
1366 ret = SPI_Com_SS(0U);
1370 (void)SPI_Com_Configure(&spi_com_config_inactive);
1372 // Wait until timeout expires
1373 curr_tick = osKernelGetTickCount();
1374 if ((curr_tick - start_tick) < spi_xfer_timeout) {
1375 (void)osDelay(spi_xfer_timeout - (curr_tick - start_tick));
1378 // Wait additional 10 ms to insure that Client has deactivated
1381 // Revert communication settings to default
1382 (void)SPI_Com_Configure(&spi_com_config_default);
1388 \fn static int32_t SPI_Cmd_GetCnt (const char *cmd)
1389 \brief Handle command "GET CNT".
1390 \detail Return number of items transferred (sent/received) in last transfer
1391 (requested by last XFER command).
1392 \param[in] cmd Pointer to null-terminated command string
1393 \return execution status
1394 - EXIT_SUCCESS: Operation successful
1395 - EXIT_FAILURE: Operation failed
1397 static int32_t SPI_Cmd_GetCnt (const char *cmd) {
1404 memset(spi_cmd_buf_tx, 0, 16);
1405 if (snprintf((char *)spi_cmd_buf_tx, 16, "%u", SPI_Com_GetCnt()) < 16) {
1406 ret = SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(16U, SPI_SERVER_DATA_BITS), spi_cmd_timeout);