这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 企业专区 » Renesas » wangku001wei的开发进程

共61条 5/7 |‹ 2 3 4 5 6 7 跳转至
高工
2012-09-07 01:16:06     打赏
41楼

实现了SPI模式读写SD卡

看了镇南和力天天子的视频和代码

首先是SD卡的一些规范







其次是单片机上SPI模式的设置问题

单次传输和连续传输好像在判断发送结束的方式是有区别的 我使用连续传输的时候老是SPI出错,使用单词传输的时候正常

然后是电平兼容的问题
虽然说SD卡能够hold5V的电压 但是为了安全起见 看了使用手册,尝试3.3V 和 5V 电平兼容


于是我设计的电路图如下


同时也要根据说明手册上对SPI的IO口进行设置
由于我使用了CSI00 需要对P10 P11 P12 进行设置 片选采用了P00口做输出 也要进行设置




主函数
void  main(void)
{
 /* Start user code. Do not edit comment generated here */
   // 打开SPI通信
   // 测试SD卡是否初始化成功
   CSI00_Start();
 
 sdFlag = SD_Reset();  //复位SD卡
 if(!sdFlag)
 {
    // 复位成功
    sdFlag = SD_Init();  //初始化SD卡
  if(!sdFlag); 
  {
     // 初始化成功
     // 点亮LED D2
     // PORT_ChangeP77Output(0);
     // 通过WinHex发现我的 test.txt 文档在 520 扇区
   sdFlag = SD_Read_Sector(520, sdRxBuf);
     
     /sdFlag = SD_Write_Sector(520, sdTxBuf);
   if(!sdFlag); 
   {
      // 读取成功
      // 点亮LED D2
      PORT_ChangeP77Output(0);
   }
  }
  
 }
 
 
 while (1U)
 {
  ;
 }
 /* End user code. Do not edit comment generated here */
}

使用SPI通信要注意 防止溢出 我采用判断标志变量的方法 等待
CSI00_SendReceiveData(sdTxBuf, 512, sdRxBuf);
 while(!spiSendFlag)
 {
  NOP();
  if(spiErroFlag)
  {
     spiErroFlag = 0;
   return SPI_ERROR;
  }
 }
 spiSendFlag = 0;

实物图如下


为了实现对SD卡的读写 我先在SD的根目录下建立两个test.txt 文件 并输入文本“Hello, EEPW”


同时使用WinHex软件对SD卡进行查看 由于我没有使用文件系统






可见 一个扇区为 512 字节 并且我们的文本内容是从520个扇区开始的

下面是读数据时候的硬件仿真截图


写数据也是类似 只不过由于没有实现文件系统 没有更新文件长度 即使我写入了 在windows下可能也看不到 而且还有可能破坏文件系统
写入文件的过程如下

然后在电脑上先用WinHex打开磁盘 弹出了两个警告对话框
估计是自动修复了SD卡的文件系统 所以我才能看到修改后的文件




SPI 读写SD卡的功能已经实现 时间充足的情况下可以考虑将镇南的znFAT 文件系统移植下
而且SPI读写外部FLASH的话 STM32不完全手册上介绍了 读写W25X16 的方法
可以参考


高工
2012-09-07 15:38:06     打赏
42楼

今天试了试 镇南的znFAT 发现
容易调试时候
打开文件 读取SD卡扇区时候
一直在 SD_Read_Sector 函数中 下面处的代码卡死

 //一直读,当读到0xfe时,说明后面的是512字节的数据了 // 
 do
 {
    CSI00_SendReceiveData(clk8Buff, 1, spiRxBuff);  // 接收响应出问题
  while(!spiSendFlag)
  {
   NOP();
   if(spiErroFlag)
   {
     spiErroFlag = 0;
   return SPI_ERROR;
   }
  }
  spiSendFlag = 0;
  NOP();
  NOP();
 }
 while(spiRxBuff[0]!=0xfe);



不知道为啥 我甚至能获取SD卡的信息了


难道是我代码太大了? 都80多k了 
而且我今天发现 SD卡的SPI模式 1 和 4 都可以 
而且速度可以上到 153600 bps

我准备先放放 看看论坛上有没有人做出来 分享下
周末找个SPI 的片子 做做外部flash


