GD32F350 LogicKids基本外设驱动

撸完PCB后
花了几天时间,调试了一下基本的片上外设
1、GPIO
输出:
#define MCU_LED_PORT GPIOC
#define USR_LED_PORT GPIOA
#define MCU_LED_PIN GPIO_PIN_13
#define USR_LED_PIN GPIO_PIN_15
#define MCU_LED_RCU RCU_GPIOC
#define USR_LED_RCU RCU_GPIOA
#define USR_LED_ON GPIO_BC(USR_LED_PORT) = USR_LED_PIN
#define USR_LED_OFF GPIO_BOP(USR_LED_PORT) = USR_LED_PIN
#define USR_LED_TG GPIO_TG(USR_LED_PORT) = USR_LED_PIN
#define MCU_LED_ON GPIO_BC(MCU_LED_PORT) = MCU_LED_PIN
#define MCU_LED_OFF GPIO_BOP(MCU_LED_PORT) = MCU_LED_PIN
#define MCU_LED_TG GPIO_TG(MCU_LED_PORT) = MCU_LED_PIN
/ enable the led clock /
rcu_periph_clock_enable(MCU_LED_RCU);
rcu_periph_clock_enable(USR_LED_RCU);
/ configure mcu_led GPIO port /
gpio_mode_set(MCU_LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, MCU_LED_PIN);
gpio_output_options_set(MCU_LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, MCU_LED_PIN);
GPIO_BOP(MCU_LED_PORT) = MCU_LED_PIN;
/ configure user_led GPIO port /
gpio_mode_set(USR_LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, USR_LED_PIN);
gpio_output_options_set(USR_LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, USR_LED_PIN);
GPIO_BOP(USR_LED_PORT) = USR_LED_PIN; //拉高
GPIO_BC(USR_LED_PORT) = USR_LED_PIN;//拉低
复制代码

输入:
#define SYS_FACTORYRESET_PORT GPIOB
#define SYS_WA_SEL_PORT GPIOA
#define SYS_FACTORYRESET_PIN GPIO_PIN_9
#define SYS_WA_SEL_PIN GPIO_PIN_0
#define SYS_FACTORYRESET_RCU RCU_GPIOB
#define SYS_WA_SEL_RCU RCU_GPIOA
rcu_periph_clock_enable(SYS_FACTORYRESET_RCU);
rcu_periph_clock_enable(SYS_WA_SEL_RCU);
gpio_mode_set(SYS_FACTORYRESET_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SYS_FACTORYRESET_PIN);
gpio_mode_set(SYS_WA_SEL_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SYS_WA_SEL_PIN);
复制代码

然后gpio_input_bit_get(SYS_FACTORYRESET_PORT, SYS_FACTORYRESET_PIN);
就能读pin的电平鸟

基本上比较好理解
时钟—端口—模式,很常规的配置过程
比较好的是,官方demo中,每句关键代码、每个函数都会有对应的注释
虽然是国际接轨文
也算是比较贴心了

2、usart

/ enable COM GPIO clock /
rcu_periph_clock_enable(RCU_GPIOA);
/ enable USART clock /
rcu_periph_clock_enable(RCU_USART0);
/ connect port to USARTx_Tx /
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);
/ connect port to USARTx_Rx /
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10);
/ configure USART Tx as alternate function push-pull /
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);
/ configure USART Rx as alternate function push-pull /
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10);
/ USART configure /
usart_deinit(USART0);
usart_baudrate_set(USART0, 115200U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
复制代码

没有采用填充结构体的方式
而是很简单粗暴地直接通过调用各种函数来配置
也是时钟—端口—复用功能这样的配置套路
在实际使用中,没有出现发送时,类似STM32首个字符丢失的问题
估计GD对Usart外设逻辑有一定的优化
发送和接受分别是
usart_data_transmit(uint32_t usart_periph, uint32_t data)
usart_data_receive(uint32_t usart_periph)
复制代码

如果要发送字符串,就得需要手写一个发送函数了
这里直接重定向,使用printf

/ retarget the C library debug function to the USART /
int fputc(int ch, FILE *f)
{
usart_data_transmit(USART0, (uint8_t)ch);
while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
return ch;
}
复制代码

3、SPI
GD32F350CBT6支持2路SPI
分别是SPI0和SPI1

rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_SPI0);
gpio_af_set(GPIOA, GPIO_AF_0, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);
/ 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_HIGH_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(spi_periph, &spi_init_struct);
spi_enable(spi_periph);
复制代码

