This section introduces the Serial Peripheral Interface (SPI) Slave APIs including terms and acronyms, supported features, software architecture, details on how to use this driver, enums, structures and functions.
More...
This section introduces the Serial Peripheral Interface (SPI) Slave APIs including terms and acronyms, supported features, software architecture, details on how to use this driver, enums, structures and functions.
Terms and acronyms
Terms | Details |
DMA | Direct Memory Access. DMA is a feature of computer systems that allows certain hardware subsystems to access main system memory independent from the central processing unit (CPU). |
GPIO | General Purpose Inputs-Outputs. For more details, please refer to GPIO. |
IRQ | Interrupt Request. For more information, please refer to IRQ. |
MISO | Master Input, Slave Output. Output from the SPI slave. |
MOSI | Master Output, Slave Input. Output from the SPI master. |
NVIC | Nested Vectored Interrupt Controller. NVIC is the interrupt controller of ARM Cortex-M series processors. For more details, please refer to ARM Cortex-M4 technical reference manual. |
SCLK | Serial Clock. Output from the SPI master. |
SPI | Serial Peripheral Interface. The SPI bus is a synchronous serial communication interface specification used for short distance communication. For more information, please refer to Serial Peripheral Interface Bus in Wikipedia. |
SS | Slave Select. Output from the SPI master, active low. |
Supported features
Emerging sensor applications support SPI interface communication. An example application is a sensor hub. SPI slave interface is required to communicate with SPI master interface. This controller is a common SPI slave interface that only supports the DMA mode. The SPI slave hardware is enabled to receive a set of commands from the SPI master to handle specific operations. The SPI slave software provides automatic error handling and status update, if the SPI slave hardware detects any malfunction.
- Supporting commands.
- POWER ON command (poweron): This should be the first command the SPI master sends to the SPI slave during a transaction. The length of each POWER ON command is 1 byte.
- POWER OFF command (poweroff): This should be the last command the SPI master sends to the SPI slave during a transaction. The length of each POWER OFF command is 1 byte.
- Configure write command: Use this command to configure parameters for the write operation. The command includes a configure write command (1 byte), addr_id (4 bytes) and (data_length-1)(4 bytes). The total length of this command is 9 bytes, addr_id is used to distinguish between different SPI slave devices. The user needs to make sure different SPI slave devices have different addr_id in one system, data_length is the length of the data to be transferred.
- Write data command: This command is used to write data to the SPI slave device. The command includes a write data command (1 byte), transfer_length (4 bytes) and the total length of this command is (1+transfer_length) bytes, so that slave select signal stays valid for the SPI master to finish the transaction. Note, that transfer_length must be configured with the same value as the data_length in the write command.
- Configure read command: This command is used to configure parameters for the read operation. The command includes a configure read command (1 byte), addr_id (4 bytes) and (data_length-1)(4 bytes). The total length of this command is 9 bytes, addr_id is used to distinguish between different SPI slave devices, the user needs to make sure different SPI slave devices have different addr_id in one system, data_length is the length of the data to be transferred.
- Read data command: This command is used to read data from the SPI slave device. The command includes a read data command (1 byte), transfer_length (4 bytes) and the total length of this command is (1+transfer_length) bytes, so that slave select signal stays valid for the SPI master to finish the transaction. Note, that transfer_length must be configured with the same value as the data_length in the read command.
- Read status command: This command is used for the master to get the SPI slave status. The command includes a read status command (1 byte) and the total length of this command is 2 bytes, so that slave select signal stays valid for master to get the status of SPI slave device.
- Write status command: This command is used for the master to clear the SPI slave device's error status. The command includes a write status command(1 byte) and the bitmap of status to be cleared(1 byte), so the total length of this command is 2 bytes.
- Supporting the command patterns.
In order to use the SPI slave controller, user must make sure the SPI master uses the defined command to send the data out, otherwise it will result in a state machine error. The basic rules of the defined command pattern are shown below: Write command pattern:
- The configure write command must be followed by write data command with no other commands running in between. Read command pattern:
- The configure read command must be followed by read data command with no other commands running in between.
- The poweron command must be the first command to start the data transaction. If the SPI slave is no longer in use, the SPI master should send the poweroff command to the slave. It's possible to have multiple read and write command patterns between the POWER ON and POWER OFF commands.
- Except for the read status command and write status command, any other command sent from the SPI master should be checked whether the command is accepted by the SPI slave successfully by sending a read status command.
- Support the DMA mode.
In DMA mode, functions return a value once the SPI slave hardware register and DMA configuration are set. When functions return, the transaction is usually unfinished. After it's finished, an interrupt is triggered and related user callback is called in the SPI slave interrupt service routine (ISR).
Software architecture of the SPI slave
- The DMA mode architecture.
The DMA mode architecture is similar to the interrupt mode architecture in HAL overview. See HAL Driver Model for interrupt mode architecture.
- The sleep feature support.
SPI slave driver supports locking or unlocking sleep to save power, if #HAL_SLEEP_MANAGER_ENABLED is on. After the SPI slave receives POWER ON command from the SPI master, SPI slave driver will lock sleep to prevent the system to enter sleep mode. After the SPI slave receives POWER OFF command from the SPI master, SPI slave driver will unlock sleep to allow the system to enter sleep mode.
How to use this driver
- Using the SPI slave in the DMA mode. Call hal_pinmux_set_function() to pinmux GPIO pins to four SPI pins (SS, SCLK, MOSI, and MISO) based on the user's hardware platform design. Then call hal_spi_slave_init() in the callback function to apply basic settings for SPI slave hardware. And call hal_spi_slave_register_callback() to register a callback function. Since the SPI slave's behavior is passive, most of the operations are carried through a callback function. If a POWER ON interrupt occurred, SPI slave driver will lock sleep to allow the user to communicate with the SPI master. Once the transaction is over, if a POWER OFF interrupt occurred, SPI slave driver will unlock sleep to allow the system to enter sleep status. The user should call hal_spi_slave_deinit() in the callback function to release the SPI slave resource to make it available for other users. The steps are shown below:
- Step 1. Call hal_gpio_init() to init the pins, if EPT tool hasn't been used to configure the related pinmux.
- Step 2. Call hal_pinmux_set_function() to set the GPIO pinmux, if the EPT tool hasn't been used to configure the related pinmux. For more details about hal_pinmux_set_function(), please refer to GPIO.
- Step 3. Call hal_spi_slave_init() in the callback function, if POWER ON interrupt occurred, to initialize a single SPI slave controller.
- Step 4. Call hal_spi_slave_set_command() to set a user-defined command that matches the SPI master user-defined command. Apply this function to avoid the default settings.
- Step 5. Call hal_spi_slave_set_early_miso() to change the SPI timing.
- Step 6. Call hal_spi_slave_register_callback() to register a user callback.
- Step 7. Call hal_spi_slave_send() in the callback function, if configure read finish interrupt occurred, to send data in the DMA mode.
- Step 8. Call hal_spi_slave_receive() in the callback function, if configure write finish interrupt occurred, to receive data in the DMA mode.
- Step 9. Call hal_spi_slave_deinit() in the callback function, if POWER OFF interrupt occurred, to deinitialize the SPI slave that is no longer in use.
- sample code:
uint16_t slave_status;
}
}
}
{
const uint8_t *data = 0x04000000;
uint32_t size = 0x00000010;
uint8_t *buffer = 0x04000400;
slave_status = status.slave_status;
switch (slave_status) {
break;
}
break;
}
break;
}
break;
break;
break;
break;
break;
break;
default:
break;
}
printf("HAL_SPI_SLAVE_FSM_ERROR_PWROFF_AFTER_CR, current state machine is poweroff\n");
break;
printf("HAL_SPI_SLAVE_FSM_ERROR_PWROFF_AFTER_CW, current state machine is poweroff\n");
break;
printf("HAL_SPI_SLAVE_FSM_ERROR_CONTINOUS_CR, current state machine is CR\n");
break;
printf("HAL_SPI_SLAVE_FSM_ERROR_CR_AFTER_CW, current state machine is CR\n");
break;
printf("HAL_SPI_SLAVE_FSM_ERROR_CONTINOUS_CW, current state machine is CW\n");
break;
printf("HAL_SPI_SLAVE_FSM_ERROR_CW_AFTER_CR, current state machine is CW\n");
break;
printf("HAL_SPI_SLAVE_FSM_ERROR_WRITE_AFTER_CR, current state machine is poweron\n");
break;
printf("HAL_SPI_SLAVE_FSM_ERROR_READ_AFTER_CW, current state machine is poweron\n");
break;
default:
break;
}
} else {
}
}
|
hal_spi_slave_status_t | hal_spi_slave_init (hal_spi_slave_port_t spi_port, hal_spi_slave_config_t *spi_configure) |
| This function initializes the SPI slave and sets user defined common parameters such as timeout threshold, bit order, clock polarity and clock phase. More...
|
|
hal_spi_slave_status_t | hal_spi_slave_deinit (hal_spi_slave_port_t spi_port) |
| This function resets the SPI slave, gates its clock and disables interrupts. More...
|
|
hal_spi_slave_status_t | hal_spi_slave_register_callback (hal_spi_slave_port_t spi_port, hal_spi_slave_callback_t callback_function, void *user_data) |
| This function registers user's callback in the SPI slave driver. More...
|
|
hal_spi_slave_status_t | hal_spi_slave_send (hal_spi_slave_port_t spi_port, const uint8_t *data, uint32_t size) |
| This function sends data asynchronously with DMA mode, this function should be called from user's callback function. More...
|
|
hal_spi_slave_status_t | hal_spi_slave_get_master_read_config (hal_spi_slave_port_t spi_port, uint32_t *address, uint32_t *length) |
| This function queries the address and length from the config read command sent by the SPI master. More...
|
|
hal_spi_slave_status_t | hal_spi_slave_receive (hal_spi_slave_port_t spi_port, uint8_t *buffer, uint32_t size) |
| This function receives data asynchronously with DMA mode. More...
|
|
hal_spi_slave_status_t | hal_spi_slave_get_master_write_config (hal_spi_slave_port_t spi_port, uint32_t *address, uint32_t *length) |
| This function querys the address and the length from the config write command sent by the SPI master. More...
|
|
hal_spi_slave_status_t | hal_spi_slave_set_early_miso (hal_spi_slave_port_t spi_port, hal_spi_slave_early_miso_t early_miso) |
| This function configures the SPI slave send MISO early half SCLK cycle parameter. More...
|
|
hal_spi_slave_status_t | hal_spi_slave_set_command (hal_spi_slave_port_t spi_port, hal_spi_slave_command_type_t command, uint8_t value) |
| This function configures the SPI slave command value. More...
|
|
This function queries the address and length from the config read command sent by the SPI master.
- Parameters
-
[in] | spi_port | is the SPI slave port number, the value is defined at hal_spi_slave_port_t. |
[in] | address | is the address of data to read from. |
[in] | length | is the data length to read. |
- Returns
- HAL_SPI_SLAVE_STATUS_ERROR_PORT, if the SPI slave port is invalid.
HAL_SPI_SLAVE_STATUS_INVALID_PARAMETER, if an invalid parameter is given by user.
HAL_SPI_SLAVE_STATUS_ERROR, if the address and length of data cannot be queried.
HAL_SPI_SLAVE_STATUS_OK, if this function returned successfully.
- Example
1 hal_spi_slave_status_t user_spi_slave_callback(hal_spi_slave_transaction_status_t status,void *user_data)
4 hal_spi_slave_callback_event_t slave_status;
5 uint32_t request_address, request_length;
6 uint32_t actual_address, actual_length;
9 if (HAL_SPI_SLAVE_FSM_SUCCESS_OPERATION == (status.fsm_status)) {
10 slave_status = status.slave_status;
11 switch (slave_status) {
12 case HAL_SPI_SLAVE_EVENT_CRD_FINISH:
13 hal_spi_slave_get_master_read_config(HAL_SPI_SLAVE_0, &request_address, &request_length);
14 need_convert = user_check_convert(); // User decides whether to convert the requested address to an actual address.
15 if (need_convert == true) {
16 actual_address = user_convert_address(request_address, request_length); // Convert the requested address to an actual.
19 actual_address = request_address; // Use the requested address as an actual address.
21 actual_length = request_length; // Actual length should always be the same as the requested length.
22 user_prepare_buffer(actual_address, actual_length); // Prepare a buffer before sending or receiving data.
23 hal_spi_slave_send(HAL_SPI_SLAVE_0, (uint8_t *)actual_address, actual_length);
25 // Other event handler;
- See also
- hal_spi_slave_send()
This function querys the address and the length from the config write command sent by the SPI master.
- Parameters
-
[in] | spi_port | is the SPI slave port number, the value is defined at hal_spi_slave_port_t. |
[in] | address | is the address of data the master want to write to. |
[in] | length | is the data length to write. |
- Returns
- HAL_SPI_SLAVE_STATUS_ERROR_PORT, if the SPI slave port is invalid.
HAL_SPI_SLAVE_STATUS_INVALID_PARAMETER, if an invalid parameter is given by user.
HAL_SPI_SLAVE_STATUS_ERROR, if the address and length of data cannot be queried.
HAL_SPI_SLAVE_STATUS_OK, if this function returned successfully.
- Example
1 hal_spi_slave_status_t user_spi_slave_callback(hal_spi_slave_transaction_status_t status,void *user_data)
4 hal_spi_slave_callback_event_t slave_status;
5 uint32_t request_address, request_length;
6 uint32_t actual_address, actual_length;
9 if (HAL_SPI_SLAVE_FSM_SUCCESS_OPERATION == (status.fsm_status)) {
10 slave_status = status.slave_status;
11 switch (slave_status) {
12 case HAL_SPI_SLAVE_EVENT_CWR_FINISH:
13 hal_spi_slave_get_master_write_config(HAL_SPI_SLAVE_0, &request_address, &request_length);
14 need_convert = user_check_convert(); // User decides whether to convert the requested address to an actual address.
15 if (need_convert == true) {
16 actual_address = user_convert_address(request_address, request_length); // Convert the requested address to an actual.
19 actual_address = request_address; // Use the requested address as an actual address.
21 actual_length = request_length; // Actual length should always be the same as the requested length.
22 user_prepare_buffer(actual_address, actual_length); // Prepare a buffer before sending or receiving data.
23 hal_spi_slave_receive(HAL_SPI_SLAVE_0, (uint8_t *)actual_address, actual_length);
25 // Other event handler;
- See also
- hal_spi_slave_receive()
This function registers user's callback in the SPI slave driver.
This function should always be called when using the SPI slave driver, the callback will be called in SPI ISR.
- Parameters
-
[in] | spi_port | is the SPI slave port number, the value is defined at hal_spi_slave_port_t. |
[in] | callback_function | is the callback function given by user, which will be called at SPI slave interrupt service routine. |
[in] | user_data | is a parameter given by user and will pass to user while the callback function is called. See the last parameter of hal_spi_slave_callback_t. |
- Returns
- HAL_SPI_SLAVE_STATUS_ERROR_PORT, if the SPI slave port is invalid.
HAL_SPI_SLAVE_STATUS_INVALID_PARAMETER, if an invalid parameter is given by user.
HAL_SPI_SLAVE_STATUS_OK, if this function returned successfully.
- Example
- Sample code please refer to How to use this driver.