GD32E230 SPI DMA通信(读取传感器数据)

因ST单片机交期不稳定、供货慢且价格翻倍,博主进行了从ST到GD单片机的代码移植。介绍了SPI初始化,GD32与ST的SPI配置方式类似但库函数封装不同;还提及DMA配置和读取数据,采用DMA方式,使用两个通道,解决了数据只能读取一次的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一场疫情让公司的生意越来越好,忙得不可开交,产品大卖特卖。结果ST的单片机开始出现交期不稳定,供货慢,价格翻倍。无奈之下只好从国产单片机下手。于是就有了我的ST-GD的代码移植。

一、SPI初始化

/************************************************
函数名称 : rcu_config
功    能 : RCU时钟配置
参    数 : 无
返 回 值 : 无
作    者 : Mico
*************************************************/
void rcu_config(void)
{
    rcu_periph_clock_enable(RCU_GPIOA);
	rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_DMA);
    rcu_periph_clock_enable(RCU_SPI0);
}
/************************************************
函数名称 : gpio_config
功    能 : SPI映射GPIO初始化
参    数 : 无
返 回 值 : 无
作    者 : Mico
*************************************************/
void gpio_config(void)
{
	rcu_config();
    /* SPI0 GPIO config: SCK/PA5, MISO/PA6, MOSI/PA7 */
    gpio_af_set(GPIOB, GPIO_AF_0, 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_50MHZ,GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
	gpio_bit_reset(GPIOB,GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5);
	
	gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_15);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
	gpio_bit_set(GPIOA,GPIO_PIN_15);//拉低片选
}
/************************************************
函数名称 : spi_config
功    能 : SPI 初始化
参    数 : 无
返 回 值 : 无
作    者 : Mico
*************************************************/
void spi_config(void)
{
    spi_parameter_struct spi_init_struct;
    /* deinitilize SPI and the parameters */
    spi_i2s_deinit(SPI0);
    spi_struct_para_init(&spi_init_struct);

    /* SPI0 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;
    spi_init_struct.device_mode          = SPI_MASTER;
    spi_init_struct.frame_size           = SPI_FRAMESIZE_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_8;
    spi_init_struct.endian               = SPI_ENDIAN_MSB;
    spi_init(SPI0, &spi_init_struct);
  
}

GD32的SPI配置和ST的方式差不多,区别就在于库函数的封装方式不同。

二、DMA配置

/************************************************
函数名称 : dma_config
功    能 : SPI DMA初始化
参    数 : 无
返 回 值 : 无
作    者 : Mico
*************************************************/
void dma_config(void)
{
    dma_parameter_struct  dma_init_struct;
    dma_struct_para_init(&dma_init_struct);
    /* SPI0 transmit dma config */
    dma_deinit(DMA_CH2);   
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI0);//外设基地址
    dma_init_struct.memory_addr = (uint32_t)SPI_TX_BUF ;//内存基地址
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;   //数据传输方向:内存到外设
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;//外设数据宽度8位
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;   //内存数据宽度8位
    dma_init_struct.priority = DMA_PRIORITY_HIGH;           //DMA通道传输软件优先级
    dma_init_struct.number = ARRAYSIZE;                     //DMA通道数据传输数量
    dma_init_struct.periph_inc =  DMA_PERIPH_INCREASE_DISABLE;//外设地址生成算法模式使能
    dma_init_struct.memory_inc =  DMA_MEMORY_INCREASE_ENABLE;//存储器地址生成算法模式失能
    dma_init(DMA_CH2, &dma_init_struct);                     //初始化DMA通道2	
//	dma_circulation_enable(DMA_CH2);                         //DMA循环模式使能

    /* SPI0 receive dma config */
    dma_deinit(DMA_CH1);
    dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI0);
    dma_init_struct.memory_addr = (uint32_t)spi0_receive_array;
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
    dma_init(DMA_CH1, &dma_init_struct);
//    dma_circulation_enable(DMA_CH1);
}

三、读取数据

