XIV PWM output

I won't talk about the principle of PWM here. Pulse width modulation can meet different power requirements of load by changing cycle and duty cycle.

1. PWM function of mx6ul

1. When the PWM of mx6ul is connected with the processor core, it follows the peripheral bus protocol. Between PWM and other modules, there is only clock signal (CCM module) and restart signal (SRC module) (as well as interrupt processing) and a separate output signal. The functional features are as follows:

  • 16 bit up counter and clock source can be selected.
  • 4X16 bit FIFO can reduce interrupt resources
  • Configurable output high and low level mode
  • You can roll back production or compare interrupts

1. Mx6ul provides 8 groups of PWM, and the output signal of each group can be selected through multiplexing configuration between several pins., The overall frame structure is as follows:

 

 

1. The PWM generation process of mx6ul is as follows:

The clock selector determines the working frequency of the counter. As before, we use the peripheral clock cycle (IPG_CLK,66MHz)

The 12 bit frequency divider can realize 1 ~ 4097 frequency division. Suppose we choose 66 frequency division, and it is 1us every time the counter counts

Period Resgiter, a 16 bit cycle register, generates an interrupt when the value of the counter is equal to the value of the cycle register (this interrupt can not be generated, similar to overflow interrupt). The counter value is equal to the cycle and is counted again from 0.

Sample Register, 16 bits. The value of this register determines the duty cycle of the signal. This is more important. Let's talk about it separately later. But it means that the signal is reversed when the value of the counter is equal to the value of the SampleRegister.

SampleRegister and FIFO

The duty cycle is handed to FIFO through SampleRegister. Note that the depth of FIFO is 4 groups, and the duty cycle of the actual signal is determined by the value of FIFO. Therefore, FIFO needs to keep writing new values to continuously generate new signals. FIFO can write at any time, but to read the value, it must be under the condition of PWM enabling. Because the depth of FIFO is 4, when writing data, pay attention to prevent overflow, otherwise FWE exception (FIFO Write Error). Similarly, we also need to detect the number of internal elements of FIFO to prevent FIFO from being empty and unable to generate new signals. This process can be generated by interrupt. When the element in FIFO is lower than the specified value, an interrupt can be generated. In the interrupt, new data is written to FIFO. A few more notes

  • As long as we read the SampleRegister, the FIFO data will be reduced;
  • After PWM is disabled, FIFO elements are no longer reduced;
  • If PWM is soft reset, all contents in FIFO will be cleared

Rollback and compare events

When the counter to PWM_ The value of PR register + 2 will be reset to 0 and the counting will be restarted. This process is the same as the timer interrupt counter. This event can be regarded as a rollback. During rollback, the output can be set to 0, 1 or no response according to the settings; This process can also generate an interrupt (provided that the interrupt is enabled). When the counter value accumulates to the sample value, the output state will be changed according to the setting. This is a comparison event, and an interrupt can also be triggered. In short, the signal is reversed when it reaches the Period and then reversed when it reaches the sample value to form a signal cycle.

 

 

Register description

1. The mx6ul provides 8 sets of PWM, each using 6 registers

 

CNR, PR and SAR are three 16 bit registers that store the values of counter, Sample and Period. We won't talk about it later. Let's take a look at the rest

PWMCR

Control register,

 

FWM [27:26]: how much FIFO remains will trigger FIFO null interrupt, which is generally set to 2. If 1 is dangerous, FIFO null error may be reported

 

POUTC[19:18]: output configuration, which sets the output status when rolling back and comparing events

 

CLKSRC[17:16]: clock source, we generally select the peripheral clock source, and the value is 01

SWR[3]: soft reset, soft reset when set to 1, and automatically return to 0 after reset

Repeat [2:1]: repeat Sample. You can set the number of times each Sample value is reused

 

EN[0]:PWM enable

PWMSR

Status register

 

FWE[6]:FIFO write error

CMP[5]: compare events

ROV[4]: rollback event

FE[3]:FIFO empty status

Fifoav [2:0]: number of elements in FIFO

 

Interrupt enable

There are three bit s available for interrupt enable

 

CIE[2]: compare interrupt enable

RIE[1]: rollback interrupt enable

FIE[0]:FIFO air interrupt is enabled, and the FIFO element is less than the value specified by FWM to trigger the interrupt.

PWMPR

Cycle register, calculated as follows

 

PWMO: PWM output signal frequency

PCLK: clock cycle after frequency division by frequency divider

period: write the value of PR register

Note that the actual period is period+1. When the value of PR written is 0xFFFF, the actual effect is the same as 0xFFFE.

Code writing

The code is very simple. The main thing is to set a global variable_ Duty, this variable will be modified every time you call to set the duty cycle. This variable is mainly used to interrupt the service. At the beginning of debugging, I forgot this variable and could not measure the output. By constantly adding print nodes, I found that only four values of duty meet the setting requirements, which should correspond to the depth of FIFO. There must be a problem with the interrupt service. Later, it was found that the value of the parameter passed when the interrupt called the function was 0.

