这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 【GD32F527】SPI+DMA实现数据发送

共1条 1/1 1 跳转至

【GD32F527】SPI+DMA实现数据发送

工程师
2025-09-27 23:17:15     打赏

【前言】

准备使用GD32F527的SPI来实现WS2812的驱动,由于SPI只需要MOSI,但是为了方便观察数据,还需要SCK。这一篇只需要MOSI通过DMA数据输出就行,不需要CS、MISO。

GD32F5xx在示例中没有SPI的示例,因此需要自己摸索进行SPI总线的配置与DMA的配置,经过很长时间的摸索,实现了SPI+DMA的数据传送。

【资料准备与IO的分配】

1、GD32F527有一个UART+DMA的示例,从其中学习DMA的配置的参照。

2、GD32F5xx的数据手册。在数据手册中,首先找到与开发板引出的IO进行配置,通过阅读,找到了可用的IO:

使用PC1为SPI1的MOSI

image.png

数据手册的PC1的IO复用:

image.png

3、找到SPI1的SCK为PA9,在开发板上有引出:

image.png

数据手册的PA9的复用:

image.png

4、分配好IO后,我们还需要找到AF复用通道,在数据手册中找到复用表:

PC1复用为AF7

image.png

PA9为AF5

image.png

6、DMA0通道与外设通道,在DMA配置中需要用到这两个参数,在它的数据手册中有找到

image.png

找到SPI1_TX是DMA0,CH4,同时外设通道为0

到此资料准备完毕,下面准备配置SPI以及DMA。

【SPI1初始化配置】

我们使用到的外设时钟有GPIOA、GPIOC、SPI1四个时钟。

void spi_config(void) {
   spi_parameter_struct spi_init_struct;
	
   rcu_periph_clock_enable(RCU_GPIOA);
   rcu_periph_clock_enable(RCU_GPIOC);
   rcu_periph_clock_enable(RCU_SPI1);
	
   // SPI1_SCK  PA9 AF5  SPI1_MOSI PC1   AF7
   gpio_af_set(GPIOC, GPIO_AF_7, GPIO_PIN_1);
    gpio_mode_set(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_1);
    gpio_output_options_set(GPIOC, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_1);
	
   gpio_af_set(GPIOA, GPIO_AF_5, GPIO_PIN_9);
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_9);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9);
	
   // SPI 参数初始化
   spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX; // 全双工模式
   spi_init_struct.device_mode = SPI_MASTER; // 主机模式
   spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT; // 数据帧长度为 8 位
   spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; // 时钟极性和相位
   spi_init_struct.nss = SPI_NSS_SOFT; // 软件控制 NSS
   spi_init_struct.prescale = SPI_PSC_64; // 时钟分频
   spi_init_struct.endian = SPI_ENDIAN_MSB; // 高位优先
   spi_init(SPI1, &spi_init_struct); // 初始化 SPI1
   spi_enable(SPI1); // 启用 SPI
}

2、初始化后,编写一个测试函数:

// 发送数据
void spi_send_data(uint16_t data) {
   while (RESET == spi_i2s_flag_get(SPI1, SPI_FLAG_TBE)); // 等待发送缓冲区空
   spi_i2s_data_transmit(SPI1, data); // 写入数据
}

在main中执行发送一个0xEE进行观察

image.png

使用逻辑分析仪,捕获时序,频率为775KHz基于能满足WS2812的传输时序:

image.png

使用SPI发送正常后,下面进行DMA的配置

【SPI-DMA配置】

void usart_dma_config(void)
{
    dma_single_data_parameter_struct dma_init_struct;
    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);
    /* deinitialize DMA channel4(SPI1 TX) */
    dma_deinit(DMA0, DMA_CH4);
	  
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.memory0_addr = (uint32_t)tx_buffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.number = 24;
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI1);;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
	
    dma_init_struct.priority = DMA_PRIORITY_LOW;
    dma_single_data_mode_init(DMA0, DMA_CH4, &dma_init_struct);
		
	  dma_channel_subperipheral_select(DMA0, DMA_CH4, DMA_SUBPERI0);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH4);
		dma_channel_disable(DMA0,DMA_CH4);

}

// 启动DMA发送函数
void spi1_dma_send(uint8_t *data, uint16_t length) {
    // 清除DMA通道
   dma_single_data_parameter_struct dma_init_struct;
    dma_channel_disable(DMA0, DMA_CH4);

    // 设置发送数据地址和长度
   dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
   dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
	
    dma_init_struct.memory0_addr = (uint32_t)data;
    dma_init_struct.number = length;
	  dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI1);;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
	
    dma_init_struct.priority = DMA_PRIORITY_LOW;
	  dma_single_data_mode_init(DMA0, DMA_CH4, &dma_init_struct);
    // 清除DMA标志
    dma_flag_clear(DMA0, DMA_CH4, DMA_FLAG_FTF);
    dma_circulation_disable(DMA0, DMA_CH4);
    // 启动DMA传输
		
    dma_channel_enable(DMA0, DMA_CH4);
    spi_dma_enable(SPI1, SPI_DMA_TRANSMIT);
    while(!dma_flag_get(DMA0,DMA_CH4, DMA_FLAG_FTF));
}

在配置中,我们使用DMA0 CH4进行配置,数据方向为内存到外设,数据宽度为8BIT。

特别注意的是,在使能dma传输时,需要使用spi_dma_enable对SPI的DMATEN位进行置1,来启用。在数据手册中有描述如下:

image.png

【测试效果】

测试代码如下:

int main(void)
{
    uint8_t dat[] = {0x11,0x33};
    systick_config();

		spi_config();
	  usart_dma_config();
	  spi_send_data(0xEE);
	  spi1_dma_send(&dat[0], 2);
		while(!spi1_dma_tx_complete())
		{
			;
		}
    while(1) {
        /* turn on led1, turn off led4 */

    }
}

通过逻辑分析仪的数据捕获,如期实现其功能:

image.png

【总结】

由于没有SPI+DMA的示例,只能通过阅读用户手册,慢慢的进行摸索,希望这篇文章能帮助到在需要使用SPI_TX+DMA的大佬。




关键词: GD32F527     SPI+DMA    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]