AM263Px MCU+ SDK: MCSPI Low Level Driver

| AM263Px MCU+ SDK 26.00.00 |

MCSPI Low Level Driver

# 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

- Default TX data feature is not supported in DMA mode.
- In DMA mode, FIFO is not enabled.

# Usage Overview

## API Sequence

To use the MCSPI driver to send data over the SPI bus, the application calls the following APIs:

- MCSPI_lld_init(): Initialize the MCSPI driver.
- MCSPI_lld_readWrite() / MCSPI_lld_readWriteIntr() / MCSPI_lld_readWriteDma(): Read and Write data in polling, interrupt, and Dma mode respectively.
- MCSPI_lld_read() / MCSPI_lld_readIntr() / MCSPI_lld_readDma(): Read data in polling, interrupt, and Dma mode respectively.
- MCSPI_lld_write() / MCSPI_lld_writeIntr() / MCSPI_lld_writeDma(): Write data in polling, interrupt, and Dma mode respectively.
- MCSPI_lld_deInit(): De-initialize the MCSPI instance.

## 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/DebugP.h>
#include <kernel/dpl/SystemP.h>
#include <kernel/dpl/SemaphoreP.h>
#include <kernel/dpl/HwiP.h>
#include <kernel/dpl/MutexArmP.h>
#include <kernel/nortos/dpl/r5/HwiP_armv7r_vim.h>
#include <drivers/mcspi/v0/lld/mcspi_lld.h>

Instance Open Example

int32_t status = MCSPI_STATUS_SUCCESS;
gMcspiHandle0 = &gMcspiObject[CONFIG_MCSPI0];
status = MCSPI_lld_init(gMcspiHandle0);
DebugP_assert(status == MCSPI_STATUS_SUCCESS);

Instance Close Example

int32_t status = MCSPI_STATUS_SUCCESS;
status = MCSPI_lld_deInit(gMcspiHandle0);
DebugP_assert(status == MCSPI_STATUS_SUCCESS);

Non-Blocking Transfer Example

uint32_t bufIndex;
uint32_t count;
uint32_t timeout = MCSPI_WAIT_FOREVER;
int32_t status = MCSPI_STATUS_SUCCESS;
MCSPI_ExtendedParams extendedParams;
/* Interrupt configuration and registration*/
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);
HwiP_enableInt(intrNum);
if(status == MCSPI_STATUS_SUCCESS)
{
DebugP_log("\n[MCSPI] Loopback example started ...\r\n");
/* Memfill buffers */
for(bufIndex = 0U; bufIndex < APP_MCSPI_MSGSIZE; bufIndex++)
{
gMcspiTxBuffer[bufIndex] = bufIndex;
gMcspiRxBuffer[bufIndex] = 0U;
}
gMcspiObject[CONFIG_MCSPI0].transferMutex = &gMutexLockUnlock;
/* populate extended parameters */
extendedParams.channel = 0;
extendedParams.csDisable = TRUE;
extendedParams.dataSize = 32;
count = APP_MCSPI_MSGSIZE / (extendedParams.dataSize/8);
status = MCSPI_lld_readWriteIntr(gMcspiHandle0, \
gMcspiTxBuffer, \
&gMcspiRxBuffer, \
count, \
timeout, \
&extendedParams);
while(try_lock_mutex(gMcspiObject[CONFIG_MCSPI0].transferMutex) == MUTEX_ARM_LOCKED);
if(MCSPI_TRANSFER_COMPLETED != status)
{
DebugP_assert(FALSE); /* MCSPI transfer failed!! */
}
else
{
/* Compare data */
for(bufIndex = 0U; bufIndex < APP_MCSPI_MSGSIZE; bufIndex++)
{
if(gMcspiTxBuffer[bufIndex] != gMcspiRxBuffer[bufIndex])
{
status = MCSPI_STATUS_FAILURE; /* Data mismatch */
DebugP_log("Data Mismatch at offset %d\r\n", bufIndex);
break;
}
}
}
}
/* Deregister IRQ */
HwiP_setVecAddr(intrNum, 0);
HwiP_setPri(intrNum, 15);
if(MCSPI_STATUS_SUCCESS == status)
{
DebugP_log("All tests have passed!!\r\n");
}
else
{
DebugP_log("Some tests have failed!!\r\n");
}

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)
{
ISR_CALL_LEVEL_NONFLOAT_REENTRANT(MCSPI_lld_controllerIsr, \
gMcspiHandle0, \
intrNum, \
gMcspiVimStsAddr, \
gMcspiVimStsClrMask,
gVimBaseAddr);
}

# API

APIs for MCSPI LLD

args
void * args
Definition: hsmclient_msg.h:4
MCSPI_WAIT_FOREVER
#define MCSPI_WAIT_FOREVER
Value to use when needing a timeout of infinity or wait forver until resource is available.
Definition: mcspi_lld.h:122
SystemP.h
MCSPI_lld_controllerIsr
void MCSPI_lld_controllerIsr(void *args)
This is the McSPI Controller ISR and can be used as IRQ handler in Controller mode.
MCSPI_STATUS_SUCCESS
#define MCSPI_STATUS_SUCCESS
Return status when the API execution was successful.
Definition: mcspi_lld.h:82
MCSPI_lld_readWriteIntr
int32_t MCSPI_lld_readWriteIntr(MCSPILLD_Handle hMcspi, void *txBuf, void *rxBuf, uint32_t count, uint32_t timeout, const MCSPI_ExtendedParams *extendedParams)
This API reads writes data from the McSPI instance in Interrupt mode.
SemaphoreP.h
MCSPI_TRANSFER_COMPLETED
#define MCSPI_TRANSFER_COMPLETED
Definition: mcspi_lld.h:188
DebugP_log
#define DebugP_log(format,...)
Function to log a string to the enabled console.
Definition: DebugP.h:235
__attribute__
struct lld_sockaddr __attribute__
This is the SecureBoot Stream type which holds the data for a specific bootloader to HSM call....
MCSPI_lld_init
int32_t MCSPI_lld_init(MCSPILLD_Handle hMcspi)
This API Initializes the McSPI instance.
HwiP.h
HwiP_enableInt
void HwiP_enableInt(uint32_t intNum)
Enable a specific interrupt.
MCSPI_ExtendedParams
Data structure used with MCSPI_lld_read(), MCSPI_lld_readIntr(), MCSPI_lld_readDma(),...
Definition: mcspi_lld.h:532
mcspi_lld.h
MCSPI LLD Driver API/interface file.
MCSPI_lld_deInit
int32_t MCSPI_lld_deInit(MCSPILLD_Handle hMcspi)
This API De-Initializes the McSPI instance.
DebugP.h
DebugP_assert
#define DebugP_assert(expression)
Function to call for assert check.
Definition: DebugP.h:187
MCSPI_STATUS_FAILURE
#define MCSPI_STATUS_FAILURE
Return status when the API execution was not successful due to a failure.
Definition: mcspi_lld.h:87