STM32 - 定時器的設定 - 基礎 - 05 - Arbitrary waveform generation using timer DMAburst feature - 任意波形的序列產生

 DMA的功能不說了,如何產生任意序列的波形,我們仔細看看:

本節敘述了同DMA的方法,在不佔用MCU資源的情況下,通過提前編輯一組任意定製的波形參數,實現複雜的波形輸出。


STM32 DMA-burst feature overview

The direct memory access (DMA) peripheral is used in order to provide a high-speed data transfer both between peripherals and memory and also between memory and memory. This action saves CPU resources that could be used in other tasks. Each DMA transfer is made of two stages:

In the first stage, the data to be transferred is loaded from the source location

In the second stage, the retrieved data is stored into the destination location.

This two-stage data transfer operation is associated with an update of the DMA peripherals transfer index register; this is the register used to track how much data is left to be transferred.

In STM32 microcontroller families, there are two DMA peripheral variants:

• The DMA burst transfer feature supported only by the STM32F2 products DMA peripheral variant where the DMA peripheral can transfer a configurable number of data elements next to a single data transfer trigger.

• In another variant, like the one on the STM32F1 products, the DMA peripheral variant supports only single transfers; this means that only one data element is transferred next to a data transfer trigger.

The paragraph above is not intended to give a detailed description of the STM32 DMA-burst feature supported by many STM32 microcontrollers. The information stated above aims to mitigate any misunderstanding of this feature and any possible confusion with the STM32 timer burst feature which makes the focus of this chapter. For more information about the STM32 DMA peripheral, consult the STM32 microcontrollers documentation reference manuals and application note STM32 cross-series timer overview (AN4013).


Timer DMA-burst feature

The timer peripherals have the capability to generate multiple successive DMA requests next to a single timer event. The main usage of this feature is to update the content of multiple registers of the timer peripheral each time a given timer event is triggered. This can be done either to dynamically reconfigure the timer operating mode (switching from one output mode to another, for instance from PWM2 mode to force-active-level mode), or to change the run-time parameters on several channels simultaneously (change the dutycycles for more than one timer channel at once).

DMA在定時器的應用,主要是講一大批定時器的更新數據更新到寄存器,例如改變佔空比。這個更新只需要一個定時器觸發就完成了。

The same feature can also be used to transfer the content of a number of timer peripheral registers out into a memory buffer. This feature allows to modify on the fly the waveform outputted by a timer peripheral output by adjusting the timer peripheral registers content. For example, it allows to update the TIMx_ARR register content to adjust the outputted waveform frequency or update the TIMx_CCRx register to adjust the signal duty-cycle.

當然,同樣可以用於將一大批數據傳到內存buffer裏面去。這個功能可以即使的改變定時器的輸出調整定時器的內容。


DMA相關的控制寄存器:

In order to use the timer’s DMA-burst feature the programmer has to deal with below timer peripheral registers:

– The DMA address register (TIMx_DMAR): this is the read/write access redirection register.地址寄存器

– The DMA control register (TIMx_DCR): this is the burst-transfer state-machine control register控制寄存器

– DMA controller’s peripheral-address-register setting.設定

Timer peripheral DMA-burst feature address register

The peripheral address register, within the DMA peripheral, is used to configure the transfer destination register address when the DMA is configured in memory-to-peripheral mode. It is also used to configure the transfer source register address when the DMA is configured in peripheral-to-memory mode. The DMA peripheral should update the content of a series of timer peripheral registers with the content of a memory buffer of predefined and/or precomputed values, but it does not mean that the transfer address pointed by the DMA peripheral address register should be configured to be post-incremented by the DMA controller next to each data transfer. The DMA controller peripheral address register has to point to the TIMx_DMAR timer peripheral register.

