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.

[参考译文] CCS/TMS320F28379D:如何使用 DMA 持续读取 SPI 数据?

Guru**** 2546270 points


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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/913776/ccs-tms320f28379d-how-to-use-dma-to-continuously-read-spi-data

器件型号:TMS320F28379D

工具/软件:Code Composer Studio

您好!

我正在尝试使用 DMA 从外部器件连续读取 Rx SPIB 数据并输出到 SCIA。

我能够通过组合"spi_loopback _dma_cpu01"和"sci_echoback_cpu01"示例来创建工作代码。

但是、我发现我只能读取一次数据。 DMA "local_D_INTCH6_ISR"回调仅触发一次。

每次传输时、外部器件重复发送 SPI 数据115、200字节。 我打算以较小的块(例如1024字节)读取传入数据、输出到 SCI、然后重构数据。

我不确定需要进行哪些更改才能连续读取 Rx SPI-DMA。

你能提供建议吗? 非常感谢。

以下是我的代码:

//
//包含的文件
//

#include "F28x_Project.h"


//
//定义
//
#define MEM_buffer_size 1024
#define BURST (FIFO_LVL-1)//突发大小应小于8
#define 传输(MEM_BACK_SIZE /FIFO_LVL)-1 //[(MEM_BACK_SIZE /FIFO_LVL)-1]
#define FIFO_LVL 8 // FIFO 中断级别

#if CPU_FRQ_200MHz
#define SPI_BRR ((200E6/4)/500E3)- 1.
#endif

#if CPU_FRQ_150MHz
#define SPI_BRR ((150E6/4)/500E3)- 1.
#endif

#if CPU_FRQ_120MHz
#define SPI_BRR ((120E6/4)/500E3)- 1.
#endif

//
//全局
//
#pragma DATA_SECTION (sdata、"ramgs0");//将 TX 数据映射到存储器
#pragma DATA_SECTION (RDATA、"ramgs1");//将 RX 数据映射到存储器
uint16 sdata[MEM_buffer_size];//发送数据缓冲区
uint16 RDATA[MEM_buffer_size];//接收数据缓冲区
uint16 gData[MEM_buffer_size];
uint16 RDATA_POINT;//跟踪我们的位置
//在数据流中检查接收到的数据
易失性 uint16 * DMADest;
易失性 uint16 * DMASSOURCE;
易失性 uint16完成;

//
//函数原型
//
_interrupt void local_D_INTCH5_ISR (void);
_interrupt void local_D_INTCH6_ISR (void);
void delay_loop (void);
void InitSpibGpio (void);
void dma_init (void);
void SPI_Fifo_init (void);
void InitSpiB (void);
void error();
void scia_echoback_init (void);
void scia_fifo_init (void);
void scia_xmit (int a);
void scia_msg (char * msg);

//
//主函
//
void main (void)

uint16 i;

//
//步骤1. 初始化系统控制:
// PLL、安全装置、启用外设时钟
//此示例函数位于 F2837xD_SYSCTRL.c 文件中。
//
InitSysCtrl();

//
//步骤2. 初始化 GPIO:
//此示例函数位于 F2837xD_GPIO.c 文件和中
//说明了如何将 GPIO 设置为其默认状态。
//仅为 SPI-B 功能设置 GP I/O
//
InitGpio();

GPIO_SetupPinMux (43、GPIO_MUX_CPU1、15);
GPIO_SetupPinOptions (43、GPIO_INPUT、GPIO_PushPull);
GPIO_SetupPinMux (42、GPIO_MUX_CPU1、15);
GPIO_SetupPinOptions (42、GPIO_output、GPIO_Async);

InitSpibGpio();

//
//步骤3. 初始化 PIE 矢量表:
//禁用并清除所有 CPU 中断
//
Dint;
IER = 0x0000;
IFR = 0x0000;

