2 * Copyright (c) 2020 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"
34 #include "SPI_Server_HW.h"
36 #include "cmsis_os2.h"
37 #include "cmsis_compiler.h"
38 #include "cmsis_vio.h"
40 #include "Driver_SPI.h" // ::CMSIS Driver:SPI
42 #ifndef SPI_SERVER_DEBUG
43 #define SPI_SERVER_DEBUG 0
46 #define SPI_EVENTS_MASK (ARM_SPI_EVENT_TRANSFER_COMPLETE | \
47 ARM_SPI_EVENT_DATA_LOST | \
48 ARM_SPI_EVENT_MODE_FAULT)
50 #define DATA_BITS_TO_BYTES(data_bits) (((data_bits) > 16) ? (4U) : (((data_bits) > 8) ? (2U) : (1U)))
51 #define BYTES_TO_ITEMS(bytes,data_bits) ((bytes + DATA_BITS_TO_BYTES(data_bits) - 1U) / DATA_BITS_TO_BYTES(data_bits))
53 /* Access to Driver_SPI# */
54 #define SPI_Driver_Aux(n) Driver_SPI##n
55 #define SPI_Driver_Name(n) SPI_Driver_Aux(n)
56 extern ARM_DRIVER_SPI SPI_Driver_Name(SPI_SERVER_DRV_NUM);
57 #define drvSPI (&SPI_Driver_Name(SPI_SERVER_DRV_NUM))
59 typedef struct { // SPI Interface settings structure
68 // Structure containing command string and pointer to command handling function
71 int32_t (*Command_Func) (const char *command);
76 // Main thread (reception and execution of command)
78 static void SPI_Server_Thread (void *argument);
80 // SPI Interface communication functions
81 static void SPI_Com_Event (uint32_t event);
82 static int32_t SPI_Com_Initialize (void);
83 static int32_t SPI_Com_Uninitialize (void);
84 static int32_t SPI_Com_PowerOn (void);
85 static int32_t SPI_Com_PowerOff (void);
86 static int32_t SPI_Com_Configure (const SPI_COM_CONFIG_t *config);
87 static int32_t SPI_Com_Receive ( void *data_in, uint32_t num, uint32_t timeout);
88 static int32_t SPI_Com_Send (const void *data_out, uint32_t num, uint32_t timeout);
89 static int32_t SPI_Com_Transfer (const void *data_out, void *data_in, uint32_t num, uint32_t timeout);
90 static int32_t SPI_Com_Abort (void);
91 static uint32_t SPI_Com_GetCnt (void);
93 // Command handling functions
94 static int32_t SPI_Cmd_GetVer (const char *cmd);
95 static int32_t SPI_Cmd_GetCap (const char *cmd);
96 static int32_t SPI_Cmd_SetBuf (const char *cmd);
97 static int32_t SPI_Cmd_GetBuf (const char *cmd);
98 static int32_t SPI_Cmd_SetCom (const char *cmd);
99 static int32_t SPI_Cmd_Xfer (const char *cmd);
100 static int32_t SPI_Cmd_GetCnt (const char *cmd);
104 // Command specification (command string, command handling function)
105 static const SPI_CMD_DESC_t spi_cmd_desc[] = {
106 { "GET VER" , SPI_Cmd_GetVer },
107 { "GET CAP" , SPI_Cmd_GetCap },
108 { "SET BUF" , SPI_Cmd_SetBuf },
109 { "GET BUF" , SPI_Cmd_GetBuf },
110 { "SET COM" , SPI_Cmd_SetCom },
111 { "XFER" , SPI_Cmd_Xfer },
112 { "GET CNT" , SPI_Cmd_GetCnt }
115 static osThreadId_t spi_server_thread_id = NULL;
116 static osThreadAttr_t thread_attr = {
117 .name = "SPI_Server_Thread",
121 static uint8_t spi_server_state = SPI_SERVER_STATE_RECEPTION;
122 static uint32_t spi_cmd_timeout = SPI_SERVER_CMD_TIMEOUT;
123 static uint32_t spi_xfer_timeout = SPI_SERVER_CMD_TIMEOUT;
124 static uint32_t spi_xfer_cnt = 0U;
125 static uint32_t spi_xfer_buf_size = SPI_SERVER_BUF_SIZE;
126 static const SPI_COM_CONFIG_t spi_com_config_default = { ARM_SPI_MODE_SLAVE,
127 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk),
128 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk),
129 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk),
131 0U // Bus speed for Slave mode is unused
133 static SPI_COM_CONFIG_t spi_com_config_xfer;
134 static uint8_t spi_bytes_per_item = 1U;
135 static uint8_t spi_cmd_buf_rx[32] __ALIGNED(4);
136 static uint8_t spi_cmd_buf_tx[32] __ALIGNED(4);
137 static uint8_t *ptr_spi_xfer_buf_rx = NULL;
138 static uint8_t *ptr_spi_xfer_buf_tx = NULL;
139 static void *ptr_spi_xfer_buf_rx_alloc = NULL;
140 static void *ptr_spi_xfer_buf_tx_alloc = NULL;
144 \fn int32_t SPI_Server_Start (void)
145 \brief Initialize, power up, configure SPI interface and start SPI Server thread.
146 \return execution status
147 - EXIT_SUCCESS: Operation successful
148 - EXIT_FAILURE: Operation failed
150 int32_t SPI_Server_Start (void) {
154 (void)vioPrint(vioLevelHeading, " SPI Server v1.0.0 ");
156 // Initialize local variables
157 spi_server_state = SPI_SERVER_STATE_RECEPTION;
158 spi_cmd_timeout = SPI_SERVER_CMD_TIMEOUT;
159 spi_xfer_timeout = SPI_SERVER_CMD_TIMEOUT;
161 spi_xfer_buf_size = SPI_SERVER_BUF_SIZE;
162 spi_bytes_per_item = DATA_BITS_TO_BYTES(SPI_SERVER_DATA_BITS);
163 memset(spi_cmd_buf_rx, 0, sizeof(spi_cmd_buf_rx));
164 memset(spi_cmd_buf_tx, 0, sizeof(spi_cmd_buf_tx));
165 memcpy(&spi_com_config_xfer, &spi_com_config_default, sizeof(SPI_COM_CONFIG_t));
167 // Allocate buffers for data transmission and reception
168 // (maximum size is incremented by 4 bytes to ensure that buffer can be aligned to 4 bytes)
170 ptr_spi_xfer_buf_rx_alloc = malloc(SPI_SERVER_BUF_SIZE + 4U);
171 if (((uint32_t)ptr_spi_xfer_buf_rx_alloc & 3U) != 0U) {
172 // If allocated memory is not 4 byte aligned, use next 4 byte aligned address for ptr_tx_buf
173 ptr_spi_xfer_buf_rx = (uint8_t *)((((uint32_t)ptr_spi_xfer_buf_rx_alloc) + 3U) & (~3U));
175 // If allocated memory is 4 byte aligned, use it directly
176 ptr_spi_xfer_buf_rx = (uint8_t *)ptr_spi_xfer_buf_rx_alloc;
178 ptr_spi_xfer_buf_tx_alloc = malloc(SPI_SERVER_BUF_SIZE + 4U);
179 if (((uint32_t)ptr_spi_xfer_buf_tx_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_tx = (uint8_t *)((((uint32_t)ptr_spi_xfer_buf_tx_alloc) + 3U) & (~3U));
183 // If allocated memory is 4 byte aligned, use it directly
184 ptr_spi_xfer_buf_tx = (uint8_t *)ptr_spi_xfer_buf_tx_alloc;
187 if ((ptr_spi_xfer_buf_rx != NULL) || (ptr_spi_xfer_buf_tx != NULL)) {
188 memset(ptr_spi_xfer_buf_rx, 0, SPI_SERVER_BUF_SIZE);
189 memset(ptr_spi_xfer_buf_rx, 0, SPI_SERVER_BUF_SIZE);
195 if (ret == EXIT_SUCCESS) {
196 ret = SPI_Com_Initialize();
199 if (ret == EXIT_SUCCESS) {
200 ret = SPI_Com_PowerOn();
203 if (ret == EXIT_SUCCESS) {
204 ret = SPI_Com_Configure(&spi_com_config_default);
207 if ((ret == EXIT_SUCCESS) && (spi_server_thread_id == NULL)) {
208 // Create SPI_Server_Thread thread
209 spi_server_thread_id = osThreadNew(SPI_Server_Thread, NULL, &thread_attr);
210 if (spi_server_thread_id == NULL) {
215 if (ret != EXIT_SUCCESS) {
216 vioPrint(vioLevelError, "Server Start failed!");
223 \fn int32_t SPI_Server_Stop (void)
224 \brief Terminate SPI Server thread, power down and uninitialize SPI interface.
225 \return execution status
226 - EXIT_SUCCESS: Operation successful
227 - EXIT_FAILURE: Operation failed
229 int32_t SPI_Server_Stop (void) {
235 if (spi_server_thread_id != NULL) {
236 spi_server_state = SPI_SERVER_STATE_TERMINATE;
237 for (i = 0U; i < 10U; i++) {
238 if (osThreadGetState(spi_server_thread_id) == osThreadTerminated) {
239 spi_server_thread_id = NULL;
247 if (ret == EXIT_SUCCESS) {
248 ret = SPI_Com_PowerOff();
251 if (ret == EXIT_SUCCESS) {
252 ret = SPI_Com_Uninitialize();
255 if (ptr_spi_xfer_buf_rx_alloc != NULL) {
256 free(ptr_spi_xfer_buf_rx_alloc);
257 ptr_spi_xfer_buf_rx = NULL;
258 ptr_spi_xfer_buf_rx_alloc = NULL;
260 if (ptr_spi_xfer_buf_tx_alloc != NULL) {
261 free(ptr_spi_xfer_buf_tx_alloc);
262 ptr_spi_xfer_buf_tx = NULL;
263 ptr_spi_xfer_buf_tx_alloc = NULL;
266 if (ret != EXIT_SUCCESS) {
267 vioPrint(vioLevelError, "Server Stop failed! ");
277 \fn static void SPI_Server_Thread (void *argument)
278 \brief SPI Server thread function.
279 \detail This is a thread function that waits to receive a command from SPI Client
280 (Driver Validation suite), and after command is received it is executed
281 and the process starts again by waiting to receive next command.
282 \param[in] argument Not used
285 static void SPI_Server_Thread (void *argument) {
291 switch (spi_server_state) {
293 case SPI_SERVER_STATE_RECEPTION: // Receive a command
294 vioPrint(vioLevelMessage, "Status: Receiving");
295 if (SPI_Com_Receive(spi_cmd_buf_rx, BYTES_TO_ITEMS(sizeof(spi_cmd_buf_rx),SPI_SERVER_DATA_BITS), osWaitForever) == EXIT_SUCCESS) {
296 spi_server_state = SPI_SERVER_STATE_EXECUTION;
298 // If 32 byte command was not received restart the reception of 32 byte command
301 case SPI_SERVER_STATE_EXECUTION: // Execute a command
302 vioPrint(vioLevelMessage, "Status: Executing\r\n%.20s ", spi_cmd_buf_rx);
303 // Find the command and call handling function
304 for (i = 0U; i < (sizeof(spi_cmd_desc) / sizeof(SPI_CMD_DESC_t)); i++) {
305 if (memcmp(spi_cmd_buf_rx, spi_cmd_desc[i].command, strlen(spi_cmd_desc[i].command)) == 0) {
306 (void)spi_cmd_desc[i].Command_Func((const char *)spi_cmd_buf_rx);
310 spi_server_state = SPI_SERVER_STATE_RECEPTION;
313 case SPI_SERVER_STATE_TERMINATE: // Self-terminate the thread
314 default: // Should never happen, processed as terminate request
315 vioPrint(vioLevelError, "Server stopped! ");
316 (void)SPI_Com_Abort();
317 (void)osThreadTerminate(osThreadGetId());
324 \fn static void SPI_Com_Event (uint32_t event)
325 \brief SPI communication event callback (called from SPI driver from IRQ context).
326 \detail This function dispatches event (flag) to SPI Server thread.
327 \param[in] event SPI event
328 - ARM_SPI_EVENT_TRANSFER_COMPLETE: Data Transfer completed
329 - ARM_SPI_EVENT_DATA_LOST: Data lost: Receive overflow / Transmit underflow
330 - ARM_SPI_EVENT_MODE_FAULT: Master Mode Fault (SS deactivated when Master)
333 static void SPI_Com_Event (uint32_t event) {
335 if (spi_server_thread_id != NULL) {
336 (void)osThreadFlagsSet(spi_server_thread_id, event);
341 \fn static int32_t SPI_Com_Initialize (void)
342 \brief Initialize SPI interface.
343 \return execution status
344 - EXIT_SUCCESS: Operation successful
345 - EXIT_FAILURE: Operation failed
347 static int32_t SPI_Com_Initialize (void) {
352 if (drvSPI->Initialize(SPI_Com_Event) == ARM_DRIVER_OK) {
360 \fn static int32_t SPI_Com_Uninitialize (void)
361 \brief Uninitialize SPI interface.
362 \return execution status
363 - EXIT_SUCCESS: Operation successful
364 - EXIT_FAILURE: Operation failed
366 static int32_t SPI_Com_Uninitialize (void) {
371 if (drvSPI->Uninitialize() == ARM_DRIVER_OK) {
379 \fn static int32_t SPI_Com_PowerOn (void)
380 \brief Power-up SPI interface.
381 \return execution status
382 - EXIT_SUCCESS: Operation successful
383 - EXIT_FAILURE: Operation failed
385 static int32_t SPI_Com_PowerOn (void) {
390 if (drvSPI->PowerControl(ARM_POWER_FULL) == ARM_DRIVER_OK) {
398 \fn static int32_t SPI_Com_PowerOff (void)
399 \brief Power-down SPI interface.
400 \return execution status
401 - EXIT_SUCCESS: Operation successful
402 - EXIT_FAILURE: Operation failed
404 static int32_t SPI_Com_PowerOff (void) {
409 if (drvSPI->PowerControl(ARM_POWER_OFF) == ARM_DRIVER_OK) {
417 \fn static int32_t SPI_Com_Configure (const SPI_COM_CONFIG_t *config)
418 \brief Configure SPI interface.
419 \param[in] config Pointer to structure containing SPI interface configuration settings
420 \return execution status
421 - EXIT_SUCCESS: Operation successful
422 - EXIT_FAILURE: Operation failed
424 static int32_t SPI_Com_Configure (const SPI_COM_CONFIG_t *config) {
429 if (drvSPI->Control(config->mode |
434 config->bus_speed ) == ARM_DRIVER_OK) {
435 spi_bytes_per_item = DATA_BITS_TO_BYTES((config->bit_num & ARM_SPI_DATA_BITS_Msk) >> ARM_SPI_DATA_BITS_Pos);
439 if (((config->mode == ARM_SPI_MODE_MASTER) && (config->ss_mode == ARM_SPI_SS_MASTER_UNUSED)) ||
440 ((config->mode == ARM_SPI_MODE_SLAVE) && (config->ss_mode == ARM_SPI_SS_SLAVE_SW))) {
441 // For Master mode with unused Slave Select and for Slave mode with software Slave Select handling
442 // configure Slave Select line to GPIO mode and drive it inactive because usually when
443 // Slave Select pin is deinitialized it results in pin having low logical state which could
444 // interfere with testing
445 SPI_Server_Pin_SS_Initialize();
446 SPI_Server_Pin_SS_SetState(ARM_SPI_SS_INACTIVE);
453 \fn static int32_t SPI_Com_Receive (void *data_in, uint32_t num, uint32_t timeout)
454 \brief Receive data (command) over SPI interface.
455 \param[out] data_in Pointer to memory where data will be received
456 \param[in] num Number of data items to be received
457 \param[in] timeout Timeout for reception (in ms)
458 \return execution status
459 - EXIT_SUCCESS: Operation successful
460 - EXIT_FAILURE: Operation failed
462 static int32_t SPI_Com_Receive (void *data_in, uint32_t num, uint32_t timeout) {
464 uint32_t flags, tmo, time, cnt;
468 if (spi_server_thread_id != NULL) {
469 memset(data_in, (int32_t)'?', spi_bytes_per_item * num);
470 vioSetSignal (vioLED0, vioLEDon);
473 if (drvSPI->Receive(data_in, num) == ARM_DRIVER_OK) {
480 flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, tmo);
481 if (flags == osFlagsErrorTimeout) { // If timeout
482 if (time != osWaitForever) {
485 if (drvSPI->GetDataCount() != 0U) {
486 while (cnt != drvSPI->GetDataCount()) { // While count is changing
487 cnt = drvSPI->GetDataCount();
488 flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, 10U);
489 if (flags == osFlagsErrorTimeout) { // If timeout
490 if (time != osWaitForever) {
498 } else if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
499 // If completed event was signaled
503 // In all other cases exit with failed status
508 // If something was received but not of expected size then terminate the reception
512 } else if ((flags & (0x80000000U | ARM_SPI_EVENT_TRANSFER_COMPLETE)) == ARM_SPI_EVENT_TRANSFER_COMPLETE) {
513 // If completed event was signaled
517 // In all other cases exit with failed status
521 if (ret != EXIT_SUCCESS) {
522 // If receive was activated but failed to receive expected data then abort the transfer
523 (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
525 vioSetSignal (vioLED0, vioLEDoff);
533 \fn static int32_t SPI_Com_Send (const void *data_out, uint32_t num, uint32_t timeout)
534 \brief Send data (response) over SPI interface.
535 \param[out] data_out Pointer to memory containing data to be sent
536 \param[in] num Number of data items to be sent
537 \param[in] timeout Timeout for send (in ms)
538 \return execution status
539 - EXIT_SUCCESS: Operation successful
540 - EXIT_FAILURE: Operation failed
542 static int32_t SPI_Com_Send (const void *data_out, uint32_t num, uint32_t timeout) {
548 if (spi_server_thread_id != NULL) {
549 vioSetSignal (vioLED1, vioLEDon);
550 if (drvSPI->Send(data_out, num) == ARM_DRIVER_OK) {
551 flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, timeout);
552 if ((flags & ARM_SPI_EVENT_TRANSFER_COMPLETE) != 0U) {
553 // If completed event was signaled
556 vioSetSignal (vioLED1, vioLEDoff);
557 if (ret != EXIT_SUCCESS) {
558 // If error or timeout
559 (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
568 \fn static int32_t SPI_Com_Transfer (const void *data_out, void *data_in, uint32_t num, uint32_t timeout)
569 \brief Transfer (send/receive) data over SPI interface.
570 \param[in] data_out Pointer to memory containing data to be sent
571 \param[out] data_in Pointer to memory where data will be received
572 \param[in] num Number of data items to be transferred
573 \param[in] timeout Timeout for transfer (in ms)
574 \return execution status
575 - EXIT_SUCCESS: Operation successful
576 - EXIT_FAILURE: Operation failed
578 static int32_t SPI_Com_Transfer (const void *data_out, void *data_in, uint32_t num, uint32_t timeout) {
584 if (spi_server_thread_id != NULL) {
585 vioSetSignal (vioLED2, vioLEDon);
586 if (drvSPI->Transfer(data_out, data_in, num) == ARM_DRIVER_OK) {
587 flags = osThreadFlagsWait(SPI_EVENTS_MASK, osFlagsWaitAny, timeout);
588 vioSetSignal (vioLED2, vioLEDoff);
589 if ((flags & ARM_SPI_EVENT_TRANSFER_COMPLETE) != 0U) {
590 // If completed event was signaled
593 // If error or timeout
594 (void)drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U);
603 \fn static int32_t SPI_Com_Abort (void)
604 \brief Abort current transfer on SPI interface.
605 \return execution status
606 - EXIT_SUCCESS: Operation successful
607 - EXIT_FAILURE: Operation failed
609 static int32_t SPI_Com_Abort (void) {
614 if (drvSPI->Control(ARM_SPI_ABORT_TRANSFER, 0U) == ARM_DRIVER_OK) {
622 \fn static uint32_t SPI_Com_GetCnt (void)
623 \brief Get number of data items transferred over SPI interface in last transfer.
624 \return number of data items transferred
626 static uint32_t SPI_Com_GetCnt (void) {
631 // Command handling functions
634 \fn static int32_t SPI_Cmd_GetVer (const char *cmd)
635 \brief Handle command "GET VER".
636 \detail Return SPI Server version over SPI interface (16 bytes).
637 \param[in] cmd Pointer to null-terminated command string
638 \return execution status
639 - EXIT_SUCCESS: Operation successful
640 - EXIT_FAILURE: Operation failed
642 static int32_t SPI_Cmd_GetVer (const char *cmd) {
646 memset(spi_cmd_buf_tx, 0, 16);
647 memcpy(spi_cmd_buf_tx, SPI_SERVER_VER, sizeof(SPI_SERVER_VER));
649 return (SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(16U, SPI_SERVER_DATA_BITS), spi_cmd_timeout));
653 \fn static int32_t SPI_Cmd_GetCap (const char *cmd)
654 \brief Handle command "GET CAP".
655 \detail Return SPI Server capabilities over SPI interface (32 bytes).
656 \param[in] cmd Pointer to null-terminated command string
657 \return execution status
658 - EXIT_SUCCESS: Operation successful
659 - EXIT_FAILURE: Operation failed
661 static int32_t SPI_Cmd_GetCap (const char *cmd) {
663 uint32_t mode_mask, format_mask, data_bits_mask, bit_order_mask, bus_speed_min, bus_speed_max;
671 // Determine supported minimum bus speed
672 // Find minimum speed setting at which Control function succeeds
675 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
676 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
677 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
678 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
679 ARM_SPI_SS_MASTER_HW_OUTPUT ,
680 bs ) == ARM_DRIVER_OK) {
683 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
684 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
685 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
686 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
687 ARM_SPI_SS_MASTER_HW_OUTPUT ,
688 bs * 2U) == ARM_DRIVER_OK) {
692 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
693 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
694 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
695 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
696 ARM_SPI_SS_MASTER_HW_OUTPUT ,
697 bs * 5U) == ARM_DRIVER_OK) {
701 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
702 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
703 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
704 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
705 ARM_SPI_SS_MASTER_HW_OUTPUT ,
706 bs * 10U) == ARM_DRIVER_OK) {
711 } while (bs < 1000000U);
714 // Determine supported maximum bus speed
715 // Find maximum speed setting at which Control function succeeds
718 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
719 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
720 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
721 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
722 ARM_SPI_SS_MASTER_HW_OUTPUT ,
723 bs ) == ARM_DRIVER_OK) {
726 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
727 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
728 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
729 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
730 ARM_SPI_SS_MASTER_HW_OUTPUT ,
731 bs / 2U) == ARM_DRIVER_OK) {
735 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
736 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
737 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
738 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
739 ARM_SPI_SS_MASTER_HW_OUTPUT ,
740 bs / 5U) == ARM_DRIVER_OK) {
744 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
745 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
746 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
747 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
748 ARM_SPI_SS_MASTER_HW_OUTPUT ,
749 bs / 10U) == ARM_DRIVER_OK) {
754 } while (bs > 1000000U);
757 // Determine supported modes
759 if (drvSPI->Control(ARM_SPI_MODE_MASTER |
760 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
761 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
762 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
763 ARM_SPI_SS_MASTER_HW_OUTPUT ,
764 bus_speed_min ) == ARM_DRIVER_OK) {
768 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
769 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
770 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
771 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
772 ARM_SPI_SS_SLAVE_HW ,
773 0U ) == ARM_DRIVER_OK) {
774 mode_mask |= 1U << 1;
777 // Determine supported clock / frame format
779 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
780 ARM_SPI_CPOL0_CPHA0 |
781 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
782 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
783 ARM_SPI_SS_SLAVE_HW ,
784 0U ) == ARM_DRIVER_OK) {
787 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
788 ARM_SPI_CPOL0_CPHA1 |
789 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
790 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
791 ARM_SPI_SS_SLAVE_HW ,
792 0U ) == ARM_DRIVER_OK) {
793 format_mask |= 1U << 1;
795 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
796 ARM_SPI_CPOL1_CPHA0 |
797 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
798 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
799 ARM_SPI_SS_SLAVE_HW ,
800 0U ) == ARM_DRIVER_OK) {
801 format_mask |= 1U << 2;
803 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
804 ARM_SPI_CPOL1_CPHA1 |
805 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
806 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
807 ARM_SPI_SS_SLAVE_HW ,
808 0U ) == ARM_DRIVER_OK) {
809 format_mask |= 1U << 3;
811 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
813 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
814 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
815 ARM_SPI_SS_SLAVE_HW ,
816 0U ) == ARM_DRIVER_OK) {
817 format_mask |= 1U << 4;
819 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
821 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
822 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
823 ARM_SPI_SS_SLAVE_HW ,
824 0U ) == ARM_DRIVER_OK) {
825 format_mask |= 1U << 5;
828 // Determine supported data bits
830 for (i = 1U; i <= 32U; i++) {
831 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
832 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
833 ((i << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
834 ((SPI_SERVER_BIT_ORDER << ARM_SPI_BIT_ORDER_Pos) & ARM_SPI_BIT_ORDER_Msk) |
835 ARM_SPI_SS_SLAVE_HW ,
836 0U ) == ARM_DRIVER_OK) {
837 data_bits_mask |= 1UL << (i - 1U);
841 // Determine bit order
843 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
844 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
845 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
847 ARM_SPI_SS_SLAVE_HW ,
848 0U ) == ARM_DRIVER_OK) {
849 bit_order_mask |= 1U;
851 if (drvSPI->Control(ARM_SPI_MODE_SLAVE |
852 ((SPI_SERVER_FORMAT << ARM_SPI_FRAME_FORMAT_Pos) & ARM_SPI_FRAME_FORMAT_Msk) |
853 ((SPI_SERVER_DATA_BITS << ARM_SPI_DATA_BITS_Pos) & ARM_SPI_DATA_BITS_Msk) |
855 ARM_SPI_SS_SLAVE_HW ,
856 0U ) == ARM_DRIVER_OK) {
857 bit_order_mask |= 1U << 1;
860 // Revert communication settings to default because they were changed during auto-detection of capabilities
861 (void)SPI_Com_Configure(&spi_com_config_default);
863 memset(spi_cmd_buf_tx, 0, 32);
864 if (snprintf((char *)spi_cmd_buf_tx, 32, "%02X,%02X,%08X,%02X,%i,%i",
869 (bus_speed_min / 1000U),
870 (bus_speed_max / 1000U)) <= 32) {
871 ret = SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(32U, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
878 \fn static int32_t SPI_Cmd_SetBuf (const char *cmd)
879 \brief Handle command "SET BUF RX/TX,len[,pattern]".
880 \detail Initialize content of the buffer in the following way:
881 - fill whole buffer with 'pattern' value if it is specified, and 'len' is 0
882 - fill whole buffer with 0 if 'pattern' is not provided and 'len' is 0
883 - load 'len' bytes from start of the buffer with content
884 received in IN data phase
885 \param[in] cmd Pointer to null-terminated command string
886 \return execution status
887 - EXIT_SUCCESS: Operation successful
888 - EXIT_FAILURE: Operation failed
890 static int32_t SPI_Cmd_SetBuf (const char *cmd) {
904 // Parse 'RX' or 'TX' selection
905 if (strstr(cmd, "RX") != NULL) {
906 ptr_buf = ptr_spi_xfer_buf_rx;
907 } else if (strstr(cmd, "TX") != NULL) {
908 ptr_buf = ptr_spi_xfer_buf_tx;
913 if (ret == EXIT_SUCCESS) {
915 ptr_str = strstr(cmd, ","); // Find ','
916 if (ptr_str != NULL) { // If ',' was found
917 ptr_str++; // Skip ','
918 while (*ptr_str == ' ') { // Skip whitespaces after ','
921 if (sscanf(ptr_str, "%u", &val) == 1) {
922 if (val <= spi_xfer_buf_size) {
935 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
936 // Parse optional 'pattern'
937 ptr_str = strstr(ptr_str, ","); // 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, "%x", &val) == 1) {
944 pattern = (uint8_t)val;
951 if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL)) {
952 // Fill the whole buffer with 'pattern', if 'pattern' was not specified
953 // in the command then the whole buffer will be filled with 0
954 memset(ptr_buf, (int32_t)pattern, spi_xfer_buf_size);
957 if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL) && (len != 0U)) {
958 // Load 'len' bytes from start of buffer with content received in IN data phase
959 ret = SPI_Com_Receive(ptr_buf, BYTES_TO_ITEMS(len, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
966 \fn static int32_t SPI_Cmd_GetBuf (const char *cmd)
967 \brief Handle command "GET BUF RX/TX,len".
968 \detail Send content of buffer over SPI interface.
969 \param[in] cmd Pointer to null-terminated command string
970 \return execution status
971 - EXIT_SUCCESS: Operation successful
972 - EXIT_FAILURE: Operation failed
974 static int32_t SPI_Cmd_GetBuf (const char *cmd) {
976 const uint8_t *ptr_buf;
986 // Parse 'RX' or 'TX' selection
987 if (strstr(cmd, "RX") != NULL) {
988 ptr_buf = ptr_spi_xfer_buf_rx;
989 } else if (strstr(cmd, "TX") != NULL) {
990 ptr_buf = ptr_spi_xfer_buf_tx;
995 if (ret == EXIT_SUCCESS) {
997 ptr_str = strstr(cmd, ","); // Find ','
998 if (ptr_str != NULL) { // If ',' was found
999 ptr_str++; // Skip ','
1000 while (*ptr_str == ' ') { // Skip whitespaces after ','
1003 if (sscanf(ptr_str, "%u", &val) == 1) {
1004 if ((val > 0U) && (val <= spi_xfer_buf_size)) {
1017 if ((ret == EXIT_SUCCESS) && (ptr_buf != NULL) && (len != 0U)) {
1018 ret = SPI_Com_Send(ptr_buf, BYTES_TO_ITEMS(len, SPI_SERVER_DATA_BITS), spi_cmd_timeout);
1025 \fn static int32_t SPI_Cmd_SetCom (const char *cmd)
1026 \brief Handle command "SET COM mode,format,bit_num,bit_order,ss_mode,bus_speed".
1027 \detail Set communication configuration settings used for transfers (XFER commands).
1028 \param[in] cmd Pointer to null-terminated command string
1029 \return execution status
1030 - EXIT_SUCCESS: Operation successful
1031 - EXIT_FAILURE: Operation failed
1033 static int32_t SPI_Cmd_SetCom (const char *cmd) {
1034 const char *ptr_str;
1041 ptr_str = &cmd[7]; // Skip "SET COM"
1042 while (*ptr_str == ' ') { // Skip whitespaces
1047 if (sscanf(ptr_str, "%u", &val) == 1) {
1049 case 0U: // Master mode
1050 spi_com_config_xfer.mode = ARM_SPI_MODE_MASTER;
1052 case 1U: // Slave mode
1053 spi_com_config_xfer.mode = ARM_SPI_MODE_SLAVE;
1063 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1064 // Parse 'format' (clock polarity/phase or frame format)
1065 ptr_str = strstr(ptr_str, ","); // Find ','
1066 if (ptr_str != NULL) { // If ',' was found
1067 ptr_str++; // Skip ','
1068 while (*ptr_str == ' ') { // Skip whitespaces after ','
1071 if (sscanf(ptr_str, "%u", &val) == 1) {
1073 case 0: // Clock polarity 0, clock phase 0
1074 spi_com_config_xfer.format = ARM_SPI_CPOL0_CPHA0;
1076 case 1: // Clock polarity 0, clock phase 1
1077 spi_com_config_xfer.format = ARM_SPI_CPOL0_CPHA1;
1079 case 2: // Clock polarity 1, clock phase 0
1080 spi_com_config_xfer.format = ARM_SPI_CPOL1_CPHA0;
1082 case 3: // Clock polarity 1, clock phase 1
1083 spi_com_config_xfer.format = ARM_SPI_CPOL1_CPHA1;
1085 case 4: // Texas Instruments Frame Format
1086 spi_com_config_xfer.format = ARM_SPI_TI_SSI;
1088 case 5: // National Microwire Frame Format
1089 spi_com_config_xfer.format = ARM_SPI_MICROWIRE;
1101 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1103 ptr_str = strstr(ptr_str, ","); // Find ','
1104 if (ptr_str != NULL) { // If ',' was found
1105 ptr_str++; // Skip ','
1106 while (*ptr_str == ' ') { // Skip whitespaces after ','
1109 if (sscanf(ptr_str, "%u", &val) == 1) {
1110 if ((val > 0U) && (val <= 32U)) {
1111 spi_com_config_xfer.bit_num = ARM_SPI_DATA_BITS(val);
1121 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1122 // Parse 'bit_order'
1123 ptr_str = strstr(ptr_str, ","); // Find ','
1124 if (ptr_str != NULL) { // If ',' was found
1125 ptr_str++; // Skip ','
1126 while (*ptr_str == ' ') { // Skip whitespaces after ','
1129 if (sscanf(ptr_str, "%u", &val) == 1) {
1131 spi_com_config_xfer.bit_order = ARM_SPI_MSB_LSB;
1132 } else if (val == 1U) {
1133 spi_com_config_xfer.bit_order = ARM_SPI_LSB_MSB;
1143 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
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) {
1152 if (spi_com_config_xfer.mode == ARM_SPI_MODE_MASTER) {
1153 // Slave Select modes for Master mode
1156 spi_com_config_xfer.ss_mode = ARM_SPI_SS_MASTER_UNUSED;
1159 spi_com_config_xfer.ss_mode = ARM_SPI_SS_MASTER_HW_OUTPUT;
1166 // Slave Select modes for Slave mode
1169 spi_com_config_xfer.ss_mode = ARM_SPI_SS_SLAVE_SW;
1172 spi_com_config_xfer.ss_mode = ARM_SPI_SS_SLAVE_HW;
1185 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1186 // Parse 'bus_speed'
1187 ptr_str = strstr(ptr_str, ","); // Find ','
1188 if (ptr_str != NULL) { // If ',' was found
1189 ptr_str++; // Skip ','
1190 while (*ptr_str == ' ') { // Skip whitespaces after ','
1193 if (sscanf(ptr_str, "%u", &val) == 1) {
1194 spi_com_config_xfer.bus_speed = val;
1205 \fn static int32_t SPI_Cmd_Xfer (const char *cmd)
1206 \brief Handle command "XFER num[,delay][,timeout][,num_ss]".
1207 \detail Send data from SPI TX buffer and receive data to SPI RX buffer
1208 (buffers must be set with "SET BUF" command before this command).
1209 Transfer start is delayed by optional parameter 'delay' in milliseconds.
1210 Optional parameter 'num_ss' specifies number of items that should be transferred
1211 before GPIO driving Slave Select line of SPI Client is activated, this situation
1212 is used to force mode fault error in multi-master setting.
1213 \param[in] cmd Pointer to null-terminated command string
1214 \return execution status
1215 - EXIT_SUCCESS: Operation successful
1216 - EXIT_FAILURE: Operation failed
1218 static int32_t SPI_Cmd_Xfer (const char *cmd) {
1219 const char *ptr_str;
1220 uint32_t val, num, delay, num_ss;
1222 uint8_t num_ss_provided;
1229 num_ss_provided = 0U;
1231 ptr_str = &cmd[4]; // Skip "XFER"
1232 while (*ptr_str == ' ') { // Skip whitespaces
1237 if (sscanf(ptr_str, "%u", &val) == 1) {
1238 if ((val > 0U) && (val <= spi_xfer_buf_size)) {
1247 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1248 // Parse optional 'delay'
1249 ptr_str = strstr(ptr_str, ","); // Find ','
1250 if (ptr_str != NULL) { // If ',' was found
1251 ptr_str++; // Skip ','
1252 while (*ptr_str == ' ') { // Skip whitespaces after ','
1255 if (sscanf(ptr_str, "%u", &val) == 1) {
1256 if (val != osWaitForever) {
1267 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1268 // Parse optional 'timeout'
1269 ptr_str = strstr(ptr_str, ","); // Find ','
1270 if (ptr_str != NULL) { // If ',' was found
1271 ptr_str++; // Skip ','
1272 while (*ptr_str == ' ') { // Skip whitespaces after ','
1275 if (sscanf(ptr_str, "%u", &val) == 1) {
1276 if (val != osWaitForever) {
1277 spi_xfer_timeout = val;
1287 if ((ret == EXIT_SUCCESS) && (ptr_str != NULL)) {
1288 // Parse optional 'num_ss'
1289 ptr_str = strstr(ptr_str, ","); // Find ','
1290 if (ptr_str != NULL) { // If ',' was found
1291 ptr_str++; // Skip ','
1292 while (*ptr_str == ' ') { // Skip whitespaces after ','
1295 if (sscanf(ptr_str, "%u", &val) == 1) {
1298 num_ss_provided = 1U;
1308 if ((ret == EXIT_SUCCESS) && (delay != 0U)) {
1309 (void)osDelay(delay);
1312 if (ret == EXIT_SUCCESS) {
1313 // Configure communication settings before transfer
1314 ret = SPI_Com_Configure(&spi_com_config_xfer);
1316 if (ret == EXIT_SUCCESS) {
1317 if (num_ss_provided == 0U) { // Normal transfer (in Slave or Master mode)
1319 ret = SPI_Com_Transfer(ptr_spi_xfer_buf_tx, ptr_spi_xfer_buf_rx, num, spi_xfer_timeout);
1320 spi_xfer_cnt = drvSPI->GetDataCount();
1321 } else { // Special handling for generation of master mode fault
1323 // Transfer num_ss number of items if num_ss != 0
1324 ret = SPI_Com_Transfer(ptr_spi_xfer_buf_tx, ptr_spi_xfer_buf_rx, num_ss, spi_xfer_timeout);
1325 spi_xfer_cnt = drvSPI->GetDataCount();
1328 if (ret == EXIT_SUCCESS) {
1329 // Activate GPIO driving Slave Select line of SPI Client
1330 SPI_Server_Pin_SS_Initialize();
1331 SPI_Server_Pin_SS_SetState(ARM_SPI_SS_ACTIVE);
1333 SPI_Server_Pin_SS_SetState(ARM_SPI_SS_INACTIVE);
1334 SPI_Server_Pin_SS_Uninitialize();
1342 // Revert communication settings to default
1343 (void)SPI_Com_Configure(&spi_com_config_default);
1349 \fn static int32_t SPI_Cmd_GetCnt (const char *cmd)
1350 \brief Handle command "GET CNT".
1351 \detail Return number of items transferred (sent/received) in last transfer
1352 (requested by last XFER command).
1353 \param[in] cmd Pointer to null-terminated command string
1354 \return execution status
1355 - EXIT_SUCCESS: Operation successful
1356 - EXIT_FAILURE: Operation failed
1358 static int32_t SPI_Cmd_GetCnt (const char *cmd) {
1365 memset(spi_cmd_buf_tx, 0, 16);
1366 if (snprintf((char *)spi_cmd_buf_tx, 16, "%u", SPI_Com_GetCnt()) < 16) {
1367 ret = SPI_Com_Send(spi_cmd_buf_tx, BYTES_TO_ITEMS(16U, SPI_SERVER_DATA_BITS), spi_cmd_timeout);