高工
2012-09-09 00:27:41     打赏
43楼
使用自带SPI 模式读取外部flash存储器 PCT25VF016B

目前读取厂商ID 和 设备ID 以及内部状态寄存器成功
( PCT25VF016B 貌似就是SST25VF016,读取的ID号是一致的 )

Applilet 的设置

貌似波特率要设置的大一些才行 

电路图可以参考

管教兼容

至于上拉电阻和单片机IO口的设置 可参考SD卡部分 
我的单片机上的SI口没有外接上拉 SO SCK CS 都有上拉 但是上拉的电平为3.3V

实物图

上面是单片机 中间的电路板负责实现3.3V电平 最下面的是上拉电阻部分 最右侧是PCT25VF016的转接板  线比较乱

目前调试的图(读取ID 和寄存器)


高工
2012-09-09 12:17:38     打赏
44楼
真的不错。。

高工
2012-09-10 00:43:24     打赏
45楼

把SST25VF016的驱动完善了一下

头文件 flash.h

#ifndef WW_25VF06
#define WW_25VF06

// flash.h
// ww 25VF016 v1.0 提供了简化的驱动版本
// 后继应该继续添加写入flash之前的读取判断是否被擦除的工作 以及4k 32k 64k的分块
// 适用于SSTVF25016
#include "CG_macrodriver.h"

// 定义CS口
#define FLASH_CS P0_bit.no0
// 定义MCU输入端口 SI
#define FLASH_SI P1_bit.no1

#define FLASH_ID 0XBF41

//指令表
#define T25VF_WriteEnable  0x06
#define T25VF_WriteDisable  0x04
#define T25VF_ReadStatusReg  0x05
#define T25VF_WriteStatusReg 0x01
#define T25VF_WriteStatusRegEnable 0x50;
#define T25VF_ReadData   0x03
#define T25VF_FastReadData  0x0B
#define T25VF_ByteProgram  0x02
#define T25VF_BlockErase32k  0x52
#define T25VF_BlockErase64k  0xD8
#define T25VF_SectorErase4k  0x20
#define T25VF_ChipErase   0xC7
//#define T25VF_DeviceID   0xAB
//#define T25VF_ManufactDeviceID 0xAB
#define T25VF_ReadID    0x90
#define T25VF_JedecDeviceID   0x9F
#define T25VF_Enable_Output_BY  0x70
#define T25VF_Disable_Output_BY  0x80
#define T25VF_AAI_WordProgram  0xAD

UINT  SPI_Flash_ReadID(void);       //读取FLASH ID
// 分成两部分 读取FLASH ID
UCHAR  SPI_Flash_ReadFactoryID(void);       //读取厂商ID
UCHAR  SPI_Flash_ReadDeviceID(void);       //读取 设备ID
ULONG SPI_Flash_ReadJedecID(void);   // 读取Jedec ID
UCHAR SPI_Flash_ReadSR(void);          //读取状态寄存器
void SPI_Flash_Wait_Busy(void);            //等待空闲
void SPI_FLASH_Write_SR(UCHAR sr);    //写状态寄存器
void SPI_FLASH_Write_Enable(void);    //写使能
void SPI_FLASH_Write_Disable(void);   //写保护
void SPI_FLASH_Write_SR_Enable(void);   // 使使能改写状态寄存器操作void SPI_Flash_Erase_Chip(void);        //整片擦除
void SPI_Flash_Erase_Sector4k(ULONG Dst_Addr_Index);//扇区擦除
void SPI_Flash_Erase_Block_32k(ULONG Dst_Addr_Index);//block32k
void SPI_Flash_Erase_Block_64k(ULONG Dst_Addr_Index);//block64k
//检测是否可以执行写入操作
void SPI_Flash_Write_Enable_Check(void);       
//读取flash单个字节
UCHAR SPI_Flash_Read(ULONG ReadAddr);  
//连续读取flash
void SPI_Flash_Read_Continue(UCHAR* pBuffer,ULONG ReadAddr,UINT NumByteToRead);
//高速读取flash单个字节
UCHAR SPI_Flash_HighRead(ULONG ReadAddr);  
//连高速续读取flash
void SPI_Flash_HighRead_Continue(UCHAR* pBuffer,ULONG ReadAddr,UINT NumByteToRead);  
// 写入flash
void SPI_Flash_ByteWrite(UCHAR Data ,ULONG WriteAddr);
// 第一次调用AAI 记得之前写使能
void SPI_Flash_AAI_WordProgramA(UCHAR *Data, ULONG WriteAddr);
// 第二次调用AAI 之前不必写使能
void SPI_Flash_AAI_WordProgramB(UCHAR *Data);
// 整体的AAI 操作 // 需要停止AAI 时候 检测到芯片不忙 发送写禁止命令即可
void  SPI_Flash_AAI_WordProgram(UCHAR *Data, UINT NumByteToWrite, ULONG WriteAddr);     
// 在AAI模式下监测MISO线是否变为1,用以显示AAI操作模式完成  
void SPI_Flash_Poll_SO() ;
// 整体的AAI 操作 使用SO判断忙标志
void  SPI_Flash_AAI_WordProgramSO(UCHAR *Data, UINT NumByteToWrite, ULONG WriteAddr);
// 允许MISO在AAI模式期间输出RY/BY# 状态  
void SPI_Flash_Enable_Output_BY();  
// 功能: 禁止MISO在AAI模式下作为输出RY/BY#状态的信号*/  
void SPI_Flash_Disable_Output_BY();    

#endif

主函数main.c 测试
*/
void  main(void)
{
 /* Start user code. Do not edit comment generated here */
    // 初始化 接收和发送缓冲
   InitComTxBuff();
 InitComRxBuff();
 
 // 验证SPI操作 

 /* Start CSI00 operations */
 CSI00_Start(); 
 
// 测试读取ID
// ID = SPI_Flash_ReadID();
// FactoryID = SPI_Flash_ReadFactoryID();
// DeviceID = SPI_Flash_ReadDeviceID();
// 测试读取Jedec ID
// Jedec_ID = SPI_Flash_ReadJedecID();
 
// 测试读取状态寄存器
// 芯片上电读取出来的状态寄存器上电初始化为 0b00011100  全部芯片受保护
 REG = SPI_Flash_ReadSR();    
// 测试写入寄存器保护位
// 首先使能写寄存器
 REG &= 0;
 SPI_FLASH_Write_SR(REG);    //写状态寄存器
 REG = SPI_Flash_ReadSR(); 

// 测试擦除32k 索引1
// SPI_Flash_Erase_Block_32k(1); 
// 测试擦除64k 索引2
// SPI_Flash_Erase_Block_64k(2);
// 测试整片擦除
// SPI_Flash_Erase_Chip(); 
 
// 测试擦除4k 索引0
// SPI_Flash_Erase_Sector4k(0);
// 测试写入操作
 intTestWriteData();
// 单个字节的写入
 /*
 SPI_Flash_ByteWrite(testWriteData[0], 0x00);//写入flash
 SPI_Flash_ByteWrite(testWriteData[1], 0x01);//写入flash
 SPI_Flash_ByteWrite(testWriteData[2], 0x02);//写入flash
 SPI_Flash_ByteWrite(testWriteData[3], 0x03);//写入flash
 SPI_Flash_ByteWrite(testWriteData[4], 0x04);//写入flash
 SPI_Flash_ByteWrite(testWriteData[5], 0x05);//写入flash
 */
 
// 测试读取单个字节 
 /*
 testReadData[0] =  SPI_Flash_Read(0x00);  
 testReadData[1] =  SPI_Flash_Read(0x01); 
 testReadData[2] =  SPI_Flash_Read(0x02);  
 testReadData[3] =  SPI_Flash_Read(0x03);  
 testReadData[4] =  SPI_Flash_Read(0x04);  
 testReadData[5] =  SPI_Flash_Read(0x05);   
 */
 
//  多个字节写入 方式1
 /*
 SPI_Flash_Erase_Sector4k(0);
 SPI_Flash_AAI_WordProgram(testWriteData, 32, 0x00); 
 testReadData[6] =  SPI_Flash_HighRead(0x06);  
 testReadData[7] =  SPI_Flash_HighRead(0x07); 
 testReadData[8] =  SPI_Flash_HighRead(0x08);  
 testReadData[9] =  SPI_Flash_HighRead(0x09);  
 testReadData[10] =  SPI_Flash_HighRead(0x10);  
 testReadData[11] =  SPI_Flash_HighRead(0x11); 
 */
 
//  多个字节写入 方式2
 SPI_Flash_Erase_Sector4k(0);
 SPI_Flash_AAI_WordProgramSO(testWriteData, 32, 0x00); 
 
// 测试读取多个字节
 SPI_Flash_Read_Continue(testReadData,0,16);
// 第二次从第16个字节地址开始读
 SPI_Flash_HighRead_Continue(testReadData+16,16,16);
 
//  串口发送
   UART2_Start();
 // UART2_SendData(Com, 16);
 while (1U)
 {
  ;
 }
 /* End user code. Do not edit comment generated here */
}

需要注意的是 芯片第一次上电读取出来的状态寄存器上电初始化为 0b00011100  即全部芯片受保护 因此为了能够写入芯片 必须修改状态寄存器中的写保护位 

调试截图


目前基本上还剩下下面几个内容
PWM模块实现H桥直流马达驱动
ADPCM库
DMA
还有个问题 定时器输入捕获,输出比较是什么意思?


助工
2012-09-12 21:38:39     打赏
46楼

所谓输出比较的功能,就是当输出比较事件发生时,相应引脚的电平会发生变化。
楼主神速学习了


高工
2012-09-18 00:10:56     打赏
47楼

考虑到将ADPCM库移植到IAR 平台 一直卡在汇编代码上
@@CNST CSEG MIRRORP
不得已 尝试了 CubeSuite+ 平台
先看了使用手册 并下载尝试自带的ADPCM库例子
P31口即TO03 上出现了波形


高工
2012-09-18 01:05:20     打赏
48楼

我分析改造例子代码的过程
ADPCM 库给的例子给出了解码和编码的使用
解码(decode),我的理解就是ADPCM-->PCM / WAV
编码(encode),就是将WAV / PCM --> ADPCM
现在主要分析解码的过程
R_decode_main();
解码主要使用定时器0 和 定时器2 3 
定时器2 3 用于实现PWM 输出


定时器0设定的定时间隔要和我们实际录制的音频格式的采样率一样(录制的话选择单声道)
如果是11.025kHz 可以设置间隔为90.7 us
如果是8kHz 可以设置间隔为125 us

系统一直在进行解码的工作直到全部文件解码完成
 中间会有定时器0中断 将解码好的数据发送出去

定时器0的定时时间到了之后 调用
R_interrupt_decode_timer();
函数,控制PWM 输出数据

需要注意的是 宏定义 PCM_DATA_SIZE1 是 ADPCM格式的dat文件大小的2倍
同时 宏定义 ADPCM_ADDR1 的值也要和调试下载数据文件的位置一致

手册上有段话
(4) Loading of sound data
Download ADPCM data to the address set to "ADPCM_ADDR1". ADPCM data is the data created using the
ADPCM_TOOL. Please refer the CubeSuite+ manual for the downloading procedure. 
记得调试要改成E1方式


下载文件的具体设置就如同下图


我单独使用解调方式 将我录制的一段声音(单通道 8k) 经过 ADPCM自带的tool工具 ADPCM.exe 进行转换 并使用到程序中

主函数代码
void main(void)
{
    /* Start user code. Do not edit comment generated here */
   
    while (1U)
    {
        R_decode_main();
    }
    /* End user code. Do not edit comment generated here */
}

我的代码: myADPCMde_Cube.rar


高工
2012-09-19 00:05:37     打赏
49楼

为了实现
ADPCM库录音

设计的呼吸音监测方案
制作了麦克风放大电路

原理图

后面的施密特触发器是为了实现对单片机的中断

实物图


测试图


视频


视频地址:http://union.bokecc.com/flash/player.swf?vid=56EFF65BF0809519&siteid=290666218ACBA694&playerid=EEA982EE6B20F4D1&playertype=1

院士
2012-09-19 14:02:29     打赏
50楼
真棒~~
电路图,实物图都齐了……

向楼主学习……

共61条 5/7 |‹ 2 3 4 5 6 7 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]