This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28379D:使用 DMA 记录 SD 卡数据

Guru**** 2538950 points
Other Parts Discussed in Thread: CONTROLSUITE

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/610129/tms320f28379d-sd-card-data-logging-using-dma

器件型号:TMS320F28379D
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

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好!
    我写信告诉您、C2000团队成员已被分配到此帖子、应该很快回答。

    此致
    Baskaran
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Archit、

    我看到您从 ISR 中删除了 HALT=1。 您是否需要它来防止 xmit 函数之外发生的传输? 还是在代码中的其他位置停止通道?

    DMA 传输的数据是如何格式化的? 回想一下、当 SPI 字符大小小于16时、您需要保留对齐数据。 您的数据缓冲区是否格式化、以便您要传输的每个字符都位于高8位?

    谢谢、

    惠特尼

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我检查了我的代码、似乎我暂时从 ISR 中删除了 HALT=1来测试某些东西。 但它在代码中。 代码不会对正在传输的数据进行左对齐。 我完全错过了。 这是一个很好的收获。 最好的方法是什么? 我真的有非常严格的时序限制、我不想创建一个具有输入字节*缓冲区的移位版本的局部数组。 执行移位运算并每次复制超过512个字将需要额外的时间、并且不符合我的时序限制。 我的意思是、我不想在 MMC-F2837x.C 中的 disk_write 函数中执行类似的操作

    DRESULT disk_write (
    字节 drv、 /*物理驱动器编号(0)*/
    常量字节*buff、/*指向要写入的数据的指针*/
    DWORD 扇区, /*起始扇区编号(LBA)*/
    字节计数 /*扇区计数(1-.255)*/
    )
    {
    unsigned int IDX;
    unsigned int TxDataBuff[512]={ 0 };
    
    for (IDX=0;IDX<512;IDX++)
    TxDataBuff[512]=( unsigned long )Reg...++<8;
    
    DMASSource =(UX<512;IDX++)DMX56* Dx
    配置(Unvolatile DDICfu.US&DxDataConfig/DMAFF
    
    
    //如上一个帖子中所示的其余函数代码。
    //.
    
    

    您能提出一些高效的建议吗? 我已共享上一个帖子中的所有代码。

    非常感谢您抽出宝贵的时间为您提供帮助!

    谢谢、

    Archit

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    一件简单的事情。 我曾尝试按照上一个帖子中所述修改代码、将数据左移8位、并尝试执行代码。 然而,这似乎不起作用。。 当我调试代码时;下面是失败的函数调用跟踪:

    它在 disk_write 中失败的具体位置是

    if ((send_cmd (CMD24、sector)=0)/* write_block */
    && xmit_datablock_DMA (0xFE))
    计数= 0;
    

    如果语句条件通过、那么 count 变为0。 并引发错误。

    如果您需要更多信息、请告诉我。

    谢谢、

    Archit

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我是否可以询问 TX 缓冲区中正在使用哪种数据、以及是否将其用于除日志记录之外的任何其他用途? 我想知道这是不是一种情况,在填充数据缓冲区时,您可以移动或使用__byte()内在函数将数据移动到高字节中。 这是可能的吗?

    惠特尼

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    否、它不在任何地方使用。 实际上、我在触发 DMA 之前尝试了左移位、但它仍然不起作用。 如果有助于快速解决问题、我可以共享我的 CCS 项目。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是否有任何更新? 请告诉我。 我可以与您共享 CCS 项目、以便您了解它是否有用。 请告诉我。 谢谢!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好 Archit、

    很抱歉、我今天没有返回到这里。 您可以向我发送您的项目。 明天下午我应该有一些时间来看看。

    惠特尼
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我向您发送了一条包含 CCS 工程和修改后的 fatfs 库文件的私人消息。 感谢您抽出时间帮助解决此问题。 谢谢。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好 Archit、

    我还有些被骗了、但下面是我的观察结果。

    1.我注意到,如果我在虚拟 CRC 写入后单步执行您在 xmit_datablock_dma()中添加的代码,我就能够使它返回 true。 我还发现、如果我在最后一个 while 循环之前放置了一个延迟(如 SysCtlDelay (10000))、即使我没有单步执行它、它也会起作用。 我仍然不确定 RX 缓冲器中的额外8个字来自哪里。 它看起来几乎像是中断之后的最后一个 DMA 突发进入。 您能否确认看到相同的行为?

    2.您为移动数据缓冲区而添加的代码将不起作用。 您已声明一个与全局 TxDataBuff 同名的本地 TxDataBuff。 配置到 DMA 中的地址是本地地址、因此它基本上是传输您的堆栈而不是目标字符串。

    惠特尼
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    当您说它适合您时、您是否意味着您能够使用 DMA 将数据成功记录到 SD 卡? 其次、我不愿意引入"SysCtlDelay (10000)"、因为整个想法是加快传输速度、而不是挂起处理器或降低其执行速度。 最初、我想使 DMA 工作、然后我将删除所有这些等待状态、或者至少减少这些等待状态以适应时序。 我可以不收到一些定期执行的主要框架的答复。

    1) 是的、我确实会看到相同的行为、而实际响应229d 始终位于8个字节的最后一个字节。 我假设 RX FIFO LVL 设置为8、因此我们可以看到专门的8个字节。 但是,我不确定这些额外字节来自何处.........

    2) 因此、disk_write 中代码的片段如下所示:

    unsigned int IDX;
    unsigned int TxDataBuff[512]={0};
    
    for (IDX=0;IDX<512;IDX++)
    TxDataBuff[IDX]=(unsigned long)*buff+)<< 8;
    
    DMASConfig =(volatile U16 *) TxDataBuff;
    DMACH5UXBUF (DMADICFFE.ADDRF)
    

    在这里、我将左移的"buff"内容分配给 TxDataBuff。 然后将 TxDataBuff 的指针分配给 DMASource。 在之前进行调试时、我确实确保 DMASource 指向堆栈 TxDataBuff 的正确存储器位置。 其理念是调用 disk_write 不仅只是为了写入字符串。 由于它是一个文件系统、因此还有对 disk_write 的额外调用、这些调用不用于写入数据。 因此,我只需将 buff*移动 buff*的内容并分配给 TxDataBuff。 这可能是我要存储的实际数据、也可能只是文件系统管理部分。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    当我说它起作用时、我意味着我能够使写入函数返回"确定"。 我仍然看不到 SD 卡上的数据。 我看到一个空文件、没有文件或完全损坏的 SD 卡、需要重新格式化。

    我没有建议将延迟作为永久性解决方案。 我的意思是、它更多地是指有关可能发生的错误的线索。

    没错、我没有看到足够紧密地移动数据的循环。 重复使用变量名会使我失望。 不过、您需要更改链接器选项以使栈更大。

    您是否可以使用逻辑分析仪或示波器来查看正在传输的数据/数据量? 我不认为连接到 SD 卡插槽的引脚在扩展坞上是固定的、但您可能可以使用 XBAR 在不同的 GPIO 上复制信号。 类似如下:

    EALLOW;
    InputXbarRegs.INPUT1SELECT = 122;
    OutputXbarRegs.OUTPUT1MUX0TO15CFG.bit.MUX1 = 1;
    OutputXbarRegs.OUTPUT1MUXENABLE.bit.MUX1 = 1;
    EDIS;
    GPIO_SetupPinMux (2、GPIO_MUX_CPU1、5); 

    谢谢、

    惠特尼

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    Whitney、自我上次发送消息以来是否有任何更新? 我真的需要这个解决的小问题。

    此致、
    Archit
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    如果有人能提供一些见解、我将不胜感激。

    此致、
    Archit
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    自我对您的 PM 做出响应以来没有更新。 我将把它粘贴到这里、以防它不运行。

    [引述]今天我花了一些时间来讨论这个问题、但实际上仍然没有任何答案或建议。 正如我在上一条消息中所说的、即使我使函数返回"确定"状态、我在检查 SD 卡时实际上仍然看不到任何内容。

    我想在逻辑分析仪上看到一些常规 xmit_datablock()函数波形与 xmit_datablock_dma()波形的比较。 您是否在使用逻辑分析仪时碰巧做到了这一点?[/quot]

    惠特尼