Sitemap

[S32K146 RT-Thread] SPI Driver Adaptation[S32K146 RT-Thread] SPI Driver Adaptation

4 min readAug 22, 2025

Overview

RT-Thread abstracts the SPI bus driver into an spi bus device driver. Here, we study the SPI bus device driver based on the S32K146 hardware.

RT-Thread official documentation provides detailed instructions on the SPI bus driver:

https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/spi/spi

SPI Bus Driver Adaptation

The main structures involved in the driver are as follows:

rt_spi_device: the application binds to the bus through this structure and controls the SPI bus via the bus.

rt_spi_bus: abstraction of the SPI bus device.

rt_spi_ops: underlying operation functions that the bus device depends on.

The relationship between the structures is as follows:

Press enter or click to view image in full size

For the driver connection of the bus device, we need to implement the corresponding ops functions.

Configuring SPI1 with S32 Design Studio

In this experiment, lpspi1 is used. First, use S32 Design Studio to generate the pinmux and clock initialization configuration code.

● Configure SPI1 master parameters

Press enter or click to view image in full size

● Configure pimmux

Press enter or click to view image in full size

● Configure clk

Press enter or click to view image in full size

Adapting SPI1 ops Functions to RT-Thread

Based on the above analysis, implement the ops functions at the chip layer and enable the SPI device driver.

● Configure ops functions

Press enter or click to view image in full size
tatic rt_err_t spi_configure(struct rt_spi_device* device,

struct rt_spi_configuration* configuration)

{

struct rt_spi_bus * spi_bus = (struct rt_spi_bus *)device->bus;

struct s32k_spi *spi_device = (struct s32k_spi *)spi_bus->parent.user_data;

status_t ret;



RT_ASSERT(device != RT_NULL);

RT_ASSERT(configuration != RT_NULL);



/* config spi init spi bus */

//LPSPI_DRV_MasterDeinit(spi_device->instance);



switch(configuration->mode & RT_SPI_MODE_3)

{

case RT_SPI_MODE_0:

spi_device->masterconfig->clkPhase = LPSPI_CLOCK_PHASE_2ND_EDGE;

spi_device->masterconfig->clkPolarity = LPSPI_SCK_ACTIVE_LOW;

break;

case RT_SPI_MODE_1:

spi_device->masterconfig->clkPhase = LPSPI_CLOCK_PHASE_1ST_EDGE;

spi_device->masterconfig->clkPolarity = LPSPI_SCK_ACTIVE_LOW;

break;

case RT_SPI_MODE_2:

spi_device->masterconfig->clkPhase = LPSPI_CLOCK_PHASE_2ND_EDGE;

spi_device->masterconfig->clkPolarity = LPSPI_SCK_ACTIVE_HIGH;

break;

case RT_SPI_MODE_3:

spi_device->masterconfig->clkPhase = LPSPI_CLOCK_PHASE_1ST_EDGE;

spi_device->masterconfig->clkPolarity = LPSPI_SCK_ACTIVE_HIGH;

break;

}



/* MSB or LSB */

if(configuration->mode & RT_SPI_MSB)

{

spi_device->masterconfig->lsbFirst = false;

}

else

{

spi_device->masterconfig->lsbFirst = true;

}



if(configuration->max_hz < 10000000)

spi_device->masterconfig->bitsPerSec = configuration->max_hz;



spi_device->masterconfig->bitcount = configuration->data_width;



ret = LPSPI_DRV_MasterInit(spi_device->instance,spi_device->status,spi_device->masterconfig);

RT_ASSERT(ret == STATUS_SUCCESS);



ret = LPSPI_DRV_MasterSetDelay(spi_device->instance, 1, 1, 1);

RT_ASSERT(ret == STATUS_SUCCESS);



return ret == STATUS_SUCCESS ? RT_EOK:RT_ERROR;

● xfer ops functions

truct s32k_spi

{

struct rt_spi_bus spi_bus; /* spi bus device */

lpspi_master_config_t * masterconfig; /* lpspi master config */

lpspi_state_t * status; /* lpspi driver status */

uint32_t instance; /* spi instance id */

char * bus_name;

}s32k_spi_t;



static rt_ssize_t spixfer(struct rt_spi_device* device, struct rt_spi_message* message)
{

struct rt_spi_bus * spi_bus = (struct rt_spi_bus *)device->bus;

struct s32k_spi *spi_device = (struct s32k_spi *)spi_bus->parent.user_data;

status_t ret;



RT_ASSERT(device != NULL);

RT_ASSERT(message != NULL);





ret = LPSPI_DRV_MasterTransferBlocking(spi_device->instance,message->send_buf,message->recv_buf,message->length,1000);

RT_ASSERT(ret == STATUS_SUCCESS);



return ret == STATUS_SUCCESS ? message->length:0;

● Add the following initialization code to register the spibus device into the system


xtern void LPSPI_DRV_IRQHandler(uint32_t instance);



void S32K14X_LPspi1_Master_Slave_IRQHandler(void)
{

/* enter interrupt */

rt_interrupt_enter();



LPSPI_DRV_IRQHandler(1);



/* leave interrupt */

rt_interrupt_leave();

}



/* private rt-thread spi ops function */

static struct rt_spi_ops s32k_spi_ops =

{

.configure = spi_configure,

.xfer = spixfer,

};



static struct s32k_spi spi1;





int rt_hw_spi_init(void)
{

int result = 0;



/* config spi strruct */

spi1.instance = INST_LPSPI_1;

spi1.masterconfig = &lpspi_1_MasterConfig0;

spi1.status = &lpspi_1State;

spi1.spi_bus.parent.user_data = (void *)&spi1;

spi1.bus_name = "spi1";



result = rt_spi_bus_register(&spi1.spi_bus, spi1.bus_name, &s32k_spi_ops);



RT_ASSERT(result == RT_EOK);



LOG_D("%s bus init done", spi1.bus_name);



if(result == RT_EOK)

{

INT_SYS_InstallHandler(LPSPI1_IRQn,S32K14X_LPspi1_Master_Slave_IRQHandler,NULL);

}





return result;

}



INIT_APP_EXPORT(rt_hw_spi_init);

Verification

● Add the following test code, input the command spi10 open/config/readid to open and mount it to the spi1 bus, and read the SPI flash ID information on the board.

include <stdio.h>

#include <rtthread.h>

#include <rtdevice.h>

#include <board.h>

#include <drivers/spi.h>



#define SPF_R_JEDEC_CMD (0x9Fu)

#define SPF_R_JEDEC_LEN (4u)



struct rt_spi_device spi1_device;



static void spi10(int argc,char *argv[])
{

rt_err_t ret;

struct rt_spi_configuration cfg;

uint8_t sendbuff[4] = {SPF_R_JEDEC_CMD,0x00,0x00,0x00};

uint8_t recvbuff[4] = {0x00,0x00,0x00,0x00};



if(!strcmp(argv[1], "readid"))

{

rt_spi_transfer(&spi1_device,sendbuff,recvbuff,4);

rt_kprintf("read did [%x][%x][%x]\n",recvbuff[1],recvbuff[2],recvbuff[3]);

}

else if(!strcmp(argv[1], "open"))

{

ret = rt_spi_bus_attach_device(&spi1_device,"spi10","spi1",NULL);

if(ret != RT_EOK)

rt_kprintf("attach spi1 faied %d\n",ret);

}

else if(!strcmp(argv[1], "config"))

{

cfg.data_width = 8;

cfg.max_hz = 8000000;

cfg.mode = RT_SPI_MODE_3 | RT_SPI_MSB;

rt_spi_configure(&spi1_device,&cfg);

}

else if(!strcmp(argv[1], "read"))

{



}

}

MSH_CMD_EXPORT(spi10, spi10 flash test)

Enter the command to verify that the flash ID information has been read, which indicates that the SPI bus and the SPI flash communication are OK, and that the system has also added the spi1 bus device and the spi10 spi device node.

Press enter or click to view image in full size

The ID read in the experiment is consistent with the chip manual.

Press enter or click to view image in full size

The test code has been submitted at the following path:

https://gitee.com/andeyqi/rt-thread/tree/dev/bsp/s32k14x

--

--

RT-Thread IoT OS
RT-Thread IoT OS

Written by RT-Thread IoT OS

An Open-Source Community-Powered Real-Time Operating System (RTOS) Project! Let’s develop, DIY, create, share, and explore this new IoT World together!

No responses yet