撸完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的值就能调整占空比了
上个测试视频
需要使用的外设基本上就是这么多了
先到这