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.

[参考译文] RM46L852:重新配置从器件上的 SPI DMA

Guru**** 2392905 points


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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/989735/rm46l852-reconfigure-spi-dma-on-slave

器件型号:RM46L852

你(们)好

我进行了一个测试项目、当时我正在使用以下代码来接收 RM44上的数据、其中 SPI 配置为启用 DMA 的从器件。 一切都很完美、每次我从主器件发送32个字节时、我都会在从器件处获得中断。

/* USER CODE BEGIN (2) */
g_dmaCTRL g_dmaCTRLPKT_RX;
g_dmaCTRL g_dmaCTRLPKT_TX;
uint8_t TX_Data_Slave[32] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
                             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20};

uint8_t RX_Data_Slave[32] = { 0 };

//uint16_t RX_Data_Slave[8]  = { 0 };
//void dmaConfigCtrlPacket(uint32 sadd,uint32 dadd,uint32 dsize);
void dmaConfigCtrlTxPacket (uint32 sadd, uint32 dadd, uint16 ElmntCnt, uint16 FrameCnt);
void dmaConfigCtrlRxPacket (uint32 sadd, uint32 dadd, uint16 ElmntCnt, uint16 FrameCnt);
/* USER CODE END */

int main(void)
{
/* USER CODE BEGIN (3) */

    /* Enable CPU Interrupt through CPSR */
    _enable_IRQ();

    spiInit();

//  enabling dma module : this brings DMA out of reset
    dmaEnable();

//  Enable Interrupt after reception of data
    dmaEnableInterrupt(DMA_CH0, BTC);     //Block transfer complete

//  assigning dma request: channel-0 with request line - 0 (SPI1 Receive DMA Request)
    dmaReqAssign(DMA_CH0,0);
    dmaReqAssign(DMA_CH1,1);

//  configuring DMA control packets
    dmaConfigCtrlTxPacket((uint32)TX_Data_Slave, (uint32)(&spiREG1->DAT1), 1, 32);
    dmaConfigCtrlRxPacket((uint32)(&spiREG1->BUF) ,(uint32)RX_Data_Slave,1, 32);

//  setting DMA control packets
    dmaSetCtrlPacket(DMA_CH0,g_dmaCTRLPKT_RX);
    dmaSetCtrlPacket(DMA_CH1,g_dmaCTRLPKT_TX);

//  setting the DMA channel to trigger on h/w request */
    dmaSetChEnable(DMA_CH0, DMA_HW);
    dmaSetChEnable(DMA_CH1, DMA_HW);

//  DMA_REQ_Enable On first received data, a DMA_Req will be send to DMA
    spiREG1->INT0 = 0x00010000;

    while(1)
    {


    }
/* USER CODE END */

    return 0;
}


/* USER CODE BEGIN (4) */

volatile uint8_t count = 0;

void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
{
    if (inttype == BTC)
    {
        count++;
     }

}

void dmaConfigCtrlRxPacket (uint32 sadd, uint32 dadd, uint16 ElmntCnt, uint16 FrameCnt)
{
    g_dmaCTRLPKT_RX.SADD = sadd;
    g_dmaCTRLPKT_RX.DADD = dadd;
    g_dmaCTRLPKT_RX.CHCTRL = 0;
    g_dmaCTRLPKT_RX.FRCNT = FrameCnt;
    g_dmaCTRLPKT_RX.ELCNT = ElmntCnt;
    g_dmaCTRLPKT_RX.ELDOFFSET = 0;
    g_dmaCTRLPKT_RX.ELSOFFSET = 0;
    g_dmaCTRLPKT_RX.FRDOFFSET = 0;
    g_dmaCTRLPKT_RX.FRSOFFSET = 0;
    g_dmaCTRLPKT_RX.PORTASGN = 4;
    g_dmaCTRLPKT_RX.RDSIZE = ACCESS_8_BIT;
    g_dmaCTRLPKT_RX.WRSIZE = ACCESS_8_BIT;
    g_dmaCTRLPKT_RX.TTYPE = FRAME_TRANSFER;
    g_dmaCTRLPKT_RX.ADDMODERD = ADDR_FIXED;
    g_dmaCTRLPKT_RX.ADDMODEWR = ADDR_INC1;
    g_dmaCTRLPKT_RX.AUTOINIT = AUTOINIT_ON;
}

