ZHDA102 March 2026 MSPM0G3519
TIMA 通过利用其输出生成功能、影子 CCACT 功能和重复计数器机制,为 UART 发送器仿真提供稳健的解决方案。通过整合 DMA 传输可以显著提升此实现的性能,从而创建优化系统资源的端到端解决方案。通过 DMA 处理数据移动,可以更大限度地减少 CPU 干预,同时确保精确的位时序和可靠的数据传输。
这种集成的计时器 DMA 方法消除了对中断优先级的依赖,并保证一致的时序精度。该解决方案可确保确定性的行为,使其成为位操作仿真应用的理想选择。图 4-3 展示了使用 TIMA 作为 UART Tx 的流程图。
图 4-3 展示 UART Tx 的流程图配置序列如下详述:
/* Timer Configuration for Emulating UART Tx with DMA */
//For 9600 baud rate, single bit duration is 104.167us, hence configuring LOAD value as 3333, with 32MHz clock
static const DL_TimerA_ClockConfig gPWM_0ClockConfig = {
.clockSel = DL_TIMER_CLOCK_BUSCLK,
.divideRatio = DL_TIMER_CLOCK_DIVIDE_1,
.prescale = 0U
};
static const DL_TimerA_PWMConfig gPWM_0Config = {
.pwmMode = DL_TIMER_PWM_MODE_EDGE_ALIGN_UP,
.period = 3333,
.isTimerWithFourCC = false,
.startTimer = DL_TIMER_STOP,
};
SYSCONFIG_WEAK void SYSCFG_DL_PWM_0_init(void) {
DL_TimerA_setClockConfig(
PWM_0_INST, (DL_TimerA_ClockConfig *) &gPWM_0ClockConfig);
DL_TimerA_initPWMMode(
PWM_0_INST, (DL_TimerA_PWMConfig *) &gPWM_0Config);
DL_TimerA_setCounterControl(PWM_0_INST,DL_TIMER_CZC_CCCTL0_ZCOND,DL_TIMER_CAC_CCCTL0_ACOND,DL_TIMER_CLC_CCCTL0_LCOND);
DL_TimerA_setCaptureCompareOutCtl(PWM_0_INST, DL_TIMER_CC_OCTL_INIT_VAL_HIGH, //Keeping CC0 initial value as HIGH as UART idle state should be HIGH
DL_TIMER_CC_OCTL_INV_OUT_DISABLED, DL_TIMER_CC_OCTL_SRC_FUNCVAL,
DL_TIMERA_CAPTURE_COMPARE_0_INDEX);
PWM_0_INST->COUNTERREGS.CCACT_01[0]=0x2;//Configuring Zero action as CC Output LOW, as START bit in UART is always LOW
DL_TimerA_setCaptCompUpdateMethod(PWM_0_INST, DL_TIMER_CC_UPDATE_METHOD_IMMEDIATE, DL_TIMERA_CAPTURE_COMPARE_0_INDEX);
DL_Timer_setCaptCompActUpdateMethod(PWM_0_INST,DL_TIMER_CCACT_UPDATE_METHOD_IMMEDIATE, DL_TIMERA_CAPTURE_COMPARE_0_INDEX);
DL_TimerA_setCaptureCompareValue(PWM_0_INST, 834, DL_TIMER_CC_0_INDEX);//Configuring CC0 as almost 1/4th the bit width
PWM_0_INST->COUNTERREGS.CCACT_01[0]=0x2;//Configuring Zero action as CC Output LOW, as START bit in UART is always LOW
DL_Timer_enableInterrupt(PWM_0_INST, DL_TIMER_INTERRUPT_ZERO_EVENT);
DL_Timer_enableLZEventSuppression(PWM_0_INST);//This will suppress zero events until RC is equal to 0
DL_Timer_enableEvent(PWM_0_INST, DL_TIMER_EVENT_ROUTE_1, DL_TIMER_INTERRUPT_CC0_UP_EVENT);//CC0_UP Event triggers the DMA CHAN0
DL_Timer_setPublisherChanID(PWM_0_INST, DL_TIMER_PUBLISHER_INDEX_0, 1);//Timer publishing event to DMA to carry out CCACT update
DL_TimerA_enableClock(PWM_0_INST);
DL_TimerA_setCCPDirection(PWM_0_INST , DL_TIMER_CC0_OUTPUT );
}
// Below is DMA configuration
static const DL_DMA_Config gDMA_CH0Config = {
.transferMode = DL_DMA_FULL_CH_REPEAT_SINGLE_TRANSFER_MODE,
.extendedMode = DL_DMA_NORMAL_MODE,
.destIncrement = DL_DMA_ADDR_UNCHANGED,
.srcIncrement = DL_DMA_ADDR_INCREMENT,
.destWidth = DL_DMA_WIDTH_WORD,
.srcWidth = DL_DMA_WIDTH_WORD,
.trigger = DMA_GENERIC_SUB0_TRIG,
.triggerType = DL_DMA_TRIGGER_TYPE_EXTERNAL,
};
void SYSCFG_DL_DMA_CH0_init(void)
{
DL_DMA_initChannel(DMA, DMA_CH0_CHAN_ID , (DL_DMA_Config *) &gDMA_CH0Config);
DL_DMA_clearInterruptStatus(DMA, DL_DMA_INTERRUPT_CHANNEL0);
DL_DMA_enableInterrupt(DMA, DL_DMA_INTERRUPT_CHANNEL0);
DL_DMA_setSubscriberChanID(DMA, DL_DMA_SUBSCRIBER_INDEX_0, 0x01);//DMA subscribing to Timer event
}
void SYSCFG_DL_DMA_init(void){
SYSCFG_DL_DMA_CH0_init();
}/* Application Code for Emulating UART Tx Using Timer */
uint8_t data_to_transmit[8]={1,1,0,1,0,1,0,0};//this equals to 0x2B
uint8_t uart_frame_to_transmit[9];//8 data bits + STOP Bit
uint8_t number_of_bits_in_each_frame=0;
uint8_t number_of_bits_in_uart_frame=0;
uint32_t DMA_frame_to_transmit[9];
int number_of_CC_interrupts=0;
int number_of_zero_int=0;
//int number_of_load_int=0;
volatile bool gIsTimerExpired;
int main(void)
{
bool isRetentionError;
NVIC_EnableIRQ(PWM_0_INST_INT_IRQN);
SYSCFG_DL_init();
DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)&PWM_0_INST->COUNTERREGS.CCACT_01[0]);//Set DMA destination address as TIM_CCACT MMR
DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)&DMA_frame_to_transmit );//Set DMA source address as the array which contains CCACT config for each bit
DL_DMA_setTransferSize( DMA, DMA_CH0_CHAN_ID,number_of_bits_in_uart_frame);//Configure DMA SZ for the number of bits in each frame
DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);//Enable DMA channel
number_of_bits_in_each_frame=sizeof(data_to_transmit);
uart_frame_to_transmit[number_of_bits_in_each_frame+1]=1;//STOP bit is always 1
for(int i=0;i<number_of_bits_in_each_frame;i++){
uart_frame_to_transmit[i]=data_to_transmit[i];
}
number_of_bits_in_uart_frame=sizeof(uart_frame_to_transmit); //Adding 1 Stop bit Frame
DL_Timer_setRepeatCounter(PWM_0_INST,number_of_bits_in_uart_frame);//Configuring RCLD as the number_of_bits_in_uart_frame
/////////PRE-PROCESS THE ARRAY WHICH CONTAINS THE CORRESPONDING CCACT CONFIGURATION FOR EACH BIT//////////////////////////
for( number_of_CC_interrupts=0;number_of_CC_interrupts<(number_of_bits_in_uart_frame+1);number_of_CC_interrupts++){
if(uart_frame_to_transmit[number_of_CC_interrupts]==0){
DMA_frame_to_transmit[number_of_CC_interrupts]=0x2;//if bit value is 0 configure ZACT as CC Output LOW
}
else if(uart_frame_to_transmit[number_of_CC_interrupts]==1){
DMA_frame_to_transmit[number_of_CC_interrupts]=0x1;//if bit value is 1 configure ZACT as CC Output HIGH
}
else{
}
if(number_of_CC_interrupts==number_of_bits_in_uart_frame-1){
DMA_frame_to_transmit[number_of_CC_interrupts]=0x1;//Always generate a HIGH stop bit
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DL_TimerA_startCounter(PWM_0_INST);//Start Counter
while(1);
}
void PWM_0_INST_IRQHandler(void)
{
switch (DL_TimerA_getPendingInterrupt(PWM_0_INST)) {
case DL_TIMER_IIDX_ZERO:
number_of_zero_int++;
DL_TimerA_stopCounter(PWM_0_INST);//Stop the counter
PWM_0_INST->COUNTERREGS.CCACT_01[0]=0x2;//Configure ZACT for the next UART Transmission
delay_cycles(3333);//Adding 1 bit of delay between 2 UART frames
number_of_CC_interrupts=0;
DL_TimerA_startCounter(PWM_0_INST);//Start counter for the next UART Transmission
break;
default:
break;
}
}
图 4-4 使用 TIMA 以 UART 格式发送 0x2B对于上述应用,可以使用 TIMG 而不是 TIMA 作为替代实现。但是,TIMG 不支持重复计数器功能。因此,使用 TIMG 时,需要通过 ISR 内的软件干预手动重新加载计数器。