void spi_init_pins(spi_t bus) { gpio_init(spi_config[bus].clk, GPIO_OUT); gpio_init(spi_config[bus].mosi, GPIO_OUT); gpio_init(spi_config[bus].miso, GPIO_IN); gpio_init_mux(spi_config[bus].clk, spi_config[bus].mux); gpio_init_mux(spi_config[bus].mosi, spi_config[bus].mux); gpio_init_mux(spi_config[bus].miso, spi_config[bus].mux); }
void spi_init_pins(spi_t bus) { gpio_init(spi_config[bus].miso_pin, GPIO_IN); gpio_init(spi_config[bus].mosi_pin, GPIO_OUT); gpio_init(spi_config[bus].clk_pin, GPIO_OUT); gpio_init_mux(spi_config[bus].miso_pin, spi_config[bus].miso_mux); gpio_init_mux(spi_config[bus].mosi_pin, spi_config[bus].mosi_mux); gpio_init_mux(spi_config[bus].clk_pin, spi_config[bus].clk_mux); }
uint32_t pwm_init(pwm_t dev, pwm_mode_t mode, uint32_t freq, uint16_t res) { uint8_t prescaler; int scale = 1; uint32_t f_real; if ((unsigned int)dev >= PWM_NUMOF) { return 0; } /* calculate the closest possible clock presacler */ prescaler = get_prescaler(CLOCK_CORECLOCK / (freq * res), &scale); if (prescaler == 0xff) { return 0; } f_real = (CLOCK_CORECLOCK / (scale * res)); /* configure the used pins */ for (int i = 0; i < PWM_MAX_CHANNELS; i++) { if (pwm_config[dev].chan[i].pin != GPIO_UNDEF) { gpio_init(pwm_config[dev].chan[i].pin, GPIO_OUT); gpio_init_mux(pwm_config[dev].chan[i].pin, pwm_config[dev].chan[i].mux); } } /* power on the device */ poweron(dev); /* reset TCC module */ _tcc(dev)->CTRLA.reg = TCC_CTRLA_SWRST; while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_SWRST) {} /* set PWM mode */ switch (mode) { case PWM_LEFT: _tcc(dev)->CTRLBCLR.reg = TCC_CTRLBCLR_DIR; /* count up */ break; case PWM_RIGHT: _tcc(dev)->CTRLBSET.reg = TCC_CTRLBSET_DIR; /* count down */ break; case PWM_CENTER: /* currently not supported */ default: return 0; } while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) {} /* configure the TCC device */ _tcc(dev)->CTRLA.reg = (TCC_CTRLA_PRESCSYNC_GCLK_Val | TCC_CTRLA_PRESCALER(prescaler)); /* select the waveform generation mode -> normal PWM */ _tcc(dev)->WAVE.reg = (TCC_WAVE_WAVEGEN_NPWM); while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_WAVE) {} /* set the selected period */ _tcc(dev)->PER.reg = (res - 1); while (_tcc(dev)->SYNCBUSY.reg & TCC_SYNCBUSY_PER) {} /* start PWM operation */ _tcc(dev)->CTRLA.reg |= (TCC_CTRLA_ENABLE); /* return the actual frequency the PWM is running at */ return f_real; }
static int init_base(uart_t uart, uint32_t baudrate) { uint32_t baud; SercomUsart *dev; if ((unsigned int)uart >= UART_NUMOF) { return -1; } /* get the devices base register */ dev = _uart(uart); /* calculate baudrate */ baud = ((((uint32_t)CLOCK_CORECLOCK * 10) / baudrate) / 16); /* enable sync and async clocks */ uart_poweron(uart); /* configure pins */ gpio_init(uart_config[uart].rx_pin, GPIO_IN); gpio_init_mux(uart_config[uart].rx_pin, uart_config[uart].mux); gpio_init(uart_config[uart].tx_pin, GPIO_OUT); gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux); /* reset the UART device */ dev->CTRLA.reg = SERCOM_USART_CTRLA_SWRST; while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_SWRST) {} /* set asynchronous mode w/o parity, LSB first, TX and RX pad as specified * by the board in the periph_conf.h, x16 sampling and use internal clock */ dev->CTRLA.reg = (SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_SAMPR(0x1) | SERCOM_USART_CTRLA_TXPO(uart_config[uart].tx_pad) | SERCOM_USART_CTRLA_RXPO(uart_config[uart].rx_pad) | SERCOM_USART_CTRLA_MODE_USART_INT_CLK); /* set baudrate */ dev->BAUD.FRAC.FP = (baud % 10); dev->BAUD.FRAC.BAUD = (baud / 10); /* enable receiver and transmitter, use 1 stop bit */ dev->CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN); while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_CTRLB) {} /* finally, enable the device */ dev->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; return 0; }
int uart_init_blocking(uart_t uart, uint32_t baudrate) { uint32_t baud; SercomUsart *dev; if (uart < 0 || uart >= UART_NUMOF) { return -1; } /* get the devices base register */ dev = _uart(uart); /* calculate baudrate */ baud = ((((uint32_t)CLOCK_CORECLOCK * 10) / baudrate) / 16); /* enable sync and async clocks */ uart_poweron(uart); /* configure pins */ gpio_init(uart_config[uart].rx_pin, GPIO_DIR_IN, GPIO_NOPULL); gpio_init_mux(uart_config[uart].rx_pin, uart_config[uart].mux); gpio_init(uart_config[uart].tx_pin, GPIO_DIR_OUT, GPIO_NOPULL); gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux); /* reset the UART device */ dev->CTRLA.reg = SERCOM_USART_CTRLA_SWRST; while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_SWRST); /* set asynchronous mode w/o parity, LSB first, PAD0 to TX, PAD1 to RX and * use internal clock */ dev->CTRLA.reg = (SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_RXPO(0x1) | SERCOM_USART_CTRLA_SAMPR(0x1) | SERCOM_USART_CTRLA_MODE_USART_INT_CLK); /* set baudrate */ dev->BAUD.FRAC.FP = (baud % 10); dev->BAUD.FRAC.BAUD = (baud / 10); /* enable receiver and transmitter, use 1 stop bit */ dev->CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN); while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_CTRLB); /* finally, enable the device */ dev->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; return 0; }
int gpio_init(gpio_t pin, gpio_dir_t dir, gpio_pp_t pullup) { (void) dir; unsigned _pin = pin & 31; unsigned port = pin >> 5; FIO_PORT_t *_port = &FIO_PORTS[port]; /* set mask */ _port->MASK = ~(0x1<<_pin); /* set direction */ _port->DIR = ~0; /* set pullup/pulldown **/ PINMODE[pin>>4] |= pullup << (_pin*2); gpio_init_mux(pin, 0); return 0; }
int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) { SercomSpi* spi_dev = spi[dev].dev; uint8_t dopo = 0; uint8_t dipo = 0; uint8_t cpha = 0; uint8_t cpol = 0; uint32_t f_baud = 0; switch(speed) { case SPI_SPEED_100KHZ: f_baud = 100000; break; case SPI_SPEED_400KHZ: f_baud = 400000; break; case SPI_SPEED_1MHZ: f_baud = 1000000; break; case SPI_SPEED_5MHZ: return -1; case SPI_SPEED_10MHZ: return -1; } switch(conf) { case SPI_CONF_FIRST_RISING: /**< first data bit is transacted on the first rising SCK edge */ cpha = 0; cpol = 0; break; case SPI_CONF_SECOND_RISING:/**< first data bit is transacted on the second rising SCK edge */ cpha = 1; cpol = 0; break; case SPI_CONF_FIRST_FALLING:/**< first data bit is transacted on the first falling SCK edge */ cpha = 0; cpol = 1; break; case SPI_CONF_SECOND_FALLING:/**< first data bit is transacted on the second falling SCK edge */ cpha = 1; cpol = 1; break; } /* Enable sercom4 in power manager */ MCLK->APBCMASK.reg |= spi[dev].mclk; /* Setup clock */ GCLK->PCHCTRL[ spi[dev].gclk_id ].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0; while (!(GCLK->PCHCTRL[spi[dev].gclk_id].reg & GCLK_PCHCTRL_CHEN)); /* SCLK+MOSI = output */ gpio_init(spi[dev].sclk.pin, GPIO_DIR_OUT, GPIO_NOPULL); gpio_init(spi[dev].mosi.pin, GPIO_DIR_OUT, GPIO_NOPULL); /* MISO = input */ gpio_init(spi[dev].miso.pin, GPIO_DIR_IN, GPIO_PULLUP); /* * Set alternate funcion (PMUX) for our ports. */ gpio_init_mux(spi[dev].sclk.pin, spi[dev].sclk.pmux); gpio_init_mux(spi[dev].miso.pin, spi[dev].miso.pmux); gpio_init_mux(spi[dev].mosi.pin, spi[dev].mosi.pmux); /* pin pad mapping */ dipo = spi[dev].dipo; dopo = spi[dev].dopo; /* Disable spi to write config */ spi_dev->CTRLA.bit.ENABLE = 0; while (spi_dev->SYNCBUSY.reg); /* setup baud */ spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t) GCLK_REF) / (2 * f_baud) - 1); /* Syncronous mode*/ spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3) /* 0x2 = slave 0x3 = master */ | (SERCOM_SPI_CTRLA_DOPO(dopo)) | (SERCOM_SPI_CTRLA_DIPO(dipo)) | (cpha << SERCOM_SPI_CTRLA_CPHA_Pos) | (cpol << SERCOM_SPI_CTRLA_CPOL_Pos); while (spi_dev->SYNCBUSY.reg); spi_dev->CTRLB.reg = (SERCOM_SPI_CTRLB_CHSIZE(0) | SERCOM_SPI_CTRLB_RXEN); while(spi_dev->SYNCBUSY.reg); spi_poweron(dev); return 0; }
void i2c_init(i2c_t dev) { uint32_t timeout_counter = 0; int32_t tmp_baud; assert(dev < I2C_NUMOF); /* Initialize mutex */ mutex_init(&locks[dev]); /* DISABLE I2C MASTER */ _i2c_poweroff(dev); /* Reset I2C */ bus(dev)->CTRLA.reg = SERCOM_I2CM_CTRLA_SWRST; while (bus(dev)->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK) {} /* Turn on power manager for sercom */ sercom_clk_en(bus(dev)); /* I2C using CLK GEN 0 */ sercom_set_gen(bus(dev),i2c_config[dev].gclk_src); /* Check if module is enabled. */ if (bus(dev)->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) { DEBUG("STATUS_ERR_DENIED\n"); return; } /* Check if reset is in progress. */ if (bus(dev)->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) { DEBUG("STATUS_BUSY\n"); return; } /************ SERCOM PAD0 - SDA and SERCOM PAD1 - SCL *************/ gpio_init_mux(i2c_config[dev].sda_pin, i2c_config[dev].mux); gpio_init_mux(i2c_config[dev].scl_pin, i2c_config[dev].mux); /* I2C CONFIGURATION */ while (bus(dev)->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK) {} /* Set sercom module to operate in I2C master mode and run in Standby if user requests it */ bus(dev)->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE_I2C_MASTER | ((i2c_config[dev].flags & I2C_FLAG_RUN_STANDBY) ? SERCOM_I2CM_CTRLA_RUNSTDBY : 0); /* Enable Smart Mode (ACK is sent when DATA.DATA is read) */ bus(dev)->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; /* Find and set baudrate. Read speed configuration. Set transfer * speed: SERCOM_I2CM_CTRLA_SPEED(0): Standard-mode (Sm) up to 100 * kHz and Fast-mode (Fm) up to 400 kHz */ switch (i2c_config[dev].speed) { case I2C_SPEED_NORMAL: case I2C_SPEED_FAST: bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(0); break; case I2C_SPEED_HIGH: bus(dev)->CTRLA.reg |= SERCOM_I2CM_CTRLA_SPEED(2); break; default: DEBUG("BAD BAUDRATE\n"); return; } /* Get the baudrate */ tmp_baud = (int32_t)(((CLOCK_CORECLOCK + (2 * (i2c_config[dev].speed)) - 1) / (2 * (i2c_config[dev].speed))) - (i2c_config[dev].speed == I2C_SPEED_HIGH ? 1 : 5)); /* Ensure baudrate is within limits */ if (tmp_baud < 255 && tmp_baud > 0) { bus(dev)->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud); } /* ENABLE I2C MASTER */ _i2c_poweron(dev); /* Start timeout if bus state is unknown. */ while ((bus(dev)->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE_Msk) == BUSSTATE_UNKNOWN) { if (timeout_counter++ >= SAMD21_I2C_TIMEOUT) { /* Timeout, force bus state to idle. */ bus(dev)->STATUS.reg = BUSSTATE_IDLE; } } }