gd32 spi dma全双工发送接收例程

Master
SPI0_NSS PA4 AF5
SPI0_SCK PA5 AF5
SPI0_MISO PA6 AF5
SPI0_MOSI PA7 AF5

Slave
SPI4_NSS PK1 AF5
SPI4_SCK PK0 AF5
SPI4_MOSI PJ10 AF5
SPI4_MISO PJ11 AF5

spi_master_transmit_receive_dma 主机发送接收
spi_slave_transmit_receive_dma 从机发送接收

main.c

/*!
    \file    main.c
    \brief   running LED

    \version 2023-03-31, V1.0.0, firmware for GD32H7xx
*/


#include "gd32h7xx.h"
#include "systick.h"

#include "string.h"
#include "stdio.h"


/*!
    \brief      enable the CPU Chache
    \param[in]  none
    \param[out] none
    \retval     none
*/
static void cache_enable(void)
{
    /* Enable I-Cache */
    SCB_EnableICache();

    /* Enable D-Cache */
//    SCB_EnableDCache();
}

void led_config()
{
    rcu_periph_clock_enable(RCU_GPIOJ);

    gpio_mode_set(GPIOJ, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8);
    gpio_output_options_set(GPIOJ, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_8);

    gpio_mode_set(GPIOJ, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_9);
    gpio_output_options_set(GPIOJ, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_9);

    gpio_bit_set(GPIOJ, GPIO_PIN_8);
    gpio_bit_set(GPIOJ, GPIO_PIN_9);

}

void usart_config()
{
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_USART0);

    gpio_af_set(GPIOB, GPIO_AF_7, GPIO_PIN_6);
    gpio_af_set(GPIOB, GPIO_AF_7, GPIO_PIN_7);

    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_6);

    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_7);

    usart_deinit(USART0);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_baudrate_set(USART0, 921600U);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_enable(USART0);
}

void usart_transmit(char* buff, int size)
{
    for (int i = 0; i < size; ++i) {
        usart_data_transmit(USART0, buff[i]);
        while (RESET == usart_flag_get(USART0, USART_FLAG_TBE)) {}
    }
}


/*
 * Master
 * SPI0_NSS  PA4 AF5
 * SPI0_SCK  PA5 AF5
 * SPI0_MISO PA6 AF5
 * SPI0_MOSI PA7 AF5
 */
void spi0_config()
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_SPI0);

    gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);


    spi_i2s_deinit(SPI0);

    spi_parameter_struct spi_init_struct;
    spi_struct_para_init(&spi_init_struct);
    spi_init_struct.device_mode = SPI_MASTER;
    spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.data_size = SPI_DATASIZE_8BIT;
    spi_init_struct.nss = SPI_NSS_SOFT;
    spi_init_struct.endian = SPI_ENDIAN_MSB;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.prescale = SPI_PSC_64;
    spi_init(SPI0, &spi_init_struct);

    spi_byte_access_enable(SPI0);
    spi_nss_output_enable(SPI0);
    spi_nss_internal_high(SPI0);
    spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
    spi_dma_enable(SPI0, SPI_DMA_RECEIVE);

    spi_enable(SPI0);
}