//
//将 PIE 控制寄存器初始化为默认状态:
//此函数位于 F2837xD_PIECTRL.c 文件中。
//
InitPieCtrl();

//
//使用指向 shell 中断的指针初始化 PIE 矢量表
//服务例程(ISR)。
//这将填充整个表,即使是中断也是如此
//在本例中未使用。 这对于调试很有用。
//可以在 F2837xD_DefaultIsr.c 中找到 shell ISR 例程
//此函数可在 F2837xD_PieVect.c 中找到
//
InitPieVectTable();

scia_fifo_init();//初始化 SCI FIFO
scia_echoback_init ();//初始化用于 echoback 的 SCI

//
//此示例中使用的中断被重新映射到
//此文件中的 ISR 函数。
//
EALLOW;//这是写入 EALLOW 受保护寄存器所必需的
PieVectTable.DMA_CH5_INT=&LOCAL_D_INTCH5_ISR;
PieVectTable.DMA_CH6_INT=&LOCAL_D_INTCH6_ISR;
EDIS;//这是禁止写入 EALLOW 受保护寄存器所必需的

//
//步骤4. 初始化器件外设:
//
dma_init ();//为 SPI 配置设置 DMA
SPI_Fifo_init();//仅初始化 SPI

//
//确保 DMA 连接到外设帧2桥接器(EALLOW 受保护)
//
EALLOW;
CpuSysRegs.SECMSEL.bit.PF2SEL = 1;
EDIS;

//
//步骤5. 特定于用户的代码、启用中断:
//

//
//初始化数据缓冲区
//
for (i=0;<MEM_BUFFER_SIZE; i++)

sdata[i]= i;
RDATA[i]= 0;
gData[i]= 0;

RDATA_POINT = 0;

//
//启用此示例所需的中断
//
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;//启用 PIE 块
PieCtrlRegs.PIEIER7.bit.INTx5 = 1;//启用 PIE 组7、INT 1 (DMA CH1)
PieCtrlRegs.PIEIER7.bit.INTx6 = 1;//启用 PIE 组7、INT 2 (DMA CH2)
IER = M_INT7;//启用 CPU INT6
EINT;//启用全局中断

char *msg;
MSG ="\r\n\n\nHello World!\0";
scia_msg (msg);

ESTOP0;

StartDMACH6 ();//启动 SPI RX DMA 通道
StartDMACH5 ();//启动 SPI TX DMA 通道

while (1)

DONE = 0;//测试尚未完成

while (!done);//等待 DMA 传输完成
//完成

对于(I = 0;I < MEM_BUFFER_SIZE;+I)

scia_xmit (gData[i]);

// StartDMACH6 ();//启动 SPI RX DMA 通道
// StartDMACH5 ();//启动 SPI TX DMA 通道
// SpibRegs.SPIFFTX.bit.TXFIFO = 0;
// SpibRegs.SPIFFTX.bit.TXFIFO = 1;
// SpibRegs.SPIFFRX.bit.RXFIFORESET = 0;
// SpibRegs.SPIFFRX.bit.RXFIFORESET = 1;

//
// DMA 传输完成后,程序将在此处停止
//
// ESTOP0;
};

//
// delay_loop -添加延迟的函数
//
void delay_loop ()

长 I;
对于(i = 0;i < 1000000;i++){}

//
//错误-收到错误时停止调试器
//
空错误(空)

asm (" ESTOP0");//测试失败!!! 停下来!
适用于(;);

//
// InitSpibGpio -初始化 SPIB GPIO
//
空 InitSpibGpio()

EALLOW;

