您尚未登录。

楼主 #1 2021-03-04 22:51:55

airpumpkin
会员
注册时间: 2021-03-04
已发帖子: 14
积分: 44

F1C100s用DMA加速spiflash启动

最近开始入坑F1C100s,在坑网蹭了诸多前辈的使用经验,本着能够继续蹭经验的目的,贡献一下使用DMA加速spiflash启动的代码
基于 https://gitee.com/tiny200s/lv7_rtthread_f1c100s.git (https://whycan.com/t_4942.html)的代码,编译出来的程序大约2.6M,把芒果派换上spiflash之后,启动时间大约需要6s,强迫症表示不能忍。

仔细阅读f1c100s_spl里的代码,跟xboot里的也是一样的,都是直读spiflash,每次64字节,

中间浪费的时间不少。最后决定用DMA读取spi,每次128K字节。不得不吐槽一下,
全志的手册真是节省,不参考别人的代码都很难读懂。
改成DMA读取spiflash后,基本就是秒起了。
f1c100s_spl.zip

参考各位大神的代码:
https://whycan.com/t_1514.html
https://whycan.com/t_4209.html

离线

#2 2021-03-04 23:45:30

david
会员
注册时间: 2018-03-05
已发帖子: 385
积分: 316.5

Re: F1C100s用DMA加速spiflash启动

这个好 一直觉得启动慢是个问题

离线

#3 2021-03-05 08:04:01

a32425262
会员
注册时间: 2018-05-06
已发帖子: 104
积分: 401

Re: F1C100s用DMA加速spiflash启动

这个修改之后。开机时间能到多少呢

离线

楼主 #4 2021-03-05 09:18:28

airpumpkin
会员
注册时间: 2021-03-04
已发帖子: 14
积分: 44

Re: F1C100s用DMA加速spiflash启动

没有仔细测,摁下reset,大约1-2s的样子

离线

#5 2021-03-05 09:28:20

raspberryman
会员
注册时间: 2019-12-27
已发帖子: 503
积分: 465

Re: F1C100s用DMA加速spiflash启动

airpumpkin 说:

没有仔细测,摁下reset,大约1-2s的样子

请教楼主,uboot有没有办法改 ^_^

离线

楼主 #6 2021-03-05 09:43:00

airpumpkin
会员
注册时间: 2021-03-04
已发帖子: 14
积分: 44

Re: F1C100s用DMA加速spiflash启动

uboot代码有点复杂,我改dma的时候还想参考来着,看看也是直读spiflash就没继续研究了
我这只是抛砖引玉,期待别的大神能够改过去

raspberryman 说:
airpumpkin 说:

没有仔细测,摁下reset,大约1-2s的样子

请教楼主,uboot有没有办法改 ^_^

离线

#7 2021-03-05 10:02:11

达克罗德
会员
注册时间: 2018-04-10
已发帖子: 1,138
积分: 1090.5

Re: F1C100s用DMA加速spiflash启动

我记得当时玩xboot的时候3MB也没有6秒这么慢,2~3秒的样子

离线

楼主 #8 2021-03-05 10:33:00

airpumpkin
会员
注册时间: 2021-03-04
已发帖子: 14
积分: 44

Re: F1C100s用DMA加速spiflash启动

可能测试起止时间标准不一样
我用手机秒表测的,从摁下reset开始,到rtthread的debug串口输出显示启动结束,6s多一点点
实际的视觉体验是屏幕从开始变花到刷新显示,也差不多要这么多时间

达克罗德 说:

我记得当时玩xboot的时候3MB也没有6秒这么慢,2~3秒的样子

离线

#9 2021-03-09 10:42:39

muxi01
会员
注册时间: 2020-10-24
已发帖子: 62
积分: 144

Re: F1C100s用DMA加速spiflash启动

666.楼主可以直接在原来的基础上打个补丁就行,把补丁发布出来。

离线

#10 2021-03-12 10:30:32

xk2yx
会员
注册时间: 2020-12-19
已发帖子: 4
积分: 9

Re: F1C100s用DMA加速spiflash启动

学习下,,,不错

离线

#11 2021-09-26 15:28:53

honglingjin001
会员
注册时间: 2021-09-26
已发帖子: 1
积分: 0.5

Re: F1C100s用DMA加速spiflash启动

..\Driver\Source\sys_spi.c(334): error:  #852: expression must be a pointer to a complete object type rxbuf += bytes_cnt;

请教一下你这里编译的时候报错了咋解决呀

离线

#12 2021-11-27 10:06:49

haistart
会员
注册时间: 2020-01-05
已发帖子: 14
积分: 4

Re: F1C100s用DMA加速spiflash启动

好东西,虽然我对现在的速度要求不高,1M多的代码也就1-2秒。

离线

#13 2021-11-29 20:12:18

somnus
会员
注册时间: 2021-11-29
已发帖子: 17
积分: 2

Re: F1C100s用DMA加速spiflash启动

启动速度可以这么快?太牛了,学习

