int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) { /* get exclusive access to the device */ mutex_lock(&locks[bus]); /* power on the device */ poweron(bus); /* configure bus clock, in synchronous mode its calculated from * BAUD.reg = (f_ref / (2 * f_bus) - 1) * with f_ref := CLOCK_CORECLOCK as defined by the board */ dev(bus)->BAUD.reg = (uint8_t)(((uint32_t)CLOCK_CORECLOCK) / (2 * clk) - 1); /* configure device to be master and set mode and pads, * * NOTE: we could configure the pads already during spi_init, but for * efficiency reason we do that here, so we can do all in one single write * to the CTRLA register */ dev(bus)->CTRLA.reg = (SERCOM_SPI_CTRLA_MODE(0x3) | /* 0x3 -> master */ SERCOM_SPI_CTRLA_DOPO(spi_config[bus].mosi_pad) | SERCOM_SPI_CTRLA_DIPO(spi_config[bus].miso_pad) | (mode << SERCOM_SPI_CTRLA_CPOL_Pos)); /* also no synchronization needed here, as CTRLA is write-synchronized */ /* finally enable the device */ dev(bus)->CTRLA.reg |= SERCOM_SPI_CTRLA_ENABLE; while (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_ENABLE) {} return SPI_OK; }
/* ========================= * ===== Sercom SPI * ========================= */ void SERCOM::initSPI(SercomSpiTXPad mosi, SercomRXPad miso, SercomSpiCharSize charSize, SercomDataOrder dataOrder) { resetSPI(); initClockNVIC(); //Setting the CTRLA register sercom->SPI.CTRLA.reg = SERCOM_SPI_CTRLA_MODE_SPI_MASTER | SERCOM_SPI_CTRLA_DOPO(mosi) | SERCOM_SPI_CTRLA_DIPO(miso) | dataOrder << SERCOM_SPI_CTRLA_DORD_Pos; //Setting the CTRLB register sercom->SPI.CTRLB.reg = SERCOM_SPI_CTRLB_CHSIZE(charSize) | SERCOM_SPI_CTRLB_RXEN; //Active the SPI receiver. }
/*************************************************************************//** *****************************************************************************/ 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(); }
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; }
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; 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: #if CLOCK_CORECLOCK >= 5000000 f_baud = 5000000; break; #else return -1; #endif case SPI_SPEED_10MHZ: #if CLOCK_CORECLOCK >= 10000000 f_baud = 10000000; break; #else return -1; #endif } 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; } switch(dev) { #ifdef 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; break; #endif #ifdef 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; break; #endif default: return -1; } spi_dev->CTRLA.bit.ENABLE = 0; /* Disable spi to write confs */ while (spi_dev->SYNCBUSY.reg) {} spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE_SPI_MASTER; while (spi_dev->SYNCBUSY.reg) {} spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t)CLOCK_CORECLOCK) / (2 * f_baud) - 1); /* Syncronous 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); 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; }
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; uint32_t f_baud = 0; /* Speed < ½ f_ref, current f_ref = 8`000`000 * baud = f_ref/(2 f_baud) - 1 */ switch(speed) { case SPI_SPEED_100KHZ: /**< drive the SPI bus with 100KHz */ f_baud = 100000; break; case SPI_SPEED_400KHZ: /**< drive the SPI bus with 400KHz */ f_baud = 400000; break; case SPI_SPEED_1MHZ: /**< drive the SPI bus with 1MHz */ f_baud = 1000000; break; case SPI_SPEED_5MHZ: /**< drive the SPI bus with 5MHz */ return -1; case SPI_SPEED_10MHZ: /**< drive the SPI bus with 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; } switch(dev) { #ifdef 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); pmux_set(SPI_0_SCLK_PIN, F); pmux_set(SPI_0_MISO_PIN, F); pmux_set(SPI_0_MOSI_PIN, F); // uint32_t pinmask = (((1UL << (SPI_0_SCLK_PIN % 32)) | (1UL << (SPI_0_MISO_PIN % 32))) >> 16); // /* PMUX */ // SPI_0_PORT0.WRCONFIG.reg |= // PORT_WRCONFIG_HWSEL // | PORT_WRCONFIG_WRPMUX // | (0x5 << PORT_WRCONFIG_PMUX_Pos) // | PORT_WRCONFIG_PMUXEN // | (pinmask << PORT_WRCONFIG_PINMASK_Pos); // pinmask = (1UL << (SPI_0_MOSI_PIN % 32)) >> 16; // SPI_0_PORT1.WRCONFIG.reg |= // PORT_WRCONFIG_HWSEL // | PORT_WRCONFIG_WRPMUX // | (0x5 << PORT_WRCONFIG_PMUX_Pos) // | PORT_WRCONFIG_PMUXEN // | (pinmask << PORT_WRCONFIG_PINMASK_Pos); //SCLK+MOSI SPI_0_SCLK_DEV.DIRSET.reg = (1 << (SPI_0_SCLK_PIN % 32)); SPI_0_MOSI_DEV.DIRSET.reg = (1 << (SPI_0_MOSI_PIN % 32)); //MISO = input /* configure as input */ SPI_0_MISO_DEV.DIRCLR.reg = (1<<(SPI_0_MISO_PIN % 32)); SPI_0_MISO_DEV.PINCFG[SPI_0_MISO_PIN % 32].bit.INEN = true; SPI_0_MISO_DEV.OUTCLR.reg = (1 << (SPI_0_MISO_PIN % 32)); SPI_0_MISO_DEV.PINCFG[SPI_0_MISO_PIN % 32].bit.PULLEN = true; dopo = SPI_0_DOPO; dipo = SPI_0_DIPO; break; #endif #ifdef 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))); while (GCLK->STATUS.reg); pmux_set(SPI_1_SCLK_PIN, D); pmux_set(SPI_1_MISO_PIN, D); pmux_set(SPI_1_MOSI_PIN, D); //SCLK+MOSI SPI_1_SCLK_DEV.DIRSET.reg = (1 << (SPI_1_SCLK_PIN % 32)); SPI_1_MOSI_DEV.DIRSET.reg = (1 << (SPI_1_MOSI_PIN % 32)); //MISO = input /* configure as input */ SPI_1_MISO_DEV.DIRCLR.reg = (1<<(SPI_1_MISO_PIN % 32)); SPI_1_MISO_DEV.PINCFG[SPI_1_MISO_PIN % 32].bit.INEN = true; SPI_1_MISO_DEV.OUTCLR.reg = (1 << (SPI_1_MISO_PIN % 32)); SPI_1_MISO_DEV.PINCFG[SPI_1_MISO_PIN % 32].bit.PULLEN = true; dopo = SPI_1_DOPO; dipo = SPI_1_DIPO; break; #endif } spi_dev->CTRLA.bit.ENABLE = 0; // Disable spi to write confs while (spi_dev->SYNCBUSY.reg); spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE_SPI_MASTER; while (spi_dev->SYNCBUSY.reg); spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t) SPI_0_F_REF) / (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); 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; }