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.

[参考译文] TM4C129XNCZAD:SSI1无法使用 DMA 获取 AD 采样数据

Guru**** 2428140 points
Other Parts Discussed in Thread: TM4C129XNCZAD, ADS131A04

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/727322/tm4c129xnczad-ssi1-cannot-get-ad-sample-data-with-dma

器件型号:TM4C129XNCZAD
主题中讨论的其他器件: ADS131A04

您好!

我一直在调试一个程序。它还不起作用。

CPU 为 TM4C129XNCZAD、ADC 为 ADS131A04 (每通道24位、32kbps)、它们与 SSI1信号引脚链接、CLK、DI 和 DOUT 通常被初始化、CS 引脚被配置为 GPIO 输入引脚、并链接至 ADS131A04的 RDY 除外。 该方案如下:

GPIOPinConfigure (GPIO_PB5_SSI1CLK);// Clk
//GPIOPinConfigure (GPIO_PB4_SSI1FSS);// CS
GPIOPinConfigure (GPIO_PE5_SSI1XDAT1);// Rx
GPIOPinConfigure (GPIO_PE4_SSI1XDAT0);// Tx

GPIOPinTypeSSI (GPIO_PORTB_BASE、GPIO_PIN_5/*| GPIO_PIN_4*/);
GPIOPinTypeSSI (GPIO_Porte _BASE、GPIO_PIN_4 | GPIO_PIN_5);

// SSI1 CS
GPIOPinTypeGPIOOutput (GPIO_PORTB_BASE、GPIO_PIN_4);
GPIOPinWrite (GPIO_PORTB_BASE、GPIO_PIN_4、GPIO_PIN_4);

SSI1的初始化为:

//
//必须启用 SSI1外设才能使用。
//
SysCtlPeripheralEnable (SYSCTL_Periph_SSI1);
//
//将 SSI 外设的数据时钟源设置为 SYSCLK
//
SSIClockSourceSet (SSI1_base、SSI_Cock_SYSTEM);
//
//为 SPI 主控模式配置和启用 SSI 端口。  
//
SSIConfigSetExpClk (SSI1_base、/*16384000*/g_ui32SysClock、SSI_FRF_MOTO_MODE_1、
SSI_MODE_MASTER、15360000/*15360000*/、8);

//
//启用 SSI1模块。
//
SSIEnable (SSI1_base);

然后、我通过向 ADS131A04发送相应的 cmds 来初始化 ADS131A04 、如下所示:

ads131A04SendCmd (ADS131A04_UNCH_COMMAND);

ads131A04SendCmd (WRITE_REGISTER_COMMAND (CLK1、CLK_DIV_2));

ads131A04SendCmd (WRITE_REGISTER_COMMAND (ADC_ENA、ADC_ENA_ENABLE_ALL_CHANNEL_CHINESS_ALL_CHANNELS));

在唤醒 ADS131A04之前、我按如下方式设置 uDMA 参数:

//将通道分配给 SSI1
//
uDMAChannelAssign (UDMA_CHANGE_SSI1RX);
uDMAChannelAssign (UDMA_CHANGE_SSI1TX);
//
//设置 uDMA TX
//
//
//将 uDMA SSI1 TX 通道的属性置于已知状态。 这些
默认情况下、//应已禁用。
//
uDMAChannelAttributeDisable (UDMA_CHANGE_SSI1TX、
UDMA_ATTR_USEBURST |
UDMA_ATTR_ALTSELECT |
//uDMA_attr_high_priority |
UDMA_ATTR_REQMASK);
//
//设置 uDMA SSI1 TX 通道的 USEBURST 属性。 这将会
//强制控制器在传输数据时始终使用突发
//将 TX 缓冲器连接到 UART。 这是比较有效的总线使用
//不是允许单次或突发传输的默认值。
//
uDMAChannelAttributeEnable (UDMA_CHANGE_SSI1TX、/* UDMA_ATTR_USEBURST |*/ UDMA_ATTR_HIGH_PRIORY);
//
//配置 SSI1 TX 的控制参数。 UDMA SSI1 TX
//通道用于将数据块从缓冲区传输到 SSI1。
//数据大小为8位。 源地址增量为8位字节
//因为数据来自缓冲区。 目的增量为
//由于数据将被写入 SSI1数据寄存器,因此不存在。 。
//仲裁数目设置为1,与 SSI1 TX FIFO 触发值匹配
//阈值。
//
uDMAChannelControlSet (UDMA_CHANGE_SSI1TX | UDMA_PRI_SELECT、
UDMA_SIZE_8 |
UDMA_SRC_INC_8 |
UDMA_DST_INC_NONE |
UDMA_ARB_1);

