您尚未登录。

楼主 # 2023-07-11 18:01:30

北极的企鹅
会员
注册时间: 2023-06-29
已发帖子: 4
积分: 16

裸机boot启动使用SPI DMA读取app数据,3MB用时0.5s

boot的代码使用的是:https://gitee.com/zhangheyang/f1c100s_rt-thread/tree/master/f1c100s_spl

boot读取app数据的时候,SPI速率使用的是50MHZ,3MB用时约0.5s;

SPI速率是100MHz的时候,3MB数据用时约为0.25s,不过这时读取的第一个数据会错误,导致不能正常跳转,需要跳转前把第一个数据修改下才能正常跳转,不过不确定是否其它数据还会不会有概率性问题,正在寻找解决办法~

文件上传不上来,就直接传代码了

#include <io.h>

extern void print_hex(uint32_t num);
extern void print_string(const char *s);

enum {
	SPI_GCR	= 0x04,
	SPI_TCR	= 0x08,
	SPI_IER	= 0x10,
	SPI_ISR	= 0x14,
	SPI_FCR	= 0x18,
	SPI_FSR	= 0x1c,
	SPI_WCR	= 0x20,
	SPI_CCR	= 0x24,
	SPI_MBC	= 0x30,
	SPI_MTC	= 0x34,
	SPI_BCC	= 0x38,
	SPI_TXD	= 0x200,
	SPI_RXD	= 0x300,
};

/*********** DMA *************/
enum {
	DMA0	= 0,
	DMA1,
	DMA2,
	DMA3,
};

enum {
	NDMA	= 0,
	DDMA,
};


#define	NDMA_TRANS_LEN	(128*1024)
#define	DDMA_TRANS_LEN	(16*1024*1024)

/********** DMA info *************/
#define DMA_NO			(DMA0)
#define DMA_MODE		(NDMA)	/* SPI only support NDMA */
/*********************************/

#define DMA_TRANS_LEN	((DMA_MODE == NDMA) ? (NDMA_TRANS_LEN) : (DDMA_TRANS_LEN))

#define DMA_BASE	(0x01C02000)

#define DMA_ICR	(DMA_BASE + 0x00)
#define DMA_ISR	(DMA_BASE + 0x04)
#define DMA_PCR	(DMA_BASE + 0x08)

#define NDMA_CR(dma_n) 			(DMA_BASE + 0x100 + 0x20*dma_n + 0x0)	
#define NDMA_SRC_ADDR(dma_n) 	(DMA_BASE + 0x100 + 0x20*dma_n + 0x4)	
#define NDMA_DES_ADDR(dma_n) 	(DMA_BASE + 0x100 + 0x20*dma_n + 0x8)	
#define NDMA_BCR(dma_n) 		(DMA_BASE + 0x100 + 0x20*dma_n + 0xC)	


#define DDMA_CR(dma_n) 			(DMA_BASE + 0x300 + 0x20*dma_n + 0x0)	
#define DDMA_SRC_ADDR(dma_n) 	(DMA_BASE + 0x300 + 0x20*dma_n + 0x4)	
#define DDMA_DES_ADDR(dma_n) 	(DMA_BASE + 0x300 + 0x20*dma_n + 0x8)	
#define DDMA_BCR(dma_n) 		(DMA_BASE + 0x300 + 0x20*dma_n + 0xC)
#define DDMA_PR(dma_n) 			(DMA_BASE + 0x300 + 0x20*dma_n + 0x18)
#define DDMA_GD(dma_n) 			(DMA_BASE + 0x300 + 0x20*dma_n + 0x1C)

#define F1C100S_CCU_BASE 	(0x01C20000)
#define CCU_BUS_CLK_GATE0	(0x0060)
#define CCU_BUS_SOFT_RST0 	(0x02C0)

typedef struct 
{
	int dma_id;
	int dma_mode;
	int dma_len;
}spi_dma_info;

spi_dma_info g_spi_dma_info;


void sys_dma_init(void)
{
	g_spi_dma_info.dma_id = DMA_NO;
	g_spi_dma_info.dma_mode = DMA_MODE;
	g_spi_dma_info.dma_len = DMA_TRANS_LEN;

	/* Enable gate for DMA clock, and perform softreset */
	write32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0, read32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0) | (0x1 << 6));
	write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) & (~(0x1 << 6)));
	for(int i = 0; i < 10; i++)
		continue;
	write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) | (0x1 << 6));
}

void sys_dma_deinit(void)
{
	write32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0, read32(F1C100S_CCU_BASE + CCU_BUS_CLK_GATE0) & (~(0x1 << 6)));
}

int sys_dma_transfer_len_get(void)
{
	return g_spi_dma_info.dma_len;
}

void sys_dma_wait_end(void)
{
	spi_dma_info *spi_dma_info = &g_spi_dma_info;

	uint32_t cfg_reg = 0x80000000;
	/* when the dma end, it clear this bit automatically */
	while ((cfg_reg & 0x80000000) ) 
	{
		cfg_reg = read32(NDMA_CR(spi_dma_info->dma_id));
	}
}