file structure

 

c Documents

/**
 * @file bsp_pwm.c
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2022-01-22
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#include "bsp_pwm.h"
#include "stdio.h"
unsigned char pwm_duty;

/**
 * @brief PWM1 initialization
 * 
 * @param period Cycle microseconds
 * @param duty   Duty cycle
 */
void pwm1_init(unsigned int period,unsigned int duty)
{   
    /**
     * IO Initialize electrical performance:
     *bit [16]      : 0 HYS close
     *bit [15:14]   : 10 100K Pull up
     *bit [13]      : 1 pull function
     *bit [12]      : 1 pull/keeper Enable
     *bit [11]      : 0 Turn off the open circuit output
     *bit [7:6]     : 10 Speed 100Mhz
     *bit [5:3]     : 010 The driving capacity is R0/2
     *bit [0]       : 0 Low conversion rate
     */
    IOMUXC_SetPinMux(IOMUXC_GPIO1_IO08_PWM1_OUT,0);
    IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO08_PWM1_OUT,0xB090);

    PWM1->PWMCR = 0;                            //PWMCR Clear
    PWM1->PWMCR |= (1<<26)|(1<<16)|(65<<4);     //PWCR[27:26](FWM)=01 [17:16](CLKSRC)=01 [15:4](PRESCALER)=65

    pwm1_setperiod(period);                     //Set cycle    

    for(int i=0;i<4;i++){                       //adopt SAM Register write FIFO
        pwm1_setduty(duty);                 //Constant duty cycle
    }

    PWM1->PWMIR = (1<<0);                       //FIE=1,Enable FIFO Empty interrupt
    system_register_irqHandler(PWM1_IRQn, (system_irq_handler_t)pwm1_irqhandler,NULL);  //Interrupt function registration

    GIC_EnableIRQ(PWM1_IRQn);                   //GIC Enable
    PWM1->PWMSR = 0;                            //PWMSR Register reset
    PWM1->PWMCR |= (1<<0);                      //PWMCR[0](EN)=1,Enable

}

/**
 * @brief Set cycle
 * 
 * @param value 
 */
void pwm1_setperiod(unsigned int value)
{
    unsigned int regvalue = 0;
    if (value<2){
        regvalue=2;
    }
    else{
        regvalue=value-2;
    }
    PWM1->PWMPR = (regvalue & 0xFFFF);
}

/**
 * @brief Set duty cycle
 * 
 * @param duty Duty cycle
 */
void pwm1_setduty(unsigned char duty)
{
    unsigned short period;
    unsigned short sample;
    pwm_duty = duty;                //Don't forget this line of code, global variables pwm_duty,This variable is required to interrupt the service
    period = PWM1->PWMPR +2;
    sample = period *duty / 100;

    PWM1->PWMSAR = (sample & 0xFFFF);
}

void pwm1_irqhandler(unsigned int gcciar,void *userParam)
{
    if(PWM1->PWMSR &(1<<3)){
        pwm1_setduty(pwm_duty);
        PWM1->PWMSR |= (1<<3);
    }

}

The code is very clear. You can see the remarks directly, that is, the settings of several registers

Header file

/**
 * @file bsp_pwm.h
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2022-01-22
 * 
 * @copyright Copyright (c) 2022
 * 
 */
#ifndef __BSP_PWM_H
#define __BSP_PWM_H

#include "imx6ul.h"
#include "bsp_int.h"

void pwm1_init(unsigned int period,unsigned int duty);
void pwm1_setperiod(unsigned int value);
void pwm1_setduty(unsigned char duty);
void pwm1_irqhandler(unsigned int gcciar,void *userParam);
#endif

use

After the module is imported, it can be used in the main function

int main(void)
{   
    int_init();
    imx6u_clkinit();
    clk_enable();
    delay_init();
    uart_init();
    key_init();
   
    unsigned char duty = 50;    
    unsigned char kv = 0;

    pwm1_init(1000,duty); 

    while(1){
    kv = key_getvalue();
    if(kv == KEY0_VALUE){
        duty += 5;
        if(duty>100){
            duty=5;
        }
        pwm1_setduty(duty);
        delay_ms(50);
        printf("duty:%d",duty);
        }
    }
    return 0;
}

In the main function, the key is also used, and the duty cycle increases by 5% each time the key is pressed

The cycle defined during initialization is 1000, because the clock source used is 66MHz. The frequency division is directly fixed. The value 65 corresponds to 66 frequency division. The cycle is 1000 microseconds, and the output frequency is 1KHz, which is very stable. I used a hand-held oscilloscope to measure the output value. The change process is the process of changing the duty cycle by pressing the key. I have tried this output frequency of 250K, which is very stable, but at low frequency (50Hz

The waveform is not particularly good at the time of (left and right). There is a downward trend in the high level. I don't know whether it is the cause of the oscilloscope or what.

Added by Scud on Sat, 22 Jan 2022 21:13:39 +0200