diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 65b0bc72275f7d70042ac595a5e5eaf471ffd291..acfccece08139c2b5b7b961119e9a8e5738cf662 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -160,34 +160,32 @@ static const pwm_conf_t pwm_config[] = { #define SPI_1_EN 1 /* SPI0 */ -#define SPI_0_DEV SERCOM4->SPI -#define SPI_IRQ_0 SERCOM4_IRQn -#define SPI_0_DOPO (1) -#define SPI_0_DIPO (0) - -#define SPI_0_SCLK_DEV PORT->Group[2] -#define SPI_0_SCLK_PIN (18) - -#define SPI_0_MISO_DEV PORT->Group[2] -#define SPI_0_MISO_PIN (19) - -#define SPI_0_MOSI_DEV PORT->Group[1] -#define SPI_0_MOSI_PIN (30) +#define SPI_0_DEV SERCOM4->SPI +#define SPI_IRQ_0 SERCOM4_IRQn +#define SPI_0_GCLK_ID SERCOM4_GCLK_ID_CORE +/* SPI 0 pin configuration */ +#define SPI_0_SCLK GPIO_PIN(PC, 18) +#define SPI_0_SCLK_MUX GPIO_MUX_F +#define SPI_0_MISO GPIO_PIN(PC, 19) +#define SPI_0_MISO_MUX GPIO_MUX_F +#define SPI_0_MISO_PAD SERCOM_RX_PAD_0 +#define SPI_0_MOSI GPIO_PIN(PB, 30) +#define SPI_0_MOSI_MUX GPIO_MUX_F +#define SPI_0_MOSI_PAD SPI_PAD_2_SCK_3 /* SPI1 */ -#define SPI_1_DEV SERCOM5->SPI -#define SPI_IRQ_1 SERCOM5_IRQn -#define SPI_1_DOPO (1) -#define SPI_1_DIPO (0) - -#define SPI_1_SCLK_DEV PORT->Group[1] -#define SPI_1_SCLK_PIN (23) - -#define SPI_1_MISO_DEV PORT->Group[1] -#define SPI_1_MISO_PIN (02) - -#define SPI_1_MOSI_DEV PORT->Group[1] -#define SPI_1_MOSI_PIN (22) +#define SPI_1_DEV SERCOM5->SPI +#define SPI_IRQ_1 SERCOM5_IRQn +#define SPI_1_GCLK_ID SERCOM5_GCLK_ID_CORE +/* SPI 1 pin configuration */ +#define SPI_1_SCLK GPIO_PIN(PB, 23) +#define SPI_1_SCLK_MUX GPIO_MUX_D +#define SPI_1_MISO GPIO_PIN(PB, 02) +#define SPI_1_MISO_MUX GPIO_MUX_D +#define SPI_1_MISO_PAD SERCOM_RX_PAD_0 +#define SPI_1_MOSI GPIO_PIN(PB, 22) +#define SPI_1_MOSI_MUX GPIO_MUX_D +#define SPI_1_MOSI_PAD SPI_PAD_2_SCK_3 /** @} */ /** diff --git a/cpu/samd21/periph/spi.c b/cpu/samd21/periph/spi.c index a58dcc9d7f63314aa48ea00fb6077b772ed14340..f5f0b90a642a01a40d93c5fd1866207442edd8f7 100644 --- a/cpu/samd21/periph/spi.c +++ b/cpu/samd21/periph/spi.c @@ -60,10 +60,17 @@ static mutex_t locks[] = { int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) { SercomSpi* spi_dev = 0; - uint8_t dopo = 0; - uint8_t dipo = 0; - uint8_t cpha = 0; - uint8_t cpol = 0; + uint8_t sercom_gclk_id = 0; + gpio_t pin_sclk = 0; + gpio_t pin_miso = 0; + gpio_t pin_mosi = 0; + gpio_mux_t mux_sclk = 0; + gpio_mux_t mux_miso = 0; + gpio_mux_t mux_mosi = 0; + sercom_spi_txpad_t dopo = 0; + sercom_rxpad_t dipo = 0; + uint32_t cpha = 0; + uint32_t cpol = 0; uint32_t f_baud = 0; switch (speed) { @@ -93,21 +100,21 @@ int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) } switch (conf) { - case SPI_CONF_FIRST_RISING: /**< first data bit is transacted on the first rising SCK edge */ + 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; + case SPI_CONF_SECOND_RISING: /**< first data bit is transacted on the second rising SCK edge */ + cpha = SERCOM_SPI_CTRLA_CPHA; cpol = 0; break; - case SPI_CONF_FIRST_FALLING:/**< first data bit is transacted on the first falling SCK edge */ + case SPI_CONF_FIRST_FALLING: /**< first data bit is transacted on the first falling SCK edge */ cpha = 0; - cpol = 1; + cpol = SERCOM_SPI_CTRLA_CPOL; break; - case SPI_CONF_SECOND_FALLING:/**< first data bit is transacted on the second falling SCK edge */ - cpha = 1; - cpol = 1; + case SPI_CONF_SECOND_FALLING: /**< first data bit is transacted on the second falling SCK edge */ + cpha = SERCOM_SPI_CTRLA_CPHA; + cpol = SERCOM_SPI_CTRLA_CPOL; break; } switch (dev) @@ -115,92 +122,79 @@ int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed) #if SPI_0_EN case SPI_0: spi_dev = &SPI_0_DEV; - - /* Enable sercom4 in power manager */ - PM->APBCMASK.reg |= PM_APBCMASK_SERCOM4; - GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN - | GCLK_CLKCTRL_GEN_GCLK0 - | (SERCOM4_GCLK_ID_CORE << GCLK_CLKCTRL_ID_Pos))); - - /* Setup clock */ - while (GCLK->STATUS.bit.SYNCBUSY) {} - /* Mux enable*/ - SPI_0_SCLK_DEV.PINCFG[ SPI_0_SCLK_PIN ].bit.PMUXEN = 1; - SPI_0_MISO_DEV.PINCFG[ SPI_0_MISO_PIN ].bit.PMUXEN = 1; - SPI_0_MOSI_DEV.PINCFG[ SPI_0_MOSI_PIN ].bit.PMUXEN = 1; - - /*Set mux function to spi. seperate registers, for even or odd pins */ - SPI_0_SCLK_DEV.PMUX[ SPI_0_SCLK_PIN / 2].bit.PMUXE = 5; - SPI_0_MISO_DEV.PMUX[ SPI_0_MISO_PIN / 2].bit.PMUXO = 5; - SPI_0_MOSI_DEV.PMUX[ SPI_0_MOSI_PIN / 2].bit.PMUXE = 5; - - /* SCLK+MOSI */ - SPI_0_SCLK_DEV.DIRSET.reg = 1 << SPI_0_SCLK_PIN; - SPI_0_MOSI_DEV.DIRSET.reg = 1 << SPI_0_MOSI_PIN; - - /* MISO = input */ - /* configure as input */ - SPI_0_MISO_DEV.DIRCLR.reg = 1 << SPI_0_MISO_PIN; - SPI_0_MISO_DEV.PINCFG[ SPI_0_MISO_PIN ].bit.INEN = true; - - SPI_0_MISO_DEV.OUTCLR.reg = 1 << SPI_0_MISO_PIN; - SPI_0_MISO_DEV.PINCFG[ SPI_0_MISO_PIN ].bit.PULLEN = true; - - dopo = SPI_0_DOPO; - dipo = SPI_0_DIPO; + sercom_gclk_id = SPI_0_GCLK_ID; + pin_sclk = SPI_0_SCLK; + mux_sclk = SPI_0_SCLK_MUX; + pin_miso = SPI_0_MISO; + mux_miso = SPI_0_MISO_MUX; + pin_mosi = SPI_0_MOSI; + mux_mosi = SPI_0_MOSI_MUX; + dopo = SPI_0_MOSI_PAD; + dipo = SPI_0_MISO_PAD; break; #endif #if SPI_1_EN case SPI_1: spi_dev = &SPI_1_DEV; - - /* Enable sercom5 in power manager */ - PM->APBCMASK.reg |= PM_APBCMASK_SERCOM5; - /* Setup clock */ /* configure GCLK0 to feed sercom5 */; - GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN - | GCLK_CLKCTRL_GEN_GCLK0 - | (SERCOM5_GCLK_ID_CORE << GCLK_CLKCTRL_ID_Pos))); - - /* Mux enable*/ - SPI_1_SCLK_DEV.PINCFG[ SPI_1_SCLK_PIN ].bit.PMUXEN = 1; - SPI_1_MISO_DEV.PINCFG[ SPI_1_MISO_PIN ].bit.PMUXEN = 1; - SPI_1_MOSI_DEV.PINCFG[ SPI_1_MOSI_PIN ].bit.PMUXEN = 1; - /*Set mux function to spi. seperate registers, for even or odd pins */ - SPI_1_SCLK_DEV.PMUX[ SPI_1_SCLK_PIN / 2].bit.PMUXO = 3; - SPI_1_MISO_DEV.PMUX[ SPI_1_MISO_PIN / 2].bit.PMUXE = 3; - SPI_1_MOSI_DEV.PMUX[ SPI_1_MOSI_PIN / 2].bit.PMUXE = 3; - /* SCLK+MOSI */ - SPI_1_SCLK_DEV.DIRSET.reg = 1 << SPI_1_SCLK_PIN; - SPI_1_MOSI_DEV.DIRSET.reg = 1 << SPI_1_MOSI_PIN; - - /* MISO = input */ - /* configure as input */ - SPI_1_MISO_DEV.DIRCLR.reg = 1 << SPI_1_MISO_PIN; - SPI_1_MISO_DEV.PINCFG[ SPI_1_MISO_PIN ].bit.INEN = true; - - SPI_1_MISO_DEV.OUTCLR.reg = 1 << SPI_1_MISO_PIN; - SPI_1_MISO_DEV.PINCFG[SPI_1_MISO_PIN].bit.PULLEN = true; - - dopo = SPI_1_DOPO; - dipo = SPI_1_DIPO; + sercom_gclk_id = SPI_1_GCLK_ID; + pin_sclk = SPI_1_SCLK; + mux_sclk = SPI_1_SCLK_MUX; + pin_miso = SPI_1_MISO; + mux_miso = SPI_1_MISO_MUX; + pin_mosi = SPI_1_MOSI; + mux_mosi = SPI_1_MOSI_MUX; + dopo = SPI_1_MOSI_PAD; + dipo = SPI_1_MISO_PAD; break; #endif default: return -1; } + /* Use the same sequence as ArduinoCore + * - setup pins + * - disable SPI + * - init SPI (reset, init clock NVIC, CTRLA, CTRLB) + * - init cpha/cpol, BAUD.reg + * - enable SPI + */ + + gpio_init_sercom(pin_sclk, mux_sclk); + gpio_init_sercom(pin_miso, mux_miso); + gpio_init_sercom(pin_mosi, mux_mosi); + /* Disable spi to write confs */ _spi_poweroff(spi_dev); + /* reset */ + // Setting the Software Reset bit to 1 + spi_dev->CTRLA.bit.SWRST = 1; + + // Wait both bits Software Reset from CTRLA and SYNCBUSY are equal to 0 + while (spi_dev->CTRLA.bit.SWRST || spi_dev->SYNCBUSY.bit.SWRST) {} + + /* Turn on power manager for sercom */ + PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << (sercom_gclk_id - GCLK_CLKCTRL_ID_SERCOM0_CORE_Val)); + + /* Setup clock */ + /* SPI using CLK GEN 0 */ + GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | + GCLK_CLKCTRL_GEN_GCLK0 | + GCLK_CLKCTRL_ID(sercom_gclk_id)); + while (GCLK->STATUS.bit.SYNCBUSY) {} + + /* ???? init NVIC. Maybe not needed in master mode. */ + + /* Master mode */ spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE_SPI_MASTER; - while (spi_dev->SYNCBUSY.reg) {} // ???? not needed + while (spi_dev->SYNCBUSY.reg) {}// ???? not needed spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t)CLOCK_CORECLOCK) / (2 * f_baud) - 1); /* Synchronous mode*/ spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_DOPO(dopo) | SERCOM_SPI_CTRLA_DIPO(dipo) - | (cpha << SERCOM_SPI_CTRLA_CPHA_Pos) - | (cpol << SERCOM_SPI_CTRLA_CPOL_Pos); + | cpha + | cpol; while (spi_dev->SYNCBUSY.reg) {} // ???? not needed /* datasize 0 => 8 bits */ @@ -263,7 +257,7 @@ int spi_transfer_byte(spi_t dev, char out, char *in) while (!spi_dev->INTFLAG.bit.DRE) {} /* while data register is not empty*/ spi_dev->DATA.bit.DATA = out; - while (!spi_dev->INTFLAG.bit.RXC) {} /* while receive is not complete*/ + while (!spi_dev->INTFLAG.bit.DRE || !spi_dev->INTFLAG.bit.RXC) {} /* while receive is not complete*/ tmp = (char)spi_dev->DATA.bit.DATA; if (in != NULL)