/*
* -20KHZ의 PWM 신호를 발생시키는 예제
* -두개의 LED를 COMPLEMENTARY PWM에 연결하여 하나는 밝아질때 하나는 어두워지는 것을 관찰할
* 수 있음
* -modification1: configure ADC- PWM신호의 듀티사이클이 ADC값을 반영하게 변경
* -modification2:
*/
/*
* ATSAM3X8E가 가지고 있는 8개의 PWM들은 모두 COMPLEMENTARY로 생성가능함.
* 듀에에는 8개의 PWM이 모두 나와있는 것은 아니고 7개까지만 나와있는데, 그중에서도 PWML4는
* 없기때문에 실제로 COMPLEMENTARY로 사용가능한 PWM은 6개임.
* 20KHZ의 PWM을 생성하기 때문에 PWM resolution으로 2100을 사용해보자.
* pwm생성에 사용되는 clock은 20000*2100*2=84mhz가 되어 마스터 클럭을 그대로 사용하면 된다.
* 위에서 2를 곱한 것은 center aligned방식은 left aligned방식에 비해 주파수가 2배가 되기 때문.
*
*/
/* pin34 PWML0(PC2) LED1
* pin35 PWMH0(PC3) LED2
* pin36 PWML1(PC4)
* pin37 PWMH1(PC5)
* pin38 PWML2(PC6)
* pin39 PWMH2(PC7)
*/
float sim_time =0;//simulation time 초기값.
uint32_t duty=0;
void setup()
{
Serial.begin(115200);
//pwm 을 사용하기 위해서는 해당 pin을 PIO 가 아니라 Peripheral function 기능을 사용해야 한다.
//pin의 peripheral function기능을 활성화 시키기 위해서는 해당 pin의 PIO 를 disable하여야 한다.
PIOC->PIO_PDR = PIO_PC2 | PIO_PC3 | PIO_PC4 | PIO_PC5 | PIO_PC6 | PIO_PC7;//pc2~pc7의 pio(gpio사용기능해제)
//PC2~7을 pwm출력 pin으로 설정하자. pin은 PIO가 아니라 peripheral function기능으로 사용되어야 한다.
//pc2~7을 모두 peripheral B로 설정해야 pwm 출력 pin으로 사용할 수 있다.
//PIO_ABSR레지스터의 해당 비트에 0을 쓰면 peripheral A function, 1을 쓰면 B function으로 설정된다.
PIOC->PIO_ABSR |= PIO_PC2 | PIO_PC3 | PIO_PC4 | PIO_PC5 | PIO_PC6 | PIO_PC7 ;//PC2~7을 peripheral B로 설정
pmc_enable_periph_clk(ID_PWM);//prtipheral pwm 에 공급되는 clock을 enable시킨다
PWM-> PWM_DIS = (1u<<0) | (1u<<1) | (1u<<2) ;//pwm channel 0,1,2번을 disable시킨다.
//pwm을 발생시키기 위해선 clock generator 설정을 해주어야 한다.
//이 설정은 PWM_CLK에서 하는데, 여기서 하는일은 다음과 같다.
//<1>마스터클럭을 그대로 쓸지, 아니면 분주된 클럭을 쓸지를 결정한다.(이것은 PREA,PREB를 통해 설정된다)
//<2>이렇게 일차적으로 분주된 클럭을 다시 한번 linear division할 수 있는데 DIVA,DIVB를 통해 분주비를
//설정할 수 있다.
//<3>clock generator의 경우 클럭A와 클럭B를 생성할 수 있는데 2개가 모두 사용될 수 있고, 하나만 사용할 수 있다
//<4>마스터클럭을 분주하지 않으려면 PREA를 0b0000으로 설정하고 linear division을 1로 설정하려면 DIVA=1로 하면 된다.
//CLKB를 사용하지 않으려면 DIVB=0으로 설정하면 된다
PWM->PWM_CLK &= ~0x0F000F00; //PREB,PREA = 0000 -> MCK(84MHz)를 사용하겠다
PWM->PWM_CLK &= ~0x00FF0000; //DIVB = 0x00 clkb turn off
PWM->PWM_CLK &= ~0x000000FF; //DIVA = 0x00 clka역시 turn off
PWM->PWM_CLK |= (0x000000FF & 1); //DIVA = 1 DIVA=1
//위와 같이 설정하면, 클럭 B는 사용하지 않는 상태가 되고 클럭A의 PREA는 0이므로 마스터클럭을 그대로 이용
//하게 된다. DIVA가 1이므로 PREA에서 설정한 클럭(마스터클럭)그대로 사용하게 된다.
//각 채널별로 처리해주어야 할것들이 있다. 이것들은 PWM_CMR레지스터를 이용하여 처리된다.
//PWM_CMR의 CPRE 비트에서는 어떤 클럭을 사용할 것인지 선택하는데, 마스터클럭을 분주한 하위클럭들과 CLKA,CLKB
//중 하나를 선택하게 된다.
//PWM WAVE FORM을 center aligned 하게 되면 left aligned 보다 주기가 2배 늘어나서 pwm 주파수가 느려지게 된다.
//polarity설정의 경우, polarity의 비트가 0일때 듀티가 10%가 나오면 1일때 듀티가 90이 나오게 된다.
PWM-> PWM_CH_NUM[0].PWM_CMR &= ~0x0000000F; //CPRE를 모두 0으로 CLEAR
PWM-> PWM_CH_NUM[0].PWM_CMR |= 0xB; //CPRE=0XB=0b1011로 설정, 즉 clka를 선택함.
PWM-> PWM_CH_NUM[0].PWM_CMR |= 1u<<8; //CALG=1, center aligned
PWM-> PWM_CH_NUM[0].PWM_CMR &= ~(1u<<9); //CPOL=0
//PWM-> PWM_CH_NUM[0].PWM_CMR |= 1u<<9; //CPOL=1
//PWM-> PWM_CH_NUM[0].PWM_CMR |= 1u<<17;//DTL=1
//PWM-> PWM_CH_NUM[0].PWM_CMR |= 1u<<18;//DTH=1
//CH0,CH1,CH2의 dead time generator 를 enable시킴.
PWM-> PWM_CH_NUM[0].PWM_CMR |= (1u<<16); //channel mode resistor deadtime generator enable
PWM-> PWM_CH_NUM[1].PWM_CMR |= (1u<<16);
PWM-> PWM_CH_NUM[2].PWM_CMR |= (1u<<16);
//데드타임의 값을 설정함.
//PWM_DT레지스터는 DTL(PWML의 데드타임)과 DTH(PWMH의 데드타임)으로 나뉜다.
PWM-> PWM_CH_NUM[0].PWM_DT = 0x00030003;//CHO: DTL=3, DTH=3
PWM-> PWM_CH_NUM[1].PWM_DT = 0x00050005;//CH1: DTL=5. DTH=5
PWM-> PWM_CH_NUM[2].PWM_DT = 0x000F000F;//CH2: DTL=15 DTH=15
//PWM channel period 설정
//만일 pwm channel 이 disable된 상태라면 PWM_CPRD에 period값을 쓴다.
//그렇지 않고 enable된 상태라면 PWM_CPRDUPD에 period값을 쓴다. 뒤에 UPD가 붙은것은 버퍼이다.
//우리는 disable한 상태이다.
PWM-> PWM_CH_NUM[0].PWM_CPRD = 2100; //tpo value -> 84M/(2*2100) = 20000Hz 마스터클럭을 그대로 사용했고 centeraligned 방식이므로 2를 나눈다.
//pwm channel duty설정.
//PWM CHANNEL 이 DISABLE된 상태라면 PWM_CDTY에 DUTY값을 작성한다.
//그렇지 않고 ENABLE된 상태라면 PWM_CDTYUPD에 DUTY값을 작성한다. 우리는 DISABLE한 상태이다.
//이때 듀티값은 period값보다 작거나 같아야 한다.
//이곳에 작성한 듀티값은 초기값이다.
PWM-> PWM_CH_NUM[0].PWM_CDTY = 0;
PWM-> PWM_CH_NUM[1].PWM_CDTY = 0;
PWM-> PWM_CH_NUM[2].PWM_CDTY = 0;
PWM-> PWM_SCM |= 0x00000007; //same Source Sync pwm sync channels mode registor
PWM-> PWM_SCM &= ~0x00030000;
//PWM_ENA는 하위 8비트가 CHIDx(x=0~7)을 구성한다. 여기서 해당 비트에 0을 쓰면 아무일도 안일어나고 해당비트
//에 1을 쓰면 해당 채널의 pwm output이 enable된다.
PWM->PWM_ENA=1u<<0; //0번 채널을 enable한 것.
}
void loop()
{
//sim_time += 0.005; //클수록 빨라짐 simulation time 갱신
//duty = (uint32_t)(1050*cos(sim_time)+1050); //0<=듀티<=2100
duty=2000;//(0~2100사이의 값을 가져야 함)
PWM-> PWM_CH_NUM[0].PWM_CDTYUPD = duty;//PWM Channel Duty Cycle Update Register
PWM-> PWM_CH_NUM[1].PWM_CDTYUPD = duty;//CDTYUPD는 This register acts as a double buffer for the CDTY value.
PWM-> PWM_CH_NUM[2].PWM_CDTYUPD = duty;
PWM->PWM_SCUC =1;//pwm 과 관련한 모든 정보를 갱신하게 해주는 레지스터이다. 항상 1로 해놓자.
Serial.println(duty);
delay(1);
}
'Programming > Embedded' 카테고리의 다른 글
[Arduino Due]-micro periodic library test code (0) | 2022.02.19 |
---|---|
[Arduino Due]-basic ADC code (0) | 2022.02.19 |
[Arduino Due]-basic timer interrupt code (0) | 2022.02.18 |
[Arduino Due]-basic pin change interrupt code (0) | 2022.02.18 |
[Arduino Due]-basic PIO control code (0) | 2022.02.18 |