Peripheral feature and how this peripheral works
The QSCI allows asynchronous serial communications with peripheral devices.
Features
- Full-duplex or single-wire operation
- Standard mark/space non-return-to-zero (NRZ) format
- 16-bit integer and 3-bit fractional baud rate selection
- Separately enabled and separate DSC core interrupt request for transmitter and receiver
- Configurable data formats
- Programmable 8-bit or 9-bit data format
- Programmable polarity for transmitter and receiver
- Interrupt-driven operation with multiple flags
- Transmitter empty
- Transmitter idle
- Receiver full
- Receiver idle
- Receiver input edge
- Error detection with multiple flags
- Receiver overrun
- 1/16 bit-time noise error detection
- Receiver framing error detection
- Receiver parity checking
- Receiver Wakeup
- Two receiver wake-up methods: idle line or address mark
- Clockless receiver wake-up on active input edge
- DMA support
- Supports Local Interconnect Network (LIN)
How this driver is designed to make this peripheral works
On abstraction level, the QSCI driver provides 2 parallel layers for different users with different requirements on flexibility: Functional layer and Transactional layer. Do not mix the usage of these 2 layers.
- Functional Layer is provided with highly optimized implementation and highly flexible usage of the peripheral features. All hardware features' configuration are supported. It requires user to have decent understanding of the hardware detail to know how to organize these functional APIs together to meet application requirement.
- Transactional layer is provided with high abstraction, limited flexibility/optimization, and not all features are covered. Their aim is to let user implement QSCI transaction with least knowledge requirement of this specific QSCI peripheral and least coding effort. It achieves this goal by hiddening the setup of interrupt processing inside driver and implementing complete software state machine for QSCI transaction. To distinguish Transactional layer from Functional layer easily, all Transactional APIs have 'Transfer' in API name.
Functional Layer
- Preface
- Design purpose To provide various peripheral configuration and bus operation interfaces, covering all hardware features. Users can customize their code freely with functional APIs, especially when application has critical requirements of code size and performance.
- Advantages:
- Functional APIs are simple and optimized, with proper usage user can customize their code to be highly optimized
- Disadvantages:
- It requires user to have deep understanding of peripheral features, in order to organize functional APIs to meet the application requirements
- The functional APIs that each driver provides are peripheral specific, which adds the work load porting application to another platform
- Sub API Groups
- Module Init/Deinit Sub-group
- APIs to initialize and de-initialize QSCI module.
- Hardware Status Flags Sub-group
- APIs to get/clear status flags.
- Interrupt Sub-group
- APIs to enable, disable or get the enabled interrupt source.
- Peripheral Configuration Sub-group
- General Peripheral configuration: APIs for QSCI general configuration, such as parity, data bits.
- FIFO Configuration Sub-group: APIs for FIFO relevant features.
- DMA Configuration Sub-group: APIs for DMA relevant features.
- Bus Operation Sub-group
Transactional Layer
- Preface
- Design purpose To let user set up and carry out transfer quickly from the begining without worring about detailed hardware features and software operations. After transactional APIs are called, the whole transfer process is handled by driver internally without further operation from user until transfer ends.
- Advantages:
- User can perform transfer with these APIs without peripheral specific knowledge
- They are totally state retained, all bus operations and configurations are handled inside the driver which simplifies the user application code
- Transactional APIs use common programming model, different peripherals of same bus protocol have same usage on application level. This makes code integration and porting simplier
- Disadvantages:
- Transactional APIs are based on common programming model of QSCI protocol, they are of little peripheral specific so they have average optimization on performance and code size
- Software Implementation Logic
- Double Weak Mechanism One of the key features of Transactional layer compared to Functional layer is user need not setup interrupt handling codes, but can still get IRQ service function executed when interrupt happens. This is achieved by the 'double weak' mechanism. Refer to the general section of API Reference Manual for detail. In breif, SDK place a weak function A for this peripheral's vector entry. The default implementation of this function calls another weak function B. By default, when a interrupt happen, the code will be executed as A (Weak) -> B (Weak). This driver implements the function B as non-weak inside, thus once user gets the driver file into the application project, when interrupt happens, code will be executed as A (Weak) -> B (Non-Weak, in this driver). If user wants to implement his/her own IRQ service routine, just define A in application as non-weak.
- Transfer Handling Framework The Transactional Layer's IRQ service routine is hidden inside the driver, but user can still insert his/her own processing logic inside IRQ service using callback. User can code his/her own logic inside the callback function and register it when calling QSCI_TransferCreateHandle to initialize the transfer using Transactional API. When transfer ends or module detects certain hardware error like receiver overrun, callback will be invoked and user's logic will be executed.
- Structure list
- qsci_transfer_t describes a transfer, the data buffer pointer and the transferred data count
- qsci_transfer_handle_t qsci_edma_transfer_handle_t Transactional layer is state retained thus it use the qsci_transfer_handle_t or qsci_edma_transfer_handle_tto specify the peripheral. User need to initialize the handle by calling QSCI_TransferCreateHandle or QSCI_TransferCreateHandleEDMA.
- Sub API Groups
How to use this driver
General Control Macro
- FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL SDK genneral Macro, controls whether to ungate/gate peripheral's clock source inside driver. Set it to none-zero value then driver will not ungate/gate clock source during initialization/de-initialization.
- QSCI_RETRY_TIMES QSCI specific Macro, controls the retry times when checking the module's status flags. During transfer, at certain stages program needs to wait for some flag to be set/cleared then folowing steps can proceed. Set it to non-zero value then driver retries the check QSCI_RETRY_TIMES. If it counts down to zero but the flag remains unchanged, API returns kStatus_QSCI_Timeout. Set it to zero then the driver keeps waiting until the flag changes.
Callback Macro
For efficiency's sake, user callback interface is designed to have only one parameter psHandle defined as qsci_transfer_handle_t. Since the handle shall not be modified by user application, macros are provided for user to get bus status or user data.
- QSCI_GET_BUS_STATUS Returns the bus status in result of the transfer.
- QSCI_GET_TRANSFER_USER_DATA Returns the user data passed to transational layer when creating handle.
Configuration Items Before Calling QSCI Driver APIs
- Mux the QSCI TXD/RXD signals to on-board pins, and configure them with expected port pin feature.
- Select and attach proper clock source to QSCI module.
- Ungate the QSCI clock if user wish to do it outside driver by setting FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL to non-zero value.
- If user wish to use interrupt for QSCI transfer while other modules' interrupt sources are also enabled, set proper interrupt priority before initiating QSCI transfer, so that QSCI IRQ service can be properly executed.
Functional layer usage model
- Configuration Items Before Calling Driver APIs
- Except the items described in the general part, define the QSCI interrupt entry in the application code if interrupt is needed for this peripheral usage.
- Call flow
- Init the module with QSCI_Init. Note QSCI_GetDefaultConfig can help user to get a ready-to-use init data structure.
- Do the QSCI transaction with other functional layer APIs
Transactional layer usage model
Typical Use Cases
These code snipets shows the general calling sequence to use functional APIs and transactional APIs. For detail usage on appilcation level, refer to QSCI driver examples in SDK package under boards/<board_name>/driver_examples/QSCI.
//TODO