//
//设置 uDMA RX
//
//
//将 UDMA SSI1 RX 通道的属性置于已知状态。 这些
默认情况下、//应已禁用。
//
uDMAChannelAttributeDisable (UDMA_CHANGE_SSI1RX、
UDMA_ATTR_USEBURST |
UDMA_ATTR_ALTSELECT |
//uDMA_attr_high_priority |
UDMA_ATTR_REQMASK);
//
//设置 UDMA SSI1 RX 通道的 USEBURST 属性。 这将会
//强制控制器在传输数据时始终使用突发
//将 TX 缓冲器连接到 SSI1。 这是比较有效的总线使用
//不是允许单次或突发传输的默认值。
//
uDMAChannelAttributeEnable (UDMA_CHANGE_SSI1RX、/* UDMA_ATTR_USEBURST |*/ UDMA_ATTR_HIGH_PRIORY);
//
//配置 SSI1 RX 的控制参数。 UDMA RX
//通道用于将数据块从 SSI1传输到缓冲区。
//数据大小为8位。 源地址增量为 none
//因为数据来自 SSI1。 目的增量为
//由于数据来自 SSI1数据寄存器。 。
//仲裁大小设置为1,与 UART TX FIFO 触发器匹配
//阈值。
//
uDMAChannelControlSet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT、
UDMA_SIZE_8 | UDMA_SRC_INC_NONE |
UDMA_DST_INC_8 |
UDMA_ARB_1);

在 ADS131A04 RDY 的 IntHander 常规中:

//清除整型标志
GPIOIntClear (PORT_ADS131A04_DRDY、GPIOINTFLAG_ADS131A04_DRDY);

//启用 INT
GPIOIntEnable (PORT_ADS131A04_DRDY、GPIOINTFLAG_ADS131A04_DRDY);

