Features Supported
- Controller and Peripheral mode of operation
- Per transfer selection of different channels/chip select
- Non-blocking (Callback) transfers
- Multi Word Acess. To use this feature, following requirement must be satisfied.
- It is only supported in interrupt mode.
- The channel selected must have the FIFO enabled.
- Transmit and receive registers must write and read 32-bits respectively.
- FIFO Trigger level must be 32 bit aligned i.e, It must be in power of 2.
- Data Size must be 8 bits or 1 byte.
- Total frame i.e spiTransaction.count must be in multiple of data size.
Features NOT Supported
- For MCU domain instances, DMA mode is not supported.
- Default TX data feature is not supported in DMA mode.
- In DMA mode, FIFO is not enabled.
Constraint
- Due to the design constraint maximum DMA PKTDMA_0 TX/RX channels each can be used is 3 per R5F core. So in case of MCSPI instance with DMA mode enabled can use atmost 3 CS in multi-controller mode.
Usage Overview
API Sequence
To use the MCSPI driver to send data over the SPI bus, the application calls the following APIs:
Initializing the MCSPI Driver
MCSPI_lld_init() must be called before any other MCSPI APIs. This function iterates till the channel count. This function uses mcspi handle to initialize each instance. Calling MCSPI_lld_init() a second time with the same handle previously passed to MCSPI_lld_init() will result in an error. You can, though, re-use the handle if the instance is closed via MCSPI_lld_deInit(). In DMA mode, MCSPI_lld_initDma() needs to be called instead of MCSPI_lld_init() to acquire and initialize mcspi instance. Please note that initializing MCSPI driver is taken care by the SysConfig generated code.
MCSPI Transfer Mode
The MCSPI driver supports three transfer modes of operation: Interrupt, Polling and DMA Mode. Interrupt and DMA mode, it supports only callback mode. Once a MCSPI driver is opened, the only way to change the operation mode is to close and re-open the MCSPI instance with the new transfer mode.
In callback mode, a MCSPI transaction functions asynchronously, which means that it does not block code execution. After a MCSPI transaction has been completed, the MCSPI driver calls a user-provided hook function. Callback mode is supported in the execution context of tasks and hardware interrupt routines.
In multichannel mode connected to multiple external devices, the MCSPI exchanges data with one MCSPI device at a time and FIFO is enabled per each channel at a time.
NOTE: The size of txBuf and RxBuf must be greater than the data size bits, if data size is not a multiple of 8 bits. Mask the data size bits in txBuf and rxBuf as the remaining bits will be discarded. For example, consider datasize = 18 bits then txBuf and rxBuf size should be uint32_t and the mask bits should be 0x3FFFF.
Important Usage Guidelines
- The MCSPI protocol does not account for a built-in handshaking mechanism and neither does this driver. Therefore, when operating in MCSPI_MS_MODE_PERIPHERAL mode, the application must provide such a mechanism to ensure that the MCSPI peripheral is ready for the MCSPI controller. The MCSPI peripheral must call MCSPI_lld_readWrite() / MCSPI_lld_readWriteIntr() / MCSPI_lld_readWriteDma() before the controller starts transmitting. Some example application mechanisms could include:
- Timed delays on the MCSPI controller to guarantee the MCSPI peripheral is ready for a MCSPI transaction.
- A form of GPIO flow control from the peripheral to the MCSPI controller to notify the controller when ready.
- In case of DMA mode, as R5F core is not Cache Coherent, Cache Writeback is required if R5F writes to the buffers. And before reading the buffers, application needs to invalidate those. Please refer MCSPI Loopback DMA LLD.
Example Usage
Include the below file to access the APIs
#include <kernel/dpl/MutexArmP.h>
#include <kernel/nortos/dpl/r5/HwiP_armv7r_vim.h>
Instance Open Example
gMcspiHandle0 = &gMcspiObject[CONFIG_MCSPI0];
Instance Close Example
Non-Blocking Transfer Example
uint32_t bufIndex;
intrNum = gConfigMcspi0InitObject[CONFIG_MCSPI0].intrNum;
gMcspiVimStsAddr = gVimBaseAddr + (0x404u + (((intrNum)>> 5) & 0xFu) * 0x20u);
gMcspiVimStsClrMask = 0x1u << ((intrNum) & 0x1Fu);
HwiP_setVecAddr(intrNum, (uintptr_t)&App_MCSPI_ISR);
HwiP_setPri(intrNum, gConfigMcspi0InitObject[CONFIG_MCSPI0].intrPriority);
{
DebugP_log(
"\n[MCSPI] Loopback example started ...\r\n");
for(bufIndex = 0U; bufIndex < APP_MCSPI_MSGSIZE; bufIndex++)
{
gMcspiTxBuffer[bufIndex] = bufIndex;
gMcspiRxBuffer[bufIndex] = 0U;
}
gMcspiObject[CONFIG_MCSPI0].transferMutex = &gMutexLockUnlock;
extendedParams.channel = 0;
extendedParams.csDisable = TRUE;
extendedParams.dataSize = 32;
count = APP_MCSPI_MSGSIZE / (extendedParams.dataSize/8);
gMcspiTxBuffer, \
&gMcspiRxBuffer, \
timeout, \
&extendedParams);
while(try_lock_mutex(gMcspiObject[CONFIG_MCSPI0].transferMutex) == MUTEX_ARM_LOCKED);
{
}
else
{
for(bufIndex = 0U; bufIndex < APP_MCSPI_MSGSIZE; bufIndex++)
{
if(gMcspiTxBuffer[bufIndex] != gMcspiRxBuffer[bufIndex])
{
DebugP_log(
"Data Mismatch at offset %d\r\n", bufIndex);
break;
}
}
}
}
HwiP_setVecAddr(intrNum, 0);
HwiP_setPri(intrNum, 15);
{
}
else
{
}
Non-Blocking Example transfer callback
void MCSPI_lld_transferCallback(void *args, uint32_t transferStatus)
{
unlock_mutex(gMcspiObject[CONFIG_MCSPI0].transferMutex);
}
Non-Blocking Example ISR CALL callback
static __attribute__((__section__(
".text.hwi"), noinline, naked, target(
"arm"), aligned(4))) void App_MCSPI_ISR(
void)
{
gMcspiHandle0, \
intrNum, \
gMcspiVimStsAddr, \
gMcspiVimStsClrMask,
gVimBaseAddr);
}
API
APIs for MCSPI LLD