void spi0_dma_config()
{
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(RCU_DMAMUX);


    nvic_irq_enable(DMA0_Channel0_IRQn, 1, 1);
    nvic_irq_enable(DMA0_Channel1_IRQn, 1, 0);


    dma_deinit(DMA0, DMA_CH1); //SPI0_RX
    dma_single_data_parameter_struct dma_init_struct_rx;
    dma_single_data_para_struct_init(&dma_init_struct_rx);
    dma_init_struct_rx.request = DMA_REQUEST_SPI0_RX;
    dma_init_struct_rx.direction = DMA_PERIPH_TO_MEMORY;
    dma_init_struct_rx.memory0_addr = (uint32_t)0;
    dma_init_struct_rx.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct_rx.periph_memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct_rx.number = 0;
    dma_init_struct_rx.periph_addr = (uint32_t)&SPI_RDATA(SPI0);
    dma_init_struct_rx.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct_rx.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH1, &dma_init_struct_rx);
    dma_circulation_disable(DMA0, DMA_CH1); //用循环模式接收会出现问题,每次接收的第一个数据都是0x00
    dma_interrupt_enable(DMA0, DMA_CH1, DMA_INT_FTF);


    dma_deinit(DMA0, DMA_CH0); //SPI0_TX
    dma_single_data_parameter_struct dma_init_struct_tx;
    dma_single_data_para_struct_init(&dma_init_struct_tx);
    dma_init_struct_tx.request = DMA_REQUEST_SPI0_TX;
    dma_init_struct_tx.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct_tx.memory0_addr = (uint32_t)0;
    dma_init_struct_tx.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct_tx.periph_memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct_tx.number = 0;
    dma_init_struct_tx.periph_addr = (uint32_t)&SPI_TDATA(SPI0);
    dma_init_struct_tx.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct_tx.priority = DMA_PRIORITY_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct_tx);
    dma_circulation_disable(DMA0, DMA_CH0);
    dma_interrupt_enable(DMA0, DMA_CH0, DMA_INT_FTF);
}

//主机DMA发送接收
void spi_master_transmit_receive_dma(uint8_t* tx_buff, uint8_t* rx_buff, int size)
{
    dma_memory_address_config(DMA0, DMA_CH1, DMA_MEMORY_0, rx_buff);
    dma_transfer_number_config(DMA0, DMA_CH1, size);
    dma_channel_enable(DMA0, DMA_CH1);

    dma_memory_address_config(DMA0, DMA_CH0, DMA_MEMORY_0, tx_buff);
    dma_transfer_number_config(DMA0, DMA_CH0, size);
    dma_channel_enable(DMA0, DMA_CH0);

    spi_nss_internal_low(SPI0);
    spi_master_transfer_start(SPI0, SPI_TRANS_START);
}


//主机发送DMA callback
void DMA0_Channel0_IRQHandler()
{
    if (RESET != dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FTF)) {
        dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FTF);


        spi_master_transfer_start(SPI0, SPI_TRANS_IDLE);
        spi_nss_internal_high(SPI0);
    }
}

//主机接收DMA callback
void DMA0_Channel1_IRQHandler()
{
    if (RESET != dma_interrupt_flag_get(DMA0, DMA_CH1, DMA_INT_FLAG_FTF)) {
        dma_interrupt_flag_clear(DMA0, DMA_CH1, DMA_INT_FLAG_FTF);



    }
}



/*
 * Slave
 * SPI4_NSS  PK1 AF5
 * SPI4_SCK  PK0 AF5
 * SPI4_MOSI PJ10  AF5
 * SPI4_MISO PJ11  AF5
 */
void spi4_config()
{
    rcu_periph_clock_enable(RCU_GPIOK);
    rcu_periph_clock_enable(RCU_GPIOJ);
    rcu_periph_clock_enable(RCU_SPI4);

    gpio_af_set(GPIOK, GPIO_AF_5, GPIO_PIN_0 | GPIO_PIN_1);
    gpio_mode_set(GPIOK, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1);
    gpio_output_options_set(GPIOK, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_0 | GPIO_PIN_1);

    gpio_af_set(GPIOJ, GPIO_AF_5, GPIO_PIN_10 | GPIO_PIN_11);
    gpio_mode_set(GPIOJ, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_10 | GPIO_PIN_11);
    gpio_output_options_set(GPIOJ, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ, GPIO_PIN_10 | GPIO_PIN_11);


    spi_i2s_deinit(SPI4);

    spi_parameter_struct spi_init_struct;
    spi_struct_para_init(&spi_init_struct);
    spi_init_struct.device_mode = SPI_SLAVE;
    spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.data_size = SPI_DATASIZE_8BIT;
    spi_init_struct.nss = SPI_NSS_HARD;
    spi_init_struct.endian = SPI_ENDIAN_MSB;
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
    spi_init_struct.prescale = SPI_PSC_64;
    spi_init(SPI4, &spi_init_struct);

    spi_byte_access_enable(SPI4);
    spi_dma_enable(SPI4, SPI_DMA_TRANSMIT);
    spi_dma_enable(SPI4, SPI_DMA_RECEIVE);

    spi_enable(SPI4);
}


