DMA timed data transfer on ch32v307 - Page 1
Forum section: electronics / general

author: ali_asadzadeh
author_rank: Super Contributor
timestamp: June 15, 2025, 03:02:13 pm
content: Hi,I want to use an external clock to trigger DMA to transfer Data to USART1 of CH32v307 , Here is my code and it's not working, I'm pulling out my hair as what's wrong and i can not figure it out, Do you have any Idea what might be wrong?Code:/********************************** (C) COPYRIGHT ******************************** File Name : main.c* Author : WCH* Version : V1.0.0* Date : 2021/06/06* Description : Main program body.********************************************************************************** Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.* Attention: This software (modified or not) and binary are used for* microcontroller manufactured by Nanjing Qinheng Microelectronics.*******************************************************************************//**@NoteUSART Print debugging routine:USART1_Tx(PA9).This example demonstrates using USART1(PA9) as a print debug port output.*/#include "debug.h"/* Global typedef *//* Global define */#define Size 100volatile uint16_t TxData = { 0 };volatile uint16_t RxData = { 0 };/* Global Variable */void TIM1_ExternalClock_Init(void) {TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// Reset TIM1TIM_DeInit(TIM1);// Configure TIM1 in external clock modeTIM_TimeBaseStructure.TIM_Period = 0xFFFF; // Trigger on every edge (no reload)TIM_TimeBaseStructure.TIM_Prescaler = 0; // No prescalingTIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);// Configure external clock source (ETR)TIM_ETRClockMode1Config(TIM1, TIM_ExtTRGPSC_OFF, TIM_ExtTRGPolarity_NonInverted, 0);TIM_SelectInputTrigger(TIM1, TIM_TS_ETRF); // External trigger on ETR// Enable TIM1 update DMA requestTIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);// Select TRGO as Update EventTIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update);}/********************************************************************** @fn main** @brief Main program.** @return none*/int main(void){NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);SystemCoreClockUpdate();Delay_Init();USART_Printf_Init(115200);printf("SystemClk:%d\r\n",SystemCoreClock);printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );printf("This is printf example\r\n");for (int i = 0; i < Size; i++) {TxData = i;}TxData = -1;USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE); // Enable DMA request for TX// Enable clocks for GPIOA, TIM1, and DMA1RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// Configure PA12 as TIM1_ETR (alternate function, input)GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // Input with pull-upGPIO_Init(GPIOA, &GPIO_InitStructure);TIM1_ExternalClock_Init();// Configure DMA1 Channel1 for memory-to-peripheral transferDMA_InitTypeDef DMA_InitStructure = {0};DMA_DeInit(DMA1_Channel5);DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DATAR; // SourceDMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) TxData; // DestinationDMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // Memory-to-memory (source is "peripheral")DMA_InitStructure.DMA_BufferSize = 1; // Number of transfersDMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Disable peripheral source address IncDMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Increment destination addressDMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 32-bitDMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 32-bitDMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // Circular modeDMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; // Memory-to-memory modeDMA_Init(DMA1_Channel5, &DMA_InitStructure);// Enable DMA channelDMA_Cmd(DMA1_Channel5, ENABLE);// Enable TIM1 to start generating update eventsTIM_Cmd(TIM1, ENABLE);printf("TIM1 %d \r\n",TIM1->CNT);while(1){//printf("TIM1 %d \r\n",TIM1->CNT);Delay_Ms(100);}}

