[STM32F0] STM32F051 SPI+DMA 读25Q16

[复制链接]
2549|12
 楼主| edan_lee 发表于 2021-11-20 11:22 | 显示全部楼层 |阅读模式
本帖最后由 edan_lee 于 2021-11-20 11:26 编辑
  1. /**
  2. * [url=home.php?mod=space&uid=247401]@brief[/url] 通过DMA的方式从Flash中读取数据
  3. *
  4. * @param addr  //Flash的绝对地址
  5. * @param buf   //接收数据缓存
  6. * @param len   //读取字节总数
  7. */
  8. void ReadFlashDataByDMA(u32 addr, u8 buf[], u32 len)
  9. {
  10.     //如果长度为 0 需要直接退出,否则在等DMA完成时会卡住
  11.      if(len == 0)
  12.     {
  13.       return;
  14.     }

  15.     SPI_CS_LOW();

  16.     //发送读快速读命令 0x03,0x0B 是快速读指令 需要在发送地址之后多发一个0xFF
  17.     spiTranAndReceiveData(0x03);   

  18.     //发送地址
  19.     spiTranAndReceiveData((uint8)(addr>>16));
  20.     spiTranAndReceiveData((uint8)(addr>>8));
  21.     spiTranAndReceiveData((uint8)addr);  

  22.     //发送0xB指令需要加上下面的命令
  23.     //spiTranAndReceiveData(0xFF);

  24.     //关闭DMA
  25.     LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);

  26.     //设置内存大小
  27.     LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, len);
  28.   
  29.     //设置DMA的内存地址
  30.     LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4,(uint32_t)buf);
  31.    
  32.     //设置DMA外设地址
  33.     LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4,(uint32_t)(&SPI2->DR));
  34.    
  35.      //清除通道完成标志
  36.     LL_DMA_ClearFlag_TC4(DMA1);
  37.    
  38.     //使能DMA通道
  39.     LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4);
  40.    
  41.     //关闭SPI
  42.     LL_SPI_Disable(SPI2);
  43.    
  44.     //修改SPI为只读模式,需要在失能SPI前提下修改,不然修改完后SCLK立刻有输出
  45.     LL_SPI_SetTransferDirection(SPI2,LL_SPI_SIMPLEX_RX);  
  46.    
  47.     //再次清除RXNE标志,如果没有这个操作在接收缓冲区头部多出一些字节
  48.     while(0 != LL_SPI_IsActiveFlag_RXNE(SPI2))
  49.     {
  50.         LL_SPI_ReceiveData8(SPI2);
  51.     }
  52.    
  53.     //使能DMA RX
  54.     SPI2->CR2 |= SPI_CR2_RXDMAEN;

  55.     //使能SPI
  56.     SPI2->CR1 |= SPI_CR1_SPE;
  57.    
  58.     //等待读完成
  59.     while(0 == LL_DMA_IsActiveFlag_TC4(DMA1));
  60.   
  61.     //关闭SPI的DMA读
  62.     LL_SPI_DisableDMAReq_RX(SPI2);
  63.    
  64.     //改回全双工
  65.     LL_SPI_SetTransferDirection(SPI2,LL_SPI_FULL_DUPLEX);  
  66.    
  67.     //关闭DMA通道
  68.     LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4);
  69.   
  70.     //清除DMA完成标志
  71.     LL_DMA_ClearFlag_TC4(DMA1);

  72.     //置cs高不选中
  73.     SPI_CS_HIGH();                 
  74. }

关键的操作在于失能SPI之后把 SPI 改成只读模式。
因为最近在学习单片机播语音,需要快速读Flash的内容,所以就研究了DMA读,关于写还没有学习到。毕竟不要求大量写数据。粗略测试 24M 读 256 Bytes 需要 106.6uS 左右,发送地址/指令、配置等耗费了大约 20uS 的时间。


小叶三千 发表于 2021-11-22 08:40 | 显示全部楼层
感谢分享
yljon 发表于 2021-11-24 14:57 | 显示全部楼层
路过,支持
kxsi 发表于 2021-12-11 09:58 | 显示全部楼层
这个是几线制的啊
drer 发表于 2021-12-11 09:59 | 显示全部楼层
如果不这样会导致接收死机是吗
gwsan 发表于 2021-12-11 10:01 | 显示全部楼层
不可以延时吗
nawu 发表于 2021-12-11 10:05 | 显示全部楼层
需要立刻把 SPI 改成只读模式吗
qcliu 发表于 2021-12-11 10:07 | 显示全部楼层
这个微秒的时间是怎么得到的呢
 楼主| edan_lee 发表于 2021-12-11 14:42 | 显示全部楼层
kxsi 发表于 2021-12-11 09:58
这个是几线制的啊

4线,因为要发指令,MOSI是不能少的。
 楼主| edan_lee 发表于 2021-12-11 14:43 | 显示全部楼层
drer 发表于 2021-12-11 09:59
如果不这样会导致接收死机是吗

你指的“这样”是哪样呢?
 楼主| edan_lee 发表于 2021-12-11 14:45 | 显示全部楼层

这么操作就是为了快,加延时不就慢了吗?
 楼主| edan_lee 发表于 2021-12-11 14:46 | 显示全部楼层
nawu 发表于 2021-12-11 10:05
需要立刻把 SPI 改成只读模式吗

是的需要改成只读模式
 楼主| edan_lee 发表于 2021-12-11 14:47 | 显示全部楼层
qcliu 发表于 2021-12-11 10:07
这个微秒的时间是怎么得到的呢

256/20M 等于106.66uS 示波器的测试结果也是这样
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

51

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部