RT-thread下ARM926EJS的CPU移植SPI 并挂载w25q128

1:环境
芯片:NUC977
CPU: ARM926EJS
OS:RT-Thread
在这里插入图片描述
在这里插入图片描述
2:RT-thread下架构分析
在这里插入图片描述
上图时SPI所在的驱动架构
其中已经有的是SPI 的驱动 nuc97x_spi.c
SPI驱动框架需要在RT-thread下通过menuconfig进行添加

在这里插入图片描述
代码中会新增下面的代码文件
在这里插入图片描述

2:SPI驱动
添加SPI的驱动 向SPI的驱动框架下注册设备SPI0
drv_spi.c

int rt_hw_spi_bus_init(void)
{
	rt_err_t result;
	for (int i = 0; i < sizeof(spi_config) / sizeof(spi_config[0]); i++) {
		spi_bus_obj[i].config = &spi_config[i];
		spi_bus_obj[i].spi_bus.parent.user_data = &spi_config[i];
		result = rt_spi_bus_register(&spi_bus_obj[i].spi_bus, spi_config[i].bus_name, &stm_spi_ops);
		RT_ASSERT(result == RT_EOK);
	}
	 return result;
}

其中result = rt_spi_bus_register(&spi_bus[0], spi_config[0].bus_name, &stm_spi_ops);
会向SPI的架构注册SPI的名字,操作函数ops

static const struct rt_spi_ops stm_spi_ops =
{
    .configure = spi_configure,
    .xfer = spixfer,
};

其中spi_configure 会进行对SPI的配置,例如模式,速度,传输长度
最终调用下面的函数

static rt_err_t stm32_spi_init(struct nuc97x_spi *spi_drv, struct rt_spi_configuration *cfg)
{
	struct stm32_spi_config *config = spi_drv->config;
	rt_uint32_t fd = config->fd;
	/*初始化SPI时钟*/
	outpw(REG_CLK_PCLKEN1, inpw(REG_CLK_PCLKEN0) | 0x10);
	/*复用GPIO PB6,7,8,9引脚*/
	outpw(REG_SYS_GPB_MFPL, (inpw(REG_SYS_GPB_MFPL) & ~0xff000000) | 0xBB000000);
	outpw(REG_SYS_GPB_MFPH, (inpw(REG_SYS_GPB_MFPH) & ~0xff) | 0xBB);
	/*SPI init*/	
//	 spiInit(0);
	 spiOpen(fd);
	
    // 设置SPI时钟
    spiIoctl(fd, SPI_IOC_SET_SPEED, cfg->max_hz, RT_NULL);
    // 设置传输长度为
    spiIoctl(fd, SPI_IOC_SET_TX_BITLEN, cfg->data_width, RT_NULL);
    // 设置传输模式
    spiIoctl(fd, SPI_IOC_SET_MODE, cfg->mode, RT_NULL);
	spiIoctl(fd, SPI_IOC_SET_LSB_MSB, RT_NULL, RT_NULL);
	
	return RT_EOK;

}

spixfer 是真正传输时会调用的函数,原型如下:
大概意思就是:上层函数会把传输的命令,数据,大小,是否片选放到结构体rt_spi_message 中去
然后通过,SPI_Transmit和SPI_Receive来进行数据的传输和接收

static rt_uint32_t spixfer(struct rt_spi_device *device, struct rt_spi_message *message)
{
    rt_size_t message_length, already_send_length;
    rt_uint16_t send_length;
    rt_uint8_t *recv_buf;
    const rt_uint8_t *send_buf;
	RT_ASSERT(device != RT_NULL);
    RT_ASSERT(device->bus != RT_NULL);
    RT_ASSERT(device->bus->parent.user_data != RT_NULL);
    RT_ASSERT(message != RT_NULL);
    if (message->cs_take)
    {
            // /CS: 使能
			spiIoctl(0, SPI_IOC_ENABLE_SS, SPI_SS_SS0, 0);
    }
	message_length = message->length;
    recv_buf = message->recv_buf;
    send_buf = message->send_buf;
	
	 while (message_length)
    {
        /* the HAL library use uint16 to save the data length */
        if (message_length > 65535)
        {
            send_length = 65535;
            message_length = message_length - 65535;
        }
        else
        {
            send_length = message_length;
            message_length = 0;
        }

        /* calculate the start address */
        already_send_length = message->length - send_length - message_length;
        send_buf = (rt_uint8_t *)message->send_buf + already_send_length;
        recv_buf = (rt_uint8_t *)message->recv_buf + already_send_length;
       if (message->send_buf)
        {
				//SpiFlash_NormalPageProgram(0, send_buf);
				SPI_Transmit(0, (uint8_t *)send_buf, send_length);
			
                //state = HAL_SPI_Transmit(spi_handle, (uint8_t *)send_buf, send_length, 1000);
 
        }
        else
        {
            memset((uint8_t *)recv_buf, 0xff, send_length);
			//SpiFlash_NormalRead(0, recv_buf);
			SPI_Receive(0, (uint8_t *)recv_buf, send_length);
            //state = HAL_SPI_Receive(spi_handle, (uint8_t *)recv_buf, send_length, 1000);

        }

        }
    if (message->cs_release)
    {
        spiIoctl(0, SPI_IOC_DISABLE_SS, SPI_SS_SS0, 0);
    }

    return message->length;
}

