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.

TMS570LS3137: 如何使用 SCI DMA 进行数据接收?

Part Number: TMS570LS3137
Other Parts Discussed in Thread: HALCOGEN
  • 1.大家好?TI技术人员你们好?是否有570  DMA相关数据接收的例程? 变长度和不变长度?或者SPI 相关也可以,我只找到一些发送的 没找到接收的。
  • 2.我在调试SCI DMA 时候遇到一些问题,我的代码如下 :

g_dmaCTRL g_dmaCTRLPKT_TX;
g_dmaCTRL g_dmaCTRLPKT_RX;
uint32 DMA_Comp_Flag_Tx;
uint32 DMA_Comp_Flag_Rx;

/** @fn void scidmaInit(sciBASE_t *sci)
 *   @brief 初始化 SCI 和 DMA 以通过 DMA 传输 SCI 数据
 *   @note 此函数配置 SCI 以在 SCI TX 完成时触发 DMA 请求。
 */
void scidmaInit(sciBASE_t *sci)
{
    /* 启用 DMA */
    dmaEnable();

    if (sci == scilinREG)
    { /* SCI2 是 LAUNCHXL2 启动板上的默认串口 */

        /* 在接收数据后启用中断 */
        dmaEnableInterrupt(DMA_CH0, BTC); /* DMA_CH0 是最高优先级 */
        dmaEnableInterrupt(DMA_CH1, BTC); /* DMA_CH1 用于 RX */

        /* 分配 DMA 请求:通道-0 与请求线-1 - TX */
        /* DMA 请求 29 是 LIN(SCI2)传输 */
        dmaReqAssign(DMA_CH0, 29);
        /* DMA 请求 28 是 LIN(SCI2)接收 */
        dmaReqAssign(DMA_CH1, 28);
    }
    else if (sci == sciREG)
    {           /* SCI1 */
        return; /* 目前不支持 SCI1 */
    }
    else
    {
        return; /* 未知寄存器 */
    }

    /* - 填充 dma 控制包结构 */
    g_dmaCTRLPKT_TX.CHCTRL = 0;              /* 通道控制            */
    g_dmaCTRLPKT_TX.ELCNT = 1;               /* 元素计数              */
    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;            /* 端口 b                     */
    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_OFF; /* 自动初始化                   */


        /* - 填充 RX dma 控制包结构 */
    g_dmaCTRLPKT_RX.CHCTRL = 0;
    g_dmaCTRLPKT_RX.ELCNT = 1;
    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_OFF;

    /* 重置标志 */
    DMA_Comp_Flag_Tx = 0x55AAD09E;
    DMA_Comp_Flag_Rx = 0x55AAD09E;

    /* 通道 40 - 在 HalCoGen 中启用 VIM 通道以包含 dmaBTCAInterrupt 函数 */
    vimChannelMap(40, 40, &dmaBTCAInterrupt);

    /* 在 SCI2 传输完成时启用 VIM DMA BTCA 中断到 CPU */
    vimEnableInterrupt(40, SYS_IRQ);

        /* 通道 41 - 在 HalCoGen 中启用 VIM 通道以包含 dmaBTCAInterrupt 函数 */
    vimChannelMap(41, 41, &dmaBTCAInterrupt);

    /* 在 SCI2 接收完成时启用 VIM DMA BTCA 中断到 CPU */
    vimEnableInterrupt(41, SYS_IRQ);

} /* scidmaInit */

/** @fn void scidmaSend(char *source_address)
 *   @brief 初始化 SCI 和 DMA 以通过 DMA 传输 SCI 数据
 *   @note 此函数配置 SCI 以在 SCI TX 完成时触发 DMA 请求。
 *
 *   此函数配置 DMA 以单缓冲或多缓冲模式工作。
 *   在单缓冲模式(0)下,DMA 在请求设置时将每个字节移动到 SCI 传输寄存器。
 *   在多缓冲模式(1)下,DMA 在请求设置时将 4 个字节移动到 SCI 传输缓冲区。
 */