/************************************************
函数名称 : SPI_DMA_WriteReadByte
功    能 : SPI DMA读取角度
参    数 : 无
返 回 值 : 无
作    者 : Mico
*************************************************/
void SPI_DMA_WriteReadByte(void)
{	
	GPIO_BC (GPIOA) = (uint32_t)GPIO_PIN_15;
	SPI_CTL1(SPI0) |= (uint32_t)SPI_CTL1_DMATEN; /*SPI DMA发送使能*/
	SPI_CTL1(SPI0) |= (uint32_t)SPI_CTL1_DMAREN;/*SPI DMA接收使能*/
	DMA_CHCTL(DMA_CH2) &= ~DMA_CHXCTL_CHEN;     /*失能DMA通道2*/
	DMA_CHCNT(DMA_CH2) = ARRAYSIZE ;            /*传输长度*/
	DMA_CHCTL(DMA_CH2) |= DMA_CHXCTL_CHEN;      /*使能DMA通道2*/
    dma_channel_disable(DMA_CH1);               /*失能DMA通道2*/
//	DMA_CHCTL(DMA_CH1) &= ~DMA_CHXCTL_CHEN;
	DMA_CHCNT(DMA_CH1) = ARRAYSIZE ;            /*传输长度*/
//	DMA_CHCTL(DMA_CH1) |= DMA_CHXCTL_CHEN;
    dma_channel_enable(DMA_CH1);                /*使能DMA通道2*/

	while(RESET == dma_flag_get(DMA_CH2,DMA_FLAG_FTF));
    while(RESET == dma_flag_get(DMA_CH1,DMA_FLAG_FTF));

	GPIO_BOP(GPIOA) = (uint32_t)GPIO_PIN_15;

}

依旧是ST的那个味道,一开始我用GD给的例程写的SPI通信,发现数据只能读取一次。最后还是用ST的那个思想,先失能DMA通道,再重新定义数据长度,再使能DMA通道。因为我SPI的发送和接收都是使用DMA方式,所以使用了两个通道。通道2的发送和通道1的接收。PA15是SPI的使能引脚。

### GD32E230 串口 DMA 使用方法 对于GD32E230系列微控制器,在实现串口DMA传输时,主要涉及配置UART接口以及DMA控制器来完成高效的数据传输。具体来说: - **初始化USART模块**:需要设定波特率、字长、停止位等参数,并开启相应的中断或DMA请求功能。 - **配置DMA通道**:由于GD32E230仅有一个DMA控制器,因此只需指定具体的DMA通道用于发送或接收操作即可。 #### 发送数据流程说明 当通过DMA方式发送数据时,程序应当遵循如下逻辑处理过程[^1]: - 失能当前使用的DMA流; - 设置待传送缓冲区首地址及长度至相应寄存器; - 启动DMA传输并等待直到传输完成标志置位; 下面给出一段基于上述描述的C语言代码片段作为参考实例,展示了如何利用DMA机制向RS485总线发送一组字符序列: ```c void RS_485_SEND(uint8_t *psrc_data, int num) { // 控制DE引脚状态切换到驱动端 GPIO_BOP(GPIOA) = (uint32_t)GPIO_PIN_8; // 调用自定义函数执行实际的DMA发送动作 MYDMA_Send(psrc_data, num); // 循环检测直至本次DMA事务结束 while(RESET == usart_flag_get(USART0, USART_FLAG_TC)); // 切换回监听模式(关闭DE) GPIO_BC(GPIOA) = (uint32_t)GPIO_PIN_8; } ``` 这段代码中`MYDMA_Send()`负责配置DMA的具体细节,比如加载源地址、目标地址、传输数量等信息给DMA硬件单元。而外部循环则用来阻塞主线程直到所有字节都被成功发出为止。 #### 接收数据注意事项 针对GD32E230GD32F103之间的差异,在采用DMA配合空闲线(IDLE line)检测的方式进行异步接收时需要注意几点特殊之处[^2]: - 对于GD32E230而言,可以直接通过对IDLEC位置一来进行IDLE中断标记清除工作; - 当使用Keil MDK V6工具链开发时,建议将参与条件判断的状态变量声明为`volatile`类型以防止编译优化带来的潜在问题。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呐咯密密

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值