//设置 uDMA SSI1 RX 通道的传输参数。 这将会
//配置传输源和目的以及传输大小。
//使用基本模式是因为外设正在进行 UDMA 传输
//请求。 源是 SSI1数据寄存器和目的
//是 RX 缓冲器。
//
uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT、
UDMA_MODE_AUTO、gui8SSI1RxDMABufA、
(void *)(SSI1_base + SSI_O_DR)、
15/*sizeof (gui8SSI1TxDMABuf)*/;
//
//设置 uDMA SSI1 TX 通道的传输参数。 这将会
//配置传输源和目的以及传输大小。
//使用基本模式是因为外设正在进行 UDMA 传输
//请求。 源是 TX 缓冲区、目的是 SSI1
//数据寄存器。
//
uDMAChannelTransferSet (UDMA_CHANGE_SSI1TX | UDMA_PRI_SELECT、
UDMA_MODE_AUTO、gui8SSI1TxDMABuf、
(void *)(SSI1_base + SSI_O_DR)、
15/*sizeof (gui8SSI1TxDMABuf)*/;
//
//必须重新启用 uDMA TX 通道。
//
uDMAChannelEnable (UDMA_CHANGE_SSI1TX);
uDMAChannelEnable (UDMA_CHANGE_SSI1RX);
//
//启用 SSI1 DMA TX/RX 中断。
//
SSIDMAEnable (SSI1_BASE、SSI_DMA_RX | SSI_DMA_TX);
SSIIntEnable (SSI1_BASE、SSI_DMARX | SSI_DMATX);
//
//请求 uDMA 通道启动传输。
//
uDMAChannelRequest (UDMA_CHANGE_SSI1TX);
uDMAChannelRequest (UDMA_CHANGE_SSI1RX);
//
//将 ADS131A04的 CS 信号置为有效  
//
ADS131A04_CS_ENABLE;

但是、SSI1和 UDMA 无法正常工作。 事实是:输入的 ADS131A04 RDY IntHandler 和 SSI1 IntHandler 的数量是对的(32K)、但 AD 样本数据全部为0!  在示波器上、CLK 的频率小于156KB、这显然是错误的。 正确的 CLK 频率可能是32 x 24 x 5=3840Kb。

因此、我想知道我的程序的问题。 正常模式和 DMA 模式之间的 SSI1 CLK 有何区别? 我的计划的错误(句子或流程)在哪里?

非常感谢!

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

    您好、Frank、

     要解决此问题、您是否曾尝试在没有 UDMA 的情况下首次运行程序? 一次调试一个东西更容易。 在非 uDMA SSI 操作开始后、您可以添加 uDMA。  

    [引用用户="Frank CAi">示波器、CLK 的频率小于156KB、这是明显错误的。 正确的 CLK 频率可能是32 x 24 x 5=3840Kb。

    您能否解释一下您的计算中的5项是什么?

    您具有以下 SSI 时钟配置。 您的系统时钟很可能为120MHz。 不能精确分频到15360000、因为分频器只是一个整数分频器。 您在示波器中看到了什么 SSI 时钟频率?  

    SSIConfigSetExpClk (SSI1_base、/*16384000*/g_ui32SysClock、SSI_FRF_MOTO_MODE_1、
    SSI_MODE_MASTER、15360000/*15360000*/、8);

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

    首先、我在没有 UDMA 的情况下很好地运行我的程序、ADS131A04就绪型 IntHandler 的整个代码位于此处:
    空 IntADS131A04ReadyHandler (空)

    //清除中断标志
    GPIOIntClear (PORT_ADS131A04_DRDY、GPIOINTFLAG_ADS131A04_DRDY);

    //启用 INT
    GPIOIntEnable (PORT_ADS131A04_DRDY、GPIOINTFLAG_ADS131A04_DRDY);

    if (u32DMAReadyCnt++>32000){
    u32DMAReadyCnt = 0;
    UARTprintf ("DMA Rdy...\n");

    #if CONDASM_ADS131A04_DMA
    //设置 uDMA SSI1 RX 通道的传输参数。 这将会
    //配置传输源和目的以及传输大小。
    //使用基本模式是因为外设正在进行 UDMA 传输
    //请求。 源是 SSI1数据寄存器和目的
    //是 RX 缓冲器。
    //
    uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT、
    UDMA_MODE_AUTO、gui8SSI1RxDMABufA、
    (void *)(SSI1_base + SSI_O_DR)、
    15/*sizeof (gui8SSI1TxDMABuf)*/;
    //
    //设置 uDMA SSI1 TX 通道的传输参数。 这将会
    //配置传输源和目的以及传输大小。
    //使用基本模式是因为外设正在进行 UDMA 传输
    //请求。 源是 TX 缓冲区、目的是 SSI1
    //数据寄存器。
    //
    uDMAChannelTransferSet (UDMA_CHANGE_SSI1TX | UDMA_PRI_SELECT、
    UDMA_MODE_AUTO、gui8SSI1TxDMABuf、
    (void *)(SSI1_base + SSI_O_DR)、
    15/*sizeof (gui8SSI1TxDMABuf)*/;
    //
    //必须重新启用 uDMA TX 通道。
    //
    uDMAChannelEnable (UDMA_CHANGE_SSI1TX);
    uDMAChannelEnable (UDMA_CHANGE_SSI1RX);
    //
    //启用 SSI1 DMA TX/RX 中断。
    //
    SSIDMAEnable (SSI1_BASE、SSI_DMA_RX | SSI_DMA_TX);
    SSIIntEnable (SSI1_BASE、SSI_DMARX | SSI_DMATX);
    //
    //请求 uDMA 通道启动传输。
    //
    uDMAChannelRequest (UDMA_CHANGE_SSI1TX);
    uDMAChannelRequest (UDMA_CHANGE_SSI1RX);
    //
    //将 ADS131A04的 CS 信号置为有效
    //
    ADS131A04_CS_ENABLE;
    其他
    uint16_t 接收= 0;
    uint8_t u8TempByte、u8Loop;

    //
    //将 ADS131A04的 CS 信号置为有效
    //
    ADS131A04_CS_ENABLE;

    对于(u8Loop = 0;u8Loop < 15;u8Loop +){
    gui8SSI1RxDMABufA[u8Loop ]= ads131A04SPIOut (0);
    //SysCtlDelay (20);

    //甜点 CS 信号
    ADS131A04_CS_DISABLE;
    #endif

    这些代码运行良好、采样数据正确、但几乎 CPU 整个时间都被这个循环占用、所以我想将传输模式更改为 uDMA。

    第二、我解释"正确的 CLK 频率可能是32 x 24 x 5=3840Kb":
    是的、我的 SYSCLK 为120MHz。
    当 ADS131A04唤醒时、它会在一帧内发送其整个数据、包括1个状态、4通道数据和1个 CRC。 因为 CRC 是
    在 ADS131A04中禁用、因此我必须读取5个器件字、每个器件字24位。 采样率为32kbps、因此 CLK 必须
    大于3840Kb。 因此、我将 SSI1的比特率设置为15360K (=3840K * 4)、以便让 CPU 有时间执行其他工作。

    此致、

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

    您好!  

     您为 RX 通道编写了以下代码片段。  

    uDMAChannelTransferSet (UDMA_CHANGE_SSI1RX | UDMA_PRI_SELECT、
    UDMA_MODE_AUTO、gui8SSI1RxDMABufA、
    (void *)(SSI1_base + SSI_O_DR)、
    15/*sizeof (gui8SSI1TxDMABuf)*/;

    请查看下面此 API 的函数原型。 第三个参数应该是源地址指针。 如果您从 RX 通道读取数据、则应从 (void *)(SSI1_base + SSI_O_DR)读取数据。 我想您交换了源和目的。

    void uDMAChannelTransferSet (uint32_t ui32ChannelStructIndex、uint32_t ui32Mode、void
    pvSrcAddr、void pvDstAddr、uint32_t ui32TransferSize)

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

    奥霍赫,非常粗心,谢谢你,非常棒。

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

    我们可以问、"供应商的 Charles (NEAT)修复-成功吗?   (您的帖子未(完全)-传达此事实。)

    如果确实如此、您是否可以通过(正确)使用 MCU 的 μ µDMA 实现"轻松改进"。

    如果您"努力"-并在此处报告-(其他人)可能会注意到"需要进一步改进的人"您的代码-哪些好处、"全在这里!"  (尤其是您!)

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

    您好、 Charles、

    非常感谢。 根据您的注释、我交换函数 uMDAChannelTransferSet 中的参数、然后程序运行良好。

    很抱歉耽误你这么晚的时间。

    此致

    弗兰克