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的值就能調整佔空比了

上個測試視頻

需要使用的外設基本上就是這麼多了
先到這

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章