i.MX RT1050 LPSPI Driver Usage

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MX RT1050 LPSPI Driver Usage

2,353 Views
kylehutchens
Contributor II

A few questions regarding the LPSPI driver.

1) Does the FreeRTOS version of the driver use DMA? It doesn't appear to from my quick scan of the source. If not, is it straightforward to enable DMA using the FreeRTOS version of this driver?

2) How is the FreeRTOS LPSPI intended to be called? From what I can tell, you have to initialize the driver first with a lpspi_master_config_t struct, which includes things like PCS and frame size, then initiate a transfer. This implies that the driver must be reinitialized each time I want to change either PCS or frame size. Am I understanding this correctly?

I'm basically trying to understand how to use this driver to allow several threads to access different ICs on the same SPI bus.

Labels (1)
6 Replies

1,569 Views
jimmychan
NXP TechSupport
NXP TechSupport

There is LPSPI eDMA driver. For details, please refer to the Chapter 30 of document below:

SDK_2.3.1_MIMXRT1052\docs\MCUXpresso SDK API Reference Manual_MIMXRT105x.pdf

There is an example about lpspi edma transfer:

SDK_2.3.1_MIMXRT1052\boards\evkbimxrt1050\cmsis_driver_examples\lpspi\edma_b2b_transfer

0 Kudos

1,569 Views
kylehutchens
Contributor II

A bit of follow up. On the first point, as far as I can tell there is a driver supplied for either eDMA *or* FreeRTOS, but there's no supplied solution to use eDMA *with* FreeRTOS. I'd still like some clarification on this point if possible. I can obviously roll my own here, but I'd rather not reinvent the wheel if there's already a solution that I'm missing.

Regarding the second point, it looks like LPSPI_RTOS_Transfer() does allow different frame sizes and PCS selections via lpspi_transer_t, which includes settings for PCS as well as data size. However, lpspi_master_config_t also has settings for frame size and PCS, which is confusing to me since they aren't associated with a particular transfer. Can anyone provide any clarity on the difference between these settings and how they're meant to be used? Just to reiterate, I'm asking about:

lpspi_master_config_t.bitPerFrame

lpspi_master_config_t.whichPcs

vs.

lpspi_transfer_t.dataSize

lpspi_transfer_t.configFlags // includes PCS

Why is the Init function setting this fields in TCR when they are overwritten by the Transfer function for each transfer?

0 Kudos

1,569 Views
jimmychan
NXP TechSupport
NXP TechSupport

They are different. One is for initialization and one is for transfer data.

0 Kudos

1,569 Views
kylehutchens
Contributor II

Right, it's pretty clear that they're different since they are in different structs that are passed as parameters to different functions. The question here is *why* are they different? As far as I can tell it's meaningless to set bitsPerFrame and whichPcs during initialization because they are set at the beginning of each transaction. It seems like they shouldn't be initialization parameters at all.

My concern is that they *are* there, and maybe that means they're there for a reason and I'm just missing something. I'm trying to confirm that I understand the intent and I'm not doing anything wrong. As it is, I'm not setting those parameters during initialization and it's working fine.

In case anyone else is looking for an example of how to use this driver, below is what I'm currently doing.

Initialization:

typedef struct {
 LPSPI_Type *peripheral; // e.q. LPSPI1
 int irq; // e.q. LPSPI1_IRQn
 int baudrate; // e.q. 500000
 clock_name_t clock_source; // e.q. kCLOCK_Usb1PllPfd0Clk
 int clock_div; // e.q. 7
} lpspi_config_t;

static lpspi_rtos_handle_t lpspi1_handle;

status_t BOARD_InitLPSPI(lpspi_rtos_handle_t *handle, lpspi_config_t *config)
{
 lpspi_master_config_t masterConfig;
 uint32_t sourceClock = (CLOCK_GetFreq(config->clock_source) / (config->clock_div + 1U));

/* Initialize SPI. */
 CLOCK_SetMux(kCLOCK_LpspiMux, 1); // USB1 PLL PFD0 (720 MHz) as lpspi clock source
 CLOCK_SetDiv(kCLOCK_LpspiDiv, config->clock_div);
 NVIC_SetPriority(config->irq, 3);

LPSPI_MasterGetDefaultConfig(&masterConfig);
 masterConfig.baudRate = config->baudrate;
 //masterConfig.bitsPerFrame = 8 * SPI_SIZE; // ??
 masterConfig.cpol = kLPSPI_ClockPolarityActiveHigh;
 masterConfig.cpha = kLPSPI_ClockPhaseFirstEdge;
 masterConfig.direction = kLPSPI_MsbFirst;
 masterConfig.pcsToSckDelayInNanoSec = 1000000000 / masterConfig.baudRate;
 masterConfig.lastSckToPcsDelayInNanoSec = 1000000000 / masterConfig.baudRate;
 masterConfig.betweenTransferDelayInNanoSec = 1000000000 / masterConfig.baudRate;
 //masterConfig.whichPcs = kLPSPI_Pcs0; // ??
 masterConfig.pcsActiveHighOrLow = kLPSPI_PcsActiveLow;
 masterConfig.pinCfg = kLPSPI_SdiInSdoOut;
 masterConfig.dataOutConfig = kLpspiDataOutRetained;
 return LPSPI_RTOS_Init(handle, config->peripheral, &masterConfig, sourceClock);
}

Transaction:

static lpspi_rtos_handle_t *SPI_handle; // Initialized elsewhere to point to 'handle'
static enum _lpspi_transfer_config_flag_for_master SPI_pcs; // Initialized elsewhere to kLPSPI_MasterPcs0

status_t reg_read(uint8_t addr, uint32_t *value) {
 uint32_t tx = addr << 24;
 uint32_t rx = 0;

 lpspi_transfer_t transfer = {
  .txData = (uint8_t*)&tx,
  .rxData = (uint8_t*)&rx,
  .dataSize = 4,
  .configFlags = SPI_pcs | kLPSPI_MasterPcsContinuous,
 };
 status_t status = LPSPI_RTOS_Transfer(SPI_handle, &transfer);
 if(status != kStatus_Success) {
  return status;
 }

 *value = rx & 0xffffff; 
 return kStatus_Success;
}

1,569 Views
nbgatgi
Contributor IV

Couldn't help but notice that jimmychan bailed on this!

Did you ever come to a conclusion on this?

0 Kudos

1,569 Views
kylehutchens
Contributor II

It doesn't really look like there's much info in that doc beyond what's in the driver headers. It looks like the docs are mostly just generated from the code and don't provide any context at all regarding the actual architecture of the drivers or how they're conceptually meant to be used.

I see there are three different drivers: peripheral driver, eDMA driver, and FreeRTOS driver. It's not clear if they're meant to be a stack or if they're alternatives. I.e. can I use DMA *and* FreeRTOS without having to do a bunch of hacking, or are these drivers not meant to be used this way?