void scidmaSend(char *source_address)
{
#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
    uint8 dest_addr_offset = 0; /* 小端模式为 0 */
#else
    uint8 dest_addr_offset = 3; /* 大端模式为 3 */
#endif

    /* 等待 DMA 完成任何现有传输 */
    while (DMA_Comp_Flag_Tx != 0x55AAD09E)
        ;

    /* 将标志重置为未完成 */
    DMA_Comp_Flag_Tx = ~0x55AAD09E;

    /* - 填充 dma 控制包结构 */
    g_dmaCTRLPKT_TX.SADD = (uint32)source_address; /* 源地址             */

    if (((scilinREG->GCR1 >> 10U) & 1U) == 0U)
    {                                                                         /* SCI2 多缓冲模式 */
        g_dmaCTRLPKT_TX.DADD = (uint32)(&(scilinREG->TD)) + dest_addr_offset; /* 在大端设备中,目的地址需要调整 */
        g_dmaCTRLPKT_TX.RDSIZE = ACCESS_8_BIT;                                /* 读取大小                  */
        g_dmaCTRLPKT_TX.WRSIZE = ACCESS_8_BIT;                                /* 写入大小                 */
        g_dmaCTRLPKT_TX.FRCNT = strlen(source_address);                       /* 帧计数                */
    }
    else
    {
        g_dmaCTRLPKT_TX.DADD = (uint32)(&(linREG->TDx));        /* 在大端设备中,目的地址需要调整
                                                                 * 以进行字节访问。DMA 是大端主控。SCI 传输缓冲区
                                                                 * 可在最低有效字节处访问。  */
        g_dmaCTRLPKT_TX.RDSIZE = ACCESS_32_BIT;                 /* 读取大小                  */
        g_dmaCTRLPKT_TX.WRSIZE = ACCESS_32_BIT;                 /* 写入大小                 */
        g_dmaCTRLPKT_TX.FRCNT = strlen(source_address) / 4 + 8; /* 帧计数                */
    }

    /* - 设置传输的 dma 控制包 */
    dmaSetCtrlPacket(DMA_CH0, g_dmaCTRLPKT_TX);

    /* - 设置 dma 通道以触发硬件请求 */
    dmaSetChEnable(DMA_CH0, DMA_HW);

    /* 启用 TX DMA */
    scilinREG->SETINT = (1 << 16);

} /* scidmaSend */


void scidmaReceive(char *dest_address, uint32 length)
{
#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
    uint8 src_addr_offset = 0; /* 小端模式为 0 */
#else
    uint8 src_addr_offset = 3; /* 大端模式为 3 */
#endif

    /* 等待 DMA 完成任何现有传输 */
    while (DMA_Comp_Flag_Rx != 0x55AAD09E)
        ;

    /* 将标志重置为未完成 */
    DMA_Comp_Flag_Rx = ~0x55AAD09E;

    /* - 填充 dma 控制包结构 */
    g_dmaCTRLPKT_RX.SADD = (uint32)(&(scilinREG->RD)) + src_addr_offset; /* 源地址 */
    g_dmaCTRLPKT_RX.DADD = (uint32)dest_address; /* 目的地址 */
    g_dmaCTRLPKT_RX.FRCNT = length; /* 帧计数 */

    /* 设置传输的 dma 控制包 */
    dmaSetCtrlPacket(DMA_CH1, g_dmaCTRLPKT_RX);

    /* 设置 dma 通道以触发硬件请求 */
    dmaSetChEnable(DMA_CH1, DMA_HW);

    /* 启用 RX DMA */
    scilinREG->SETINT = (1 << 17);

}


void Update_DMA_Comp_Flag_Tx()
{
    /* 设置发送完成标志 */
    DMA_Comp_Flag_Tx = 0x55AAD09E;

    /* 禁用 TX DMA 中断 */
    scilinREG->CLEARINT = (1 << 16);
}