呃,开始填充结构体了
其中SPI1是可以支持QSPI
并且官方外设库中也放出了相关的配置代码
B10和B11可以用作IO2和IO3

gpio_af_set(GPIOB, GPIO_AF_6, GPIO_PIN_10 | GPIO_PIN_11);
qspi_io23_output_enable(SPI1);
qspi_read_enable(SPI1);
qspi_write_enable(SPI1);
qspi_enable(SPI1);
复制代码

但是楼主配置后并没有成功
似乎和板载的GD25Q16有关
貌似需要对其进行配置后再进行QSPI的通信
相对比较麻烦
度娘了一下,很多网友反馈QSPI的实际性能受到FLASH性能的影响
读写速度提高有限
最后还是在使用普通的三线SPI
发送一字节

uint8_t SPI_SendByte(uint32_t spi_periph, uint8_t byte)
{
/ Loop while DR register in not emplty /
while (spi_i2s_flag_get(spi_periph, SPI_FLAG_TBE) == RESET);
/ Send byte through the SPI1 peripheral /
spi_i2s_data_transmit(spi_periph, byte);
/ Wait to receive a byte /
while (spi_i2s_flag_get(spi_periph, SPI_FLAG_RBNE) == RESET);
/ Return the byte read from the SPI bus /
return spi_i2s_data_receive(spi_periph);
}
复制代码

接收一字节

#define Dummy_Byte 0xFF
uint8_t SPI_ReadByte(uint32_t spi_periph)
{
return (SPI_SendByte(spi_periph, Dummy_Byte));
}
复制代码

4、IIC
有坑
特别是多字节连续读取的时候
官方文档给出了A、B两种读取方式

GD32F350的IIC在每次接收一个字节后
都会硬件产生一个ACK信号
所以在接收多个字节的时候要记得把ACK信号给Disable掉
配置代码

rcu_periph_clock_enable(RCU_GPIOB);
rcu_periph_clock_enable(RCU_I2C0);
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_6);
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_7);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_6);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_6);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP,GPIO_PIN_7);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ,GPIO_PIN_7);
i2c_clock_config(I2C0, 400000, I2C_DTCY_2);
i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_OWN_ADDRESS7);
i2c_enable(i2c_periph);
i2c_ack_config(i2c_periph, I2C_ACK_ENABLE);
复制代码

发送一个字节

void IIC_SendByte(uint32_t i2c_periph, uint32_t slave_addr, uint32_t sub_addr, uint8_t data)
{
while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));
i2c_start_on_bus(i2c_periph);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
i2c_master_addressing(i2c_periph, slave_addr, I2C_TRANSMITTER);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_TBE));
i2c_data_transmit(i2c_periph, sub_addr);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
i2c_data_transmit(i2c_periph, data);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
i2c_stop_on_bus(i2c_periph);
while(I2C_CTL0(i2c_periph)&0x0200);
}
复制代码

接收一个字节

uint8_t IIC_ReadByte(uint32_t i2c_periph, uint32_t slave_addr, uint32_t sub_addr)
{
uint8_t i2c_receiver;
while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));
i2c_start_on_bus(i2c_periph);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
i2c_master_addressing(i2c_periph, slave_addr, I2C_TRANSMITTER);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);
i2c_data_transmit(i2c_periph, sub_addr);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
i2c_start_on_bus(i2c_periph);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
i2c_master_addressing(i2c_periph, slave_addr, I2C_RECEIVER);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);
i2c_ack_config(i2c_periph, I2C_ACK_DISABLE);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_RBNE));
i2c_receiver = i2c_data_receive(i2c_periph);
i2c_stop_on_bus(i2c_periph);
while(I2C_CTL0(i2c_periph)&0x0200);
i2c_ack_config(i2c_periph, I2C_ACK_ENABLE);
return i2c_receiver;
}
复制代码

发送一堆字节

void IIC_SendBuffer(uint32_t i2c_periph, uint32_t slave_addr, uint32_t sub_addr, uint8_t *buffer, uint16_t send_nums)
{
uint16_t i=0;
while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));
i2c_start_on_bus(i2c_periph);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
i2c_master_addressing(i2c_periph, slave_addr, I2C_TRANSMITTER);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_TBE));
i2c_data_transmit(i2c_periph, sub_addr);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
for(i=0; i<send_nums; i++)
{
i2c_data_transmit(i2c_periph, buffer[i]);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
}
i2c_stop_on_bus(i2c_periph);
while(I2C_CTL0(i2c_periph)&0x0200);
}
复制代码