void spi4_dma_config()
{
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(RCU_DMAMUX);

    nvic_irq_enable(DMA0_Channel2_IRQn, 0, 1);
    nvic_irq_enable(DMA0_Channel3_IRQn, 0, 0);

    dma_deinit(DMA0, DMA_CH2); //SPI1_TX
    dma_single_data_parameter_struct dma_init_struct_tx;
    dma_single_data_para_struct_init(&dma_init_struct_tx);
    dma_init_struct_tx.request = DMA_REQUEST_SPI4_TX;
    dma_init_struct_tx.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct_tx.memory0_addr = (uint32_t)0;
    dma_init_struct_tx.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct_tx.periph_memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct_tx.number = 0;
    dma_init_struct_tx.periph_addr = (uint32_t)&SPI_TDATA(SPI4);
    dma_init_struct_tx.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct_tx.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH2, &dma_init_struct_tx);
    dma_circulation_disable(DMA0, DMA_CH2);
    dma_interrupt_enable(DMA0, DMA_CH2, DMA_INT_FTF);

    dma_deinit(DMA0, DMA_CH3); //SPI1_RX
    dma_single_data_parameter_struct dma_init_struct_rx;
    dma_single_data_para_struct_init(&dma_init_struct_rx);
    dma_init_struct_rx.request = DMA_REQUEST_SPI4_RX;
    dma_init_struct_rx.direction = DMA_PERIPH_TO_MEMORY;
    dma_init_struct_rx.memory0_addr = (uint32_t)0;
    dma_init_struct_rx.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct_rx.periph_memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct_rx.number = 0;
    dma_init_struct_rx.periph_addr = (uint32_t)&SPI_RDATA(SPI4);
    dma_init_struct_rx.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct_rx.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH3, &dma_init_struct_rx);
    dma_circulation_disable(DMA0, DMA_CH3); //用循环模式接收会出现问题,每次接收的第一个数据都是0x00
    dma_interrupt_enable(DMA0, DMA_CH3, DMA_INT_FTF);
}

//从机DMA发送接收
void spi_slave_transmit_receive_dma(uint8_t* tx_buff, uint8_t* rx_buff, int size)
{
    dma_memory_address_config(DMA0, DMA_CH2, DMA_MEMORY_0, tx_buff);
    dma_transfer_number_config(DMA0, DMA_CH2, size);
    dma_channel_enable(DMA0, DMA_CH2);

    dma_memory_address_config(DMA0, DMA_CH3, DMA_MEMORY_0, rx_buff);
    dma_transfer_number_config(DMA0, DMA_CH3, size);
    dma_channel_enable(DMA0, DMA_CH3);
}


//从机发送DMA callback
void DMA0_Channel2_IRQHandler()
{
    if (RESET != dma_interrupt_flag_get(DMA0, DMA_CH2, DMA_INT_FLAG_FTF)) {
        dma_interrupt_flag_clear(DMA0, DMA_CH2, DMA_INT_FLAG_FTF);


    }
}