void sys_spi_dma_set(void *dst, void *src, int len)
{
	spi_dma_info *spi_dma_info = &g_spi_dma_info;
	uint32_t val;

	write32(NDMA_SRC_ADDR(spi_dma_info->dma_id), (uint32_t)src);

	write32(NDMA_DES_ADDR(spi_dma_info->dma_id), (uint32_t)dst);
	write32(NDMA_BCR(spi_dma_info->dma_id), len);

	val = (1 << 31) | (0x11 << 16) | (0x1 << 5) | (0x4 << 0);
	write32(NDMA_CR(spi_dma_info->dma_id), val);

}


void sys_spi_flash_init(void)
{
	uint32_t addr;
	uint32_t val;

	/* Config GPIOC0, GPIOC1, GPIOC2 and GPIOC3 */
	addr = 0x01c20848 + 0x00;
	val = read32(addr);
	val &= ~(0xf << ((0 & 0x7) << 2));
	val |= ((0x2 & 0x7) << ((0 & 0x7) << 2));
	write32(addr, val);

	val = read32(addr);
	val &= ~(0xf << ((1 & 0x7) << 2));
	val |= ((0x2 & 0x7) << ((1 & 0x7) << 2));
	write32(addr, val);

	val = read32(addr);
	val &= ~(0xf << ((2 & 0x7) << 2));
	val |= ((0x2 & 0x7) << ((2 & 0x7) << 2));
	write32(addr, val);

	val = read32(addr);
	val &= ~(0xf << ((3 & 0x7) << 2));
	val |= ((0x2 & 0x7) << ((3 & 0x7) << 2));
	write32(addr, val);

	/* Deassert spi0 reset */
	addr = 0x01c202c0;
	val = read32(addr);
	val |= (1 << 20);
	write32(addr, val);

	/* Open the spi0 bus gate */
	addr = 0x01c20000 + 0x60;
	val = read32(addr);
	val |= (1 << 20);
	write32(addr, val);

	/* Set spi clock rate control register, divided by 4 */
	addr = 0x01c05000;
	write32(addr + SPI_CCR, 0x00001001);
	//淇敼SPI閫熷害涓100M
	// write32(addr + SPI_CCR, 0x00001000);
	/* Enable spi0 and do a soft reset */
	addr = 0x01c05000;
	val = read32(addr + SPI_GCR);
	val |= (1 << 31) | (1 << 7) | (1 << 1) | (1 << 0);
	write32(addr + SPI_GCR, val);
	while(read32(addr + SPI_GCR) & (1 << 31));

	val = read32(addr + SPI_TCR);
	val &= ~(0x3 << 0);
	val |= (1 << 6) | (1 << 2);
	write32(addr + SPI_TCR, val);

	val = read32(addr + SPI_FCR);
	val |= (1 << 31) | (1 << 15);
	write32(addr + SPI_FCR, val);
	while(read32(addr + SPI_FCR) & (1 << 31));
	while(read32(addr + SPI_FCR) & (1 << 15));

	sys_dma_init();
}

void sys_spi_flash_exit(void)
{
	uint32_t addr = 0x01c05000;
	uint32_t val;

	/* Disable the spi0 controller */
	val = read32(addr + SPI_GCR);
	val &= ~((1 << 1) | (1 << 0));
	write32(addr + SPI_GCR, val);

	// sys_dma_deinit();
}

static void sys_spi_select(void)
{
	uint32_t addr = 0x01c05000;
	uint32_t val;

	val = read32(addr + SPI_TCR);
	val &= ~((0x3 << 4) | (0x1 << 7));
	val |= ((0 & 0x3) << 4) | (0x0 << 7);
	write32(addr + SPI_TCR, val);
}

static void sys_spi_deselect(void)
{
	uint32_t addr = 0x01c05000;
	uint32_t val;

	val = read32(addr + SPI_TCR);
	val &= ~((0x3 << 4) | (0x1 << 7));
	val |= ((0 & 0x3) << 4) | (0x1 << 7);
	write32(addr + SPI_TCR, val);
}

static void sys_spi_write_txbuf(uint8_t * buf, int len)
{
	uint32_t addr = 0x01c05000;
	int i;

	if(!buf)
		len = 0;

	write32(addr + SPI_MTC, len & 0xffffff);
	write32(addr + SPI_BCC, len & 0xffffff);
	for(i = 0; i < len; ++i)
		write8(addr + SPI_TXD, *buf++);
}


static int sys_spi_transfer(void * txbuf, void * rxbuf, int len)
{
	uint32_t addr = 0x01c05000;
	int count = len;
	uint8_t * tx = txbuf;
	uint8_t * rx = rxbuf;
	uint8_t val;
	int n, i;

	while(count > 0)
	{
		n = (count <= 64) ? count : 64;
		write32(addr + SPI_MBC, n);
		sys_spi_write_txbuf(tx, n);
		write32(addr + SPI_TCR, read32(addr + SPI_TCR) | (1 << 31));

		while((read32(addr + SPI_FSR) & 0xff) < n);
		for(i = 0; i < n; i++)
		{
			val = read8(addr + SPI_RXD);
			if(rx)
			{
				*rx++ = val;
			}
		}

		if(tx)
			tx += n;
		count -= n;
	}
	return len;
}


