Skip to content
Snippets Groups Projects
Commit 845ef0de authored by Kees Bakker's avatar Kees Bakker
Browse files

cpu/samd21: Refactor spi using ArduinoCore as example

The pinmux is now part of the board config. The pad setting is done with
clear names instead of numbers.
parent f794bd4c
Branches
No related tags found
No related merge requests found
......@@ -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
/** @} */
/**
......
......@@ -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)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment