同一块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);
}
}