离线

#14 2022-08-13 08:54:21

ggk1989
会员
注册时间: 2018-12-19
已发帖子: 8
积分: 3

Re: F1C100s用DMA加速spiflash启动

3.6m的bin文件  使用dma启动速度约2秒  不用dma需要8秒的样子  点赞

离线

#15 2022-08-13 16:55:34

tangj
会员
注册时间: 2022-08-13
已发帖子: 1
积分: 1

Re: F1C100s用DMA加速spiflash启动

到现在都不太清楚SPL是啥,是uboot里面重定向前的那一部分吗,但是看公司里又是spl来加载uboot

离线

#16 2022-09-27 08:24:59

lfs911
会员
注册时间: 2020-09-24
已发帖子: 37
积分: 22

Re: F1C100s用DMA加速spiflash启动

多谢楼主,正好在调spi和dma,一直没调通

离线

#17 2022-09-27 13:17:10

Chin
会员
注册时间: 2020-10-19
已发帖子: 61
积分: 39

Re: F1C100s用DMA加速spiflash启动

这是启动到linux,还是boot?

离线

#18 2022-09-27 18:59:07

kiss8381
会员
注册时间: 2022-01-28
已发帖子: 2
积分: 2

Re: F1C100s用DMA加速spiflash启动

询问下是否能在1s内快速启动

离线

#19 2023-06-12 03:11:07

506826164@qq.com
会员
注册时间: 2022-08-07
已发帖子: 57
积分: 77

Re: F1C100s用DMA加速spiflash启动

实测,没用DMA情况下,从flash拷16M固件到DRAM仅需0.75s,真正的秒启动

离线

#20 2023-06-24 16:51:30

bidezhi7777
会员
注册时间: 2021-04-22
已发帖子: 23
积分: 3

Re: F1C100s用DMA加速spiflash启动

加开机LOGO就是为了掩饰启动慢吗?

离线

#21 2023-07-10 10:24:42

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

Re: F1C100s用DMA加速spiflash启动

这个spi确实太慢了,3M的代码要加载6s,楼主这个好

离线

#22 2023-10-12 16:55:20

wenjiu
会员
注册时间: 2023-10-12
已发帖子: 6
积分: 1

Re: F1C100s用DMA加速spiflash启动

gitee上没看到有spi + dma的代码呀?楼主能再分享一下吗?

离线

#24 2024-09-03 08:35:24

网络孤客
会员
注册时间: 2022-06-09
已发帖子: 22
积分: 7

Re: F1C100s用DMA加速spiflash启动

wenjiu 说:

gitee上没看到有spi + dma的代码呀?楼主能再分享一下吗?

另一个帖子上有
https://gitee.com/LicheePiNano/lv7_rtthread_f1c100s.git

离线

#25 2024-09-03 19:55:59

armstrong
会员
注册时间: 2019-04-10
已发帖子: 286
积分: 195.5

Re: F1C100s用DMA加速spiflash启动

DOUT+DMA模式,太快了!若SPI时钟设为100MHZ,能达到25MB/S;保险起见设置SPI为50MHZ,也有12.5MB/S。
启动个RTOS应用简直了。

#include <stdint.h>
#include <string.h>
#include "f1c100s/reg-ccu.h"
#include "io.h"

#define SPI_USE_DMA (1)

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,
};

#if SPI_USE_DMA > 0

enum {
  DMA0 = 0,
  DMA1,
  DMA2,
  DMA3,
};

enum {
  NDMA = 0,
  DDMA,
};

#define NDMA_TRANS_LEN  (128u*1024)
#define DDMA_TRANS_LEN  (16u*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)

static void sdelay(int loops)
{
loop_again:
  __asm volatile {
    SUBS loops, loops, #1
    BNE loop_again
  }
}

static void sys_dma_init(void)
{
  /* 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)));
  sdelay(20);
  write32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0, read32(F1C100S_CCU_BASE + CCU_BUS_SOFT_RST0) | (0x1 << 6));
}

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

static uint32_t sys_dma_transfer_len_get(void)
{
  return DMA_TRANS_LEN;
}

static void sys_spi_dma_set(void* dst, void* src, uint32_t len)
{
  uint32_t val;

  write32(NDMA_SRC_ADDR(DMA_NO), (uint32_t)src);
  write32(NDMA_DES_ADDR(DMA_NO), (uint32_t)dst);
  write32(NDMA_BCR(DMA_NO), len);

  val = (1u << 31) | (0x11 << 16) | (0x1 << 5) | (0x4 << 0);
  write32(NDMA_CR(DMA_NO), val);
}

static void sys_spi_dma_start(uint32_t len)
{
  uint32_t reg_base = 0x01c05000;
  uint32_t val;

  write32(reg_base + SPI_MBC, len);
  write32(reg_base + SPI_MTC, 0);
  write32(reg_base + SPI_BCC, (1 << 28)); // dual-mode

  val = read32(reg_base + SPI_FCR);
  val |= (1 << 8) | (1 << 0);
  write32(reg_base + SPI_FCR, val);

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

static void sys_dma_wait_end(void)
{
  /* when the dma end, it clear this bit automatically */
  while (read32(NDMA_CR(DMA_NO)) & (1u << 31));
}