void Update_DMA_Comp_Flag_Rx()
{
    /* 设置接收完成标志 */
    DMA_Comp_Flag_Rx = 0x55AAD09E;

    /* 禁用 RX DMA 中断 */
    scilinREG->CLEARINT = (1 << 17);
}



/** @fn void linsci2enableMBUFF()
 *   @brief Switch SCI2 to multi-buffer (4 Byte) transfers
 *   @note This function requires scidmaInit(scilinREG) and _enable_IRQ() to be called first.
 *
 *   In multi buffer mode (1)  the DMA moves 4 Bytes to the SCI transmit buffer when the request is set.
 *   The DMA interconnect does not support 64bit unaligned accesses which limits transfers to a max of 4 bytes.
 */
void linsci2enableMBUFF()
{
    /* Enable Multi- Buffer Mode */
    scilinREG->GCR1 |= (uint32)((uint32)1U << 10U); /* Enable MBUFMODE (SCI2 Only) */

    /* Set transmission length in Bytes */
    scilinREG->FORMAT = (uint32)((uint32)7U << 0U)     /* character length (bits) -1 */
                        | (uint32)((uint32)3U << 16U); /* frame length (bytes) -1    */
} /* linsci2enableMBUFF */

/** @fn void linsci2disableMBUFF()
 *   @brief Switch SCI2 to single byte transfers
 *   @note This function requires linsci2enableMBUFF() to be called first.
 *
 *   In multi buffer mode (1)  the DMA moves 4 Bytes to the SCI transmit buffer when the request is set.
 *   The DMA interconnect does not support 64bit unaligned accesses which limits transfers to a max of 4 bytes.
 */
void linsci2disableMBUFF()
{
    /* Enable Multi- Buffer Mode */
    scilinREG->GCR1 &= ~(uint32)((uint32)1U << 10U); /* Disable MBUFMODE (SCI2 Only) */

    /* Set transmission length in Bytes */
    scilinREG->FORMAT = (uint32)((uint32)7U << 0U)     /* character length (bits) -1 */
                        | (uint32)((uint32)0U << 16U); /* frame length (bytes) -1    */

} /* linsci2enableMBUFF */
notification.c 文件中:
void dmaGroupANotification(dmaInterrupt_t inttype, uint32 channel)
{
    /* 用户代码开始 (54) */
    if (channel == DMA_CH0)
    {
        Update_DMA_Comp_Flag_Tx();
    }
    else if (channel == DMA_CH1)
    {
        Update_DMA_Comp_Flag_Rx();
    }
}

