아두이노 듀에는 아두이노 사에서 제공하는 여타 아두이노시리즈 중에서 월등한 사양을 자랑합니다.
기본적으로 AVR 코어를 실장한 ATmega시리즈가 8비트 프로세서인 반면 듀에는 ARM 32비트 프로세서를 이용하며
수많은 peripheral기능을 제공합니다. 여타 자세한 사항은 듀에의 사양과 관련해 포스팅한 글을 참조하면 됩니다.
해서 듀에의 출력 주파수를 어느정도 올려볼 수 있는지 간단한 실험을 해보았습니다.
1. 아두이노에서 제공하는 라이브러리를 사용
void setup() {
pinMode(8, OUTPUT);
}
void loop() {
while (true) {
digitalWrite(8, HIGH);
digitalWrite(8, LOW);
}
}

위의 코드를 듀에에 올려 출력한 파형으로, 240khz정도가 나옵니다.
우노로 실험했을때(아래사진)과 크게 성능차이를 볼 수 없습니다.

<우노로 실험한 내역>
2. 레지스터에 직접 접근하여 사용
void setup() { pinMode(8, OUTPUT); } void loop() { while (true) { g_APinDescription[8].pPort -> PIO_SODR = g_APinDescription[8].ulPin; g_APinDescription[8].pPort -> PIO_CODR = g_APinDescription[8].ulPin; } }

출력주파수가 대략 17MHZ정도로 월등히 속도가 빨라집니다.
3. 아두이노 듀 보드에서 제공하는 PWM peripheral 을 레지스터로 제어하여 pwm control
float duty=0;
void setup()
{
Serial.begin(115200);
PIOC->PIO_PDR = PIO_PC2 | PIO_PC3 | PIO_PC4 | PIO_PC5 | PIO_PC6 | PIO_PC7;//pc2~pc7의 pio(gpio사용기능해제)
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->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
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<<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-> 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-> PWM_CH_NUM[0].PWM_CPRD = 5;
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->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=4;
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);
}

해당 코드를 사용하여, 약 17MHZ까지는 올려보았습니다.
하지만 configure을 어설프게 한 탓인지 그 이상으로 올리진 못했습니다.
이후 해외유저들이 작성한 코드를 발견하게 되었는데 , one bit PWM을 이용하여 매우 높은 주파수를 출력할 수 있었습니다.
master clock인 84mhz뿐만 아니라 그 이상의 주파수도 출력할 수 있는것으로 보입니다
uint32_t pwmPin = 8;
uint32_t maxDutyCount = 2;
uint32_t clkAFreq = 42000000ul;
uint32_t pwmFreq = 42000000ul;
void setup()
{
pmc_enable_periph_clk(PWM_INTERFACE_ID);
PWMC_ConfigureClocks(clkAFreq, 0, VARIANT_MCK);
PIO_Configure(
g_APinDescription[pwmPin].pPort,
g_APinDescription[pwmPin].ulPinType,
g_APinDescription[pwmPin].ulPin,
g_APinDescription[pwmPin].ulPinConfiguration);
uint32_t channel = g_APinDescription[pwmPin].ulPWMChannel;
PWMC_ConfigureChannel(PWM_INTERFACE, channel , pwmFreq, 0, 0);
PWMC_SetPeriod(PWM_INTERFACE, channel, maxDutyCount);
PWMC_EnableChannel(PWM_INTERFACE, channel);
PWMC_SetDutyCycle(PWM_INTERFACE, channel, 1);
pmc_mck_set_prescaler(2);
}
void loop()
{
}

'Programming > Embedded' 카테고리의 다른 글
[stm32f103c8] 학습 (0) | 2022.02.19 |
---|---|
USART 통신 문자열 전송 (0) | 2022.02.19 |
[아두이노] 아두이노 기반의, 레이더형 전면부 감지장치 (0) | 2022.02.19 |
[Arduino Due]-micro periodic library test code (0) | 2022.02.19 |
[Arduino Due]-basic ADC code (0) | 2022.02.19 |