#endif

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);

  /* Enable spi0 and do a soft reset */
  addr = 0x01c05000;
  val = read32(addr + SPI_GCR);
  val |= (1UL << 31) | (1 << 7) | (1 << 1) | (1 << 0);  // Transmit Pause Enable (TP_EN)
  write32(addr + SPI_GCR, val);
  while (read32(addr + SPI_GCR) & (1UL << 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 |= (1UL << 31) | (1 << 15);
  write32(addr + SPI_FCR, val);

#if SPI_USE_DMA > 0
  sys_dma_init();
#endif
}

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);

#if SPI_USE_DMA > 0
  sys_dma_deinit();
#endif
}

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) | (1UL << 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;
}

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

void sys_spi_flash_read(int addr, void* buf, int count)
{
  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();
  sys_spi_write_then_read(tx, 4, buf, count);
  sys_spi_deselect();
}

void sys_spi_flash_read_dualout(int addr, void* buf, int count)
{
  uint32_t reg_base = 0x01c05000;
  uint8_t* rxbuf = buf;
  uint8_t tx[5];
  int n, i, c;

  n = 0;
  tx[n++] = 0x3b;   // fast read dual-output
  tx[n++] = (uint8_t)(addr >> 16);
  tx[n++] = (uint8_t)(addr >> 8);
  tx[n++] = (uint8_t)(addr >> 0);
  tx[n++] = 0;
  sys_spi_select();
  write32(reg_base + SPI_MBC, n);
  write32(reg_base + SPI_MTC, n);
  write32(reg_base + SPI_BCC, n);
  for (i = 0; i < n; i++) {
    write8(reg_base + SPI_TXD, tx[i]);
  }
  write32(reg_base + SPI_TCR, read32(reg_base + SPI_TCR) | (1u << 31));
  while (read32(reg_base + SPI_TCR) & (1u << 31));
  write32(reg_base + SPI_FCR, read32(reg_base + SPI_FCR) | 0x80008000u);
  while (count > 0) {
    n = ((count <= 4096) ? count : 4096);
    write32(reg_base + SPI_MBC, n);
    write32(reg_base + SPI_MTC, 0);
    write32(reg_base + SPI_BCC, (1 << 28)); // dual-mode
    write32(reg_base + SPI_TCR, read32(reg_base + SPI_TCR) | (1u << 31));
    for (i = n; i > 0;) {
      if ((c = (read32(reg_base + SPI_FSR) & 0xff)) > 0) {
        i -= c;
        while (c-- > 0) {
          *rxbuf++ = read8(reg_base + SPI_RXD);
        }
      }
    }
    count -= n;
  }
  sys_spi_deselect();
}

#if SPI_USE_DMA > 0

void sys_spi_flash_read_dma(int addr, void* buf, uint32_t count)
{
  uint32_t reg_base = 0x01c05000;
  uint32_t dma_max_len;
  uint8_t* rxbuf = buf;
  uint8_t tx[5];
  uint32_t n, i;

  n = 0;
  tx[n++] = 0x3b;   // fast read dual-output
  tx[n++] = (uint8_t)(addr >> 16);
  tx[n++] = (uint8_t)(addr >> 8);
  tx[n++] = (uint8_t)(addr >> 0);
  tx[n++] = 0;
  sys_spi_select();
  write32(reg_base + SPI_MBC, n);
  write32(reg_base + SPI_MTC, n);
  write32(reg_base + SPI_BCC, n);
  for (i = 0; i < n; i++) {
    write8(reg_base + SPI_TXD, tx[i]);
  }
  write32(reg_base + SPI_TCR, read32(reg_base + SPI_TCR) | (1u << 31));
  while (read32(reg_base + SPI_TCR) & (1u << 31));
  write32(reg_base + SPI_FCR, read32(reg_base + SPI_FCR) | 0x80008000u);
  dma_max_len = sys_dma_transfer_len_get();
  while (count > 0) {
    n = ((count <= dma_max_len) ? count : dma_max_len);
    sys_spi_dma_set(rxbuf, (void*)(reg_base + SPI_RXD), n);
    sys_spi_dma_start(n);
    sys_dma_wait_end();
    rxbuf += n;
    count -= n;
  }
  sys_spi_deselect();
}

#endif

离线

#26 2024-09-09 11:51:48

AAA_GET
会员
注册时间: 2024-08-28
已发帖子: 10
积分: 5

Re: F1C100s用DMA加速spiflash启动

能不能加速SD卡呢

离线

#27 2024-09-10 08:56:30

EndStation
会员
注册时间: 2024-09-10
已发帖子: 2
积分: 2

Re: F1C100s用DMA加速spiflash启动

请问这个对NandFlash适用吗?

离线

页脚

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

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