Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
沁恒开发文档
https://github.com/zh-commander/qingheng-ch32v307-document
Admin
本仓库提供沁恒微电子CH32V307系列RISC-V微控制器的完整开发资料,包括数据手册、外设驱动示例、开发工具指南和评估板文档等。
Tokens:
32,283
Snippets:
98
Trust Score:
4
Update:
4 months ago
Context
Chat
Benchmark
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Main Function Example: PWM Control Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt Demonstrates the usage of the PWM_Init function in the main loop. It initializes PWM with specific parameters to achieve a 1kHz frequency and then enters an infinite loop to alternately set the duty cycle to 25% and 75% every second. This example assumes a system clock of 144MHz and requires a Delay_Ms function to be defined elsewhere. ```c // Assume Delay_Ms is defined elsewhere // void Delay_Ms(uint32_t time); int main(void) { // 1kHz PWM with 50% duty cycle (assuming 144MHz clock) // Frequency = 144MHz / (143 + 1) / (999 + 1) = 1kHz PWM_Init(999, 143, 500); while(1) { // Adjust duty cycle TIM_SetCompare1(TIM1, 250); // 25% duty Delay_Ms(1000); TIM_SetCompare1(TIM1, 750); // 75% duty Delay_Ms(1000); } } ``` -------------------------------- ### Main Function for CH32V307 ADC DMA Example in C Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt The main function demonstrates the usage of the ADC DMA initialization and processing of received samples. It initializes the ADC with DMA, enables the DMA channel, and starts ADC conversion. After the DMA transfer is complete, it iterates through the received samples, applies calibration, and prints each sample value. ```c int main(void) { ADC_DMA_Init(); DMA_Cmd(DMA1_Channel1, ENABLE); ADC_SoftwareStartConvCmd(ADC1, ENABLE); // Wait for DMA transfer complete while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); // Process 1024 samples in TxBuf for(int i = 0; i < 1024; i++) { printf("Sample[%d]: %d\r\n", i, Get_ConversionVal(TxBuf[i])); } } ``` -------------------------------- ### RTC Initialization and Time Management in C Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt This C code snippet demonstrates the initialization of the Real-Time Clock (RTC) module, including setting the time and date. It handles LSE clock source configuration, prescaler setup, and enables second interrupts. The code also includes functions to set and retrieve the current time, along with an RTC interrupt handler. ```c #include "ch32v30x.h" typedef struct { uint8_t hour, min, sec; uint16_t year; uint8_t month, day, week; } Calendar_t; Calendar_t calendar; const uint8_t mon_table[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; uint8_t Is_Leap_Year(uint16_t year) { return ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))); } // RTC Initialization uint8_t RTC_Init(void) { uint16_t timeout = 0; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); // Check if RTC already configured if(BKP_ReadBackupRegister(BKP_DR1) != 0xA1A1) { BKP_DeInit(); RCC_LSEConfig(RCC_LSE_ON); while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET && timeout < 250) { timeout++; Delay_Ms(20); } if(timeout >= 250) return 1; // LSE startup failed RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); RTC_WaitForLastTask(); RTC_WaitForSynchro(); RTC_ITConfig(RTC_IT_SEC, ENABLE); RTC_WaitForLastTask(); RTC_EnterConfigMode(); RTC_SetPrescaler(32767); // 32.768kHz / 32768 = 1Hz RTC_WaitForLastTask(); RTC_Set(2024, 1, 1, 0, 0, 0); // Initial time RTC_ExitConfigMode(); BKP_WriteBackupRegister(BKP_DR1, 0xA1A1); } else { RTC_WaitForSynchro(); RTC_ITConfig(RTC_IT_SEC, ENABLE); RTC_WaitForLastTask(); } NVIC_EnableIRQ(RTC_IRQn); RTC_Get(); return 0; } // Set RTC time uint8_t RTC_Set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) { uint32_t seccount = 0; if(year < 1970 || year > 2099) return 1; // Calculate seconds since 1970-01-01 for(uint16_t t = 1970; t < year; t++) { seccount += Is_Leap_Year(t) ? 31622400 : 31536000; } for(uint8_t t = 0; t < month - 1; t++) { seccount += (uint32_t)mon_table[t] * 86400; if(Is_Leap_Year(year) && t == 1) seccount += 86400; } seccount += (uint32_t)(day - 1) * 86400; seccount += (uint32_t)hour * 3600 + (uint32_t)min * 60 + sec; RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); RTC_SetCounter(seccount); RTC_WaitForLastTask(); return 0; } // Read RTC time void RTC_Get(void) { uint32_t timecount = RTC_GetCounter(); uint32_t temp = timecount / 86400; uint16_t temp1 = 1970; while(temp >= 365) { if(Is_Leap_Year(temp1)) { if(temp >= 366) temp -= 366; else break; } else temp -= 365; temp1++; } calendar.year = temp1; temp1 = 0; while(temp >= 28) { if(Is_Leap_Year(calendar.year) && temp1 == 1) { if(temp >= 29) temp -= 29; else break; } else { if(temp >= mon_table[temp1]) temp -= mon_table[temp1]; else break; } temp1++; } calendar.month = temp1 + 1; calendar.day = temp + 1; temp = timecount % 86400; calendar.hour = temp / 3600; calendar.min = (temp % 3600) / 60; calendar.sec = temp % 60; } void RTC_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_SEC) != RESET) { RTC_Get(); printf("%04d-%02d-%02d %02d:%02d:%02d\r\n", calendar.year, calendar.month, calendar.day, calendar.hour, calendar.min, calendar.sec); } RTC_ClearITPendingBit(RTC_IT_SEC | RTC_IT_OW); RTC_WaitForLastTask(); } int main(void) { if(RTC_Init() == 0) { printf("RTC Init Success\r\n"); } // Set alarm for 10 seconds from now uint32_t alarm_time = RTC_GetCounter() + 10; RTC_SetAlarm(alarm_time); RTC_ITConfig(RTC_IT_ALR, ENABLE); while(1) { // RTC updates via interrupt } } ``` -------------------------------- ### Main Program Body Example (C) Source: https://github.com/zh-commander/qingheng-ch32v307-document/blob/main/Docs/WCH-LinkUserManual-EN.md This C code snippet represents the main program body for the CH32V307 microcontroller. It includes author information, version, date, and copyright details. It also declares a buffer `TaBuf` and a calibration value `Calibration_Val`. This code is intended for microcontrollers manufactured by Nanjing Ouheng Microelectronics Co. ```c // File Name : Main.c // Author : WCH // Version : V1.0.0 // Date : 2019/10/18 // Description : Main program body // No UUNLK2/ME Device found // Copyright (c) 2021 Nanjing Ouheng Microelectronics Co., Ltd. // attention: This software (modified or not) and binary are used for microcontrollers manufactured by Nanjing Ouheng Microelectronics Co. // Microcontrollers manufactured by Nanjing Ouheng Microelectronics Co. // UUNLK2/ME Cortex-M Error X // Main program body. // No UUNLK2/ME Device found // Main program body. // No UUNLK2/ME Device found // No UUNLK2/ME Device found // Main program body. // No UUNLK2/ME Device found // No UUNLK2/ME Device found // No UUNLK2/ME Device found // No UUNLK2/ME Device found // No Global Variable +/- // Global Variable +/- u6 TaBuf[1024]; u6 Calibration_Val = 0; // Main program body. // Main program body. ``` ```c // File Name : Main.c // Author : WCH // Version : V1.0.0 // Date : 2021/08/08 // Description : Main program body. // No UUNLK2/ME Device found // Copyright (c) 2021 Nanjing Ouheng Microelectronics Co., Ltd. // attention: This software (modified or not) and binary are used for microcontrollers manufactured by Nanjing Ouheng Microelectronics Co. // No UUNLK2/ME Device found // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- // No Global Variable +/- u6 TaBuf[1024]; u6 Calibration_Val = 0; // Main program body. // Main program body. ``` -------------------------------- ### CH32V307 Main Function with DMA M2M Transfer Example (C) Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt The main function initializes DMA for memory-to-memory transfer and configures DMA interrupts. It then waits for the transfer to complete using a flag status check and verifies the data integrity by comparing source and destination buffers. ```c #include "ch32v30x.h" // Assume DMA_M2M_Init() and DMA_INT_Init() are defined elsewhere // Assume SRC_Buffer and DST_Buffer are defined and initialized int main(void) { // Placeholder for actual initialization functions // DMA_M2M_Init(); // DMA_INT_Init(); // Example usage within main (assuming buffers and init are done) uint32_t SRC_Buffer[32] = {0x01020304, 0x05060708, /* ... */}; uint32_t DST_Buffer[32]; // Mock initialization for demonstration purposes RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_Cmd(DMA1_Channel1, ENABLE); // Wait for transfer complete (using flag status) while(DMA_GetFlagStatus(DMA1_FLAG_TC1) == RESET); // Verify transfer uint8_t success = 1; for(int i = 0; i < 32; i++) { if(SRC_Buffer[i] != DST_Buffer[i]) { success = 0; break; } } printf("DMA M2M: %s\r\n", success ? "PASS" : "FAIL"); return 0; } ``` -------------------------------- ### Configure GPIO Output and External Interrupts for CH32V307 Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt Demonstrates configuring GPIO pins for output (LED blinking) and setting up external interrupts for pin changes on the CH32V307 microcontroller. Requires the 'ch32v30x.h' header and standard peripheral libraries. ```c #include "ch32v30x.h" // GPIO Output Configuration - LED Blink Example void GPIO_Toggle_INIT(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; // Enable GPIOA clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Configure PA0 as push-pull output GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } // GPIO External Interrupt Configuration void EXTI0_INT_INIT(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; EXTI_InitTypeDef EXTI_InitStructure = {0}; NVIC_InitTypeDef NVIC_InitStructure = {0}; // Enable AFIO and GPIOA clocks RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOA, ENABLE); // Configure PA0 as input with pull-up GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOA, &GPIO_InitStructure); // Map GPIO to EXTI line GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); // Configure EXTI for falling edge trigger EXTI_InitStructure.EXTI_Line = EXTI_Line0; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); // Configure NVIC NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } // Interrupt handler void EXTI0_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line0) != RESET) { // Handle button press GPIO_WriteBit(GPIOA, GPIO_Pin_0, (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_0) == Bit_SET) ? Bit_RESET : Bit_SET); EXTI_ClearITPendingBit(EXTI_Line0); } } int main(void) { uint8_t i = 0; GPIO_Toggle_INIT(); while(1) { Delay_Ms(250); GPIO_WriteBit(GPIOA, GPIO_Pin_0, (i == 0) ? (i = Bit_SET) : (i = Bit_RESET)); } } ``` -------------------------------- ### Initialize Ethernet and TCP Server (C) Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt Initializes the Ethernet controller and sets up a TCP server on a specified port. It requires the WCHNET library and basic network configurations like IP addresses and MAC address. The function configures a timer for the network stack and then initializes the Ethernet library. Finally, it creates a TCP listening socket. ```c #include "ch32v30x.h" #include "WCHNET.h" uint8_t MACAddr[6]; uint8_t IPAddr[4] = {192, 168, 1, 10}; uint8_t GWIPAddr[4] = {192, 168, 1, 1}; uint8_t IPMask[4] = {255, 255, 255, 0}; uint8_t SocketId; uint8_t RecvBuffer[2048]; // Network timer (required for TCP/IP stack) void TIM2_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0}; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / 1000000; TIM_TimeBaseStructure.TIM_Prescaler = WCHNETTIMERPERIOD * 1000 - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); TIM_Cmd(TIM2, ENABLE); NVIC_EnableIRQ(TIM2_IRQn); } // Ethernet Initialization void ETH_Init(void) { WCHNET_GetMacAddr(MACAddr); printf("MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", MACAddr[0], MACAddr[1], MACAddr[2], MACAddr[3], MACAddr[4], MACAddr[5]); TIM2_Init(); if(ETH_LibInit(IPAddr, GWIPAddr, IPMask, MACAddr) == 0) { printf("ETH_LibInit Success\r\n"); } } // Create TCP Server void TCP_Server_Init(uint16_t port) { SOCK_INF socket_cfg; memset(&socket_cfg, 0, sizeof(SOCK_INF)); socket_cfg.SourPort = port; socket_cfg.RecvBufLen = sizeof(RecvBuffer); SocketId = WCHNET_SocketCreat(&socket_cfg); WCHNET_SocketListen(SocketId); printf("TCP Server listening on port %d\r\n", port); } // Socket interrupt handler void WCHNET_HandleSockInt(uint8_t sockeid, uint8_t initstat) { if(initstat & SINT_STAT_RECV) { uint32_t len = sizeof(RecvBuffer); WCHNET_SocketRecv(sockeid, RecvBuffer, &len); printf("Received %d bytes\r\n", len); // Echo back WCHNET_SocketSend(sockeid, RecvBuffer, &len); } if(initstat & SINT_STAT_CONNECT) { printf("Client connected\r\n"); } if(initstat & SINT_STAT_DISCONNECT) { printf("Client disconnected\r\n"); } } // Global interrupt handler void WCHNET_HandleGlobalInt(void) { uint8_t intstat = WCHNET_GetGlobalInt(); if(intstat & GINT_STAT_UNREACH) WCHNET_ClearGlobalInt(GINT_STAT_UNREACH); if(intstat & GINT_STAT_IP_CONFLI) printf("IP Conflict!\r\n"); if(intstat & GINT_STAT_PHY_CHANGE) { printf("PHY Status Changed\r\n"); WCHNET_ClearGlobalInt(GINT_STAT_PHY_CHANGE); } if(intstat & GINT_STAT_SOCKET) { for(uint8_t i = 0; i < WCHNET_MAX_SOCKET_NUM; i++) { uint8_t socketint = WCHNET_GetSocketInt(i); if(socketint) WCHNET_HandleSockInt(i, socketint); } } } int main(void) { ETH_Init(); TCP_Server_Init(8080); while(1) { WCHNET_MainTask(); if(WCHNET_QueryGlobalInt()) WCHNET_HandleGlobalInt(); } } ``` -------------------------------- ### Start DHCP with WCHNET_DHCPStart Source: https://github.com/zh-commander/qingheng-ch32v307-document/blob/main/Docs/WCHNET Protocol Stack Library Application Note.md The WCHNET_DHCPStart function initiates the Dynamic Host Configuration Protocol (DHCP) process. It requires a callback function that will be invoked upon DHCP success or failure. Successful DHCP provides network configuration details via the callback. This function occupies a UDP socket and should be called after WCHNET_Init. ```c void my_dhcp_callback(uint8_t status, void *data) { if (status == 0) { // Success // Process IP address and other network details from data } else { // Failure // Handle DHCP failure } } // Start DHCP process WCHNET_DHCPStart(my_dhcp_callback); ``` -------------------------------- ### Configure PWM Output using TIM1 Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt Configures TIM1 to generate a PWM signal on a specified pin (PA8 in this example). This function sets up the timer base and the Output Compare channel for PWM mode. It requires GPIO and TIM1 clocks to be enabled, and the GPIO pin to be configured as an alternate function push-pull. The duty cycle can be adjusted by modifying the TIM_OCInitStructure.TIM_Pulse value. ```c #include "ch32v30x.h" // PWM Output Configuration void PWM_Init(uint16_t arr, uint16_t psc, uint16_t ccp) { GPIO_InitTypeDef GPIO_InitStructure = {0}; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure = {0}; TIM_OCInitTypeDef TIM_OCInitStructure = {0}; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE); // PA8 as TIM1_CH1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); TIM_TimeBaseStructure.TIM_Period = arr; TIM_TimeBaseStructure.TIM_Prescaler = psc; TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); // PWM Mode 1 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse = ccp; // Duty cycle TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC1Init(TIM1, &TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM1, ENABLE); TIM_CtrlPWMOutputs(TIM1, ENABLE); // Required for advanced timers TIM_Cmd(TIM1, ENABLE); } ``` -------------------------------- ### Configure CH32V307 ADC with DMA in C Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt Initializes the CH32V307's ADC1 peripheral for continuous conversion using DMA transfer. It configures GPIO pins, DMA settings, and ADC parameters. The function enables ADC, DMA, and starts the conversion process. Dependencies include the 'ch32v30x.h' header and related RCC, GPIO, ADC, and DMA configuration functions. ```c #include "ch32v30x.h" volatile int16_t Calibrattion_Val = 0; uint16_t TxBuf[1024]; // ADC with DMA Configuration void ADC_DMA_Init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; ADC_InitTypeDef ADC_InitStructure = {0}; DMA_InitTypeDef DMA_InitStructure = {0}; // Enable clocks RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div8); // ADC clock = PCLK2/8 // Configure PA1 as analog input GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOA, &GPIO_InitStructure); // Configure DMA for ADC DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->RDATAR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuf; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 1024; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(DMA1_Channel1, &DMA_InitStructure); // Configure ADC ADC_DeInit(ADC1); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = DISABLE; ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel = 1; ADC_Init(ADC1, &ADC_InitStructure); // Configure channel and calibration ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_239Cycles5); ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE); // Calibration sequence ADC_BufferCmd(ADC1,DISABLE); ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); Calibrattion_Val = Get_CalibrationValue(ADC1); } ``` -------------------------------- ### Get WCHNET Library Version Source: https://github.com/zh-commander/qingheng-ch32v307-document/blob/main/Docs/WCHNET Protocol Stack Library Application Note.md Retrieves the version of the WCHNET library. This function takes no input parameters and returns the library version as a uint8_t. ```c uint8_t WCHNET_GetVer(void); ``` -------------------------------- ### CH32V307 USBFS Device Initialization and Handler (C) Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt This C code snippet demonstrates the initialization of the USB Full-Speed (USBFSP) controller on the CH32V307 microcontroller. It includes setting up clock configurations, device descriptors, endpoint configurations, and the interrupt handler for USB events. The code configures endpoints for both transmit (TX) and receive (RX) operations and handles bus reset and transfer completion interrupts. ```c #include "ch32v30x.h" #include "usb_lib.h" __attribute__((aligned(4))) uint8_t EP0_Buf[64]; __attribute__((aligned(4))) uint8_t EP1_Buf[64]; // USB Device Descriptors const uint8_t DeviceDescriptor[] = { 0x12, // bLength 0x01, // bDescriptorType: Device 0x10, 0x01, // bcdUSB: USB 1.1 0x00, // bDeviceClass 0x00, // bDeviceSubClass 0x00, // bDeviceProtocol 0x40, // bMaxPacketSize0: 64 bytes 0x86, 0x1A, // idVendor: 0x1A86 (WCH) 0x37, 0x55, // idProduct: 0x5537 0x00, 0x01, // bcdDevice 0x01, // iManufacturer 0x02, // iProduct 0x03, // iSerialNumber 0x01 // bNumConfigurations }; // USB Clock Configuration void USBFS_RCC_Init(void) { if(SystemCoreClock == 144000000) RCC_USBFSCLKConfig(RCC_USBFSCLKSource_PLLCLK_Div3); else if(SystemCoreClock == 96000000) RCC_USBFSCLKConfig(RCC_USBFSCLKSource_PLLCLK_Div2); else if(SystemCoreClock == 48000000) RCC_USBFSCLKConfig(RCC_USBFSCLKSource_PLLCLK_Div1); RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBFS, ENABLE); } // USB Device Initialization void USBFS_Device_Init(void) { // Reset USB controller USBFSH->BASE_CTRL = USBFS_UC_RESET_SIE | USBFS_UC_CLR_ALL; Delay_Us(10); USBFSH->BASE_CTRL = 0x00; // Configure endpoints USBFSD->UEP4_1_MOD = USBFS_UEP1_RX_EN; USBFSD->UEP2_3_MOD = USBFS_UEP2_TX_EN; USBFSD->UEP0_DMA = (uint32_t)EP0_Buf; USBFSD->UEP1_DMA = (uint32_t)EP1_Buf; USBFSD->UEP0_RX_CTRL = USBFS_UEP_R_RES_ACK; USBFSD->UEP0_TX_CTRL = USBFS_UEP_T_RES_NAK; USBFSD->UEP1_RX_CTRL = USBFS_UEP_R_RES_ACK; USBFSD->UEP2_TX_CTRL = USBFS_UEP_T_RES_NAK; // Enable interrupts USBFSD->INT_EN = USBFS_UIE_SUSPEND | USBFS_UIE_BUS_RST | USBFS_UIE_TRANSFER; USBFSD->BASE_CTRL = USBFS_UC_DEV_PU_EN | USBFS_UC_INT_BUSY | USBFS_UC_DMA_EN; USBFSD->UDEV_CTRL = USBFS_UD_PD_DIS | USBFS_UD_PORT_EN; NVIC_EnableIRQ(USBFS_IRQn); } void USBFS_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast"))); void USBFS_IRQHandler(void) { uint8_t intflag = USBFSD->INT_FG; if(intflag & USBFS_UIF_TRANSFER) { uint8_t ep_status = USBFSD->INT_ST & USBFS_UIS_TOKEN_MASK; uint8_t ep_num = (USBFSD->INT_ST & USBFS_UIS_ENDP_MASK); switch(ep_status) { case USBFS_UIS_TOKEN_IN: // IN transfer complete break; case USBFS_UIS_TOKEN_OUT: if(ep_num == 1) { uint8_t len = USBFSD->RX_LEN; // Process received data in EP1_Buf } break; } USBFSD->INT_FG = USBFS_UIF_TRANSFER; } if(intflag & USBFS_UIF_BUS_RST) { USBFSD->INT_FG = USBFS_UIF_BUS_RST; // Reset device state } } int main(void) { USBFS_RCC_Init(); USBFS_Device_Init(); while(1) { // USB handled by interrupts } } ``` -------------------------------- ### Configure SPI Master Mode on CH32V307 Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt Initializes the SPI1 peripheral in master mode for full-duplex communication. Configures GPIO pins for SCK, MOSI, and MISO, and sets SPI parameters like data size, clock polarity/phase, and baud rate. Requires CH32V30x HAL library. ```c #include "ch332v30x.h" // SPI Master Full-Duplex Configuration void SPI_Master_Init(void) { GPIO_InitTypeDef GPIO_InitStructure = {0}; SPI_InitTypeDef SPI_InitStructure = {0}; // Enable clocks RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE); // SCK (PA5) and MOSI (PA7) as alternate function push-pull GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // MISO (PA6) as floating input GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // Configure SPI1 as Master SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; SPI_InitStructure.SPI_CRCPolynomial = 7; SPI_Init(SPI1, &SPI_InitStructure); SPI_Cmd(SPI1, ENABLE); } ``` -------------------------------- ### Get Host IP Address via WCHNET Source: https://github.com/zh-commander/qingheng-ch32v307-document/blob/main/Docs/WCHNET Protocol Stack Library Application Note.md Retrieves the IP address for a given hostname. It can return a cached IP or initiate a DNS query. A callback function is used to handle the result. The output buffer for the IP address must be 4-byte aligned, and the hostname cannot exceed 63 characters. ```c uint8_t WCHNET_HostNameGetIp( const char *hostname, uint8_t *addr, dns_cal11back found, void *arg ); typedef void (*dns_callback)(const char *name, uint8_t *ipaddr, void*callback_arg); ``` -------------------------------- ### Main Function for SPI Full-Duplex Transfer on CH32V307 Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt The main function initializes the SPI1 peripheral in master mode and then performs a continuous full-duplex data transfer. It sends data from TxData and receives data into RxData until all elements are processed. This example demonstrates basic SPI operation without CRC. ```c #include "ch332v30x.h" uint16_t TxData[18] = {0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, 0x0808, 0x0909, 0x0A0A, 0x0B0B, 0x0C0C, 0x0D0D, 0x0E0E, 0x0F0F, 0x1010, 0x1111, 0x1212}; uint16_t RxData[18]; // Placeholder for SPI_Master_Init function definition void SPI_Master_Init(void) { // ... implementation from previous snippet ... } int main(void) { uint16_t i = 0, j = 0; SPI_Master_Init(); // Full-duplex transfer while((i < 18) || (j < 18)) { if(i < 18 && SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) != RESET) { SPI_I2S_SendData(SPI1, TxData[i++]); } if(j < 18 && SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) != RESET) { RxData[j++] = SPI_I2S_ReceiveData(SPI1); } } return 0; // Added return statement for completeness } ``` -------------------------------- ### Initialize WCHNET Library Source: https://github.com/zh-commander/qingheng-ch32v307-document/blob/main/Docs/WCHNET Protocol Stack Library Application Note.md Initializes the WCHNET library with network configuration. It takes IP address, gateway, subnet mask, and MAC address as input. The subnet mask can be NULL, in which case a default of 255.255.255.0 is used. Returns 0 on success, or an error code. ```c uint8_t WCHNET_Init(const uint8_t *ip, const uint8_t *gwip, const uint8_t *mask, const uint8_t *macaddr); ``` -------------------------------- ### Create and Connect TCP Client Socket Source: https://github.com/zh-commander/qingheng-ch32v307-document/blob/main/Docs/WCHNET Protocol Stack Library Application Note.md This snippet outlines the sequence of function calls required to create a TCP client socket and initiate a connection. It involves setting socket parameters like ports, IP address, buffer details, and protocol type before calling creation and connection functions. The WCHNET library handles the underlying network operations. ```c /* * Procedures to create a TCP client socket: * 1. Set the source port. * 2. Set the target port. * 3. Set the target IP address. * 4. Set the start address and the length of the receive buffer. * 5. Set the protocol type to PROTO_TYPE_TCP. * 6. Call the WCHNET_SocketCreat function. * 7. Call the WCHNET_SocketConnect function. */ // Example placeholder for function calls (actual implementation depends on WCHNET library) // WCHNET_SocketCreat(source_port, target_port, target_ip, receive_buffer_addr, receive_buffer_len, PROTO_TYPE_TCP); // WCHNET_SocketConnect(socket_descriptor); ``` -------------------------------- ### Configure CH32V307 for I2C Master and EEPROM Operations (C) Source: https://context7.com/zh-commander/qingheng-ch32v307-document/llms.txt This C code snippet demonstrates how to initialize the I2C1 peripheral on the CH32V307 microcontroller to operate as an I2C master. It configures the necessary GPIO pins (PB8/PB9) for I2C communication, sets the clock speed, and configures the I2C mode. The snippet also includes functions for writing a single byte to an EEPROM and reading a single byte from an EEPROM, handling the I2C start, address transmission, data transfer, and stop conditions. ```c #include "ch32v30x.h" #define EEPROM_ADDR 0xA0 // I2C Master Configuration void I2C_Master_Init(uint32_t speed, uint16_t address) { GPIO_InitTypeDef GPIO_InitStructure = {0}; I2C_InitTypeDef I2C_InitStructure = {0}; // Enable clocks RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // Remap I2C1 to PB8/PB9 GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE); // SCL (PB8) and SDA (PB9) as open-drain GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // Configure I2C1 I2C_InitStructure.I2C_ClockSpeed = speed; I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_16_9; I2C_InitStructure.I2C_OwnAddress1 = address; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_Init(I2C1, &I2C_InitStructure); I2C_Cmd(I2C1, ENABLE); } // Write byte to EEPROM void EEPROM_WriteByte(uint16_t addr, uint8_t data) { while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET); I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, EEPROM_ADDR, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); // Send memory address (16-bit for larger EEPROMs) I2C_SendData(I2C1, (uint8_t)(addr >> 8)); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_SendData(I2C1, (uint8_t)(addr & 0xFF)); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // Send data I2C_SendData(I2C1, data); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); Delay_Ms(5); // EEPROM write cycle time } // Read byte from EEPROM uint8_t EEPROM_ReadByte(uint16_t addr) { uint8_t data; while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) != RESET); // Send address I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, EEPROM_ADDR, I2C_Direction_Transmitter); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1, (uint8_t)(addr >> 8)); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_SendData(I2C1, (uint8_t)(addr & 0xFF)); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // Repeated start for read I2C_GenerateSTART(I2C1, ENABLE); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, EEPROM_ADDR, I2C_Direction_Receiver); while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); I2C_AcknowledgeConfig(I2C1,DISABLE); while(I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == RESET); data = I2C_ReceiveData(I2C1); I2C_GenerateSTOP(I2C1, ENABLE); I2C_AcknowledgeConfig(I2C1, ENABLE); return data; } int main(void) { I2C_Master_Init(100000, 0x02); // 100kHz, own address 0x02 EEPROM_WriteByte(0x0000, 0xAB); uint8_t read = EEPROM_ReadByte(0x0000); printf("Read: 0x%02X\r\n", read); // Output: Read: 0xAB } ``` -------------------------------- ### UDP Client Socket Creation Source: https://github.com/zh-commander/qingheng-ch32v307-document/blob/main/Docs/WCHNET Protocol Stack Library Application Note.md This section describes the steps and function calls required to create a UDP client socket. ```APIDOC ## UDP Client Socket Creation ### Description Procedures to create a UDP socket for client communication. ### Method `WCHNET_SocketCreat` ### Parameters - **Source Port**: (integer) - The port number for the client. - **Target Port**: (integer) - The port number of the server. - **Target IP Address**: (string) - The IP address of the server. - **Receive Buffer Start Address**: (pointer) - The starting address of the buffer to store received data. - **Receive Buffer Length**: (integer) - The maximum length of the receive buffer. - **Protocol Type**: (constant) - Set to `PROTO_TYPE_UDP`. ### Request Example ``` // Example procedure (actual code depends on library implementation) int source_port = 12345; int target_port = 8080; char* target_ip = "192.168.1.100"; char receive_buffer[1024]; int buffer_length = 1024; WCHNET_SocketCreat(source_port, target_port, target_ip, receive_buffer, buffer_length, PROTO_TYPE_UDP); ``` ### Response #### Success Response - **Socket Information**: (pointer) - A pointer to the created socket information structure. #### Error Response - **Error Code**: (integer) - Indicates failure, e.g., if no free socket information list is found. ### UDP Message Structure `Target MAC (6 Bytes) | Source MAC (6 Bytes) | Type (2 Bytes) | IP header (20 Bytes) | UDP header (8 Bytes) | UDP data (Max 1472 Bytes) | CRC32 (4 Bytes)` ### Sending UDP Data - **Function**: `WCHNET_SocketSend` - **Maximum Packet Length**: 1472 bytes. ### Receiving UDP Data - **Interrupt**: `SINT_STAT_RECV` is generated upon receiving UDP data. - **Get Length**: Call `WCHNET_SocketRecvLen` to get the effective length of the received data. - **Read Data**: Call `WCHNET_SocketRecv` to read data from the receive buffer. - **Recommendation**: Read all data immediately after the receive interrupt to avoid data overwrites. ```