//
//为所选引脚启用内部上拉
//
//用户可以启用或禁用上拉。
//这将启用指定引脚的上拉电阻。
//注释掉其他不需要的行。
//
GpioCtrlRegs.GPBPUD.bit.GPIO63 = 0;//启用 GPIO16上的上拉电阻器(SPISIMOA)
GpioCtrlRegs.GPCPUD.bit.GPIO64 = 0;//启用 GPIO17上的上拉电阻器(SPISOMIA)
GpioCtrlRegs.GPCPUD.bit.GPIO65 = 0;//启用 GPIO18上的上拉电阻器(SPICLKA)
GpioCtrlRegs.GPCPUD.bit.GPIO66 = 0;//启用 GPIO19上的上拉电阻器(SPISTEA)

//
//仅将所选引脚的限定条件设置为异步
//
//这将为所选引脚选择异步(无限定条件)。
//注释掉其他不需要的行。
//
GpioCtrlRegs.GPBQSEL2.bit.GPIO63 = 3;//异步输入 GPIO16 (SPISIMOA)
GpioCtrlRegs.GPCQSEL1.bit.GPIO64 = 3;//异步输入 GPIO17 (SPISOMIA)
GpioCtrlRegs.GPCQSEL1.bit.GPIO65 = 3;//异步输入 GPIO18 (SPICLKA)
GpioCtrlRegs.GPCQSEL1.bit.GPIO66 = 3;//异步输入 GPIO19 (SPISTEA)

//
//使用 GPIO 寄存器配置 SPI-A 引脚
//
//这指定哪些可能的 GPIO 引脚将是 SPI 功能
//引脚。
//注释掉其他不需要的行。
//
GpioCtrlRegs.GPBMUX2.bit.GPIO63 = 3;//将 GPIO63配置为 SPISIMOB
GpioCtrlRegs.GPCMUX1.bit.GPIO64 = 3;//将 GPIO64配置为 SPISOMIB
GpioCtrlRegs.GPCMUX1.bit.GPIO65=3;//将 GPIO65配置为 SPICLKB
GpioCtrlRegs.GPCMUX1.bit.GPIO66 = 3;//将 GPIO66配置为 SPISTEB

GpioCtrlRegs.GPBGMUX2.bit.GPIO63 = 3;//将 GPIO63配置为 SPISIMOB
GpioCtrlRegs.GPCGMUX1.bit.GPIO64 = 3;//将 GPIO64配置为 SPISOMIB
GpioCtrlRegs.GPCGMUX1.bit.GPIO65=3;//将 GPIO65配置为 SPICLKB
GpioCtrlRegs.GPCGMUX1.bit.GPIO66 = 3;//将 GPIO66配置为 SPISTEB

EDIS;

//
// SPI_Fifo_init -初始化 SPIB FIFO
//
void SPI_Fifo_init()

/*
//
//初始化 SPI FIFO 寄存器
//
SpiaRegs.SPIFFRX.All=0x2040;//启用 RX FIFO、清除 FIFO 内部
SpiaRegs.SPIFFRX.bit.RXFFIL = FIFO_LVL;//设置 RX FIFO 电平

SpiaRegs.SPIFFTX.All=0xE040;// FIFO 被启用、TX FIFO 被释放、
SpiaRegs.SPIFFTX.bit.TXFFIL = FIFO_LVL;//设置 TX FIFO 电平
*

SpibRegs.SPIFFRX.All=0x2040;//启用 RX FIFO、清除 FIFO 内部
SpibRegs.SPIFFRX.bit.RXFFIL = FIFO_LVL;//设置 RX FIFO 电平
// SpibRegs.SPIFFRX.bit.RXFFIENA=1;//设置 RX FIFO 电平

SpibRegs.SPIFFTX.All=0xE040;// FIFO 被启用、TX FIFO 被释放、
SpibRegs.SPIFFTX.bit.TXFFIL = FIFO_LVL;//设置 TX FIFO 级别*/
// SpibRegs.SPIFFTX.bit.TXFFIENA=1;//设置 TX FIFO 级别*/

