ESP32 使用HSPI 读写SD卡的方法

使用ESP32也已经快一年了,有了很多体会和经验,最近开始写文章记录下心得和过程,这样的好处是方便自己查找资料和回顾,也许也能帮助到别人。也是善事一桩。

先记录一下今天的心得吧

今天要在esp32 wroom 模块上(此模块有4M FLASH,但没有PSRAM)中跑NES模拟器,硬件有ST7789的240X240 的彩屏,还有SD卡,通过sd卡上读取ROM文件,在彩屏上显示图像,然后通过I2s输出声音。还有I2C的扩展键盘,然后问题来了,彩屏和sd卡都是通过SPI总线连接的,常规都是通过乐鑫的官方库SPI.H 和sd.h 实现sd卡读写,但是此库默认使用的都是VSPI这个控制器。

知识点:
ESP32 共有 4 个 SPI 控制器 SPI0、SPI1、SPI2、SPI3,用于连接支持 SPI 协议的设备。SPI0 控制器作为 cache 访问外部存储单元接口使用,SPI1 作为主机使用,SPI2 和 SPI3 控制器既可作为主机使用又可作为从机使用。作主机使用时,每个 SPI 控制器可以使用多个片选信号 (CS0 ~ CS2) 来连接多个 SPI 从机设备。
SPI1 ~ SPI3 控制器共享两个 DMA 通道。
SPI0 和 SPI1 控制器通过一个仲裁器共用一组信号总线,这组带前缀 SPI 的信号总线由 D、Q、CS0 ~ CS2、CLK、WP 和 HD 信号组成,如表 25 所示。
相应地,控制器 SPI2 和 SPI3 分别使用带前缀 HSPI 和 VSPI 的信号总线。
这些信号总线包含的输入输出信号线可以经过 GPIO 交换矩阵和 IO_MUX 模块实现与芯片管脚的映射

虽然显示屏和sd卡是通过不同的引脚接在esp32的管脚上的,但软件上如果不作处理,将会造成冲突,因为两者都默认使用VSPI控制器。


实际测试,sd卡能读写时会造成彩屏无法显示,但如果将sd卡的代码删除,彩屏就可以显示

解决的问题是两者要使用不同的SPI,那如何才能让SD卡使用HSPI通迅呢?

  先申明一个使用HSPI总线的SPI对象,再把此对象绑定到sd卡的begin中,如下:
 

  SPIClass MySPI(HSPI);//申明一个叫MySPI的 使用HSPI的总线对象 用来读写SD卡

  pinMode(SD_CS, OUTPUT);//SD卡CS脚
  digitalWrite(SD_CS, HIGH);//低电平选中,高电平不选中


  //自定义的SPI控制器的接线重新映射(就是实际的sd卡硬件接线)
  MySPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
  MySPI.setFrequency(1000000);//设置此SPI总线频率为1M  也可不用



 //用MySPI这个SPI总线去操作SD卡
  if( !SD.begin(SD_CS,MySPI) )
  {
        Serial.println("Card Mount Failed");//返回0失败
        return;
  }

  uint64_t cardSize = SD.cardSize() / (1024 * 1024);
  Serial.printf("SD Card Size: %lluMB\n", cardSize);

通过这么一改,完美解决冲突,能读出sd卡上的文件内容显示在彩屏上了,并且也能播放sd卡上的音频文件通过esp32的内置DAC输出 25/26 脚 左右声道模拟音频输出,音质还行过的去,毕竟是8位的。

以下是读SD卡中WAV文件通过内置DAC输出的代码:

 I2S_Init();

 Serial.print("Play to :音乐");
 File file = SD.open("/8.wav");  // 44100Hz, 16bit, stereo, linear PCM
 

  //播放循环
  while (file.readBytes(data, sizeof(data)))  I2S_Write(data, sizeof(data));

  file.close();





void I2S_Init() 
{
//使用内置DAC的I2S的配置,注意因为内置DAC是8位的

     i2s_config_t i2s_config = 
     {
     .mode =(i2s_mode_t) ( I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN ),
     .sample_rate =22050,
     .bits_per_sample =(i2s_bits_per_sample_t) 16, /* the DAC module will only take the 8bits from MSB */
     .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
     .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_PCM_SHORT),
     .intr_alloc_flags = 0, // default interrupt priority
     .dma_buf_count = 16,
     .dma_buf_len = 60,
     .use_apll = false
};

    i2s_driver_install((i2s_port_t)0, &i2s_config, 5, NULL);   //install and start i2s driver
    i2s_set_pin((i2s_port_t)0, NULL); //for internal DAC
   // i2s_set_pin((i2s_port_t)0, &pin_config);//外部DAC 需要设置控制脚


    //You can call i2s_set_dac_mode to set built-in DAC output mode.
    //for internal DAC, this will enable both of the internal channels
    i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);

 //   i2s_set_sample_rates((i2s_port_t)i2s_num, 22050); //set sample rates
 //   i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver

  
}

void I2S_Write(char* data, int numData) 
{
    i2s_write_bytes(I2S_NUM_0, (const char *)data, numData, portMAX_DELAY);
}

  • 9
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值