//从机接收DMA callback
void DMA0_Channel3_IRQHandler()
{
    if (RESET != dma_interrupt_flag_get(DMA0, DMA_CH3, DMA_INT_FLAG_FTF)) {
        dma_interrupt_flag_clear(DMA0, DMA_CH3, DMA_INT_FLAG_FTF);


    }
}

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    /* enable the CPU Cache */
    cache_enable();

    /* configure systick */
    systick_config();


    led_config();
    usart_config();

    spi0_dma_config();
    spi0_config();
    spi4_dma_config();
    spi4_config();


    int cnt = 0;
    while(1) {

        uint8_t master_tx_buff[4] = {0x11, 0x22, 0x33, 0x44};
        uint8_t master_rx_buff[4] = {0};

        uint8_t slave_tx_buff[4] = {0x44, 0x33, 0x22, 0x11};
        uint8_t slave_rx_buff[4] = {0};

        spi_slave_transmit_receive_dma(slave_tx_buff, slave_rx_buff, 4);
        spi_master_transmit_receive_dma(master_tx_buff, master_rx_buff, 4);
        delay_1ms(1);
        usart_transmit(master_rx_buff, 4);
        usart_transmit(slave_rx_buff, 4);
        //上位机应该收到 0x44, 0x33, 0x22, 0x11, 0x11, 0x22, 0x33, 0x44

        delay_1ms(1000);
    }
}




### GD32H7系列微控制器SPI接口配置指南 对于GD32H7系列微控制器而言,SPI接口是一种同步串行通信协议,用于全双工数据传输。为了有效利用该功能模块,在初始化阶段需设置多个参数来满足具体应用场景的需求。 #### 配置步骤概述 在进行SPI外设编程前,应先完成基本的时钟使能操作以及结构体成员变量赋值工作。通过调用库函数`spi_init()`可以快速完成这些必要的设定过程[^1]。 ```c // 初始化SPI外设 void SPI_Init(void) { rcu_periph_clock_enable(RCU_SPIx); // 使能SPI外设时钟 spi_parameter_struct spi_initstruct; /* SPI初始化 */ spi_i2s_deInit(SPIx); spi_struct_para_init(&spi_initstruct); spi_initstruct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 设置为全双工模式 spi_initstruct.device_mode = SPI_MASTER; // 主设备模式 spi_initstruct.frame_size = SPI_FRAMESIZE_8BIT; // 帧大小为8位 spi_initstruct.direction = SPI_DIRECTION_2LINES; // 双线方向 spi_initstruct.nss = SPI_NSS_SOFT; // 软件NSS管理 spi_initstruct.prescale = SPI_PSC_256; // 波特率预分频器系数 spi_initstruct.first_bit = SPI_FIRST_BIT_MSB; // 数据帧首位(MSB/LSB) spi_init(SPIx, &spi_initstruct); } ``` 上述代码展示了如何针对特定需求定制化地配置SPI接口的各项属性,包括但不限于传输模式、设备角色定义、数据宽度选择等方面的内容[^2]。 #### DMA支持下的高效数据交换机制 当涉及到大量连续的数据流处理任务时,启用DMA(直接存储器访问)技术能够显著提升系统的整体性能表现。特别是在图像采集或者音频播放等领域内应用广泛。在此基础上构建的应用程序往往具备更高的实时性和稳定性特点[^3]。 ```c /* 开启DMA通道并启动传输 */ dma_channel_select(DMAy_Channelz, SPIx_RX_DMA_CHANNEL); dma_memory_address_config(DMAy_Channelz, (uint32_t)&SPIx->DR); dma_transfer_number_config(DMAy_Channelz, size); dma_circulation_disable(DMAy_Channelz); dma_memory_increase_enable(DMAy_Channelz); dma_priority_config(DMAy_Channelz, DMA_PRIORITY_HIGH); dma_direction_config(DMAy_Channelz, DMA_RECEIVE); dma_interrupt_enable(DMAy_Channelz, DMA_INT_FTF | DMA_INT_HFTF | DMA_INT_ERR); dma_channel_enable(DMAy_Channelz); ``` 此部分代码片段说明了怎样借助DMA引擎的力量简化复杂的多字节读写流程控制逻辑,从而减轻CPU负担的同时提高了吞吐量效率。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值