概述
RT-Thread 對SPI總線的驅(qū)動,抽象出了spi bus 的設(shè)備驅(qū)動,我們基于S32K146 的硬件學(xué)習(xí)spi bus 設(shè)備驅(qū)動。
SPI總線驅(qū)動適配
驅(qū)動涉及的主要結(jié)構(gòu)體為如下:
rt_spi_device:app 通過該結(jié)構(gòu)體和bus 綁定通過bus 控制spi總線
rt_spi_bus spi bus總線設(shè)備抽象
rt_spi_ops bus設(shè)備依賴的底層操作函數(shù)
結(jié)構(gòu)體關(guān)系如下:
對于總線設(shè)備的驅(qū)動對接我們需要實(shí)現(xiàn)對應(yīng)的ops函數(shù)。
使用S32 Design Studio 工具配置spi1
本次實(shí)驗(yàn)使用的是lpspi1 ,首先使用S32 Design Studio 工具生成pinmux 和 clk 初始化配置代碼。
配置SPI1 master 參數(shù)
配置pimmux
配置clk
適配SPI1 ops 函數(shù)至RT-Thread
根據(jù)上面的梳理,依賴芯片層實(shí)現(xiàn)ops函數(shù)并開啟spi設(shè)備驅(qū)動
config ops函數(shù)
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 函數(shù)
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;
添加如下初始化代碼像系統(tǒng)注冊spibus設(shè)備
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);
驗(yàn)證
添加如下測試代碼輸入 spi10 open/config/readid 命令打開并掛載到spi1總線,并讀取板子上的spi flash 的id信息
include
#include
#include
#include
#include
#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,spi10flashtest)
輸入命令驗(yàn)證已經(jīng)讀取到flash 的Id 信息說明SPI 總線和spi flash 通信ok ,而且系統(tǒng)內(nèi)也已經(jīng)多了spi1 bus設(shè)備和spi10 的spi 設(shè)備節(jié)點(diǎn)。
試驗(yàn)讀取的did和芯片手冊的也是一致的。
-
SPI總線
+關(guān)注
關(guān)注
4文章
104瀏覽量
27666 -
設(shè)備驅(qū)動
+關(guān)注
關(guān)注
0文章
68瀏覽量
10931 -
RT-Thread
+關(guān)注
關(guān)注
31文章
1305瀏覽量
40386
發(fā)布評論請先 登錄
相關(guān)推薦
評論