void sys_spi_dma_start(int len)
{
	uint32_t addr = 0x01c05000;
	uint32_t val;

	write32(addr + SPI_MBC, len);

	val = read32(addr + SPI_FCR);
	val &= ~((1 << 8) | (1 << 0));
	val |= (1 << 8) | (1 << 0);	
	write32(addr + SPI_FCR, val);

	write32(addr + SPI_TCR, read32(addr + SPI_TCR) | (1 << 31));
}

static int sys_spi_transfer_dma_read(void *rxbuf, int len)
{
	uint32_t spi_rxaddr = 0x01c05000 + SPI_RXD;
	uint32_t dma_max_len;
	uint8_t *rx = (uint8_t *)rxbuf;
	int count = len;
	int n;

	if (!rx)
	{
		print_string("error: rxbuf is null!\n");
		return -1;
	}

	dma_max_len = sys_dma_transfer_len_get();

	while(count > 0)
	{
		n = (count <= dma_max_len) ? count : dma_max_len;

		sys_spi_dma_set((void *)rx, (void *)spi_rxaddr, n);
		sys_spi_dma_start(n);
		sys_dma_wait_end();

		rx += n;
		count -= n;
	}

	return len;
}



static int sys_spi_write_then_read(void * txbuf, int txlen, void * rxbuf, int rxlen)
{
#if 0
	if(sys_spi_transfer(txbuf, NULL, txlen) != txlen)
		return -1;
	if(sys_spi_transfer(NULL, rxbuf, rxlen) != rxlen)
		return -1;
#else
	if(sys_spi_transfer(txbuf, NULL, txlen) != txlen)
		return -1;
	if(sys_spi_transfer_dma_read(rxbuf, rxlen) != rxlen)
		return -1;
#endif

	return 0;
}

int sys_spi_flash_read(int addr, void * buf, int count)
{
	int r;
	uint8_t tx[4];

	tx[0] = 0x03;
	tx[1] = (uint8_t)(addr >> 16);
	tx[2] = (uint8_t)(addr >> 8);
	tx[3] = (uint8_t)(addr >> 0);
	sys_spi_select();
	r = sys_spi_write_then_read(tx, 4, buf, count);
	sys_spi_deselect();

	return r;
}

最近编辑记录 北极的企鹅 (2023-07-11 18:03:08)

离线

#1 2023-07-12 23:23:34

Alexey_77
会员
注册时间: 2019-11-03
已发帖子: 8
积分: 11

Re: 裸机boot启动使用SPI DMA读取app数据,3MB用时0.5s

if you want use clock >33MHz, you need use command 0x0B instead of command 0x03(or command 0x3B if controller suport dual read).

离线

楼主 #3 2023-07-13 17:07:21

北极的企鹅
会员
注册时间: 2023-06-29
已发帖子: 4
积分: 16

Re: 裸机boot启动使用SPI DMA读取app数据,3MB用时0.5s

是这里的spi命令由0x03修改为0x0b吗?

int sys_spi_flash_read(int addr, void * buf, int count)
{
	int r;
	uint8_t tx[4];

	tx[0] = 0x0b;
	tx[1] = (uint8_t)(addr >> 16);
	tx[2] = (uint8_t)(addr >> 8);
	tx[3] = (uint8_t)(addr >> 0);
	sys_spi_select();
	r = sys_spi_write_then_read(tx, 4, buf, count);
	sys_spi_deselect();

	return r;
}

我修改了直接启动不起来,读取数据错误,magic错误,或者还需要修改其它某个地方?

离线

#4 2023-07-14 01:06:12

Alexey_77
会员
注册时间: 2019-11-03
已发帖子: 8
积分: 11

Re: 裸机boot启动使用SPI DMA读取app数据,3MB用时0.5s

int sys_spi_flash_read(int addr, void * buf, int count)
{
    int r;
    uint8_t tx[5];//one more byte required

    tx[0] = 0x0b;
    tx[1] = (uint8_t)(addr >> 16);
    tx[2] = (uint8_t)(addr >> 8);
    tx[3] = (uint8_t)(addr >> 0);
        tx[4] =  0;//Dummy byte for fast read command
    sys_spi_select();
    r = sys_spi_write_then_read(tx, 5, buf, count);//one more byte send
    sys_spi_deselect();

    return r;
}

离线

楼主 #5 2023-07-14 09:25:28

北极的企鹅
会员
注册时间: 2023-06-29
已发帖子: 4
积分: 16

Re: 裸机boot启动使用SPI DMA读取app数据,3MB用时0.5s

小小3积分不成敬意,spi DMA启动可以了,3MB,大概0.25s,多谢大侠!

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn