Thread 中讨论的其他器件:controlSUITE
大家好、
因此、对于某些参数、我需要定期将数据记录到 SD 卡中。 我开始使用 controlSUITE 中提供的 SD 卡示例。 我在 MMC-F2837x.c 文件中的 xmit_datablock 函数中将 wc=0修改为 wc=256。 我修改了主函数并在上述序列中添加了对 f_mount、f_open、f_write、f_sync、f_close 和 f_mount 的函数调用、以创建文件并向其写入字符串。 我能够成功地做到这一点,没有任何问题。 否、我尝试将 DMA 功能实施到 SPI TX 通道、但我无法成功实现。 我使用"Example_2837xD_SPI_DMA"作为 DMA 使用的示例。
我想使用 DMA 一次写入512字节的块。 这样、我就不需要大量修改代码。 那么、这里是我根据我在 SD_CARD 示例中的理解所做的配置和更改。
我在 MMC-F2837x.c 文件中添加了以下内容:
#define burst (FIFO_LVL-1)//突发大小应小于8 #define 传输 63. //[(MEM_buffer_size/FIFO_LVL)-1] #define FIFO_LVL 8. // FIFO 中断级别 // 全局 // volatile UINT16 *DMADest; volatile UINT16 *DMASource; volatile UINT16 SpiTxDmaDone = 0; //函数原型 void dma_init (void);
我在 MMC-F2837x.c 文件的 POWER_ON 函数中再次添加了以下代码:
// SPI 端口设置 //配置 SPI C 端口*/ SpicRegs.SPICCR.bit.SPISWRESET = 0;//设置复位位位低 SpicRegs.SPICTL.bit.CLK_PHASE = 0; SpicRegs.SPICCR.bit.CLKPOLARCR= 1;SpicRegs.SPICL.bit.SPICRP.0 ~= 0;SPICRP.SPICRCR.SPICKCR.SPICKCR.SPICRCR.PHASE = 0;针对正确的 SPICTRL.ST/ SPICRP.0.SPICK.SPICK.SPICK.SPICRCR.SPICRCR.SPICRCR.SPICRCR.SPICRCR.SPICK= 1;SP//将字符长度设置为8位 SpicRegs.SPICTL.bit.TALK = 1; SpicRegs.SPICCR.bit.SPISWRESET = 1;//从复位 SpicRegs.SPIPRI.bit.FREE 释放 SPI; SpicRegs.SPICRI.bit.Soft = 1;EALLOW/ INTR_5 寄存 器需要 写入保护;EALCHINT_TRIST_INIT //为 SPI 配置设置 DMA SpicRegs.SPIFFCT.all = 0x0; for (m=0;m<3;m++); SpicRegs.SPIFFRX.ALL=0x2040; //启用 RX FIFO、清除 FIFO int SpicRegs.SPIFFRX.bit.RXFFIL = 0;//设置 RX FIFO 级别 SpicRegs.SPIFFTX.All=0xE040; //启用 FIFO、TX FIFO 释放、 SpicRegs.SPIFFTX.bit.TXFFIL = FIFO_LVL;//设置 TX FIFO 级别 //确保 DMA 连接到外设帧2桥(EALLOW 受保护) EALLOW; CpuSysRegs.SECMSEL.bit.PF2SEL = 1; EDIS; //启用 PILE.PILE.ETRL 中断;//启用 PILE.PILE.PIE = 1。 //启用 PIE 组7、INT 1 (DMA CH1) PieCtrlRegs.PIEIER7.bit.INTx6 = 1;//启用 PIE 组7、INT 2 (DMA CH2) IER = M_INT7; //启用 CPU INT6
需要注意的一点是、我的 SpicRegs.SPICCR.bit.SPICHAR = 0x7、因为 SD_CARD 示例使用字节(无符号字符)类型。
DMA Init 和 TX ISR 如下所示:
//
// dma_init - TX 和 RX 通道的 DMA 设置。
//
void dma_init()
{
//
//初始化 DMA
//
DMAInitialize();
//
//为 TX 配置 DMACH5
//
// DMACH5AddrConfig (&SpicRegs.SPITXBUF、DMASource);
DMACH5BurstConfig (突发、1、0); //突发大小、src 步长、dest 步长
DMACH5TransferConfig (transfer、1、0);//传输大小、src 阶跃、dest 阶跃
DMACH5ModeConfig (DMA_SPICTX、PERINT_ENABLE、OneShot_disable、CONT_disable、
SYNC_DISABLE、SYNC_SRC、OVRFLOW_DISABLE、十六位、
CHINT_END、CHINT_ENABLE);
}
//
local_D_INTCH5_ISR - DMA 通道5 ISR
//
_interrupt void local_D_INTCH5_ISR (void)
{
EALLOW;//需要在 ISR 内执行 EALLOW!!!
// DmaRegs.ch5.control.bit.halt=1;
PieCtrlRegs.PIEACK.all = PIEACK_group7;// ACK 可接收来自此 PIE 组的更多中断
EDIS;
SpiTxDmaDone = 1;
返回;
}
我在 MMC-F2837x.c 文件中添加了一个函数"xmit_datablock_dma"、该函数将再次替换"xmit_datablock"。 正在从 disk_write 函数调用此函数。 以下是 xmit_datablock_dma.c 文件的定义。 其理念是、此新函数应具有与"xmit_datablock"完全相同的功能、但使用 DMA 传输512字节块的不同之处在于。
/*------------------ // //*使用 DMA 向 MMC 发送数据包 */ //*---------------------------------------------------------------------------------------------------- */ 静态 BOOL xmit_datablock_DMA (字节令牌) /*数据/停止令牌*/ { 字节 RESP;//、wc; unsigned int Count=0; volatile DWORD rcvdat; SpiTxDmaDone = 0; 如果(WAIT_READY ()!= 0xFF)返回 false; Xmit_SPI (令牌); /* Xmit 数据令牌*/ 如果(令牌!= 0xFD) /*是数据令牌*/ { StartDMACH5(); //启动 SPI TX DMA 通道 while (!SpiTxDmaDone); Xmit_SPI (0xFF); /* CRC (虚拟)*/ Xmit_SPI (0xFF); // RESP = RCVR_SPI (); /* Reveive 数据响应*// if ((RESP & 0x1F)!= 0x05) //返回 FLASE; // FIOEDIT:已将上述3行更改为此逻辑。 由于 RX FIFO 即使不需要也会被启用、所以必须按如下方式手动实现 RX 功能。
//从一组 RX 字符中,此代码找到0xE5。 while (SpicRegs.SPIFFTX.bit.TXFFST >= 7); SpicRegs.SPITXBUF = 0xFF00;//写入虚拟数据 while (SpicRegs.SPIFFRX.bit.RXFFST <= 0){} while (SpicRegs.SPIFFRX.bit.RXFFST > 0) { rcvdat =(SpicRegs.SPIRXBUF & 0xFF);//读取传输的数据 如果((rcvdat & 0x1F)== 0x05) 返回 true; } 返回 false; } 返回 true; }
在上面的代码中、我注意到的一件事是、当我尝试调试这个代码时、当我写入虚拟数据以接收字符时、 RXFFST 每次大约为8或9、其中一个响应为0xE5、而所有其他响应为0xFF、这就是为什么我必须实现 while 循环来检查所有接收到的响应中的0xE5。 但是、如果我不使用 DMA、我只需要以下3行代码:
RESP = RCVR_SPI (); // if ((RESP & 0x1F)!= 0x05) 返回 FLASE;
我修改的最后一个内容是 disk_write 函数、如下所示:
DRESULT disk_write ( 字节 drv、 /*物理驱动器编号(0)*/ 常量字节*buff、/*指向要写入的数据的指针*/ DWORD 扇区, /*起始扇区编号(LBA)*/ 字节计数 /*扇区计数(1.255)*/ ) { DMASource =(volatile UINT16 *) buff; DMACH5AddrConfig (&SpicRegs.SPITXBUF、DMASource); 如果(drv ||!count)返回 RES_PARERR; IF (Stat & STA_NOINIT)返回 RES_NOTRDY; IF (Stat 和 STA_PROTECT)返回 RES_WRPRT; if (!(CardType & 4)) sector *= 512;//如果需要,转换为字节地址*/ select(); /* CS = L */ 如果(计数= 1) /*单个块写入*/ { // FIOEDIT // if ((send_cmd (CMD24、sector)=0)/* write_block */ && xmit_datablock (缓冲区、0xFE) if ((send_cmd (CMD24、sector)=0)/* write_block */ && xmit_datablock_DMA (0xFE)) 计数= 0; } 其他 /*多块写入*/ { IF (CardType & 2) { SEND_cmd (CMD55、0); SEND_cmd (CMD23、COUNT);/* ACMD23 */ } if (send_cmd (CMD25、sector)=0) /* write_multiple_block */ { 操作 { // FIOEDIT //如果(!xmit_datablock (buff、0xFC))中断; //DMASSOURCE =(易失性 UINT16 *) TxDataBuff; //DMACH5AddrConfig (&SpicRegs.SPITXBUF、DMASource); 如果(!xmit_datablock_DMA (0xFC))中断; buff += 512; } while (-count); // FIOEDIT if (!xmit_datablock (0、0xFD))/* stop_Tran token */ // if (!xmit_datablock_dma (0xFD))/* stop_Tran token */ 计数= 1; } } 取消选择(); /* CS = H */ RCVR_SPI (); /*空闲(释放 DO)*/ 返回计数? RES_ERROR:RES_OK; }
在上述 disk_write 函数中、count 始终等于1、因为每次写入的字节数不超过512字节。 唯一的修改是将 DMA 源和解址分配给*缓冲区、然后将 xmit_datablock 替换为 xmit_datablock_DMA。
我尝试了很多调试、但我已经用尽了我的知识。 这是我第一次处理文件系统代码、我不是专家。 我知道 C2000文档清楚地提到了这一点:
/
写入 SIZE 寄存器的值小于预期的大小。 因此、要传输三个16位字、应将值2放置在 SIZE 寄存器中。
无论 DATASIZE 位的状态如何、SIZE 寄存器中指定的值都是针对16位地址的。 因此、要传输三个32位字、应将值5放置在 SIZE 寄存器中。
不管 DATASIZE 位的状态如何、STEP 寄存器中指定的值都是针对16位地址的。 因此、要使一个32位地址递增、应在这些寄存器中放置一个值2。
(二 /
我尝试使用这些设置以及 SpicRegs.SPICCR.bit.SPICHAR = 0x7设置、方法是将其设为等同于16位的0xF。 但是、当我尝试在启用 DMA 选项的情况下进行调试时、还没有任何效果。 :(
我知道 DMA 会被触发、因为我可以在 ISR 中遇到一个断点。
我真的需要您的建议来完成这项工作。 我有速度和时序限制、我需要 DMA 功能才能使 SD 卡数据记录正常工作。 感谢您抽出宝贵时间!
此致、
Archit