The TIMx_DMAR timer register is a virtual (虛擬)register. Any access to this register is redirected by the timer peripheral DMA-burst control logic to one of the timer peripheral physical registers. Access to the TIMx_DMAR register can be either of read or write type. The redirection of an actual access to the TIMx_DMAR register to another timer peripheral physical register depends on the content of the TIMx_DCR register on the DMA-burst interface settings.(DMA的數據方向由該寄存器決定) It depends also on the actual state of the finite-state machine (FSM) controlling the timer DMA burst interface.

DMA controller’s memory-address-register setting

The memory address register within the DMA peripheral is used to configure the transfer destination memory location address when the DMA is configured in peripheral-to-memory mode. It is used also to configure the transfer source memory location address when the DMA is configured in memory-to-peripheral mode.

The DMA peripheral should update the content of a series of timer peripheral registers with the content of a memory buffer. The transfer address pointed by the DMA memory address register should be configured to be post-incremented by the DMA controller next to each data transfer.

DMA必須要有內存buffer來進行數據緩衝

Timer peripheral DMA-burst feature control register 控制寄存器

The state-machine control register for the timer DMA burst feature, TIMx_DCR, is used to configure the number of beats during a single burst transfer. It is also used to identify the target timer register or the source of the first data transfer during a burst transfer.

The DBL [4:0](data buffer length) control bit-field sets the number (數量)of beats during one burst transfer that should be equal to the number of timer registers that is involved (either write or read) in a burst transfer. The content of the DBA(data buffer address) [4:0] control bit-field identifies the start register (DMA開始的寄存器地址)involved in a burst transfer among the timer registers. AN47

The DBA[4:0] control bit-field can identify up to 32 timer registers as it is of 5-bit width. (DBA因爲是0~4位,那就是共5位字長)Timer registers identification number is obtained from dividing the register relative address within the timer register map by four. For example, the TIMx_CR1 register has a relative ddress of 0x00, then its identification number is 0. To make a burst transfer start from TIMx_CR1 register, the DBA[4:0] control bit-field should be set to 0.

To make the burst transfer start from the TIMx_ARR register, the DBA[4:0] bit field should be set to 11.This means 44 / 4 = 11 where 44 is the relative address of the TIMx_ARR register, 0x2C(16進制)= 44 (十進制), after being encoded into decimal base.

In order to complete one timer DMA-burst transfer sequence, as shown by Figure 28, the DMA and the timer peripherals should cooperate. The data values that used to update the timer registers should be stored somewhere within the microcontroller memory. They can be stored in the SRAM memory if the pattern should be updated during the waveform generation.

The application software should configure the DMA to point to the data buffer as the source of the data transfer; it should point to the timer TIMx_DMAR register as the destination of the data transfer. Finally, the application software should configure the timer DMA-burst feature by writing the correct settings into the timer TIMx_DCR register.

The above paragraphs provide a detailed description on how to configure the timer DMA burst feature. As soon as the right configuration is done, the DMA stream or channel used for the data transfer should be enabled, followed by the enable of the timer counter.

DMA的通道使用就是通過DMA的BUFFER寄存器和地址寄存器,將數據拿到

Once enabled, the timer counter is periodically updated by being either incremented or decremented. After a while and depending on the enabled timer DMA requests, the timer peripheral may raise a DMA request internally. The DMA request is routed internally to the timer DMA-burst control logic.

一旦使能,定時器計數週期性的增加或減少更新。一段時間後,依據DMA的請求,定時器單元產生一個DMA的內部請求,這時候,DMA的請求被內部接到DMA-束髮的控制單元。

Based on the value configured into the DMA-burst length (DBL[4:0], bit-filed within the TIMx_DCR timer register), the DMA request is sent out into the DMA peripheral either as is or multiplied several times.

If the DBL[4:0] content is null then the DMA request is sent as is; else the DMA request is multiplied by DBL value + 1 factor.

