RP2040(树莓派Pico) SSP和Flash接口

他这里说SSP可能很多人不知道是什么,甚至和SPI搞混,确实在TI的芯片里面,SSP有SPI的功能,但是准确来说,这里是QSPI,连接着程序储存器,另外这个SSP可以和XIP/DMA配合,还能使用缓存功能等等.

由于没有多个SS,又因为引脚也没引出,所以暂时只能用作Flash XIP接口了,时序什么也是官方SDK配置好的,没什么好说的,官方针对Flash方面给出了5个例子.

第一讲例子cache_perfctr,讲的是Flash Cache.关注两个寄存器ctr_acc和ctr_hit,前者是访问次数,后者是命中次数.缓存是自动进行的,所以不需要特殊的操作,在例子里执行了一个循环的斐波那契递归,这段代码很小,所以很容易塞在缓存里面,目前有16KB的Cache,如果完全不用Cache用途,也可以当RAM来用.

Cache模式(通过不同的镜像地址访问):

看这个表可能更清晰.

即如果通过0x10******访问,则是可缓存,预分配的,这是默认状态,如果通过0x13******访问,则不可缓存,不可分配,等于缓存旁路了,只要通过这个地址访问,一定不存在缓存一致性问题,就是性能低点.

我们现在尝试运行cache_perfctr,为了验证函数在缓存区域,我加了一个打印.

第二个例子nuke,指的是让程序运行在RAM,然后可以清空整个Flash.和普通Flash操作差不多,也要先擦后写,当然,这是SPI Flash,还能哪里不一样,一擦就一个SECTOR呢.擦除过后当然是什么都不显示,但是下次插入PICO就会直接显示BOOT盘了,为了让整个程序都在RAM,需要在CMakeList添加以下内容.

pico_set_binary_type(flash_nuke no_flash)

第三个例子是正常的Flash编程,和普通单片机/Flash的编程方法一样,需要擦一大片,然后写部分,可以从1写0,不能从0写1,一个字节写过不能再写,由于Flash参数大同小异(基本都一样),所以基本参数都写在头文件了.


#define FLASH_PAGE_SIZE (1u << 8) # 最小编程单位
#define FLASH_SECTOR_SIZE (1u << 12) # 最小擦除单位
#define FLASH_BLOCK_SIZE (1u << 16)

然后通过flash_range_erase和flash_range_program来擦写,注意的是,实际使用最好移植spiffs之类的使用.这一点我觉得ESP做的好太多,SDK里面都移植了fs.

第四个例子是xip_stream,这是利用硬件上一些功能,实现XIP Stream,主要目的是连续访问某些数据,而不用关心处理器是否正在进行随机读写,实际大多数外置执行的芯片都有这个功能.他和第五个例子ssi_dma有类似的功效,只不过ssi_dma是直接作用在接口上,xip_stream是作用在XIP外设上,ssi是底层链接接口,带宽会更高,但是会影响系统其他代码的正常执行.

通过ssi_dma看到,实测有31MByte/s的带宽,这个并不高,正常来说QSPI接口跑54MByte/s没什么压力的.

Starting DMA
DMA finished
Transfer speed: 31.089 MB/s
Data check ok

测试速度代码:

uint32_t start_time = time_us_32();
dma_channel_wait_for_finish_blocking(dma_chan);
uint32_t finish_time = time_us_32();
    
float elapsed_time_s = 1e-6f * (finish_time - start_time);
printf("Transfer speed: %.3f MB/s\n", (sizeof(uint32_t) * count_of(random_test_data) / 1e6f) / elapsed_time_s);

最后测试出使用xip_stream速度大概如下:

Starting DMA
Transfer speed: 9.968 MB/s
DMA complete
Data check OK

不过由于芯片本身性能一般,所以这个存取速度也能满足很多应用要求了.

发表评论

邮箱地址不会被公开。 必填项已用*标注