/*
0 0 1 00000 0 1 0 00000
struct SPIFFRX_bits{// bits description
UINT16 RXFFIL:5;// 4:0 RXFIFO 中断级别
UINT16 RXFFIENA:1;// 5 RXFIFO 中断使能
UINT16 RXFFINTCLR:1;// 6 RXFIFO 中断清零
UINT16 RXFFINT:1;// 7 RXFIFO 中断标志
UINT16 RXFFST:5;// 12:8接收 FIFO 状态
UINT16 RXFIFORESET:1;// 13 RXFIFO 复位
UINT16 RXFFOVFCLR:1;// 14接收 FIFO 上溢清零
UINT16 RXFFOVF:1;// 15接收 FIFO 上溢标志
};

struct SPIFFTX_bits{// bits description
UINT16 TXFFIL:5;// 4:0 TXFIFO 中断级别
UINT16 TXFFIENA:1;// 5 TXFIFO 中断使能
UINT16 TXFFINTCLR:1;// 6 TXFIFO 中断清除
UINT16 TXFFINT:1;// 7 TXFIFO 中断标志
UINT16 TXFFST:5;// 12:8发送 FIFO 状态
UINT16 TXFIFO:1;// 13 TXFIFO 复位
UINT16 SPIFFENA:1;// 14 FIFO 增强使能
UINT16 SPIRST:1;// 15 SPI 复位
};
*
//
//初始化内核 SPI 寄存器
//
InitSpiB();

空 InitSpiB (空)

//初始化 SPI-A

//在配置更改之前将 RESET 设置为低电平
//时钟极性(0 =上升、1 =下降)
// 16位字符

SpibRegs.SPICCR.bit.SPISWRESET = 0;
SpibRegs.SPICCR.bit.CLKPOLARITY = 0;
// SpibRegs.SPICCR.bit.SPICHAR =(16-1);
SpibRegs.SPICCR.bit.SPICHAR =(8-1);

//启用环回
SpibRegs.SPICCR.bit.SPILBK = 0;

//启用主设备(0 =从设备,1 =主设备)
//启用传输(TALK)
//时钟相位(0 =正常、1 =延迟)
//禁用 SPI 中断
SpibRegs.SPICTL.bit.MASTER_SLAVE = 0;
SpibRegs.SPICTL.bit.TALK = 1;
SpibRegs.SPICTL.bit.CLK_PHASE = 0;
SpibRegs.SPICTL.bit.SPIINTENA=0;

//设置波特率
SpibRegs.SPIBRR.bit.SPI_BIT_RATE = SPI_BRR;

//设置空闲位
//在断点上停止不会停止 SPI
SpibRegs.SPIPRI.bit.FREE = 1;

//解除 SPI 复位
SpibRegs.SPICCR.bit.SPISWRESET = 1;

//
// dma_init - TX 和 RX 通道的 DMA 设置。
//
void dma_init()

//
//初始化 DMA
//
DMAInitialize();

DMASource =(volatile UINT16 *) sdata;
DMADest =(易失性 UINT16 *) RDATA;

/*
//
//为 TX 配置 DMACH5
//
DMACH5AddrConfig (SpiaRegs.SPITXBUF、DMASource);
DMACH5BurstConfig (burst、1、0);// burst size、src step、dest step
DMACH5TransferConfig (transfer、1、0);//传输大小、src 阶跃、dest 阶跃
DMACH5ModeConfig (DMA_SPIATX、PERINT_ENABLE、OneShot_disable、CONT_disable、
SYNC_DISABLE、SYNC_SRC、OVRFLOW_DISABLE、十六位、
Chint_end、CHINT_ENABLE);

//
//为 RX 配置 DMA CH2
//
DMACH6AddrConfig (DMADest、SpiaRegs.SPIRXBUF);
DMACH6BurstConfig (突发、0、1);
DMACH6TransferConfig (传输、0、1);
DMACH6ModeConfig (DMA_SPIARX、PERINT_ENABLE、OneShot_disable、CONT_disable、
SYNC_DISABLE、SYNC_SRC、OVRFLOW_DISABLE、十六位、
Chint_end、CHINT_ENABLE);
*

//
//为 TX 配置 DMACH5
//
DMACH5AddrConfig (SpibRegs.SPITXBUF、DMASource);
DMACH5BurstConfig (burst、1、0);// burst size、src step、dest step
DMACH5TransferConfig (transfer、1、0);//传输大小、src 阶跃、dest 阶跃
DMACH5ModeConfig (DMA_SPIBTX、PERINT_ENABLE、OneShot_disable、CONT_disable、
// DMACH5ModeConfig (DMA_SPIBTX、PERINT_ENABLE、OneShot_disable、CONT_ENABLE、
SYNC_DISABLE、SYNC_SRC、OVRFLOW_DISABLE、十六位、
Chint_end、CHINT_ENABLE);

//
//为 RX 配置 DMA CH2
//
DMACH6AddrConfig (DMADest、SpibRegs.SPIRXBUF);
DMACH6BurstConfig (突发、0、1);
DMACH6TransferConfig (传输、0、1);
DMACH6ModeConfig (DMA_SPIBRX、PERINT_ENABLE、OneShot_disable、CONT_disable、
// DMACH6ModeConfig (DMA_SPIBRX、PERINT_ENABLE、OneShot_disable、CONT_ENABLE、
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.CONTL.BIT.HALT=1;
// DmaRegs.ch5.control.bit.TRANSFERSTS = 1;
// DmaRegs.ch5.control.bit.run = 1;
PieCtrlRegs.PIEACK.all = PIEACK_group7;// ACK 以接收更多中断
//来自此 PIE 组
// DmaRegs.ch6.control.bit.halt = 0;
EDIS;
返回;

//
// local_D_INTCH6_ISR - DMA 通道6 ISR
//
_interrupt void local_D_INTCH6_ISR (void)

uint16 i;

EALLOW;//需要在 ISR 内执行 EALLOW!!!
DmaRegs.ch6.control.bit.halt = 1;
PieCtrlRegs.PIEACK.all = PIEACK_group7;// ACK 以接收更多中断
//来自此 PIE 组

对于(I = 0;I < MEM_BUFFER_SIZE;+I)

gData[i]= RDATA[i]和0x00FF;
// scia_xmit (RDATA[i]& 0x00FF);

// DmaRegs.ch5.control.bit.TRANSFERSTS = 1;
// DmaRegs.ch5.control.bit.run = 1;


DONE = 1;//测试完成。

// DmaRegs.ch6.control.bit.halt = 0;

EDIS;
返回;


//
// scia_echoback_init -测试1、SCIA DLB、8位字、波特率0x000F、
//默认,1个停止位,无奇偶校验
//
void scia_echoback_init ()

//
//注意:SCIA 外设的时钟被打开
//在 InitSysCtrl()函数中
//

SciaRegs.SCICCR.all = 0x0007;// 1停止位,无回路
//无奇偶校验,8个字符位,
//异步模式,空闲线协议
SciaRegs.SCICTL1.all = 0x0003;//启用 TX、RX、内部 SCICLK、
//禁用 RX ERR、睡眠、TXWAKE
SciaRegs.SCICTL2.all = 0x0003;
SciaRegs.SCICTL2.bit.TXINTENA=1;
SciaRegs.SCICTL2.bit.RXBKINTENA=1;

//
// SCIA 为9600波特
//@LSPCLK = 50MHz (200MHz SYSCLK) HBAUD = 0x02且 LBAUD = 0x8B。
//@LSPCLK = 30MHz (120MHz SYSCLK) HBAUD = 0x01且 LBAUD = 0x86。
//
// SciaRegs.SCIHBAUD.ALL = 0x0002;
// SciaRegs.SCILBAUD.ALL = 0x008B;
SciaRegs.SCIHBAUD.ALL = 0x0000;
SciaRegs.SCILBAUD.ALL = 0x0002;

SciaRegs.SCICTL1.all = 0x0023;//从复位中撤回 SCI

//
// scia_xmit -从 SCI 发送一个字符
//
void scia_xmit (int a)

while (SciaRegs.SCIFFTX.bit.TXFFST!= 0){}
SciaRegs.SCITXBUF.ALL =A;

//
// scia_msg -通过 SCIA 发送消息
//
void scia_msg (char * msg)

int i;
I = 0;
while (msg[i]!='\0')

scia_xmit (msg[i]);
i++;

//
// scia_fifo_init -初始化 SCI FIFO
//
void scia_fifo_init()

SciaRegs.SCIFFTX.ALL = 0xE040;
SciaRegs.SCIFFRX.ALL = 0x2044;
SciaRegs.SCIFFCT.all = 0x0;


//
//文件结束
//

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

    您好 Siguo Cha、

    您能否启用 DMA 连续模式并尝试。 如果连续模式被禁用、DMA 通道将在一个传输中的所有突发完成后被禁用。

    有关连续模式和单次触发模式的更多详细信息、请参阅 器件技术参考手册中的 DMA 一章

    此致、

    Veena

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

    您好、Veena、

    我尝试了以下操作来启用连续模式、但触发器仍然只有一次。

    //
    //为 TX 配置 DMACH5
    //
    DMACH5AddrConfig (SpibRegs.SPITXBUF、DMASource);
    DMACH5BurstConfig (burst、1、0);// burst size、src step、dest step
    DMACH5TransferConfig (transfer、1、0);//传输大小、src 阶跃、dest 阶跃
    // DMACH5ModeConfig (DMA_SPIBTX、PERINT_ENABLE、OneShot_disable、CONT_disable、
    DMACH5ModeConfig (DMA_SPIBTX、PERINT_ENABLE、OneShot_disable、CONT_ENABLE、
    SYNC_DISABLE、SYNC_SRC、OVRFLOW_DISABLE、十六位、
    Chint_end、CHINT_ENABLE);

    //
    //为 RX 配置 DMA CH2
    //
    DMACH6AddrConfig (DMADest、SpibRegs.SPIRXBUF);
    DMACH6BurstConfig (突发、0、1);
    DMACH6TransferConfig (传输、0、1);
    // DMACH6ModeConfig (DMA_SPIBRX、PERINT_ENABLE、OneShot_disable、CONT_disable、
    DMACH6ModeConfig (DMA_SPIBRX、PERINT_ENABLE、OneShot_disable、CONT_ENABLE、
    SYNC_DISABLE、SYNC_SRC、OVRFLOW_DISABLE、十六位、
    Chint_end、CHINT_ENABLE);

    从技术参考资料中、我从第5.4节中阅读了以下内容、但我不清楚我遗漏的内容。

    "默认情况下、continuos 模式被禁用。 当连续模式被禁用(MODE.CHX[连续]= 0)时、DMA 状态机在一个传输环路中的所有突发(TRANSFER_COUNT = 0)完成后禁用通道。 在开始另一个传输之前、必须将控制寄存器中的 RUN 位置位、以重新启用该通道。

    当连续模式被启用(MODE.CHX[连续]= 1)时、即使在一个传输环路中的所有突发(transfer_count = 0)完成后、DMA 状态机也保持通道激活。 每个 DMA 通道都可以在 DMA 传输开始(或)结束时使用 MODE.CHX[CHINTMODE]位为每个 DMA 传输触发其自己的 EPIE 中断。"

    感谢您的建议。

    此致、

    Siguo

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

    您好 Siguo、

    对延迟答复表示歉意。 此问题是否已解决?

    此致、

    Veena

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

    您好 Siguo、

    由于我们在过去几周没有收到您的消息、我们假设问题已得到解决。 我要关闭此 TT。 如果您有更多问题、请创建新主题。

    此致、

    Veena