If the DBL[4:0] bit-filed content is 2, then, as soon as one timer DMA request is raised internally, the timer DMA burst control logic send out a first DMA request into the DMA peripheral. The DMA peripheral transfers the content of the memory location; this location is pointed by the DMA register transfer source into the TIMx_DMAR timer register. It then increments the source pointer and acknowledge the timer DMA request. As soon as the first DMA acknowledgment is received, the timer DMA-burst control logic sends out a second DMA request. This DMA request is handled again by the DMA peripheral and an acknowledgment is sent again to the timer. After receiving the second DMA acknowledgment, the timer DMA-burst control logic sends out a third DMA request. This third request is again handled by the DMA peripheral. As soon as the timer receives the third acknowledgment from the DMA, the transfer sequence triggered by the internally raised DMA request is considered as successfully terminated. Then the timer DMA-burst control logic is ready for a new transfer sequence. For the previous described data transfer sequence, the transfer destination register pointed to by the DMA peripheral remains the same along the whole transfer sequence. The register remains then equal to the timer TIMx_DMAR register. The timer DMA-burst control logic redirects, each time, the write access into the timer TIMx_DMAR register to the right physical timer register. For the previous example, and if the DMA base address bit-field DBA[4:0] within the TIMx_DCR register is set to 11, note that:

• The first DMA write access to the timer TIMx_DMAR register is redirected to the TIMx_ARR timer register.The TIMx_ARR timer register is chosen to be the base address for the burst transfer.

• The second DMA access to the TIMx_DMAR timer register is redirected to the TIMx_RCR timer register (assuming that the timer used for this example embeds the TIMx_RCR register).

• The third DMA access to the TIMx_DMAR timer register is redirected to the TIMx_CCR1 timer register.

• At the end of the third DMA access to the TIMx_DMAR register, the timer DMA-burst control logic loops back the write access redirection state-machine. It points again to the configured base register for the burst transfer (the TIMx_ARR timer register in this example).

For each new DMA request generated internally within the timer peripheral, the sequence described above is repeated. To use the timer DMA burst to read out the content of timer peripheral registers periodically into a certain memory buffer, the above sequence is also valid. Only the DMA transfer direction, source address and destination address should be modified.

上次比較詳細的敘述了DMA的傳輸的順序和通道實現方法。


Application example: arbitrary waveform generation using timer DMA-burst feature

This example demonstrates one possible usage of the STM32 timer peripherals to generate an arbitrary waveform signal without CPU overhead. This example aims also to demystify the DMA-burst timer feature which is the keystone for this example.

下例,敘述瞭如何利用定時器單元產生一個自由定製的波形,而並不通過CPU的控制。

Application overview

This application is designed around the Nucleo board NUCLEO-F302R8, based on STM32F302x8 microcontroller, as the board main controller. Nevertheless, this application can be ported easily to any STM32 hardware platform. The Nucleo board embeds its own ST-Link/V2 debugger. Only a USB cable is needed to interface the Nucleo board with a PC computer both for application-binary-image download into the microcontroller and for the application debug purposes. Figure 29 illustrates the synoptic diagram for the arbitrary waveform generator application presented by this application example. The signal generated is outputted on the PA.08 IO of the STM32F302 microcontroller which is mapped to the pin 8 of the connector CN9 of the Nucleo board.

通過DMA的設定方式,將RAM裏面波形設定的參數給到Timer1中

The arbitrary waveform generator described by this example is designed to output a waveform similar to the one shown by Figure 30. The source code of this application can be easily reshaped to output different waveforms, but for demonstration purposes the one illustrated in Figure 4 on page 12 is targeted.

 

The targeted waveform in Figure 30 is composed by three waveform portions:

這個例子要生成的複雜波形如下:

• The first portion is made by two consecutive pulses with a certain on-time and off-time: t1_on and t1_off.

第一部分,一個具有兩個連續波形的,不對稱的PWM波

• The second portion is made by one pulse with a different on-time and off-time: t2_on and t2_off.

第二部分,一個脈衝波具有不同的高低電平時間