这两个函数,一个向SPI的数据寄存器写数据,一个从SPI数据寄存器读取数据

static rt_uint32_t SPI_Transmit(rt_uint32_t fd, uint8_t *pData, uint16_t Size)
{
	uint32_t i;

	// 写数据
    for(i=0;i<Size;i++)
    {
        spiWrite(fd, TX_RX_0_OFFSET, pData[i]);
        spiIoctl(fd, SPI_IOC_TRIGGER, RT_NULL, RT_NULL);
        while(spiGetBusyStatus(RT_NULL));
    }
	return RT_EOK;

}

static rt_uint32_t SPI_Receive(rt_uint32_t fd, uint8_t *pData, uint16_t Size)
{
	uint32_t i;
    for(i=0; i<Size; i++) {
        spiWrite(fd, TX_RX_0_OFFSET, ZERO_DATA);
        spiIoctl(fd, SPI_IOC_TRIGGER, RT_NULL, RT_NULL);
        while(spiGetBusyStatus(RT_NULL));
        pData[i] = spiRead(fd, TX_RX_0_OFFSET);  
    }
	return RT_EOK;

}

3:编写W25Q128的驱动

#include "w25q128bv.h"

#define TEST_LENGTH 256 /* length */
#define W25Q_SPI_DEVICE_NAME     "spi01"
rt_uint8_t W25QXX_BUFFER[4096] ={0};
struct rt_spi_device *spi_dev_w25q;

rt_uint8_t w25q_init(void)
{
	char name[RT_NAME_MAX];
	struct rt_spi_configuration cfg;
	
	rt_strncpy(name, W25Q_SPI_DEVICE_NAME, RT_NAME_MAX);
	spi_dev_w25q = (struct rt_spi_device *)rt_device_find(name);
	if(!spi_dev_w25q) {
		rt_kprintf("spi sample run failed! can't find %s device!\n", name);
		return RT_ERROR;
	}else{

         cfg.data_width = 8;
         cfg.mode = RT_SPI_MODE_0;//| RT_SPI_MSB; /* SPI Compatible: Mode 0 and Mode 3 */
         cfg.max_hz = 2 * 1000 * 1000 ; /* 50M */
         rt_spi_configure(spi_dev_w25q, &cfg);
		 return RT_EOK;
	}
}

static void read_spi_flash_id(void)
{
	RT_ASSERT(spi_dev_w25q != RT_NULL);
	rt_uint8_t w25x_read_id = W25X_ManufactDeviceID;
	rt_uint8_t id[5] = {0};			
	struct rt_spi_message msg1, msg2;
	
	msg1.send_buf = &w25x_read_id;
	msg1.recv_buf = RT_NULL;
	msg1.length = 1;
	msg1.cs_take = 1;
	msg1.cs_release = 0;
	msg1.next = &msg2;
		
	msg2.send_buf = RT_NULL;
	msg2.recv_buf = id;
	msg2.length = 5;
	msg2.cs_take = 0;
	msg2.cs_release = 1;
	msg2.next = RT_NULL;
		
	rt_spi_transfer_message(spi_dev_w25q, &msg1);
	rt_kprintf("use rt_spi_transfer_mesage() read w25q ID is :%x%x\n", id[3], id[4]);

}
MSH_CMD_EXPORT(read_spi_flash_id, spi_w25q_sample samole);