void dmaConfigCtrlTxPacket (uint32 sadd, uint32 dadd, uint16 ElmntCnt, uint16 FrameCnt)
{
    g_dmaCTRLPKT_TX.SADD = sadd;
    g_dmaCTRLPKT_TX.DADD = dadd;
    g_dmaCTRLPKT_TX.CHCTRL = 0;
    g_dmaCTRLPKT_TX.FRCNT = FrameCnt;
    g_dmaCTRLPKT_TX.ELCNT = ElmntCnt;
    g_dmaCTRLPKT_TX.ELDOFFSET = 0;
    g_dmaCTRLPKT_TX.ELSOFFSET = 0;
    g_dmaCTRLPKT_TX.FRDOFFSET = 0;
    g_dmaCTRLPKT_TX.FRSOFFSET = 0;
    g_dmaCTRLPKT_TX.PORTASGN = 4;
    g_dmaCTRLPKT_TX.RDSIZE = ACCESS_8_BIT;
    g_dmaCTRLPKT_TX.WRSIZE = ACCESS_8_BIT;
    g_dmaCTRLPKT_TX.TTYPE = FRAME_TRANSFER;
    g_dmaCTRLPKT_TX.ADDMODERD = ADDR_INC1;
    g_dmaCTRLPKT_TX.ADDMODEWR = ADDR_FIXED;
    g_dmaCTRLPKT_TX.AUTOINIT = AUTOINIT_ON;
}
/* USER CODE END */

现在、我要为不同的长度(16字节)重新配置 DMA、我尝试修改 DMA 中断例程、如下所示。 从器件正在接收正确的数据、但主器件正在缓冲区开头接收两个额外的字节。

从器件发送->{0x01、0x02、0x03、0x04、0x05、 0x06、0x07、0x08、0x09、0x0A、 0x0B、0x0C、0x0D、0x0E、0x0F、 0x10、0x11、0x12、0x13、0x14、 0x15、0x16}

主机接收-> 0x01、0x02、0x01、0x02、0x03、 0x04、0x05、0x06、0x07、0x08、 0x09、0x0A、0x0B、0x0C、0x0D、 0x0E、0x0F、0x10、 0x11、0x12、 0x13、0x14}

void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
{
    if (inttype == BTC)
    {
        count++;

        //  configuring DMA control packets
            dmaConfigCtrlTxPacket((uint32)TX_Data_Slave, (uint32)(&spiREG1->DAT1), 1, 16);
            dmaConfigCtrlRxPacket((uint32)(&spiREG1->BUF) ,(uint32)RX_Data_Slave,1, 16);

        //  setting DMA control packets
            dmaSetCtrlPacket(DMA_CH0,g_dmaCTRLPKT_RX);
            dmaSetCtrlPacket(DMA_CH1,g_dmaCTRLPKT_TX);

     }

}

请告诉我缺少什么、如果可能、您可以提供重新配置 DMA 的代码。

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

    您好!

    如果不使用 SPIENA 信号、则 SPI 主器件需要等待至少6个 VCLK 周期、然后再发送 时钟来开始传输。  

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

    非常感谢您的快速回复、我将在主器件上使用以下延迟、这似乎是正确的。

        /** - Delays */
        spiREG1->DELAY = (uint32)((uint32)250U << 24U)  /* C2TDELAY */
                       | (uint32)((uint32)0U << 16U)  /* T2CDELAY */
                       | (uint32)((uint32)0U << 8U)   /* T2EDELAY */
                       | (uint32)((uint32)0U << 0U);  /* C2EDELAY */

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

    SPI 从器件是否需要如此长的设置时间(250个 vclk 周期)? 此延迟是否有用?

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

    你好,王先生

    我保持尽可能的最大、以便为从器件 SPI 模块提供足够的时间来准备接收数据。 但是、这也不起作用、  

    您能不能指导我还有什么需要做的。

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

    我想再次检查是否在 SPI 主器件侧而不是 SPI 从器件侧中添加了延迟。

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

    优点、但延迟确实在主设备侧、请查看下图、左侧是主设备(RM48)、右侧是从设备(RM46)

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

    当 DMA 被触发时、看起来 SPI TXBUF 不是空的。

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

    主器件正在接收两个字节、这两个字节是在之前通信的起始位置发送的、再次注意到以下模式:0x01和0x02位于起始位置、如果你是对的、主器件将接收到之前通信的最后两个字节!!

    1) 1) DMA 配置为32字节

    2)第一次通信迭代(正常工作)

    从器件发送->{0x01、0x02、0x03、0x04、0x05、 0x06、0x07、0x08、0x09、0x0A、 0x0B、0x0C、0x0D、0x0E、0x0F、 0x10、
    0x11、0x12、0x13、0x14、0x15、 0x16、0x17、0x18、0x19、0x1A、 0x1b、0x1C、0x1D、0x1E、0x1F、 0x20}

    主机接收->{0x01、0x02、0x03、0x04、0x05、 0x06、0x07、0x08、0x09、0x0A、 0x0B、0x0C、0x0D、0x0E、0x0F、 0x10、
    0x11、0x12、0x13、0x14、0x15、 0x16、0x17、0x18、0x19、0x1A、 0x1b、0x1C、0x1D、0x1E、0x1F、 0x20}

    3) 3) DMA 已重新配置为16字节。

    4)第二次通信迭代(不能正常工作)

    从器件发送->{0x01、0x02、0x03、0x04、0x05、 0x06、0x07、0x08、0x09、0x0A、 0x0B、0x0C、0x0D、0x0E、0x0F、 0x10};

    主机接收-> { 0x01、0x02 0x01、0x02、0x03、 0x04、0x05、0x06、0x07、0x08、 0x09、0x0A、0x0B、0x0C、0x0D、 0x0E

    您是否可以在结尾处尝试相同的代码、这对我来说已变得不太紧急。

    谢谢、  

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

    您可以共享您的代码吗?

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

    您好 Devendra、

    在触发 DMA 之前、RX/TX BUF 和移位寄存器不为空。 触发 DMA 时、SPI 主器件生成 SPI 时钟、移位寄存器中的数据首先移出。  

    您可以通过设置 INT0寄存器的位16来禁用 SPI、然后在触发 DMA 之前重新启用 SPI。

    spiREG1->GCR1 &=~(0x1 <<24);//禁用 SPI
    spiREG1->GCR1 |=(0x1 <<24);  //启用 SPI

    当 SPI 被禁用(SPIEN 位被清零)时,以下 SPI 寄存器 将被强制进入其默认状态:

    1. TX 和 RX 移位寄存器
    2. SPI 发送数据寄存器0 (SPIDAT0)和 SPI 发送数据寄存器1 (SPIDAT1)的 TXDATA 域
    3. SPI 标志寄存器(SPIFLG)的所有字段
    4. SPIBUF 和内部 RXBUF 寄存器的内容
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的见解、

    很抱歉我的回答很晚、因为复活节假期、我今天会尝试一下、并告诉您结果、

    祝你度过美好的一天!

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

    你好,王先生

    在重新配置 DMA 之前禁用 SPI 并在重新配置 DMA 后启用 SPI 可解决此问题、以下代码精确

    void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
    {
        if (inttype == BTC)
        {
            count++;
    
                spiREG1->GCR1 &= ~(0x1 << 24); //disable SPI
            //  configuring DMA control packets
                dmaConfigCtrlTxPacket((uint32)TX_Data_Slave, (uint32)(&spiREG1->DAT1), 1, 16);
                dmaConfigCtrlRxPacket((uint32)(&spiREG1->BUF) ,(uint32)RX_Data_Slave,1, 16);
    
            //  setting DMA control packets
                dmaSetCtrlPacket(DMA_CH0,g_dmaCTRLPKT_RX);
                dmaSetCtrlPacket(DMA_CH1,g_dmaCTRLPKT_TX);
                spiREG1->GCR1 |= (0x1 << 24);    //enable SPI
    
         }
    
    }
     

    非常感谢您的支持。

    祝你度过美好的一天!