GD32 SPI — I2S 主发从收 DMA

GD32 GD32F30x_Firmware_Library V3.0.3 SPI I2S 主发从收 DMA 示例教学

SPI — I2S 主发从收 DMA

固件库: GD32F30x_Firmware_Library V3.0.3
芯片: GD32
源文件: GD32F30x_Firmware_Library_V3.0.3/Examples/SPI/I2S_master_transmit_slave_receive_dma/main.c


功能简介

本示例演示 SPI 总线通信。SPI 是高速同步串行接口,常用于连接 Flash、LCD、传感器等外设。

硬件准备

  • 需要主机和从机两块板子,或使用回环连接(MOSI→MISO)

完整代码

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "gd32f30x.h"
#include "gd32f307c_eval.h"
#define arraysize         10

void rcu_config(void);
void gpio_config(void);
void dma_config(void);
void spi_config(void);

/*!
    \brief      main function
    \param[in]  none
    \param[out] none
    \retval     none
*/
int main(void)
{
    /* init led2 */
    gd_eval_led_init(LED2);

    /* peripheral clock enable */
    rcu_config();
    /* GPIO config */
    gpio_config();
    /* DMA config */
    dma_config();
    /* SPI config */
    spi_config();

    /* SPI enable */
    i2s_enable(SPI2);
    i2s_enable(SPI1);

    /* DMA channel enable */
    dma_channel_enable(DMA0,DMA_CH4);
    dma_channel_enable(DMA1,DMA_CH0);

    /* SPI DMA enable */
    spi_dma_enable(SPI2, SPI_DMA_RECEIVE);
    spi_dma_enable(SPI1, SPI_DMA_TRANSMIT);

    /* wait DMA transmit complete */
    while(!dma_flag_get(DMA0, DMA_CH4, DMA_INTF_FTFIF));
    while(!dma_flag_get(DMA1, DMA_CH0, DMA_INTF_FTFIF));

    /* compare receive data with send data */
    if(memory_compare(spi2_receive_array, spi1_send_array, arraysize))
        gd_eval_led_on(LED2);
    else
        gd_eval_led_off(LED2);

    while(1);
}

void rcu_config(void)
{
#ifdef GD32F30X_CL
    rcu_pll2_config(RCU_PLL2_MUL8);
    rcu_osci_on(RCU_PLL2_CK);
    while((RCU_CTL & RCU_CTL_PLL2STB) == 0)
    {
    }
    rcu_i2s1_clock_config(RCU_I2S1SRC_CKPLL2_MUL2);
    rcu_i2s2_clock_config(RCU_I2S2SRC_CKPLL2_MUL2);
#endif

    rcu_periph_clock_enable(RCU_SPI1);
    rcu_periph_clock_enable(RCU_SPI2);
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_DMA0);
    rcu_periph_clock_enable(RCU_DMA1);
}

void gpio_config(void)
{
    /* I2S1 GPIO config: I2S1_WS/PB12, I2S1_CK/PB13, I2S_SD/PB15 */
    gpio_init(GPIOB, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12 | GPIO_PIN_13 |GPIO_PIN_15);

    /* I2S2 GPIO config: I2S2_WS/PA15, I2S2_CK/PB3, I2S2_SD/PB5 */
    gpio_init(GPIOB, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_3 | GPIO_PIN_5);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_15);
}

void dma_config(void)
{
    dma_parameter_struct dma_init_struct;
    
    /* SPI1 transmit dma config: DMA0,DMA_CH4  */
    dma_deinit(DMA0, DMA_CH4);
    dma_init_struct.periph_addr  = (uint32_t)&SPI_DATA(SPI1);
    dma_init_struct.memory_addr  = (uint32_t)spi1_send_array;
    dma_init_struct.direction    = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_LOW;
    dma_init_struct.number       = arraysize;
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init(DMA0, DMA_CH4, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH4);
    dma_memory_to_memory_disable(DMA0, DMA_CH4);

    /* SPI2 receive dma config: DMA1-DMA_CH0 */
    dma_deinit(DMA1, DMA_CH0);
    dma_init_struct.periph_addr  = (uint32_t)&SPI_DATA(SPI2);
    dma_init_struct.memory_addr  = (uint32_t)spi2_receive_array;
    dma_init_struct.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.priority     = DMA_PRIORITY_HIGH;
    dma_init(DMA1, DMA_CH0, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA1, DMA_CH0);
    dma_memory_to_memory_disable(DMA1, DMA_CH0);
}

void spi_config(void)
{
    spi_i2s_deinit(SPI1);
    spi_i2s_deinit(SPI2);

    i2s_init(SPI1, I2S_MODE_MASTERTX, I2S_STD_PHILIPS, I2S_CKPL_LOW);
    i2s_psc_config(SPI1, I2S_AUDIOSAMPLE_11K, I2S_FRAMEFORMAT_DT16B_CH16B, I2S_MCKOUT_DISABLE);
    
    i2s_init(SPI2, I2S_MODE_SLAVERX, I2S_STD_PHILIPS, I2S_CKPL_LOW);
    i2s_psc_config(SPI2, I2S_AUDIOSAMPLE_11K, I2S_FRAMEFORMAT_DT16B_CH16B, I2S_MCKOUT_DISABLE);
}

代码讲解

GPIO 配置:设置引脚为输出/输入模式,选择推挽/开漏输出,配置上拉/下拉。

DMA 配置:设置源地址、目标地址、传输方向、数据宽度。DMA 搬运数据不占用 CPU。

SPI 配置:设置主/从模式、时钟极性(CPOL)、时钟相位(CPHA)、分频系数。主机和从机的 CPOL/CPHA 必须一致。

实验现象

  • 主机和从机互相交换数据
  • 数据校验通过则 LED 指示成功

注意事项

  • CPOL 和 CPHA 必须主机从机一致
  • 片选(CS)信号要手动拉低选中从机
  • 时钟频率不能超过从设备的最大速率
世界是你们
使用 Hugo 构建
主题 StackJimmy 设计