直接上代码,主要参考GD32H7用户手册
gpio的配置,
没啥说的。
/***********************************************************
1. SPI3_CLK --> PE2, SPI3_MISO--> PE5, SPI3_MOSI--> PE6,
2. SPI3_NSS0 --> PE7, SPI3_NSS1 --> PE4,
************************************************************/
static void spi3_gpio_init(void)
{
rcu_periph_clock_enable(RCU_GPIOE);
rcu_periph_clock_enable(RCU_SPI3);
gpio_af_set(GPIOE, GPIO_AF_5, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_2);
gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_2);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_2);
/*PE4,NSS0*/
gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_4);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_4);
gpio_bit_set(GPIOE, GPIO_PIN_4);
/*PE7,NSS1*/
gpio_mode_set(GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_7);
gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_60MHZ, GPIO_PIN_7);
gpio_bit_set(GPIOE, GPIO_PIN_7);
}
spi的配置
重点参考手册;
spi时钟选择
这里使用单线单主机模式,即常规配置
SPI3/4的时钟,与spi1/2/5的并不完全相同,选择的时候,需要注意:
NSS配置
使用主机软件NSS模式,这里的软件模式其实是SPI的NSS引脚使用内部寄存器来控制,所以可以节约一个外部的GPIO。而上面最开始GPIO引脚配置的NSS PE4 PE7其实是连接从机SPI的NSS。
主机发送的时候,当PE4/PE7为无效电平时,仍然可以将数据发出去的,只是从机收不到而已。
简单说下NSS的功能:
从机模式
当配置为从机模式(MSTMOD = 0)时,在硬件NSS模式(NSSIM = 0)下,SPI从NSS引脚获取NSS电平,在软件NSS(NSSIM = 1)下,
SPI根据NSSI位得到NSS电平。只有当NSS为有效电平时,发送或接收数据。在软件NSS模式下,不使用NSS引脚。用户可以设置NSSIOPL
位来决定输入/输出外部信号的有效电平(在NSS引脚上)。
主机模式
主机软件NSS模式看得我云里雾里,没有ST的清晰。有没有大佬解释下?
这里要注意主机软件NSS模式时,spi的初始化配置时,也就是在使能spi之前,NSS引脚的电平,否则会产生主机配置错误
无法使能SPI。
结合下面的配置为主机软件NSS模式,废话几句:
第7行,MSTMOD = 1,主机模式;
第10行,NSSIM=1,软件模式;即NSS引脚的有效电平、输入输出,由寄存器配置决定;NSS的有效电平为低电平
至于下面第15行,是将主机模式NSS输出使能。如果注释,则SPI会产生主机配置错误,无法使能SPI,不懂为何?
大佬求解释
static void spi3_config(void)
{
1 rcu_periph_clock_enable(RCU_SPI3);
2 rcu_spi_clock_config(IDX_SPI3, RCU_SPISRC_APB2);
3 spi_i2s_deinit(SPI3);
4 spi_parameter_struct spi_init_struct;
5 spi_struct_para_init(&spi_init_struct);
6 spi_init_struct.trans_mode = SPI_TRANSMODE_FULLDUPLEX;
7 spi_init_struct.device_mode = SPI_MASTER;
8 spi_init_struct.data_size = SPI_DATASIZE_8BIT;
9 spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE;
10 spi_init_struct.nss = SPI_NSS_SOFT;
11 spi_init_struct.prescale = SPI_PSC_8;//300M/8=37.5MHZ,300M/16=18.75MHZ
12 spi_init_struct.endian = SPI_ENDIAN_MSB;
13 spi_init(SPI3, &spi_init_struct);
14 spi_byte_access_enable(SPI3);//使能按字节访问
/* enable SPI NSS output ,is important for spi3*/
15 spi_nss_output_enable(SPI3);
}
SPI收发
超时部分可自行封装为函数。高速模式下可能会出现时钟相位偏移,还需注意时钟拉伸
uint8_t spi3_trx_byte(uint32_t spi_periph, uint8_t data)
{
// SPI_STATC(spi_periph) = 0;
uint8_t retry = 0;
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_TP)) {
retry++;
if (retry > SPI_RETRY_TIME) {
return ERROR;
}
}
spi_master_transfer_start(SPI3, SPI_TRANS_START);
spi_i2s_data_transmit(spi_periph, data);
retry = 0;
while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_RP)) {
retry++;
if (retry > SPI_RETRY_TIME) {
return ERROR;
}
}
/*wait transmit/receive complete,specially in high speed mode*/
// while (RESET == spi_i2s_flag_get(spi_periph, SPI_FLAG_ET));
return(spi_i2s_data_receive(spi_periph));
}