接收一堆字节

void IIC_ReadBuffer(uint32_t i2c_periph, uint32_t slave_addr, uint32_t sub_addr, uint8_t *buffer, uint16_t read_nums)
{
uint16_t cnt = 0;
while(i2c_flag_get(i2c_periph, I2C_FLAG_I2CBSY));
i2c_start_on_bus(i2c_periph);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
i2c_master_addressing(i2c_periph, slave_addr, I2C_TRANSMITTER);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);
i2c_data_transmit(i2c_periph, sub_addr);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_BTC));
i2c_start_on_bus(i2c_periph);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_SBSEND));
i2c_master_addressing(i2c_periph, slave_addr, I2C_RECEIVER);
while(!i2c_flag_get(i2c_periph, I2C_FLAG_ADDSEND));
i2c_flag_clear(i2c_periph, I2C_FLAG_ADDSEND);

if(read_nums > 2)
{
for(cnt = 0; cnt < read_nums; cnt++)
{
if((read_nums > 1) && (cnt == read_nums-1))
{
while(!i2c_flag_get(I2C0, I2C_FLAG_BTC));
i2c_ack_config(I2C0, I2C_ACK_DISABLE);
}
while(!i2c_flag_get(i2c_periph, I2C_FLAG_RBNE));
buffer[cnt] = i2c_data_receive(i2c_periph);
}
}
else
{
for(cnt = 0; cnt < read_nums; cnt++)
{
while(!i2c_flag_get(i2c_periph, I2C_FLAG_RBNE));
buffer[cnt] = i2c_data_receive(i2c_periph);
i2c_ack_config(i2c_periph, I2C_ACK_DISABLE);
}
}
i2c_stop_on_bus(i2c_periph);
while(I2C_CTL0(i2c_periph)&0x0200);
i2c_ack_config(i2c_periph, I2C_ACK_ENABLE);
}
复制代码

5、PWM
抄库

void PWM_INIT(void)
{
timer_oc_parameter_struct timer_ocintpara;
timer_parameter_struct timer_initpara;

/Configure PB3 PB4 PB5(TIMER1-CH1 TIMER2-CH0 TIMER2-CH1) as alternate function/
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_3);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_3);

gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_4);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_4);

gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_5);

gpio_af_set(GPIOB, GPIO_AF_2, GPIO_PIN_3);
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_4);
gpio_af_set(GPIOB, GPIO_AF_1, GPIO_PIN_5);

rcu_periph_clock_enable(RCU_TIMER1);
rcu_periph_clock_enable(RCU_TIMER2);
timer_deinit(TIMER1);
timer_deinit(TIMER2);
/ TIMER1 configuration /
timer_initpara.prescaler = 107;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 15999;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER1,&timer_initpara);
/ TIMER2 configuration /
timer_initpara.prescaler = 107;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 15999;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER2,&timer_initpara);

/configuration in PWM mode0 /
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
timer_channel_output_pulse_value_config(TIMER1,TIMER_CH_1,15999);
timer_channel_output_mode_config(TIMER1,TIMER_CH_1,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER1,TIMER_CH_1,TIMER_OC_SHADOW_DISABLE);

timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_0,15999);
timer_channel_output_mode_config(TIMER2,TIMER_CH_0,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER2,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);

timer_channel_output_pulse_value_config(TIMER2,TIMER_CH_1,15999);
timer_channel_output_mode_config(TIMER2,TIMER_CH_1,TIMER_OC_MODE_PWM0);
timer_channel_output_shadow_config(TIMER2,TIMER_CH_1,TIMER_OC_SHADOW_DISABLE);
/ auto-reload preload enable /
timer_auto_reload_shadow_enable(TIMER1);
timer_auto_reload_shadow_enable(TIMER2);
/ auto-reload preload enable /
timer_enable(TIMER1);
timer_enable(TIMER2);
timer_channel_output_config(TIMER1,TIMER_CH_1,&timer_ocintpara);
timer_channel_output_config(TIMER2,TIMER_CH_0,&timer_ocintpara);
timer_channel_output_config(TIMER2,TIMER_CH_1,&timer_ocintpara);
}
复制代码

修改了几个端口和TimerX
重载timer_channel_output_pulse_value_config 中15999的值就能调整占空比了

上个测试视频

需要使用的外设基本上就是这么多了
先到这

猜你喜欢

转载自blog.51cto.com/13939022/2171716
今日推荐