硬汉嵌入式论坛

 找回密码
 立即注册
查看: 235|回复: 3
收起左侧

[技术讨论] 定时器触发spi+DMA数据传输时,每个数据会被多次传输直到定时器触发下一个数据传输

[复制链接]

4

主题

8

回帖

20

积分

新手上路

积分
20
发表于 2025-10-14 16:30:56 | 显示全部楼层 |阅读模式
使用的时GD32H737系列的芯片

定时器配置

void timer14_config(uint32_t period)
{
        /* -----------------------------------------------------------------------
    TIMER50 configuration:
    TIMER50CLK = 300MHz/300 = 1MHz, .
    ----------------------------------------------------------------------- */
    /* enable the peripherals clock */
    rcu_periph_clock_enable(RCU_TIMER14);
        /* deinit a TIMER */
    timer_deinit(TIMER14);

        timer_parameter_struct timer_initpara;
    /* initialize TIMER init parameter struct */
    timer_struct_para_init(&timer_initpara);
    /* TIMER50 configuration */
    timer_initpara.prescaler         = 299;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = period-1;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER14, &timer_initpara);
               
        /* TIMER0 update DMA request enable */
    timer_dma_enable(TIMER14, TIMER_DMA_UPD);
        /* enable a TIMER */
        timer_enable(TIMER14);
}

spi配置  (此处使用了硬件CS且每次传输定量字节后需重置片选,这点为外设需求)

void spi_config(void)
{
        rcu_periph_clock_enable(RCU_SPI4);
        rcu_spi_clock_config(IDX_SPI4, RCU_SPISRC_APB2);

        spi_parameter_struct spi4;
       
        spi_i2s_deinit(SPI4);
        spi_struct_para_init(&spi4);
        spi4.device_mode = SPI_MASTER;
        spi4.trans_mode  = SPI_TRANSMODE_BDTRANSMIT;
        spi4.data_size   = SPI_DATASIZE_32BIT;
//        spi4.nss  = SPI_NSS_SOFT;
        spi4.nss  = SPI_NSS_HARD;
        spi4.endian = SPI_ENDIAN_MSB;
        spi4.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
        spi4.prescale = SPI_PSC_256;  //300/256=1.17  <50M
        spi_init(SPI4, &spi4);
        spi_word_access_enable(SPI4);
       
        spi_fifo_threshold_level_set(SPI4, SPI_FIFO_TH_04DATA);

//        spi_nss_idleness_delay_set(SPI4, SPI_NSS_IDLENESS_03CYCLE);
        spi_data_frame_delay_set(SPI4, SPI_DATA_IDLENESS_15CYCLE);

        /* enable SPI NSS output */
        spi_nss_output_enable(SPI4);
        spi_nss_output_control(SPI4, SPI_NSS_INVALID_PULSE);
//        spi_nss_output_control(SPI4, SPI_NSS_HOLD_UNTIL_TRANS_END);
//        spi_reload_data_num_config(SPI4, 1);
//        spi_current_data_num_config(SPI4, 1);
        spi_enable(SPI4);
}

dma配置

void spi_dma_config(void)
{
        /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA1);
    /* enable DMAMUX clock */
    rcu_periph_clock_enable(RCU_DMAMUX);
       
        dma_single_data_parameter_struct dma_init_struct;
    /* deinitialize DMA registers of a channel */
    dma_deinit(DMA1, DMA_CH6);
       
    dma_single_data_para_struct_init(&dma_init_struct);
   
    /* SPI4 transmit DMA config: DMA_CH6 */
    dma_init_struct.request = DMA_REQUEST_TIMER14_UP;
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;   
    dma_init_struct.memory0_addr = (uint32_t)test_data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;
    dma_init_struct.number = 8;
    dma_init_struct.periph_addr = (uint32_t)&SPI_TDATA(SPI4);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA1, DMA_CH6, &dma_init_struct);
        dma_circulation_enable(DMA1, DMA_CH6);
               
    /* enable DMA channel */
    dma_channel_enable(DMA1, DMA_CH6);

        spi_master_transfer_start(SPI4, SPI_TRANS_START);
//        spi_dma_enable(SPI4, SPI_DMA_TRANSMIT);
}

请问上述配置有什么地方有问题吗,现在现象是每个字节被传输三次(大约120us,统一数据被完整的传输三次)后传输下一个数据,定时器配置的是10KHZ的
回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
119430
QQ
发表于 2025-10-16 10:35:43 | 显示全部楼层
你这个实现不合理,不能定时器触发DMA,因为你不知道ADC数据什么时候就绪。所以出现采集很多次同一个数值的问题。
回复

使用道具 举报

4

主题

8

回帖

20

积分

新手上路

积分
20
 楼主| 发表于 2025-10-17 11:04:55 | 显示全部楼层
我开辟了一个大缓存区,启用传输半完成中断和传输满完成中断,用来更新缓冲区数据,spi发送一半缓冲区数据时间大于更新数据时间,更新spi配置为TI模式后已经解决这个问题,现在遇到如果缓冲区不更新数据,传输无误,缓冲区的数据前一半和后一半交替重新赋值进缓冲区相同位置,一段时间后输出数据有误,但缓冲区寄存器上的数据是对的(此处已验证)。赋值前后都无效了cache内存,cache数据应该和内存数据一致(此处为猜测,看不到cache数据)。即DMA传输的数据与寄存器上的数据不一致,请问遇到这种情况的吗,该如何思考解决。
更新后spi配置如下
void spi_config(void)
{
        rcu_periph_clock_enable(RCU_SPI4);
        rcu_spi_clock_config(IDX_SPI4, RCU_SPISRC_APB2);

        spi_parameter_struct spi4;
       
        spi_i2s_deinit(SPI4);
        spi_struct_para_init(&spi4);
        spi4.device_mode = SPI_MASTER;
        spi4.trans_mode  = SPI_TRANSMODE_BDTRANSMIT;
        spi4.data_size   = SPI_DATASIZE_32BIT;
        spi4.nss  = SPI_NSS_HARD;
        spi4.endian = SPI_ENDIAN_MSB;
        spi4.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
        spi4.prescale = SPI_PSC_64;  //300/256=1.17  <50M
        spi_init(SPI4, &spi4);
        spi_word_access_enable(SPI4);
       
        spi_ti_mode_enable(SPI4);       
        /* enable SPI NSS output */
        spi_nss_output_enable(SPI4);

        spi_enable(SPI4);
}
回复

使用道具 举报

4

主题

8

回帖

20

积分

新手上路

积分
20
 楼主| 发表于 2025-10-17 13:38:22 | 显示全部楼层
已查明原因,还是cache的问题,虽然我操作dma数据缓冲区前后都加了无效cache函数,但真实传输时DMA数据应该还是经过了cache(此处为推论),我关闭cache后DMA传输数据与缓冲区一致。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-11-22 00:20 , Processed in 0.038153 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表