void W25QXX_Write_Page(rt_uint8_t* pBuffer,rt_uint32_t WriteAddr,rt_uint16_t NumByteToWrite)
{
	RT_ASSERT(spi_dev_w25q != RT_NULL);
	rt_uint8_t addr[3] = {0};
	struct rt_spi_message msg1, msg2,msg3, msg4;
	rt_uint8_t w25x_write_id = W25X_WriteEnable;
	rt_uint8_t w25x_page_id = W25X_PageProgram;
	rt_uint32_t StartAddress = WriteAddr;

	addr[0] = (StartAddress>>16) & 0xFF;
	addr[1] = (StartAddress>>8) & 0xFF;
	addr[2] = StartAddress & 0xFF;
			
	msg1.send_buf = &w25x_write_id;
	msg1.recv_buf = RT_NULL;
	msg1.length = 1;	
	msg1.cs_take = 1;
	msg1.cs_release = 1;
	msg1.next = &msg2;
		
	msg2.send_buf = &w25x_page_id;
	msg2.recv_buf = RT_NULL;
	msg2.length = 1;
	msg2.cs_take = 1;
	msg2.cs_release = 0;
	msg2.next = &msg3;
		
	msg3.send_buf = addr;
	msg3.recv_buf = RT_NULL;
	msg3.length = 3;
	msg3.cs_take = 0;
	msg3.cs_release = 0;
	msg3.next = &msg4;
				
	msg4.send_buf = pBuffer;
	msg4.recv_buf = RT_NULL;
	msg4.length = NumByteToWrite;
	msg4.cs_take = 0;
	msg4.cs_release = 1;
	msg4.next = RT_NULL;
	
	rt_spi_transfer_message(spi_dev_w25q, &msg1);

	SpiFlash_WaitReady();
}

void W25QXX_Read(rt_uint8_t* pBuffer,rt_uint32_t ReadAddr,rt_uint32_t NumByteToRead)
{
	RT_ASSERT(spi_dev_w25q != RT_NULL);
	rt_uint8_t addr[3] = {0};
	rt_uint8_t w25x_read_id = 0x03;
	rt_uint32_t StartAddress = ReadAddr;
	struct rt_spi_message msg1, msg2, msg3;

	addr[0] = (StartAddress>>16) & 0xFF;
	addr[1] = (StartAddress>>8) & 0xFF;
	addr[2] = StartAddress & 0xFF;	
		
	rt_kprintf("read addr 0x%02x......... \n", StartAddress);
	msg1.send_buf = &w25x_read_id;
	msg1.recv_buf = RT_NULL;
	msg1.length = 1;
	msg1.cs_take = 1;
	msg1.cs_release = 0;
	msg1.next = &msg2;
		
	msg2.send_buf = addr;
	msg2.recv_buf = RT_NULL;
	msg2.length = 3;
	msg2.cs_take = 0;
	msg2.cs_release = 0;
	msg2.next = &msg3;
				
	msg3.send_buf = RT_NULL;
	msg3.recv_buf = pBuffer;
	msg3.length = NumByteToRead;
	msg3.cs_take = 0;
	msg3.cs_release = 1;
	msg3.next = RT_NULL;
	rt_spi_transfer_message(spi_dev_w25q, &msg1);
	
}



void W25QXX_Erase_Sector(u32 Dst_Addr)
{
	RT_ASSERT(spi_dev_w25q != RT_NULL);
	uint8_t addr[3] = {0};
	struct rt_spi_message msg1, msg2, msg3;
	rt_uint8_t w25x_erase_sector_id = W25X_SectorErase;
	rt_uint8_t w25x_write_id = 0x06;
	rt_uint32_t StartAddress  = Dst_Addr*4096;

	addr[0] = (StartAddress>>16) & 0xFF;
	addr[1] = (StartAddress>>8) & 0xFF;
	addr[2] = StartAddress & 0xFF;	
	
	rt_kprintf("erase 0x%02x...\n",StartAddress);

	msg1.send_buf = &w25x_write_id;
	msg1.recv_buf = RT_NULL;
	msg1.length = 1;
	msg1.cs_take = 1;
	msg1.cs_release = 1;
	msg1.next = &msg2;
		
	msg2.send_buf = &w25x_erase_sector_id;
	msg2.recv_buf = RT_NULL;
	msg2.length = 1;
	msg2.cs_take = 1;
	msg2.cs_release = 0;
	msg2.next = &msg3;
		
	msg3.send_buf = addr;
	msg3.recv_buf = RT_NULL;
	msg3.length = 3;
	msg3.cs_take = 0;
	msg3.cs_release = 1;
	msg3.next = RT_NULL;
		
	rt_spi_transfer_message(spi_dev_w25q, &msg1);
	SpiFlash_WaitReady();
}

