static inline bool spi_read(spi_t *obj, uint16_t *rx_data) { /* Sanity check arguments */ MBED_ASSERT(obj); /* Check if data is ready to be read */ if (!spi_is_ready_to_read(obj)) { /* No data has been received, return */ return false; } /* Check if data is overflown */ if (_SPI(obj).STATUS.reg & SERCOM_SPI_STATUS_BUFOVF) { /* Clear overflow flag */ _SPI(obj).STATUS.reg |= SERCOM_SPI_STATUS_BUFOVF; } /* Read the character from the DATA register */ if (_SPI(obj).CTRLB.bit.CHSIZE == 1) { *rx_data = (_SPI(obj).DATA.reg & SERCOM_SPI_DATA_MASK); } else { *rx_data = (uint8_t)_SPI(obj).DATA.reg; } return true; }
static inline bool spi_is_ready_to_read(spi_t *obj) { /* Sanity check arguments */ MBED_ASSERT(obj); /* Check interrupt flag */ return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_RXC); }
static inline bool spi_is_write_complete(spi_t *obj) { /* Sanity check arguments */ MBED_ASSERT(obj); /* Check interrupt flag */ return (_SPI(obj).INTFLAG.reg & SERCOM_SPI_INTFLAG_TXC); }
static inline bool spi_is_syncing(spi_t *obj) { /* Sanity check arguments */ MBED_ASSERT(obj); /* Return synchronization status */ return (_SPI(obj).SYNCBUSY.reg); }
static inline void spi_disable(spi_t *obj) { /* Sanity check arguments */ MBED_ASSERT(obj); #if DEVICE_SPI_ASYNCH /* Disable interrupt */ NVIC_DisableIRQ(SERCOM0_IRQn + _sercom_get_sercom_inst_index(pSPI_SERCOM(obj))); #endif /* Wait until the synchronization is complete */ while (spi_is_syncing(obj)); /* Disable SPI */ _SPI(obj).CTRLA.reg &= ~SERCOM_SPI_CTRLA_ENABLE; }
static inline bool spi_write(spi_t *obj, uint16_t tx_data) { /* Sanity check arguments */ MBED_ASSERT(obj); /* Check if the data register has been copied to the shift register */ if (!spi_is_ready_to_write(obj)) { /* Data register has not been copied to the shift register, return */ return false; } /* Write the character to the DATA register */ _SPI(obj).DATA.reg = tx_data & SERCOM_SPI_DATA_MASK; return true; }
// enable SPI access SPI fd SPI::SPI(const char *spi_path, uint32_t bps) { _SPI(spi_path, bps, GPIO::GPIO_P9_17); }
/** Initialize the SPI peripheral * * Configures the pins used by SPI, sets a default format and frequency, and enables the peripheral * @param[out] obj The SPI object to initialize * @param[in] mosi The pin to use for MOSI * @param[in] miso The pin to use for MISO * @param[in] sclk The pin to use for SCLK * @param[in] ssel The pin to use for SSEL */ void spi_init(spi_t *obj, PinName mosi, PinName miso, PinName sclk, PinName ssel) { uint16_t baud = 0; uint32_t ctrla = 0; uint32_t ctrlb = 0; enum status_code error_code; if (g_sys_init == 0) { system_init(); g_sys_init = 1; } /* TODO: Calculate SERCOM instance from pins */ /* TEMP: Giving external SPI module value of SAMR21 for now */ pSPI_SERCOM(obj) = EXT1_SPI_MODULE; /* Disable SPI */ spi_disable(obj); /* Check if reset is in progress. */ if (_SPI(obj).CTRLA.reg & SERCOM_SPI_CTRLA_SWRST) { return; } uint32_t sercom_index = _sercom_get_sercom_inst_index(pSPI_SERCOM(obj)); uint32_t pm_index, gclk_index; #if (SAML21) if (sercom_index == 5) { pm_index = MCLK_APBDMASK_SERCOM5_Pos; gclk_index = SERCOM5_GCLK_ID_CORE; } else { pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; } #else pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; #endif /* Turn on module in PM */ #if (SAML21) if (sercom_index == 5) { system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBD, 1 << pm_index); } else { system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); } #else system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); #endif /* Set up the GCLK for the module */ struct system_gclk_chan_config gclk_chan_conf; system_gclk_chan_get_config_defaults(&gclk_chan_conf); gclk_chan_conf.source_generator = GCLK_GENERATOR_0; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(GCLK_GENERATOR_0, false); #if DEVICE_SPI_ASYNCH /* Save the object */ _sercom_instances[sercom_index] = obj; /* Configure interrupt handler */ NVIC_SetVector((SERCOM0_IRQn + sercom_index), (uint32_t)_sercom_handlers[sercom_index]); #endif /* Set the SERCOM in SPI master mode */ _SPI(obj).CTRLA.reg |= SERCOM_SPI_CTRLA_MODE(0x3); pSPI_S(obj)->mode = SPI_MODE_MASTER; /* TODO: Do pin muxing here */ struct system_pinmux_config pin_conf; system_pinmux_get_config_defaults(&pin_conf); pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; uint32_t pad_pinmuxes[] = { EXT1_SPI_SERCOM_PINMUX_PAD0, EXT1_SPI_SERCOM_PINMUX_PAD1, EXT1_SPI_SERCOM_PINMUX_PAD2, EXT1_SPI_SERCOM_PINMUX_PAD3 }; /* Configure the SERCOM pins according to the user configuration */ for (uint8_t pad = 0; pad < 4; pad++) { uint32_t current_pinmux = pad_pinmuxes[pad]; if (current_pinmux != PINMUX_UNUSED) { pin_conf.mux_position = current_pinmux & 0xFFFF; system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf); } }