/* 定时器回调函数 */
uint32_t g_u32timerDiv = 0u;
void vTimerCallback(TimerHandle_t xTimer)
{

    g_u32timerDiv++;
    xSemaphoreGive(xSemaphoreTask1);
    xSemaphoreGive(xSemaphoreTask2);
    // if (g_u32timerDiv == 2u)
    // {
    //     g_u32timerDiv = 0u;
    xSemaphoreGive(xSemaphoreTask3);
    // }
}
主函数中:
int main(void)
{
    /* 用户代码开始 (3) */

    sciInit();
    scidmaInit(scilinREG);
    hetInit();
    /* 初始化 can 1 和 2 */
    canInit(); /* can1 -> can2 */
    midSci_init();
    midLed_int();

    /* Enable CPU Interrupts */
    _enable_IRQ();

    number_string((char *)buffer, 500);

    uint32 IDLECOUNT = 0;
    scidmaSend(buffer);

    while (DMA_Comp_Flag_Tx != 0x55AAD09E)
    {
        IDLECOUNT++;
    }

    /* Enable SCI2 Multi-buffer (4 Byte) transfers */
    linsci2enableMBUFF();

    scidmaSend(buffer);

    while (DMA_Comp_Flag_Tx != 0x55AAD09E)
    {
        IDLECOUNT++;
    }

    linsci2disableMBUFF();
    printf("\n\r Demo Complete\n\r");


        // Check if DMA reception is complete
        if (DMA_Comp_Flag_Rx == 0x55AAD09E)
        {
            // Process received data
            printf("Received data: %s\n", rxBuffer);

            // Reset flag for next reception
            DMA_Comp_Flag_Rx = ~0x55AAD09E;

            // Start another reception if needed
            scidmaReceive(rxBuffer, 50);
        }
        midSci_printf("vTask2 end ");

       
    /* 创建信号量 */
    xSemaphoreTask1 = xSemaphoreCreateBinary();
    xSemaphoreTask2 = xSemaphoreCreateBinary();
    xSemaphoreTask3 = xSemaphoreCreateBinary();
    if ((xSemaphoreTask1 == NULL) || (xSemaphoreTask2 == NULL) || (xSemaphoreTask3 == NULL))
    {
        /* 信号量创建失败 */
        printf("Failed to create semaphore\r\n");
        return 1;
    }

    /* 创建队列 */
    xQueue = xQueueCreate(5, sizeof(QueueMessage));
    if (xQueue == NULL)
    {
        /* 队列创建失败 */
        printf("Failed to create queue\r\n");
        return 1;
    }

    /* 创建任务1 */
    if (xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle) != pdTRUE)
    {
        /* 任务创建失败 */
        printf("Failed to create Task1\r\n");
        return 1;
    }

    /* 创建任务2 */
    if (xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 1, &xTask2Handle) != pdTRUE)
    {
        /* 任务创建失败 */
        printf("Failed to create Task2\r\n");
        return 1;
    }

    /* 创建任务3 */
    if (xTaskCreate(vTask3, "Task3", configMINIMAL_STACK_SIZE, NULL, 1, &xTask3Handle) != pdTRUE)
    {
        /* 任务创建失败 */
        printf("Failed to create Task3\r\n");
        return 1;
    }

    /* 创建和启动 250 ms 定时器 */
    xTimer250ms = xTimerCreate("Timer250ms", pdMS_TO_TICKS(250), pdTRUE, (void *)0, vTimerCallback);
    if (xTimer250ms == NULL)
    {
        /* 定时器创建失败 */
        printf("Failed to create 250ms timer\r\n");
        return 1;
    }
    if (xTimerStart(xTimer250ms, 0) != pdPASS)
    {
        /* 定时器启动失败 */
        printf("Failed to start 250ms timer\r\n");
        return 1;
    }

    /* 启动调度器 */
    vTaskStartScheduler();

    /* 永远运行 */
    while (1)
        ;

    return 0;
}
  • 3.目前出问题点 
在调用
scidmaReceive 函数时候 
    dmaSetCtrlPacket(DMA_CH1, g_dmaCTRLPKT_RX); , register uint32 i=0U,j=0U;

dmaRAMREG->PCP[channel].ISADDR = g_dmaCTRLPKT.SADD;,这个位置出现问题 ,
代码会进入:
_dabort
stmfd r13!, {r0 - r12, lr}; push registers and link register on to stack

ldr r12, esmsr3 ; ESM Group3 status register
ldr r0, [r12]
tst r0, #0x8 ; check if bit 3 is set, this indicates uncorrectable ECC error on B0TCM
bne ramErrorFound
tst r0, #0x20 ; check if bit 5 is set, this indicates uncorrectable ECC error on B1TCM
bne ramErrorFound2

noRAMerror
tst r0, #0x80 ; check if bit 7 is set, this indicates uncorrectable ECC error on ATCM
bne flashErrorFound

bl custom_dabort ; custom data abort handler required
; If this custom handler is written in assembly, all registers used in the routine
; and the link register must be saved on to the stack upon entry, and restored before
; return from the routine.
  • 4.我希望有人可以帮助我解答一下,或者告诉我应该怎么做?