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)
离线
是这里的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错误,或者还需要修改其它某个地方?
离线
小小3积分不成敬意,spi DMA启动可以了,3MB,大概0.25s,多谢大侠!
离线