• The third portion is made by three pulses with a third set of on-time and off-time parameters: t3_on and t3_off.

第三部分,一個不同於前兩個的,三組波形

To make an STM32 timer peripheral output this waveform, a timer peripheral featuring a repetition counter can be used. The timer peripheral embeds a TIMx_RCR register and features at least one timer channel.

要產生這個複雜的波形,可以用之前的重複計數來實現。(在一個時鐘通道,同時設定TIMx_RCR 寄存器)

 

For this example, the TIM1 timer peripheral is used as It features four timer channels as well as a repetition counter.

用定時器T1的四個通道來實現重複計數

A timer channel can generate a PWM signal with a constant predefined frequency and dutycycle parameters. The signal frequency parameter is controlled by the content of the timer TIMx_ARR auto-reload register. In this register, the duty-cycle parameter is controlled by the content of the timer channel 1 register (TIM1_CCR1). In order to make the timer channel output the requested waveform (refer to Figure 4), the content of these two timer register at the end of each PWM cycle must be updated.

定時器通道可以產生PWM的類似的一個固定頻率和佔空比的信號波形。只要通過控制TIMx_ARR(自動裝載寄存器) 來控制信號頻率,而通過TIMx_ARR 來控制佔空比。如果要產生上述,複雜的波形,這兩個參數都必須不停地隨時更新:

In other words, it is required to update the content of these two registers synchronously with each timer “update event”. The intuitive way to do this is by making the application software (the CPU unit) update the content of these two registers each time a timer “update event” is raised. Intuitively, these overheads the CPU unit and make the outputted waveform not deterministic.

通常的做法,是通過UTE的更新,來同時更新兩個寄存器的值,但是,這樣會極大的增加CPU的負擔。

The following paragraphs explain how to use some of the timer features in conjunction with the DMA peripheral to mitigate the CPU overhead and to generate a deterministic waveform signal.

本節,介紹如何通過DMA器件結合定時器的特性,來減緩CPU的負擔,同時產生任意我們需要的波形

To update the TIMx_ARR and TIMx_CCR1 timer registers simultaneously next to one timer “update event”, the use should use the DMA-burst timer feature in addition to one DMA channel or stream. How to configure and use the timer DMA-burst feature is described inprevious sections of this document.

如何在下一個UDE的事件之前,同時更新這兩個寄存器的值,我們需要用到DMA功能

To prevent the timer channel from generating unwanted glitches due to updating the timer channel register, the preload feature of the STM32 timer peripherals is used. To make the timer channel to output repetitive pulses with the same t_on and t_off parameters and without the timer generating an “update event” on each PWM cycle, the timer repetition counter should be used.

爲了防止定時器通道產生小瑕疵,利用preload 特性,和repetitive pulses重複脈衝(具備相同的t_on and t_off),同時屏蔽“update event”,這一點,在前面的文章裏面提到過。

In order to output the waveform illustrated in Figure 29 on channel 1 of TIM1 timer peripheral, the content of the below three registers should be updated as follow:

TIM1_ARR: contains the sum of t_on and t_off periods for the on-going pulse.(定義波形的週期,該週期由t_on and t_off 合決定)

TM1_RCR: contains the number of pulses per the on-going signal waveform portion minus one (重複波形數目)(i.e.TIM1_RCR=Number_of_pulses_per_portion–1).

TIM1_CCR1: contains the duration of the t_on period of the on-going pulse.(佔空比)

這樣我們可以把剛纔那個複雜的波形分解爲三個不同的波形數列:

The configuration for the timer registers to be used in order to reconstitute the waveform shown in Figure 29 are the following:

For the first portion of the waveform, the right configuration is:

TIM1_ARR = t1_on + t1_off , TIM1_RCR= 1, TIM1_CCR1= t1_on;

For the second portion of the signal waveform, the right configuration is:

TIM1_ARR = t2_on + t2_off , TIM1_RCR= 0, TIM1_CCR1= t2_on;