author: voltsandjolts
author_rank: Unknown
timestamp: June 15, 2025, 03:32:11 pm
content: Misleading comments make it harder to understand your code.IIUC:DMA_M2M_Enable should be DMA_M2M_Disable

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 15, 2025, 04:20:06 pm
content: That probably comes from c/c, so other comments don't match the code.Looking at the DMA config, DMA_PeripheralDataSize is not commented properly (32-bit but should be 8-bit), the config looks right though.DMA_MemoryDataSize is set to DMA_MemoryDataSize_HalfWord, which I think is 16-bit (and the comment is 32-bit).Why do you use buffers of 16-bit words? As it is, it will only transfer the LSbyte to UART.You also probably don't want to enable DMA_Mode_Circular, nor DMA_M2M_Enable (memory-to-memory). You should set the latter to DMA_M2M_Disable. As to the circular mode, with DMA_BufferSize set to 1, it will send the first byte of the TX buffer at each trigger, without the need to reconfigure DMA. Maybe that's what you intended for testing purposes. Not sure. If not, you need to change that.DMA_DIR is also improperly commented IMO: "Memory-to-memory (source is "peripheral")" doesn't seem to make sense. It's either memory-to-peripheral (should be here) or memory-to-memory.You set DMA_BufferSize to 1. It will only transfer *one word* of data (with your settings, it will read the first 16-bit word of the buffer and send the LSbyte to the UART). Is this what you want? (See above.)Just a few points to look at. The one thing that (as far as I can tell) prevents transfers to happen is enabling DMA memory-to-memory, which is not correct for memory to peripheral or peripheral to memory transfers. The rest depends on what you want to achieve.

author: ali_asadzadeh
author_rank: Super Contributor
timestamp: June 16, 2025, 11:21:44 am
content: Thanks for the inputs,Now the code is workingCode:/********************************** (C) COPYRIGHT ******************************** File Name : main.c* Author : WCH* Version : V1.0.0* Date : 2021/06/06* Description : Main program body.********************************************************************************** Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.* Attention: This software (modified or not) and binary are used for* microcontroller manufactured by Nanjing Qinheng Microelectronics.*******************************************************************************//**@NoteUSART Print debugging routine:USART1_Tx(PA9).This example demonstrates using USART1(PA9) as a print debug port output.*/#include "debug.h"/* Global typedef *//* Global define */#define Size 13volatile uint8_t TxData = { "ASiDesigner\r\n" };volatile uint8_t RxData = { 0 };/* Global Variable */void TIM1_Init(void) {TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure = {0};RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);TIM_TimeBaseInitStructure.TIM_Period = 0xFFFF;TIM_TimeBaseInitStructure.TIM_Prescaler = 0x00FF;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);TIM_ARRPreloadConfig(TIM1, ENABLE);}void TIM1_DMA_Init(DMA_Channel_TypeDef *DMA_CHx, u32 ppadr, u32 memadr, u16 bufsize){DMA_InitTypeDef DMA_InitStructure = {0};RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);DMA_DeInit(DMA_CHx);DMA_InitStructure.DMA_PeripheralBaseAddr = ppadr;DMA_InitStructure.DMA_MemoryBaseAddr = memadr;DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_BufferSize = bufsize;DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;DMA_Init(DMA_CHx, &DMA_InitStructure);DMA_Cmd(DMA_CHx, ENABLE);}/********************************************************************** @fn main** @brief Main program.** @return none*/int main(void){NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);SystemCoreClockUpdate();Delay_Init();USART_Printf_Init(115200);printf("SystemClk:%d\r\n",SystemCoreClock);printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );printf("This is printf example\r\n");TIM1_Init();TIM1_DMA_Init(DMA1_Channel5, (u32)&USART1->DATAR, (u32)TxData, Size);TIM_DMACmd(TIM1, TIM_DMA_Update, ENABLE);TIM_Cmd(TIM1, ENABLE);while(1){}}I have an Idea that would make this chip a poor mans low cost Logic analyzer, with the help of time sampled DMA transfers, the ADC,DAC and USBH, I wonder how to connect it to an opensource PC side software

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 16, 2025, 05:16:13 pm
content: Well, you'll get much higher sample rate with a RP2350 using the PIO (and there are numerous projects using the RP2040 for this, and now the RP2350). It also has a lot more RAM.Granted, the CH32V307 has USB HS and the RP2350 only USB FS.Wouldn't you wish a CH32Vxxx with something similar to the RPi PIO?(Or a RP2xxxx with a USB HS controller, depending on your perspective.)