//----------------------------------------------------------------------------- static void uart_init(uint32_t baud) { uint64_t br = (uint64_t)65536 * (F_CPU - 16 * baud) / F_CPU; HAL_GPIO_UART_TX_out(); HAL_GPIO_UART_TX_pmuxen(PORT_PMUX_PMUXE_C_Val); HAL_GPIO_UART_RX_in(); HAL_GPIO_UART_RX_pmuxen(PORT_PMUX_PMUXE_C_Val); PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0; GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM0_GCLK_ID_CORE) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0); SERCOM0->USART.CTRLA.reg = SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK | SERCOM_USART_CTRLA_RXPO(3/*PAD3*/) | SERCOM_USART_CTRLA_TXPO(1/*PAD2*/); SERCOM0->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(0/*8 bits*/); SERCOM0->USART.BAUD.reg = (uint16_t)br+1; SERCOM0->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; }
/* This is a slightly modified version of the timer setup found at: https://github.com/maxbader/arduino_tools */ void startTimer(int frequencyHz) { REG_GCLK_CLKCTRL = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID (GCM_TCC2_TC3)) ; while ( GCLK->STATUS.bit.SYNCBUSY == 1 ); TcCount16* TC = (TcCount16*) TC3; TC->CTRLA.reg &= ~TC_CTRLA_ENABLE; // Use the 16-bit timer TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16; while (TC->STATUS.bit.SYNCBUSY == 1); // Use match mode so that the timer counter resets when the count matches the compare register TC->CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; while (TC->STATUS.bit.SYNCBUSY == 1); // Set prescaler to 1024 TC->CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1024; while (TC->STATUS.bit.SYNCBUSY == 1); setTimerFrequency(frequencyHz); // Enable the compare interrupt TC->INTENSET.reg = 0; TC->INTENSET.bit.MC0 = 1; NVIC_EnableIRQ(TC3_IRQn); TC->CTRLA.reg |= TC_CTRLA_ENABLE; while (TC->STATUS.bit.SYNCBUSY == 1); }
/** * Configures the TC to generate output events at the sample frequency. * * Configures the TC in Frequency Generation mode, with an event output once * each time the audio sample frequency period expires. */ void ZerodioClass::tcConfigure(uint32_t sampleRate) { // Enable GCLK for TCC2 and TC5 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)) ; while (GCLK->STATUS.bit.SYNCBUSY); tcReset(); // Set Timer counter Mode to 16 bits TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16; // Set TC5 mode as match frequency TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE; TC5->COUNT16.CC[0].reg = (uint16_t) (SystemCoreClock / sampleRate - 1); while (tcIsSyncing()); // Configure interrupt request NVIC_DisableIRQ(TC5_IRQn); NVIC_ClearPendingIRQ(TC5_IRQn); NVIC_SetPriority(TC5_IRQn, 0); NVIC_EnableIRQ(TC5_IRQn); // Enable the TC5 interrupt request TC5->COUNT16.INTENSET.bit.MC0 = 1; while (tcIsSyncing()); }
/*************************************************************************//** *****************************************************************************/ void HAL_TimerInit(void) { halTimerIrqCount = 0; PM->APBCMASK.reg |= PM_APBCMASK_TC4; GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(0x15/*TC4,TC5*/) | GCLK_CLKCTRL_GEN(0); SYSTIMER.CTRLA.reg = TC_CTRLA_MODE(TC_CTRLA_MODE_COUNT16_Val) | TC_CTRLA_WAVEGEN(TC_CTRLA_WAVEGEN_MFRQ_Val) | TC_CTRLA_PRESCALER(3 /*DIV8*/) | TC_CTRLA_PRESCSYNC(TC_CTRLA_PRESCSYNC_PRESC_Val); halTimerSync(); SYSTIMER.COUNT.reg = 0; halTimerSync(); SYSTIMER.CC[0].reg = TIMER_TOP; halTimerSync(); SYSTIMER.CTRLA.reg = TC_CTRLA_ENABLE; halTimerSync(); SYSTIMER.INTENSET.reg = TC_INTENSET_MC(0); NVIC_EnableIRQ(TC4_IRQn); }
void RtcInit() { // SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ENABLE | SYSCTRL_XOSC32K_EN32K; // //wait for crystal to warm up // while((SYSCTRL->PCLKSR.reg & (SYSCTRL_PCLKSR_XOSC32KRDY)) == 0); GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(8); GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_SRC(GCLK_SOURCE_OSC8M) | GCLK_GENCTRL_IDC | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_GENEN; while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); // Configure RTC GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(RTC_GCLK_ID) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(2); RTC->MODE1.CTRL.reg = RTC_MODE1_CTRL_MODE_COUNT16; while (RTC->MODE1.STATUS.bit.SYNCBUSY); // Prescaler needs to be enabled separately from the mode for some reason RTC->MODE1.CTRL.reg |= RTC_MODE1_CTRL_PRESCALER_DIV1; while (RTC->MODE1.STATUS.bit.SYNCBUSY); RTC->MODE1.PER.reg = 998; while (RTC->MODE1.STATUS.bit.SYNCBUSY); RTC->MODE1.READREQ.reg |= RTC_READREQ_RCONT | RTC_READREQ_ADDR(0x10); RTC->MODE1.INTENSET.reg = RTC_MODE1_INTENSET_OVF; RTC->MODE1.CTRL.bit.ENABLE = 1; while (RTC->MODE1.STATUS.bit.SYNCBUSY); NVIC_EnableIRQ(RTC_IRQn); }
static void poweron(pwm_t dev) { PM->APBCMASK.reg |= (PM_APBCMASK_TCC0 << _num(dev)); GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(_clk_id(dev))); while (GCLK->STATUS.bit.SYNCBUSY) {} }
void enable_pclock(uint32_t clock_id, uint32_t pmask) { GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(clock_id) | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_CLKEN); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) ; PM->APBCMASK.reg |= pmask; }
void pwm_poweroff(pwm_t dev) { _tcc(dev)->CTRLA.reg &= ~(TCC_CTRLA_ENABLE); PM->APBCMASK.reg &= ~(PM_APBCMASK_TCC0 << _num(dev)); GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN_GCLK7 | GCLK_CLKCTRL_ID(_clk_id(dev))); while (GCLK->STATUS.bit.SYNCBUSY) {} }
/** * @brief Initialize RTT module * * The RTT is running at 32768 Hz by default, i.e. @ XOSC32K frequency without * divider. There are 2 cascaded dividers in the clock path: * * - GCLK_GENDIV_DIV(n): between 1 and 31 * - RTC_MODE0_CTRL_PRESCALER_DIVn: between 1 and 1024, see defines in `component_rtc.h` * * However the division scheme of GCLK_GENDIV_DIV can be changed by setting * GCLK_GENCTRL_DIVSEL: * * - GCLK_GENCTRL_DIVSEL = 0: Clock divided by GENDIV.DIV (default) * - GCLK_GENCTRL_DIVSEL = 1: Clock divided by 2^( GENDIV.DIV + 1 ) */ void rtt_init(void) { RtcMode0 *rtcMode0 = &(RTT_DEV); /* Turn on power manager for RTC */ PM->APBAMASK.reg |= PM_APBAMASK_RTC; /* RTC uses External 32,768KHz Oscillator because OSC32K isn't accurate * enough (p1075/1138). Also keep running in standby. */ SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND | SYSCTRL_XOSC32K_EN32K | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_STARTUP(6) | #if RTT_RUNSTDBY SYSCTRL_XOSC32K_RUNSTDBY | #endif SYSCTRL_XOSC32K_ENABLE; /* Setup clock GCLK2 with divider 1 */ GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(1); while (GCLK->STATUS.bit.SYNCBUSY) {} /* Enable GCLK2 with XOSC32K as source. Use divider without modification * and keep running in standby. */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_GENEN | #if RTT_RUNSTDBY GCLK_GENCTRL_RUNSTDBY | #endif GCLK_GENCTRL_SRC_XOSC32K; while (GCLK->STATUS.bit.SYNCBUSY) {} /* Connect GCLK2 to RTC */ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK2 | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(RTC_GCLK_ID); while (GCLK->STATUS.bit.SYNCBUSY) {} /* Disable RTC */ rtt_poweroff(); /* Reset RTC */ rtcMode0->CTRL.bit.SWRST = 1; while (rtcMode0->STATUS.bit.SYNCBUSY || rtcMode0->CTRL.bit.SWRST) {} /* Configure as 32bit counter with no prescaler and no clear on match compare */ rtcMode0->CTRL.reg = RTC_MODE0_CTRL_MODE_COUNT32 | RTT_PRESCALER; while (rtcMode0->STATUS.bit.SYNCBUSY) {} /* Setup interrupt */ NVIC_EnableIRQ(RTT_IRQ); /* Enable RTC */ rtt_poweron(); }
void SERCOM::initClockNVIC( void ) { uint8_t clockId = 0; IRQn_Type IdNvic=PendSV_IRQn ; // Dummy init to intercept potential error later if(sercom == SERCOM0) { clockId = GCM_SERCOM0_CORE; IdNvic = SERCOM0_IRQn; } else if(sercom == SERCOM1) { clockId = GCM_SERCOM1_CORE; IdNvic = SERCOM1_IRQn; } else if(sercom == SERCOM2) { clockId = GCM_SERCOM2_CORE; IdNvic = SERCOM2_IRQn; } else if(sercom == SERCOM3) { clockId = GCM_SERCOM3_CORE; IdNvic = SERCOM3_IRQn; } else if(sercom == SERCOM4) { clockId = GCM_SERCOM4_CORE; IdNvic = SERCOM4_IRQn; } else if(sercom == SERCOM5) { clockId = GCM_SERCOM5_CORE; IdNvic = SERCOM5_IRQn; } if ( IdNvic == PendSV_IRQn ) { // We got a problem here return ; } // Setting NVIC NVIC_EnableIRQ(IdNvic); NVIC_SetPriority (IdNvic, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority */ //Setting clock GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx) GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source GCLK_CLKCTRL_CLKEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } }
void USBDeviceClass::init() { #ifdef PIN_LED_TXL txLEDPulse = 0; pinMode(PIN_LED_TXL, OUTPUT); digitalWrite(PIN_LED_TXL, HIGH); #endif #ifdef PIN_LED_RXL rxLEDPulse = 0; pinMode(PIN_LED_RXL, OUTPUT); digitalWrite(PIN_LED_RXL, HIGH); #endif // Enable USB clock PM->APBBMASK.reg |= PM_APBBMASK_USB; // Set up the USB DP/DN pins PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); // Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(6) | // Generic Clock Multiplexer 6 GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source GCLK_CLKCTRL_CLKEN; while (GCLK->STATUS.bit.SYNCBUSY) ; USB_SetHandler(&UDD_Handler); // Reset USB Device usbd.reset(); usbd.calibrate(); usbd.setUSBDeviceMode(); usbd.runInStandby(); usbd.setFullSpeed(); // Configure interrupts NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL); NVIC_EnableIRQ((IRQn_Type) USB_IRQn); usbd.enable(); initialized = true; }
/** Configures and starts the DFLL in closed loop mode with the given reference * generator. * * \param[in] source_generator Reference generator to use for the DFLL */ static void init_dfll( const enum system_clock_source source_generator) { struct system_gclk_gen_config cpu_clock_conf; system_gclk_gen_get_config_defaults(&cpu_clock_conf); cpu_clock_conf.output_enable = ENABLE_CPU_CLOCK_OUT; /* Switch to OSC8M/OSC16M while the DFLL is being reconfigured */ #if SAML21 cpu_clock_conf.source_clock = SYSTEM_CLOCK_SOURCE_OSC16M; #else cpu_clock_conf.source_clock = SYSTEM_CLOCK_SOURCE_OSC8M; #endif system_gclk_gen_set_config(GCLK_GENERATOR_0, &cpu_clock_conf); /* Turn off DFLL before adjusting its configuration */ system_clock_source_disable(SYSTEM_CLOCK_SOURCE_DFLL); /* Configure DFLL reference clock, use raw register write to * force-configure the channel even if the currently selected generator * clock has failed */ #if SAML21 GCLK->PCHCTRL[SYSCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_GEN(source_generator); #else GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SYSCTRL_GCLK_ID_DFLL48) | GCLK_CLKCTRL_GEN(source_generator); #endif system_gclk_chan_enable(SYSCTRL_GCLK_ID_DFLL48); /* Configure DFLL */ struct system_clock_source_dfll_config config_dfll; system_clock_source_dfll_get_config_defaults(&config_dfll); config_dfll.on_demand = false; config_dfll.loop_mode = SYSTEM_CLOCK_DFLL_LOOP_MODE_CLOSED; config_dfll.multiply_factor = (48000000UL / system_gclk_chan_get_hz(SYSCTRL_GCLK_ID_DFLL48)); system_clock_source_dfll_set_config(&config_dfll); /* Restart DFLL */ system_clock_source_enable(SYSTEM_CLOCK_SOURCE_DFLL); while (system_clock_source_is_ready(SYSTEM_CLOCK_SOURCE_DFLL) == false) { /* Wait for DFLL to be stable before switch back */ } /* Switch back to the DFLL as the CPU clock source */ cpu_clock_conf.source_clock = SYSTEM_CLOCK_SOURCE_DFLL; system_gclk_gen_set_config(GCLK_GENERATOR_0, &cpu_clock_conf); };
/*************************************************************************//** *****************************************************************************/ void HAL_UartInit(uint32_t baudrate) { uint64_t brr = (uint64_t)65536 * (F_CPU - 16 * baudrate) / F_CPU; HAL_GPIO_UART_TXD_out(); HAL_GPIO_UART_TXD_pmuxen(); HAL_GPIO_UART_RXD_in(); HAL_GPIO_UART_RXD_pmuxen(); PORTA_PMUX12 = PORTA_PMUX12_PMUXE(2/*C*/) | PORTA_PMUX12_PMUXO(2/*C*/); PM_APBCMASK |= PM_APBCMASK_SERCOM3; GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(0x10/*SERCOM3_CORE*/) | GCLK_CLKCTRL_GEN(0); SC3_USART_CTRLA = SC3_USART_CTRLA_MODE(1/*USART*/) | SC3_USART_CTRLA_DORD | SC3_USART_CTRLA_RXPO(3/*PAD3*/) | SC3_USART_CTRLA_TXPO/*PAD2*/; halUartSync(); SC3_USART_CTRLB = SC3_USART_CTRLB_TXEN | SC3_USART_CTRLB_RXEN | SC3_USART_CTRLB_CHSIZE(0/*8 bits*/); halUartSync(); SC3_USART_BAUD = (uint16_t)brr; halUartSync(); SC3_USART_CTRLA |= SC3_USART_CTRLA_ENABLE; halUartSync(); SC3_USART_INTENSET = SC3_USART_INTENSET_RXC; NVIC_ISER = NVIC_ISER_SERCOM3; txFifo.data = txData; txFifo.size = HAL_UART_TX_FIFO_SIZE; txFifo.bytes = 0; txFifo.head = 0; txFifo.tail = 0; rxFifo.data = rxData; rxFifo.size = HAL_UART_RX_FIFO_SIZE; rxFifo.bytes = 0; rxFifo.head = 0; rxFifo.tail = 0; udrEmpty = true; newData = false; }
void SystemInit(void) { // Setup flash to work with 48Mhz clock NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_RWS_HALF; // Enable external 32Khz crystal uint32_t val = (SYSCTRL_XOSC32K_STARTUP(6) | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K); SYSCTRL->XOSC32K.reg = val; SYSCTRL->XOSC32K.reg = val | SYSCTRL_XOSC32K_ENABLE; while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY)) ; // Reset GCLK GCLK->CTRL.reg = GCLK_CTRL_SWRST; while (GCLK->CTRL.reg & GCLK_CTRL_SWRST) ; // Route 32Khz clock to DFLL48M GCLK->GENDIV.reg = GCLK_GENDIV_ID(CLK_32K); GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(CLK_32K) | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN); GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_ID(MCLK_DFLL48M) | GCLK_CLKCTRL_GEN(CLK_32K) | GCLK_CLKCTRL_CLKEN); // Configure DFLL48M clock SYSCTRL->DFLLCTRL.reg = 0; uint32_t mul = DIV_ROUND_CLOSEST(CONFIG_CLOCK_FREQ, CLK_32K_FREQ); SYSCTRL->DFLLMUL.reg = (SYSCTRL_DFLLMUL_CSTEP(31) | SYSCTRL_DFLLMUL_FSTEP(511) | SYSCTRL_DFLLMUL_MUL(mul)); SYSCTRL->DFLLCTRL.reg = (SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK | SYSCTRL_DFLLCTRL_QLDIS | SYSCTRL_DFLLCTRL_ENABLE); uint32_t ready = (SYSCTRL_PCLKSR_DFLLRDY | SYSCTRL_PCLKSR_DFLLLCKC | SYSCTRL_PCLKSR_DFLLLCKF); while ((SYSCTRL->PCLKSR.reg & ready) != ready) ; // Switch main clock to DFLL48M clock GCLK->GENDIV.reg = GCLK_GENDIV_ID(CLK_MAIN); GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(CLK_MAIN) | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN); }
/*************************************************************************//** *****************************************************************************/ void halPhyInit(void) { // Configure IO pins HAL_GPIO_PHY_SLP_TR_out(); HAL_GPIO_PHY_SLP_TR_clr(); HAL_GPIO_PHY_RST_out(); HAL_GPIO_PHY_IRQ_in(); HAL_GPIO_PHY_IRQ_pmuxen(); HAL_GPIO_PHY_CS_out(); HAL_GPIO_PHY_MISO_in(); HAL_GPIO_PHY_MISO_pmuxen(); HAL_GPIO_PHY_MOSI_out(); HAL_GPIO_PHY_MOSI_pmuxen(); HAL_GPIO_PHY_SCK_out(); HAL_GPIO_PHY_SCK_pmuxen(); // Configure SPI PORT->Group[HAL_GPIO_PORTA].PMUX[9].bit.PMUXE = 2/*C*/; // MOSI PORT->Group[HAL_GPIO_PORTA].PMUX[9].bit.PMUXO = 2/*C*/; // SCK PORT->Group[HAL_GPIO_PORTA].PMUX[8].bit.PMUXE = 2/*C*/; // MISO PM->APBCMASK.reg |= PM_APBCMASK_SERCOM1; GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SERCOM1_GCLK_ID_CORE) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0); SERCOM1->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_RXEN; halPhySpiSync(); #if F_CPU <= 16000000 SERCOM1->SPI.BAUD.reg = 0; #elif F_CPU <= 32000000 SERCOM1->SPI.BAUD.reg = 1; #elif F_CPU <= 48000000 SERCOM1->SPI.BAUD.reg = 2; #else #error Unsupported frequency #endif SERCOM1->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_ENABLE | SERCOM_SPI_CTRLA_MODE_SPI_MASTER | SERCOM_SPI_CTRLA_DIPO(0) | SERCOM_SPI_CTRLA_DOPO; halPhySpiSync(); }
//----------------------------------------------------------------------------- static void timer_init(void) { PM->APBCMASK.reg |= PM_APBCMASK_TC1; GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(TC1_GCLK_ID) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0); TC1->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 | TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV256 | TC_CTRLA_PRESCSYNC_RESYNC; TC1->COUNT16.COUNT.reg = 0; timer_set_period(PERIOD_SLOW); TC1->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; TC1->COUNT16.INTENSET.reg = TC_INTENSET_MC(1); NVIC_EnableIRQ(TC1_IRQn); }
void SaLBuzzerInit() { pinOut(BUZZER); pinCfg(BUZZER); // PM->APBCMASK.reg |= PM_APBCMASK_TC5; // GCLK->GENDIV.reg = GCLK_GENDIV_ID(5) | GCLK_GENDIV_DIV(1); GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(5) | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_GENEN; GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN(0) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(TC5_GCLK_ID); TC5->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16| TC_CTRLA_RUNSTDBY | // TC_CTRLA_PRESCSYNC_GCLK | TC_CTRLA_PRESCALER_DIV4; // TC5->COUNT16.EVCTRL.bit.EVACT = 0x1; TC5->COUNT16.CC[0].bit.CC = 700; //TC5->COUNT16.PER.reg = 0x02; TC5->COUNT16.INTENSET.reg = TC_INTENSET_MC0; TC5->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; TC5->COUNT16.EVCTRL.bit.EVACT = 0x1; NVIC_EnableIRQ(TC5_IRQn); NVIC_SetPriority(TC5_IRQn,0xFFF); TC5->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_STOP; }
// **************************************************************************** void HAL_spi_init(void) { // Use GLKGEN0 (48 MHz) as clock source for SPI GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(SPI_SERCOM_GCLK_ID) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0); // Reset the peripheral SPI_SERCOM->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_SWRST; while (SPI_SERCOM->SPI.CTRLA.reg & SERCOM_SPI_CTRLA_SWRST); // 12 MHz SPI clock @ 48 MHz SPI_SERCOM->SPI.BAUD.reg = 1; // Enable the SPI master, mode 0 SPI_SERCOM->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER | SERCOM_SPI_CTRLA_DOPO(0) | SERCOM_SPI_CTRLA_ENABLE ; }
/* Configure I/O interrupt sources */ static void __initialize() { memset(callbacksInt, 0, sizeof(callbacksInt)); NVIC_DisableIRQ(EIC_IRQn); NVIC_ClearPendingIRQ(EIC_IRQn); NVIC_SetPriority(EIC_IRQn, 0); NVIC_EnableIRQ(EIC_IRQn); // Enable GCLK for IEC (External Interrupt Controller) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_EIC)); /* Shall we do that? // Do a software reset on EIC EIC->CTRL.SWRST.bit = 1 ; while ((EIC->CTRL.SWRST.bit == 1) && (EIC->STATUS.SYNCBUSY.bit == 1)) { } */ // Enable EIC EIC->CTRL.bit.ENABLE = 1; while (EIC->STATUS.bit.SYNCBUSY == 1) { } }
//----------------------------------------------------------------------------- void udc_init(void) { HAL_GPIO_USB_DM_pmuxen(PORT_PMUX_PMUXE_G_Val); HAL_GPIO_USB_DP_pmuxen(PORT_PMUX_PMUXE_G_Val); PM->APBBMASK.reg |= PM_APBBMASK_USB; GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(USB_GCLK_ID) | GCLK_CLKCTRL_GEN(0); USB->DEVICE.CTRLA.bit.SWRST = 1; while (USB->DEVICE.SYNCBUSY.bit.SWRST); USB->DEVICE.PADCAL.bit.TRANSN = NVM_READ_CAL(USB_TRANSN); USB->DEVICE.PADCAL.bit.TRANSP = NVM_READ_CAL(USB_TRANSP); USB->DEVICE.PADCAL.bit.TRIM = NVM_READ_CAL(USB_TRIM); memset((uint8_t *)udc_mem, 0, sizeof(udc_mem)); USB->DEVICE.DESCADD.reg = (uint32_t)udc_mem; USB->DEVICE.CTRLA.bit.MODE = USB_CTRLA_MODE_DEVICE_Val; USB->DEVICE.CTRLA.bit.RUNSTDBY = 1; USB->DEVICE.CTRLB.bit.SPDCONF = USB_DEVICE_CTRLB_SPDCONF_FS_Val; USB->DEVICE.CTRLB.bit.DETACH = 0; USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_EORST; USB->DEVICE.DeviceEndpoint[0].EPINTENSET.bit.RXSTP = 1; USB->DEVICE.CTRLA.reg |= USB_CTRLA_ENABLE; for (int i = 0; i < USB_EPT_NUM; i++) { udc_reset_endpoint(i, USB_IN_ENDPOINT); udc_reset_endpoint(i, USB_OUT_ENDPOINT); } NVIC_EnableIRQ(USB_IRQn); }
void main_clock_init (void) { /* enable the xosc32k and set the start up time */ SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP(6) | SYSCTRL_XOSC32K_EN32K | SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_ENABLE; while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY){} /* enable the generic clock GEN1 and configure the XOSC32K as clock source for it */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID_GCLK1 | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_IDC; while (GCLK->STATUS.bit.SYNCBUSY){} /* Enable the DFLL and set the operation mode as closed loop */ SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE | SYSCTRL_DFLLCTRL_MODE; while(!SYSCTRL->PCLKSR.bit.DFLLRDY){} /* Load the Multiply factor, Coarse Step and fine Step for DFLL */ SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(0x1F/4) | SYSCTRL_DFLLMUL_FSTEP(0xFF/4) | SYSCTRL_DFLLMUL_MUL(1465); /* Enable the Generic Clock GEN 1 as DFLL48 as Reference */ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_ID(0); /* wait for fine lock */ while(!SYSCTRL->PCLKSR.bit.DFLLLCKF){} /* Set the NVM Read Wait States to 1, Since the operating frequency 48 MHz */ NVMCTRL->CTRLB.bit.RWS = 1; /* Enable the Generic Clock 0 and Configure the DFLL as Clock Source for it*/ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID_GCLK0 | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_IDC; while(GCLK->STATUS.bit.SYNCBUSY){} }
// **************************************************************************** void HAL_uart_init(uint32_t baudrate) { #define UART_CLK 48000000 uint64_t brr = (uint64_t)65536 * (UART_CLK - 16 * baudrate) / UART_CLK; // Use GLKGEN0 (48 MHz) as clock source for the UART GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(UART_SERCOM_GCLK_ID) | GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(0); // Run UART from GCLK; Setup Rx and Tx pads UART_SERCOM->USART.CTRLA.reg = SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_MODE_USART_INT_CLK | SERCOM_USART_CTRLA_RXPO(HAL_GPIO_RX.rxpo) | SERCOM_USART_CTRLA_TXPO(tx_pad); // Enable transmit and receive; 8 bit characters UART_SERCOM->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_CHSIZE(0); // 8 bits while (UART_SERCOM->USART.SYNCBUSY.reg); UART_SERCOM->USART.BAUD.reg = (uint16_t)brr; while (UART_SERCOM->USART.SYNCBUSY.reg); UART_SERCOM->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; while (UART_SERCOM->USART.SYNCBUSY.reg); // Enable the receive interrupt UART_SERCOM->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC; NVIC_EnableIRQ(UART_SERCOM_IRQN); }
/*************************************************************************//** *****************************************************************************/ void HAL_TimerInit(void) { halTimerIrqCount = 0; PM_APBCMASK |= PM_APBCMASK_TC4; GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_ID(0x15/*TC4,TC5*/) | GCLK_CLKCTRL_GEN(0); TC4_16_CTRLA = TC4_16_CTRLA_MODE(0/*16 bit*/) | TC4_16_CTRLA_WAVEGEN(1/*MFRQ*/) | TC4_16_CTRLA_PRESCALER(3/*DIV8*/) | TC4_16_CTRLA_PRESCSYNC(0x1/*PRESC*/); halTimerSync(); TC4_16_COUNT = 0; halTimerSync(); TC4_16_CC0 = TIMER_TOP; halTimerSync(); TC4_16_CTRLA |= TC4_16_CTRLA_ENABLE; halTimerSync(); TC4_16_INTENSET = TC4_16_INTENSET_MC0; NVIC_ISER = NVIC_ISER_TC4; }
void UDD_Init(void) { uint32_t pad_transn; uint32_t pad_transp; uint32_t pad_trim; uint32_t i; /* Enable USB clock */ PM->APBBMASK.reg |= PM_APBBMASK_USB; /* Set up the USB DP/DN pins */ PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1; PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u))); PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u)); PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1; PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u))); PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u)); /* ---------------------------------------------------------------------------------------------- * Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference) */ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( 6 ) | // Generic Clock Multiplexer 6 GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source GCLK_CLKCTRL_CLKEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* Reset */ USB->DEVICE.CTRLA.bit.SWRST = 1; while (USB->DEVICE.SYNCBUSY.bit.SWRST) { /* Sync wait */ } udd_enable(); /* Load Pad Calibration */ pad_transn =( *((uint32_t *)(NVMCTRL_OTP4) // Non-Volatile Memory Controller + (NVM_USB_PAD_TRANSN_POS / 32)) >> (NVM_USB_PAD_TRANSN_POS % 32)) & ((1 << NVM_USB_PAD_TRANSN_SIZE) - 1); if (pad_transn == 0x1F) { // maximum value (31) pad_transn = 5; } USB->DEVICE.PADCAL.bit.TRANSN = pad_transn; pad_transp =( *((uint32_t *)(NVMCTRL_OTP4) + (NVM_USB_PAD_TRANSP_POS / 32)) >> (NVM_USB_PAD_TRANSP_POS % 32)) & ((1 << NVM_USB_PAD_TRANSP_SIZE) - 1); if (pad_transp == 0x1F) { // maximum value (31) pad_transp = 29; } USB->DEVICE.PADCAL.bit.TRANSP = pad_transp; pad_trim =( *((uint32_t *)(NVMCTRL_OTP4) + (NVM_USB_PAD_TRIM_POS / 32)) >> (NVM_USB_PAD_TRIM_POS % 32)) & ((1 << NVM_USB_PAD_TRIM_SIZE) - 1); if (pad_trim == 0x7) { // maximum value (7) pad_trim = 3; } USB->DEVICE.PADCAL.bit.TRIM = pad_trim; /* Set the configuration */ udd_force_device_mode(); udd_device_run_in_standby(); // Set address of USB SRAM USB->DEVICE.DESCADD.reg = (uint32_t)(&usb_endpoint_table[0]); // For USB_SPEED_FULL udd_force_full_speed(); for (i = 0; i < sizeof(usb_endpoint_table); i++) { (*(uint32_t *)(&usb_endpoint_table[0]+i)) = 0; } // Configure interrupts NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL); NVIC_EnableIRQ((IRQn_Type) USB_IRQn); }
void SystemInit( void ) { /* Set 1 Flash Wait State for 48MHz, cf tables 20.9 and 35.27 in SAMD21 Datasheet */ NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val ; /* Turn on the digital interface clock */ PM->APBAMASK.reg |= PM_APBAMASK_GCLK ; /* ---------------------------------------------------------------------------------------------- * 1) Enable XOSC32K clock (External on-board 32.768Hz oscillator) */ SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP( 0x6u ) | /* cf table 15.10 of product datasheet in chapter 15.8.6 */ SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K ; SYSCTRL->XOSC32K.bit.ENABLE = 1 ; /* separate call, as described in chapter 15.6.3 */ while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_XOSC32KRDY) == 0 ) { /* Wait for oscillator stabilization */ } /* Software reset the module to ensure it is re-initialized correctly */ /* Note: Due to synchronization, there is a delay from writing CTRL.SWRST until the reset is complete. * CTRL.SWRST and STATUS.SYNCBUSY will both be cleared when the reset is complete, as described in chapter 13.8.1 */ GCLK->CTRL.reg = GCLK_CTRL_SWRST ; while ( (GCLK->CTRL.reg & GCLK_CTRL_SWRST) && (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) ) { /* Wait for reset to complete */ } /* ---------------------------------------------------------------------------------------------- * 2) Put XOSC32K as source of Generic Clock Generator 1 */ GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ) ; // Generic Clock Generator 1 while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* Write Generic Clock Generator 1 configuration */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_XOSC32K ) | // Generic Clock Generator 1 GCLK_GENCTRL_SRC_XOSC32K | // Selected source is External 32KHz Oscillator // GCLK_GENCTRL_OE | // Output clock to a pin for tests GCLK_GENCTRL_GENEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 3) Put Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference) */ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GENERIC_CLOCK_MULTIPLEXER_DFLL48M ) | // Generic Clock Multiplexer 0 GCLK_CLKCTRL_GEN_GCLK1 | // Generic Clock Generator 1 is source GCLK_CLKCTRL_CLKEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 4) Enable DFLL48M clock */ /* DFLL Configuration in Closed Loop mode, cf product datasheet chapter 15.6.7.1 - Closed-Loop Operation */ /* Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905 */ SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0 ; while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP( 31 ) | // Coarse step is 31, half of the max value SYSCTRL_DFLLMUL_FSTEP( 511 ) | // Fine step is 511, half of the max value SYSCTRL_DFLLMUL_MUL( (__CLOCK_48MHz/__CLOCK_32KHz) ) ; // External 32KHz is the reference while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } /* Write full configuration to DFLL control register */ SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | /* Enable the closed loop mode */ SYSCTRL_DFLLCTRL_WAITLOCK | SYSCTRL_DFLLCTRL_QLDIS ; /* Disable Quick lock */ while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } /* Enable the DFLL */ SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_ENABLE ; while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKC) == 0 || (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLLCKF) == 0 ) { /* Wait for locks flags */ } while ( (SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0 ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 5) Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz. */ GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_MAIN ) ; // Generic Clock Generator 0 while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* Write Generic Clock Generator 0 configuration */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_MAIN ) | // Generic Clock Generator 0 GCLK_GENCTRL_SRC_DFLL48M | // Selected source is DFLL 48MHz // GCLK_GENCTRL_OE | // Output clock to a pin for tests GCLK_GENCTRL_IDC | // Set 50/50 duty cycle GCLK_GENCTRL_GENEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 6) Modify PRESCaler value of OSC8M to have 8MHz */ SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC_0_Val ; SYSCTRL->OSC8M.bit.ONDEMAND = 0 ; /* ---------------------------------------------------------------------------------------------- * 7) Put OSC8M as source for Generic Clock Generator 3 */ GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) ; // Generic Clock Generator 3 /* Write Generic Clock Generator 3 configuration */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC8M ) | // Generic Clock Generator 3 GCLK_GENCTRL_SRC_OSC8M | // Selected source is RC OSC 8MHz (already enabled at reset) // GCLK_GENCTRL_OE | // Output clock to a pin for tests GCLK_GENCTRL_GENEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* ---------------------------------------------------------------------------------------------- * 8) Put OSC8M as source for Generic Clock Generator 2, with freq/8 */ GCLK->GENDIV.reg = GCLK_GENDIV_ID( GENERIC_CLOCK_GENERATOR_OSC1M ) | 8 << 8; // Generic Clock Generator 4 /* Write Generic Clock Generator 3 configuration */ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID( GENERIC_CLOCK_GENERATOR_OSC1M ) | // Generic Clock Generator 4 GCLK_GENCTRL_SRC_OSC8M | // Selected source is RC OSC 8MHz (already enabled at reset) // GCLK_GENCTRL_OE | // Output clock to a pin for tests GCLK_GENCTRL_GENEN ; while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ) { /* Wait for synchronization */ } /* * Now that all system clocks are configured, we can set CPU and APBx BUS clocks. * There values are normally the one present after Reset. */ PM->CPUSEL.reg = PM_CPUSEL_CPUDIV_DIV1 ; PM->APBASEL.reg = PM_APBASEL_APBADIV_DIV1_Val ; PM->APBBSEL.reg = PM_APBBSEL_APBBDIV_DIV1_Val ; PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1_Val ; SystemCoreClock=__CLOCK_48MHz ; return; }
/* * Arduino Zero board initialization * * Good to know: * - At reset, ResetHandler did the system clock configuration. Core is running at 48MHz. * - Watchdog is disabled by default, unless someone plays with NVM User page * - During reset, all PORT lines are configured as inputs with input buffers, output buffers and pull disabled. */ void init( void ) { uint32_t ul ; // Set Systick to 1ms interval, common to all Cortex-M variants if ( SysTick_Config( SystemCoreClock / 1000 ) ) { // Capture error while ( 1 ) ; } // Clock PORT for Digital I/O // PM->APBBMASK.reg |= PM_APBBMASK_PORT ; // // // Clock EIC for I/O interrupts // PM->APBAMASK.reg |= PM_APBAMASK_EIC ; // Clock SERCOM for Serial PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_SERCOM2 | PM_APBCMASK_SERCOM3 | PM_APBCMASK_SERCOM4 | PM_APBCMASK_SERCOM5 ; // Clock TC/TCC for Pulse and Analog PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 ; // Clock ADC/DAC for Analog PM->APBCMASK.reg |= PM_APBCMASK_ADC ;//| PM_APBCMASK_DAC ; // Setup all pins (digital and analog) in INPUT mode (default is nothing) for ( ul = 0 ; ul < NUM_DIGITAL_PINS ; ul++ ) { pinMode( ul, INPUT ) ; } // Initialize Analog Controller // Setting clock while(GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_ADC ) | // Generic Clock ADC GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source GCLK_CLKCTRL_CLKEN ; while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains ADC->CTRLB.reg = ADC_CTRLB_PRESCALER_DIV512 | // Divide Clock by 512. ADC_CTRLB_RESSEL_10BIT; // 10 bits resolution as default ADC->SAMPCTRL.reg = 0x3f; // Set max Sampling Time Length while( ADC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains ADC->INPUTCTRL.reg = ADC_INPUTCTRL_MUXNEG_GND; // No Negative input (Internal Ground) // Averaging (see datasheet table in AVGCTRL register description) ADC->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_1 | // 1 sample only (no oversampling nor averaging) ADC_AVGCTRL_ADJRES(0x0ul); // Adjusting result by 0 analogReference( AR_DEFAULT ) ; // Analog Reference is AREF pin (3.3v) // Initialize DAC // Setting clock // while ( GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY ); // GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID( GCM_DAC ) | // Generic Clock ADC // GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source // GCLK_CLKCTRL_CLKEN ; // while ( DAC->STATUS.bit.SYNCBUSY == 1 ); // Wait for synchronization of registers between the clock domains // DAC->CTRLB.reg = DAC_CTRLB_REFSEL_AVCC | // Using the 3.3V reference // DAC_CTRLB_EOEN ; // External Output Enable (Vout) }
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration) { if (toneIsActive && (outputPin != lastOutputPin)) noTone(lastOutputPin); // // Calculate best prescaler divider and comparator value for a 16 bit TC peripheral // uint32_t prescalerConfigBits; uint32_t ccValue; ccValue = toneMaxFrequency / frequency - 1; prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1; if (ccValue > TONE_TC_TOP) { ccValue = toneMaxFrequency / frequency / 2 - 1; prescalerConfigBits = TC_CTRLA_PRESCALER_DIV2; if (ccValue > TONE_TC_TOP) { ccValue = toneMaxFrequency / frequency / 4 - 1; prescalerConfigBits = TC_CTRLA_PRESCALER_DIV4; if (ccValue > TONE_TC_TOP) { ccValue = toneMaxFrequency / frequency / 8 - 1; prescalerConfigBits = TC_CTRLA_PRESCALER_DIV8; if (ccValue > TONE_TC_TOP) { ccValue = toneMaxFrequency / frequency / 16 - 1; prescalerConfigBits = TC_CTRLA_PRESCALER_DIV16; if (ccValue > TONE_TC_TOP) { ccValue = toneMaxFrequency / frequency / 64 - 1; prescalerConfigBits = TC_CTRLA_PRESCALER_DIV64; if (ccValue > TONE_TC_TOP) { ccValue = toneMaxFrequency / frequency / 256 - 1; prescalerConfigBits = TC_CTRLA_PRESCALER_DIV256; if (ccValue > TONE_TC_TOP) { ccValue = toneMaxFrequency / frequency / 1024 - 1; prescalerConfigBits = TC_CTRLA_PRESCALER_DIV1024; } } } } } } } toggleCount = (duration > 0 ? frequency * duration * 2 / 1000UL : -1); // Enable GCLK for TC4 and TC5 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5)); while (GCLK->STATUS.bit.SYNCBUSY); resetTC(TONE_TC); // Set Timer counter Mode to 16 bits TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16; // Set TONE_TC mode as match frequency TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ; TONE_TC->COUNT16.CTRLA.reg |= prescalerConfigBits; TONE_TC->COUNT16.CC[TONE_TC_CHANNEL].reg = (uint16_t) ccValue; WAIT_TC16_REGS_SYNC(TONE_TC) // Configure interrupt request NVIC_DisableIRQ(TONE_TC_IRQn); NVIC_ClearPendingIRQ(TONE_TC_IRQn); NVIC_SetPriority(TONE_TC_IRQn, 0); NVIC_EnableIRQ(TONE_TC_IRQn); portToggleRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTTGL.reg); portClearRegister = &(PORT->Group[g_APinDescription[outputPin].ulPort].OUTCLR.reg); portBitMask = (1ul << g_APinDescription[outputPin].ulPin); // Enable the TONE_TC interrupt request TONE_TC->COUNT16.INTENSET.bit.MC0 = 1; lastOutputPin = outputPin; digitalWrite(outputPin, LOW); pinMode(outputPin, OUTPUT); toneIsActive = true; // Enable TONE_TC TONE_TC->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE; WAIT_TC16_REGS_SYNC(TONE_TC) }
// Right now, PWM output only works on the pins with // hardware support. These are defined in the appropriate // pins_*.c file. For the rest of the pins, we default // to digital output. void analogFastWrite(uint32_t pin, uint32_t value) { PinDescription pinDesc = g_APinDescription[pin]; uint32_t attr = pinDesc.ulPinAttribute; if ((attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG) { // DAC handling code if (pin != PIN_A0) { // Only 1 DAC on A0 (PA02) return; } value = mapResolution(value, _writeResolution, 10); syncDAC(); DAC->DATA.reg = value & 0x3FF; // DAC on 10 bits. syncDAC(); DAC->CTRLA.bit.ENABLE = 0x01; // Enable DAC syncDAC(); return; } if ((attr & PIN_ATTR_PWM) == PIN_ATTR_PWM) { value = mapResolution(value, _writeResolution, 8); // change to 10 for 10 bit... must also change TCx->COUNT8.PER.reg = 0x3FF uint32_t tcNum = GetTCNumber(pinDesc.ulPWMChannel); uint8_t tcChannel = GetTCChannelNumber(pinDesc.ulPWMChannel); static bool tcEnabled[TCC_INST_NUM+TC_INST_NUM]; if (!tcEnabled[tcNum]) { tcEnabled[tcNum] = true; if (attr & PIN_ATTR_TIMER) { #if !(ARDUINO_SAMD_VARIANT_COMPLIANCE >= 10603) // Compatibility for cores based on SAMD core <=1.6.2 if (pinDesc.ulPinType == PIO_TIMER_ALT) { pinPeripheral(pin, PIO_TIMER_ALT); } else #endif { pinPeripheral(pin, PIO_TIMER); } } else { // We suppose that attr has PIN_ATTR_TIMER_ALT bit set... pinPeripheral(pin, PIO_TIMER_ALT); } uint16_t GCLK_CLKCTRL_IDs[] = { GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC0 GCLK_CLKCTRL_ID(GCM_TCC0_TCC1), // TCC1 GCLK_CLKCTRL_ID(GCM_TCC2_TC3), // TCC2 GCLK_CLKCTRL_ID(GCM_TCC2_TC3), // TC3 GCLK_CLKCTRL_ID(GCM_TC4_TC5), // TC4 GCLK_CLKCTRL_ID(GCM_TC4_TC5), // TC5 GCLK_CLKCTRL_ID(GCM_TC6_TC7), // TC6 GCLK_CLKCTRL_ID(GCM_TC6_TC7), // TC7 }; GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_IDs[tcNum]); while (GCLK->STATUS.bit.SYNCBUSY == 1); // Set PORT if (tcNum >= TCC_INST_NUM) { // -- Configure TC Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel); // Disable TCx TCx->COUNT8.CTRLA.bit.ENABLE = 0; syncTC_8(TCx); // Set Timer counter Mode to 8 bits, normal PWM TCx->COUNT8.CTRLA.reg |= TC_CTRLA_MODE_COUNT8 | TC_CTRLA_WAVEGEN_NPWM; syncTC_8(TCx); // Set the initial value TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value; syncTC_8(TCx); // Set PER to maximum counter value (resolution : 0xFF) TCx->COUNT8.PER.reg = 0xFF; syncTC_8(TCx); // Enable TCx TCx->COUNT8.CTRLA.bit.ENABLE = 1; syncTC_8(TCx); } else { // -- Configure TCC Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel); // Disable TCCx TCCx->CTRLA.bit.ENABLE = 0; syncTCC(TCCx); // Set TCx as normal PWM TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; syncTCC(TCCx); // Set the initial value TCCx->CC[tcChannel].reg = (uint32_t) value; syncTCC(TCCx); // Set PER to maximum counter value (resolution : 0xFF) TCCx->PER.reg = 0xFF; //change to 0x43FF for 10 bit... must also change mapping above syncTCC(TCCx); // Enable TCCx TCCx->CTRLA.bit.ENABLE = 1; syncTCC(TCCx); } } else { if (tcNum >= TCC_INST_NUM) { Tc* TCx = (Tc*) GetTC(pinDesc.ulPWMChannel); TCx->COUNT8.CC[tcChannel].reg = (uint8_t) value; syncTC_8(TCx); } else { Tcc* TCCx = (Tcc*) GetTC(pinDesc.ulPWMChannel); TCCx->CTRLBSET.bit.LUPD = 1; syncTCC(TCCx); TCCx->CCB[tcChannel].reg = (uint32_t) value; syncTCC(TCCx); TCCx->CTRLBCLR.bit.LUPD = 1; syncTCC(TCCx); } } return; } // -- Defaults to digital write pinMode(pin, OUTPUT); value = mapResolution(value, _writeResolution, 8); if (value < 128) { digitalWrite(pin, LOW); } else { digitalWrite(pin, HIGH); } }
/** * @brief Configure clock sources and the cpu frequency */ static void clk_init(void) { /* enable clocks for the power, sysctrl and gclk modules */ PM->APBAMASK.reg = (PM_APBAMASK_PM | PM_APBAMASK_SYSCTRL | PM_APBAMASK_GCLK); /* adjust NVM wait states, see table 42.30 (p. 1070) in the datasheet */ #if (CLOCK_CORECLOCK > 24000000) PM->APBAMASK.reg |= PM_AHBMASK_NVMCTRL; NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(1); PM->APBAMASK.reg &= ~PM_AHBMASK_NVMCTRL; #endif /* configure internal 8MHz oscillator to run without prescaler */ SYSCTRL->OSC8M.bit.PRESC = 0; SYSCTRL->OSC8M.bit.ONDEMAND = 1; SYSCTRL->OSC8M.bit.RUNSTDBY = 0; SYSCTRL->OSC8M.bit.ENABLE = 1; while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC8MRDY)) {} #if CLOCK_USE_PLL /* reset the GCLK module so it is in a known state */ GCLK->CTRL.reg = GCLK_CTRL_SWRST; while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} /* setup generic clock 1 to feed DPLL with 1MHz */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(8) | GCLK_GENDIV_ID(1)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_ID(1)); GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN(1) | GCLK_CLKCTRL_ID(1) | GCLK_CLKCTRL_CLKEN); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} /* enable PLL */ SYSCTRL->DPLLRATIO.reg = (SYSCTRL_DPLLRATIO_LDR(CLOCK_PLL_MUL)); SYSCTRL->DPLLCTRLB.reg = (SYSCTRL_DPLLCTRLB_REFCLK_GCLK); SYSCTRL->DPLLCTRLA.reg = (SYSCTRL_DPLLCTRLA_ENABLE); while(!(SYSCTRL->DPLLSTATUS.reg & (SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK))) {} /* select the PLL as source for clock generator 0 (CPU core clock) */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_PLL_DIV) | GCLK_GENDIV_ID(0)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_FDPLL | GCLK_GENCTRL_ID(0)); #else /* do not use PLL, use internal 8MHz oscillator directly */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_DIV) | GCLK_GENDIV_ID(0)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_ID(0)); #endif /* make sure we synchronize clock generator 0 before we go on */ while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} /* Setup Clock generator 2 with divider 1 (32.768kHz) */ GCLK->GENDIV.reg = (GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(0)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_SRC_OSCULP32K); while (GCLK->STATUS.bit.SYNCBUSY) {} /* redirect all peripherals to a disabled clock generator (7) by default */ for (int i = 0x3; i <= 0x22; i++) { GCLK->CLKCTRL.reg = ( GCLK_CLKCTRL_ID(i) | GCLK_CLKCTRL_GEN_GCLK7 ); while (GCLK->STATUS.bit.SYNCBUSY) {} } }
// Right now, PWM output only works on the pins with // hardware support. These are defined in the appropriate // pins_*.c file. For the rest of the pins, we default // to digital output. void analogWrite( uint32_t ulPin, uint32_t ulValue ) { #if 0 // pwm test #if 1 // port configuration *(volatile unsigned int *)0x44000010 |= 1 << 8; //GPIOx->OUTENSET //PAD_AFConfig(PAD_PC, GPIO_Pin_8, 0x01/*PAD_AF1*/); ///< PAD Config - LED used 2nd Function // (0x01 << 8) *(volatile unsigned int *)(0x41002080 + 0x20) &= ~0x03/*PAD_AF1*/; // (0x01 << 8) // *(volatile unsigned int *)(0x41002080 + 0x20) |= 0x01/*PAD_AF1*/; // (0x01 << 8) *(volatile unsigned int *)0x44000010 |= 1 << 9; //GPIOx->OUTENSET *(volatile unsigned int *)(0x41002080 + 0x24) &= ~0x03/*PAD_AF1*/; // (0x01 << 8) // *(volatile unsigned int *)(0x41002080 + 0x24) |= 0x01/*PAD_AF1*/; // (0x01 << 8) #endif // port configuration //------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------ /* Select Timer/Counter mode as Timer mode */ //PWM_CHn->TCMR = PWM_CHn_TCMR_TimerMode; // *(volatile unsigned int *)0x40005324 = (0x0ul); // ch3 *(volatile unsigned int *)0x40005024 = (0x0); /* Set Prescale register value */ //PWM_CHn->PR = PWM_TimerModeInitStruct->PWM_CHn_PR; // *(volatile unsigned int *)0x40005314 = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1; *(volatile unsigned int *)0x40005014 = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1; /* Set Match register value */ //PWM_CHn->MR = PWM_TimerModeInitStruct->PWM_CHn_MR; // *(volatile unsigned int *)0x40005318 = 80000; *(volatile unsigned int *)0x40005018 = 80000; /* Set Limit register value */ //PWM_CHn->LR = PWM_TimerModeInitStruct->PWM_CHn_LR; // *(volatile unsigned int *)0x4000531C = 100000; // 80% duty cycle *(volatile unsigned int *)0x4000501C = 100000; // 80% duty cycle /* Select Up-down mode */ //PWM_CHn->UDMR = PWM_TimerModeInitStruct->PWM_CHn_UDMR; // *(volatile unsigned int *)0x40005320 = (0x0ul); //PWM_CHn_UDMR_UpCount *(volatile unsigned int *)0x40005020 = (0x0); //PWM_CHn_UDMR_UpCount /* Select Periodic mode */ //PWM_CHn->PDMR = PWM_TimerModeInitStruct->PWM_CHn_PDMR; // *(volatile unsigned int *)0x40005334 = (0x1ul); //PWM_CHn_PDMR_Periodic *(volatile unsigned int *)0x40005034 = (0x1); //PWM_CHn_PDMR_Periodic //------------------------------------------------------------------------------------------ /* Select Timer/Counter mode as Timer mode */ //PWM_CHn->TCMR = PWM_CHn_TCMR_TimerMode; // *(volatile unsigned int *)0x40005324 = (0x0ul); // ch3 *(volatile unsigned int *)0x40005124 = (0x0ul); /* Set Prescale register value */ //PWM_CHn->PR = PWM_TimerModeInitStruct->PWM_CHn_PR; // *(volatile unsigned int *)0x40005314 = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1; *(volatile unsigned int *)0x40005114 = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1; /* Set Match register value */ //PWM_CHn->MR = PWM_TimerModeInitStruct->PWM_CHn_MR; // *(volatile unsigned int *)0x40005318 = 80000; *(volatile unsigned int *)0x40005118 = 80000; /* Set Limit register value */ //PWM_CHn->LR = PWM_TimerModeInitStruct->PWM_CHn_LR; // *(volatile unsigned int *)0x4000531C = 100000; // 80% duty cycle *(volatile unsigned int *)0x4000511C = 100000; // 80% duty cycle /* Select Up-down mode */ //PWM_CHn->UDMR = PWM_TimerModeInitStruct->PWM_CHn_UDMR; // *(volatile unsigned int *)0x40005320 = (0x0ul); //PWM_CHn_UDMR_UpCount *(volatile unsigned int *)0x40005120 = (0x0ul); //PWM_CHn_UDMR_UpCount /* Select Periodic mode */ //PWM_CHn->PDMR = PWM_TimerModeInitStruct->PWM_CHn_PDMR; // *(volatile unsigned int *)0x40005334 = (0x1ul); //PWM_CHn_PDMR_Periodic *(volatile unsigned int *)0x40005134 = (0x1ul); //PWM_CHn_PDMR_Periodic //------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------ //PWM->SSR &= PWM_SSR_SS3_Stop; // *(volatile unsigned int *)0x40005804 &= ~(0x1ul << 3); *(volatile unsigned int *)0x40005804 &= ~(0x1ul << 0); //PWM_CHn->PEEER = outputEnDisable; // *(volatile unsigned int *)0x40005328 = (0x2ul); *(volatile unsigned int *)0x40005028 = (0x2ul); //------------------------------------------------------------------------------------------ //PWM->SSR &= PWM_SSR_SS3_Stop; // *(volatile unsigned int *)0x40005804 &= ~(0x1ul << 3); *(volatile unsigned int *)0x40005804 &= ~(0x1ul << 1); //PWM_CHn->PEEER = outputEnDisable; // *(volatile unsigned int *)0x40005328 = (0x2ul); *(volatile unsigned int *)0x40005128 = (0x2ul); //------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------ //PWM->SSR |= PWM_SSR_SS3_Start; // *(volatile unsigned int *)0x40005804 |= (0x1ul << 3); *(volatile unsigned int *)0x40005804 |= (0x1ul << 0); //------------------------------------------------------------------------------------------ //PWM->SSR |= PWM_SSR_SS3_Start; // *(volatile unsigned int *)0x40005804 |= (0x1ul << 3); *(volatile unsigned int *)0x40005804 |= (0x1ul << 1); while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ; *(volatile unsigned long *) 0x4000D000 = 'P'; while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ; *(volatile unsigned long *) 0x4000D000 = 'W'; while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ; *(volatile unsigned long *) 0x4000D000 = 'M'; while(1); #endif #if 1 //------------------------------------------------------------------------------------------ *(volatile unsigned int *)(0x42000010 + pwm_pin_tbl[ulPin].port_num) |= 1 << pwm_pin_tbl[ulPin].pin_num; //GPIOx->OUTENSET //PAD_AFConfig(PAD_PC, GPIO_Pin_8, 0x01/*PAD_AF1*/); ///< PAD Config - LED used 2nd Function // (0x01 << 8) *(volatile unsigned int *)(0x41002000 + pwm_pin_tbl[ulPin].af_base + pwm_pin_tbl[ulPin].pin_num * 4) &= ~0x03/*PAD_AF1*/; // (0x01 << 8) *(volatile unsigned int *)(0x41002000 + pwm_pin_tbl[ulPin].af_base + pwm_pin_tbl[ulPin].pin_num * 4) |= pwm_pin_tbl[ulPin].af_num/*PAD_AF1*/; // (0x01 << 8) //------------------------------------------------------------------------------------------ //PWM-n /* Select Timer/Counter mode as Timer mode */ *(volatile unsigned int *)(0x40005024 + pwm_pin_tbl[ulPin].pwm_num) = (0x0); /* Set Prescale register value */ *(volatile unsigned int *)(0x40005014 + pwm_pin_tbl[ulPin].pwm_num) = (20000000 / 1000000) / 10 - 1; //PrescalerValue - 1; /* Set Match register value */ *(volatile unsigned int *)(0x40005018 + pwm_pin_tbl[ulPin].pwm_num) = 400 * ulValue; //MR /* Set Limit register value */ *(volatile unsigned int *)(0x4000501C + pwm_pin_tbl[ulPin].pwm_num) = 102400; // 80% duty cycle /* Select Up-down mode */ *(volatile unsigned int *)(0x40005020 + pwm_pin_tbl[ulPin].pwm_num) = (0x0); //PWM_CHn_UDMR_UpCount /* Select Periodic mode */ *(volatile unsigned int *)(0x40005034 + pwm_pin_tbl[ulPin].pwm_num) = (0x1); //PWM_CHn_PDMR_Periodic //------------------------------------------------------------------------------------------ //PWM->SSR &= PWM_SSR_SS3_Stop; *(volatile unsigned int *)0x40005804 &= ~(0x1 << pwm_pin_tbl[ulPin].pwm_pin); //PWM_CHn->PEEER = outputEnDisable; *(volatile unsigned int *)(0x40005028 + pwm_pin_tbl[ulPin].pwm_num) = 0x2; //------------------------------------------------------------------------------------------ //PWM->SSR |= PWM_SSR_SS3_Start; *(volatile unsigned int *)0x40005804 |= (0x1ul << pwm_pin_tbl[ulPin].pwm_pin); #if 0 // pwm serial character out while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ; *(volatile unsigned long *) 0x4000D000 = 'P'; while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ; *(volatile unsigned long *) 0x4000D000 = 'W'; while( !((*(volatile unsigned long *) 0x4000D018) & (0x01 << 7)) ) ; *(volatile unsigned long *) 0x4000D000 = 'M'; #endif // pwm serial character out #endif #if 0 uint32_t attr = g_APinDescription[ulPin].ulPinAttribute ; // uint32_t pwm_name = g_APinDescription[ulPin].ulTCChannel ; uint8_t isTC = 0 ; uint8_t Channelx ; Tc* TCx ; Tcc* TCCx ; if ( (attr & PIN_ATTR_ANALOG) == PIN_ATTR_ANALOG ) { if ( ulPin == 24 ) // Only 1 DAC on A0 (PA02) { ulValue = mapResolution(ulValue, _writeResolution, DAC_RESOLUTION); DAC->DATA.reg = ulValue & 0x3FF; // Dac on 10 bits. DAC->CTRLA.bit.ENABLE = 1; // DAC Enabled ///////////////////////////////////// syncDAC(); return; } } if ( (attr & PIN_ATTR_PWM) == PIN_ATTR_PWM ) { if ( (g_APinDescription[ulPin].ulPinType == PIO_TIMER) || g_APinDescription[ulPin].ulPinType == PIO_TIMER_ALT ) { pinPeripheral( ulPin, g_APinDescription[ulPin].ulPinType ) ; } switch ( g_APinDescription[ulPin].ulPWMChannel ) { case PWM3_CH0 : TCx = TC3 ; Channelx = 0 ; isTC = 1 ; break; case PWM3_CH1: TCx = TC3 ; Channelx = 1; isTC = 1; break; case PWM0_CH0 : TCCx = TCC0; Channelx = 0; break; case PWM0_CH1 : TCCx = TCC0; Channelx = 1; break; case PWM0_CH4 : TCCx = TCC0; Channelx = 0; break; case PWM0_CH5 : TCCx = TCC0; Channelx = 1; break; case PWM0_CH6 : TCCx = TCC0; Channelx = 2; break; case PWM0_CH7 : TCCx = TCC0; Channelx = 3; break; case PWM1_CH0 : TCCx = TCC1; Channelx = 0; break; case PWM1_CH1 : TCCx = TCC1; Channelx = 1; break; case PWM2_CH0 : TCCx = TCC2; Channelx = 0; break; case PWM2_CH1 : TCCx = TCC2; Channelx = 1; break; } // Enable clocks according to TCCx instance to use switch ( GetTCNumber( g_APinDescription[ulPin].ulPWMChannel ) ) { case 0: // TCC0 //Enable GCLK for TCC0 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ; break; case 1: // TCC1 //Enable GCLK for TCC1 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC0_TCC1 )) ; break; case 2: // TCC2 //Enable GCLK for TCC2 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC2_TC3 )) ; break; case 3: // TC3 //Enable GCLK for TC3 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TCC2_TC3 )); break; case 4: // TC4 //Enable GCLK for TC4 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TC4_TC5 )); break; case 5: // TC5 //Enable GCLK for TC5 (timer counter input clock) GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID( GCM_TC4_TC5 )) ; break; } // Set PORT if ( isTC ) { // -- Configure TC //DISABLE TCx TCx->COUNT8.CTRLA.reg &=~(TC_CTRLA_ENABLE); //Set Timer counter Mode to 8 bits TCx->COUNT8.CTRLA.reg |= TC_CTRLA_MODE_COUNT8; //Set TCx as normal PWM TCx->COUNT8.CTRLA.reg |= TC_CTRLA_WAVEGEN_NPWM; //Set TCx in waveform mode Normal PWM TCx->COUNT8.CC[Channelx].reg = (uint8_t) ulValue; //Set PER to maximum counter value (resolution : 0xFF) TCx->COUNT8.PER.reg = 0xFF; // Enable TCx TCx->COUNT8.CTRLA.reg |= TC_CTRLA_ENABLE; } else { // -- Configure TCC //DISABLE TCCx TCCx->CTRLA.reg &=~(TCC_CTRLA_ENABLE); //Set TCx as normal PWM TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; //Set TCx in waveform mode Normal PWM TCCx->CC[Channelx].reg = (uint32_t)ulValue; //Set PER to maximum counter value (resolution : 0xFF) TCCx->PER.reg = 0xFF; //ENABLE TCCx TCCx->CTRLA.reg |= TCC_CTRLA_ENABLE ; } return ; } // -- Defaults to digital write pinMode( ulPin, OUTPUT ) ; if ( ulValue < 128 ) { digitalWrite( ulPin, LOW ) ; } else { digitalWrite( ulPin, HIGH ) ; } #endif }