void erase_spi_flash_all(void)
{
	//擦除FLASH
   SpiFlash_ChipErase();

   //等待操作完成
   SpiFlash_WaitReady();
}
MSH_CMD_EXPORT(erase_spi_flash_all, erase_spi_flash_all);

//无检验写SPI FLASH 
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能 
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(rt_uint8_t* pBuffer,rt_uint32_t WriteAddr,rt_uint16_t NumByteToWrite)   
{ 			 		 
	rt_uint16_t pageremain;	   
	pageremain=256-WriteAddr%256; //单页剩余的字节数		 	    
	if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节
	while(1)
	{	   
		W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);
		if(NumByteToWrite==pageremain)break;//写入结束了
	 	else //NumByteToWrite>pageremain
		{
			pBuffer+=pageremain;
			WriteAddr+=pageremain;	

			NumByteToWrite-=pageremain;			  //减去已经写入了的字节数
			if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节
			else pageremain=NumByteToWrite; 	  //不够256个字节了
		}
	};	    
} 

//写SPI FLASH  
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)						
//NumByteToWrite:要写入的字节数(最大65535)   	 
void W25QXX_Write(rt_uint8_t* pBuffer,rt_uint32_t WriteAddr,rt_uint32_t NumByteToWrite)   
{ 
	rt_uint32_t secpos;
	rt_uint16_t secoff;
	rt_uint16_t secremain;	   
 	rt_uint16_t i;    
	rt_uint8_t *W25QXX_BUF;	  
   	W25QXX_BUF=W25QXX_BUFFER;	     
 	secpos=WriteAddr/4096;//扇区地址  
	secoff=WriteAddr%4096;//在扇区内的偏移
	secremain=4096-secoff;//扇区剩余空间大小   
 	//printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用
 	if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节
	while(1) 
	{	
		W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容

		for(i=0;i<secremain;i++)//校验数据
		{
			if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除  	  
		}
		if(i<secremain)//需要擦除
		{
			W25QXX_Erase_Sector(secpos);//擦除这个扇区
			for(i=0;i<secremain;i++)	   //复制
			{
				W25QXX_BUF[i+secoff]=pBuffer[i];
				//rt_kprintf("0x%02x ", W25QXX_BUFFER[i]);				
			}
			rt_kprintf("write sector 0x%x\n", secpos*4096);
			W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  

		}else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间. 				   
		if(NumByteToWrite==secremain)break;//写入结束了
		else//写入未结束
		{
			secpos++;//扇区地址增1
			secoff=0;//偏移位置为0 	 

		   	pBuffer+=secremain;  //指针偏移
			WriteAddr+=secremain;//写地址偏移	   
		   	NumByteToWrite-=secremain;				//字节数递减
			if(NumByteToWrite>4096)secremain=4096;	//下一个扇区还是写不完
			else secremain=NumByteToWrite;			//下一个扇区可以写完了
		}	 
	};	 
}

void W25QXX_Write_Big(rt_uint8_t* pBuffer,rt_uint32_t WriteAddr,rt_uint32_t NumByteToWrite)   
{
	rt_size_t message_length, already_send_length;
	rt_uint16_t send_length;
	message_length =NumByteToWrite;

	 while (message_length)
    {
        /* the HAL library use uint16 to save the data length */
        if (message_length > 65535)
        {
            send_length = 65535;
            message_length = message_length - 65535;
        }
        else
        {
            send_length = message_length;
            message_length = 0;
        }

        /* calculate the start address */
        already_send_length = NumByteToWrite - send_length - message_length;
        pBuffer = pBuffer + already_send_length;
		WriteAddr = WriteAddr + already_send_length;

		W25QXX_Write(pBuffer,WriteAddr,send_length);
	}
	
}

int w25q_spi_device_init()
{
    outpw(REG_CLK_PCLKEN0, inpw(REG_CLK_PCLKEN0) | 0x8);
    return rt_hw_spi_device_attach("spi0", "spi01", RT_NULL);
}

INIT_DEVICE_EXPORT(w25q_spi_device_init);


static int rt_hw_spi_flash_with_sfud_init(void)
{
    if (RT_NULL == rt_sfud_flash_probe("W25Q128", "spi01"))
    {
        return RT_ERROR;
    };
	
    return RT_EOK;
}
INIT_COMPONENT_EXPORT(rt_hw_spi_flash_with_sfud_init);
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值