硬汉嵌入式论坛

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

[技术讨论] GD32H737 SPI DMA问题

[复制链接]

3

主题

1

回帖

10

积分

新手上路

积分
10
发表于 前天 17:00 | 显示全部楼层 |阅读模式
spi + dma数据收发偶尔不正常,配置如下:



static void rcu_config(void)
{
    /* enable the peripherals clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOG);   
    rcu_periph_clock_enable(RCU_SPI0);
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(RCU_DMAMUX);     
    rcu_spi_clock_config(IDX_SPI0, RCU_SPISRC_PLL0Q);
}

static void gpio_config(void)
{
    /* connect port to SPI0_NSS->PA4
                       SPI0_SCK->PB3
                       SPI0_MISO->PB4
                       SPI0_MOSI->PB5 */
    //gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_4);
    gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_4);
    SET_SPI0_NSS_HIGH();

    gpio_af_set(GPIOB, GPIO_AF_5, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);
}

static void spi0_config(void)
{
    spi_parameter_struct spi_init_struct;
   
    /* deinitialize SPI and the parameters */
    spi_i2s_deinit(SPI0);
    spi_struct_para_init(&spi_init_struct);

    /* SPI0 parameter configuration */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.data_size            = SPI_DATASIZE_8BIT;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_128;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi_init_struct);

    /* enable SPI byte access */
    spi_byte_access_enable(SPI0);
   
    spi_nss_internal_low(SPI0);
    spi_nss_output_enable(SPI0);
   
    spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
    spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);

    spi_enable(SPI0);
   
    SET_SPI0_NSS_HIGH();
}

static void dma_config(void)
{
    dma_single_data_parameter_struct dma_init_struct;
    /* deinitialize DMA registers of a channel */
    dma_deinit(DMA0, DMA_CH0);
    dma_deinit(DMA0, DMA_CH1);
    dma_single_data_para_struct_init(&dma_init_struct);
   
    /* SPI0 transmit DMA config: DMA_CH0 */
    dma_init_struct.request = DMA_REQUEST_SPI0_TX;
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;   
    //dma_init_struct.memory0_addr = (uint32_t)spi0_send_array;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    //dma_init_struct.number = ARRAYSIZE;
    dma_init_struct.periph_addr = (uint32_t)&SPI_TDATA(SPI0);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct);

    /* SPI0 receive DMA config: DMA_CH1 */
    dma_init_struct.request = DMA_REQUEST_SPI0_RX;
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;   
    //dma_init_struct.memory0_addr = (uint32_t)spi0_receive_array;
    dma_init_struct.periph_addr = (uint32_t)&SPI_RDATA(SPI0);
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH1, &dma_init_struct);   
   
    dma_interrupt_enable(DMA0, DMA_CH0, DMA_INT_FTF);
    dma_interrupt_enable(DMA0, DMA_CH1, DMA_INT_FTF);
   
    nvic_irq_enable(DMA0_Channel0_IRQn, 1, 0);
    nvic_irq_enable(DMA0_Channel1_IRQn, 2, 0);
}

void DMA0_Channel0_IRQHandler()
{
    if (dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FEE)) {
        dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FEE);
        // 记录错误、复位 DMA 或报警

    }

    if (dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FTF)) {
        dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FTF);
        // 正常完成传输
        dma_channel_disable(DMA0, DMA_CH0);
        spi_dma_disable(SPI0, SPI_DMA_TRANSMIT);
        spi_tx_done = 1;
    }
}

void DMA0_Channel1_IRQHandler()
{
    if (dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INT_FLAG_FEE)) {
        dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INT_FLAG_FEE);
        // 记录错误、复位 DMA 或报警

    }
   
    if (RESET != dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INT_FLAG_FTF)) {
        dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INT_FLAG_FTF);
            
        // 关闭 DMA 通道和 SPI 接收DMA
        dma_channel_disable(DMA0, DMA_CH1);
        spi_dma_disable(SPI0, SPI_DMA_RECEIVE);
        
        SET_SPI0_NSS_HIGH();
        
        spi_rx_done = 1;
    }
}

/* 注意tx_buf, rx_buf的内存位置需要支持DMA */
void spi0_dma_send_recv(uint8_t *tx_buf, uint8_t *rx_buf, uint32_t length)
{
    /* 检查spi是否正在收发 */
    while(!(spi_tx_done && spi_rx_done)){};
        
    /* 开始传输,清空spi收发完成标志 */
    spi_tx_done = 0;
    spi_rx_done = 0;
        
    s_rx_buf = rx_buf;
    s_tx_buf = tx_buf;
    s_buf_len = length;

    SET_SPI0_NSS_LOW();
   
    /* DMA 缓存一致性问题,DMA 访问的是实际内存,但 CPU 修改的可能只是 Cache 中的副本,没有及时写回 */
    SCB_CleanDCache_by_Addr((uint32_t *)s_tx_buf, s_buf_len);
   
    dma_channel_disable(DMA0, DMA_CH0);
    dma_channel_disable(DMA0, DMA_CH1);

    dma_transfer_number_config(DMA0, DMA_CH0, s_buf_len);
    dma_memory_address_config(DMA0, DMA_CH0, DMA_MEMORY_0, (uint32_t)s_tx_buf);

    dma_transfer_number_config(DMA0, DMA_CH1, s_buf_len);
    dma_memory_address_config(DMA0, DMA_CH1, DMA_MEMORY_0, (uint32_t)s_rx_buf);

    dma_channel_enable(DMA0, DMA_CH1);
    dma_channel_enable(DMA0, DMA_CH0);

    spi_current_data_num_config(SPI0, s_buf_len);
            
    spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
    spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);

    spi_master_transfer_start(SPI0, SPI_TRANS_START);
}


main函数中调用

    while(1) {
        spi0_dma_send_recv((uint8_t*)send_buf, (uint8_t*)recv_buf, 1024);
    }

使用逻辑分析仪抓数据看到偶尔会在发送完成一次数据包1024bytes之后,CLK电平不会变为空闲电平(低电平空闲),如下图:


下图是正常的时序:

回复

使用道具 举报

1万

主题

7万

回帖

11万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
116197
QQ
发表于 昨天 10:16 | 显示全部楼层
spi的gpio上拉电阻使能,看看是不是好点
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-6-9 19:51 , Processed in 0.263617 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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