gd32h7 spi全双工极限速度测试

同一块H7开发板上开2个spi互相传输数据,经过测试在此频率下运行最稳定
最高运行频率 300MHz / 16 = 18.75MHz
最高传输速度 2117kb/s

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"



#define SPI_BUFF_SIZE 1024

uint32_t master_send_bytes = 0;
uint32_t master_send_error_bytes = 0;
uint32_t master_recv_error_bytes = 0;

__attribute__ ((aligned(32))) uint8_t master_tx_buff[SPI_BUFF_SIZE] = {0};
__attribute__ ((aligned(32))) uint8_t master_rx_buff[SPI_BUFF_SIZE] = {0};
__attribute__ ((aligned(32))) uint8_t slave_tx_buff[SPI_BUFF_SIZE] = {0};
__attribute__ ((aligned(32))) uint8_t slave_rx_buff[SPI_BUFF_SIZE] = {0};



void spi_master_transmit_receive_dma(uint8_t* tx_buff, uint8_t* rx_buff, int size);
void spi_slave_transmit_receive_dma(uint8_t* tx_buff, uint8_t* rx_buff, int size);


/*!
    \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_16;
    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, 0);
    nvic_irq_enable(DMA0_Channel1_IRQn, 1, 1);


    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);


        //验证数据是否正确
        if (memcmp(slave_tx_buff, master_rx_buff, SPI_BUFF_SIZE) != 0) {
            master_recv_error_bytes += SPI_BUFF_SIZE;
        }


        //接收完继续发送
        spi_slave_transmit_receive_dma(slave_tx_buff, slave_rx_buff, SPI_BUFF_SIZE);
        spi_master_transmit_receive_dma(master_tx_buff, master_rx_buff, SPI_BUFF_SIZE);
    }
}



/*
 * 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_16;
    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);

        master_send_bytes += SPI_BUFF_SIZE;


        //验证数据是否正确
        if (memcmp(master_tx_buff, slave_rx_buff, SPI_BUFF_SIZE) != 0) {
            master_send_error_bytes += SPI_BUFF_SIZE;
        }

    }
}



void timer_config()
{
    nvic_irq_enable(TIMER1_IRQn, 0,0);

    timer_parameter_struct timer_initpara;

    rcu_periph_clock_enable(RCU_TIMER1);

    //1Hz
    timer_deinit(TIMER1);
    timer_struct_para_init(&timer_initpara);
    timer_initpara.prescaler         = 30000 - 1;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = (uint64_t)(10000 - 1);
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER1, &timer_initpara);

    timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);
    timer_interrupt_enable(TIMER1, TIMER_INT_UP);
    timer_enable(TIMER1);
}

void TIMER1_IRQHandler(void)
{
    if(SET == timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_UP)){
        timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);


        char buff[128];
        snprintf(buff, 128, "speed: %.2fkb/s send_error:%d recv_error:%d\r\n", (float)master_send_bytes / 1024.0,
                 master_send_error_bytes, master_recv_error_bytes);
        usart_transmit(buff, strlen(buff));

        master_send_bytes = 0;
        master_send_error_bytes = 0;
        master_recv_error_bytes = 0;

        gpio_bit_toggle(GPIOJ, GPIO_PIN_8);
    }
}


void init_tx_buff(uint8_t* buff, int size, uint32_t seed)
{
    for (int i = 0; i < size; ++i) {
        seed ^= (13 + i);
        buff[i] = seed;
    }
}

/*!
    \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();


    timer_config();


    init_tx_buff(master_tx_buff, SPI_BUFF_SIZE, 1314);
    init_tx_buff(slave_tx_buff, SPI_BUFF_SIZE, 512);

    spi_slave_transmit_receive_dma(slave_tx_buff, slave_rx_buff, SPI_BUFF_SIZE);
    spi_master_transmit_receive_dma(master_tx_buff, master_rx_buff, SPI_BUFF_SIZE);


    int cnt = 0;
    while(1) {


        delay_1ms(1000);
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值