For the third portion of the signal waveform, the right configuration is:

TIM1_ARR = t3_on + t3_off , TIM1_RCR= 2, TIM1_CCR1= t3_on;

知道要設定上述寄存器後,我們先準備一下,相關的BUFFER

Memory-buffer content:

Considering the above values for TIM1_ARR, TIM1_RCR and TIM1_CCR1 timer registers for each portion of the targeted waveform, refer to Figure 31 for the values table to be defined in the memory of the microcontroller. Note that the order of data values within the table is the same as for their respective registers within the registers map of the timer peripheral. The correct order should be TIM1_ARR, TIM1_RCR and then TIM1_CCR1 register.

這裏有一個需要注意的地方,就是寄存器buffer的數據順序的映射,需要和寄存器的Mapping的值一一對應,

 

The C language source code for the above described values table is stated below. The Const keyword is used to indicate that the table content is not modified on the fly during the waveform generation.

The memory array is allocated in the Flash memory. If it is required to change the waveform parameters during run-time, the keyword Const should not be used. The memory array is allocated in two memory regions: the Flash memory region and the SRAM memory region.

uint32_t const aSRC_Buffer[9] = { t1_on+t1_off,1,t1_on, t2_on+t2_off,0,t2_on, t3_on+t3_off,2,t3_on};

準備好數據後,下面是DMA的傳輸設定:

Timer DMA-burst configuration

In order to output the desired waveform, the TIM1 timer DMA-burst should be configured as below:

As there are three timer registers to update, the burst transfer length is 3. The DBL[4:0] control bit-field within the TIM1_DCR should be set to 2. Three data transferred each UEV, three update event occur.

• Among the timer registers to update, the timer TIM1_ARR register is the first in the TIM1 timer register map, so it is defined as the base for the transfer. The DBA[4:0]

control bit-filed should be set in order to point to the TIM1_ARR register (DBA[4:0] = 11). Figure 32 illustrates the block diagram for the previous described configurations.

然後是時鐘設定:

Clock configuration

In this example to get TIM1 counter clock at 32 MHz:

TIM1 input clock

The TIM1 input clock (TIM1CLK) is set to APB2 clock (PCLK2):

TIM1CLK = PCLK2 and PCLK2 = HCLK => TIM1CLK = HCLK = SystemCoreClock.

TIM1 Prescaler

To get TIM1 counter clock at 32 MHz, the prescaler is computed as follows:

Prescaler = (TIM1CLK / TIM1 counter clock) - 1

Prescaler = (SystemCoreClock / 32 MHz) – 1

Frequencies and duty cycles calculation (然後依據時鐘設定,計算頻率和佔空比)

Within this example, the data pattern for the generated waveform is defined as below:

uint32_t aSRC_Buffer[9] = { 4000,1,800,10000,0,8500,4000,2,200};

And based on the below calculations:

最後輸出波形如下圖:

 

Firmware description

To achieve the generation of an arbitrary signal described in the previous section, the

following steps should be applied:

System clock

– PLL as system clock source: 64 MHz

– HSI as oscillator (no need to solder HSE in Nucleo board)

– AHB div = 1 / APB1 div = 2 / APB2 div= 1

DMA2 configuration

/* DMA1 clock enable */
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
/* Configure DMA1 Channel5 CR register */
/* Reset DMA1 Channel5 control register */
 DMA1_Channel5->CCR = 0;
/* Set CHSEL bits according to DMA Channel 5 */
/* Set DIR bits according to Memory to peripheral direction */
/* Set PINC bit according to DMA Peripheral Increment Disable */
/* Set MINC bit according to DMA Memory Increment Enable */
/* Set PSIZE bits according to Peripheral DataSize = Word */
/* Set MSIZE bits according to Memory DataSize Word */
/* Set CIRC bit according to circular mode */
/* Set PL bits according to very high priority */
/* Set MBURST bits according to single memory burst */
/* Set PBURST bits according to single peripheral burst */
 DMA1_Channel5->CCR |= DMA_MEMORY_TO_PERIPH |
 DMA_PINC_DISABLE| DMA_MINC_ENABLE|
 DMA_PDATAALIGN_WORD| DMA_MDATAALIGN_WORD |
 DMA_CIRCULAR | DMA_PRIORITY_HIGH; 
/* Write to DMA1 Channel5 number of data’s register */
 DMA1_Channel5->CNDTR = 9;
/* Write to DMA1 Channel5 peripheral address register */
 DMA1_Channel5->CPAR = (uint32_t)TIM1_DMAR_ADDRESS;
/* Write to DMA1 Channel5 Memory address register */
/* Set the address to the memory buffer “aSRC_Buffer” */
 DMA1_Channel5->CMAR = (uint32_t)aSRC_Buffer;
/* Enable DMA1 Channel5 */
DMA1_Channel5->CCR |= (uint32_t)DMA_CCR_EN;

TIM1 configuration

/* set the Timer prescaler */
 Tim1Prescaler= (uint16_t) (SystemCoreClock / 32000000) - 1;
/* Configure the period */
 TIM1->ARR = 0xFFFF;
/* Configure the Timer prescaler */
 TIM1->PSC = Tim1Prescaler;
/* Configure pulse width */
TIM1->CCR1 = 0xFFF;
/* Select the ClockDivison to 1 */
/* Reset clockDivision bit field */
 TIM1->CR1 &= ~ TIM_CR1_CKD;
/* Select DIV1 as clock division*/
TIM1->CR1 |= TIM_CLOCKDIVISION_DIV1;
/* Select the Up-counting for TIM1 counter */
/* Reset mode selection bit fiels*/
TIM1->CR1 &= ~( TIM_CR1_DIR | TIM_CR1_CMS);
/* selct Up-counting mode */
 TIM1->CR1 |= TIM_COUNTERMODE_UP;
/* SET PWM1 mode */
/* Reset the Output Compare Mode Bits */
 TIM1->CCMR1 &= ~TIM_CCMR1_OC1M;
 TIM1->CCMR1 &= ~TIM_CCMR1_CC1S;
/* Select the output compare mode 1*/
 TIM1->CCMR1 |= TIM_OCMODE_PWM1;
/* Enable the output compare 1 Preload */
 TIM1->CCMR1 |= TIM_CCMR1_OC1PE;
/* Enable auto-reload Preload */
 TIM1->CR1 |= TIM_CR1_ARPE;
/* TIM1 DMA Update enable */
 TIM1->DIER |= TIM_DMA_UPDATE; 
/* Configure of the DMA Base register and the DMA Burst Length */
/* Reset DBA and DBL bit fields */
 TIM1->DCR &= ~TIM_DCR_DBA;
 TIM1->DCR &= ~TIM_DCR_DBL;
/* Select the DMA base register and DMA burst length */
TIM1->DCR = TIM_DMABase_ARR | TIM_DMABurstLength_3Transfers;
/* Enable UEV by setting UG bit to Load buffer data into preload registers 
*/
 TIM1->EGR |= TIM_EGR_UG;
/* wait until the RESET of UG bit*/
 while((TIM1->EGR & TIM_EGR_UG) == SET){}
/* Enable UEV by setting UG bit to load data from preload to active 
registers */
 TIM1->EGR |= TIM_EGR_UG;
/* Enable the TIM1 Main Output */
 TIM1->BDTR |= TIM_BDTR_MOE;
/* Enable CC1 output*/
 TIM1->CCER |= TIM_CCER_CC1E;
/* Enable the TIM Counter */
 TIM1->CR1 |= TIM_CR1_CEN;

GPIO:

– Pin PA8: TIM1_ch1_output

– Mode: push pull

– Pull: pull-up

– Speed: high

– Alternate function: GPIO_AF6_TIM1

 

 

 

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