static void i2c_init(uint32_t bus, SercomI2cm *si) { static uint8_t have_run_init; if (have_run_init & (1<<bus)) return; have_run_init |= 1<<bus; // Configure i2c si->CTRLA.reg = 0; uint32_t areg = (SERCOM_I2CM_CTRLA_LOWTOUTEN | SERCOM_I2CM_CTRLA_INACTOUT(3) | SERCOM_I2CM_STATUS_SEXTTOUT | SERCOM_I2CM_STATUS_MEXTTOUT | SERCOM_I2CM_CTRLA_MODE(5)); si->CTRLA.reg = areg; uint32_t freq = sercom_get_pclock_frequency(bus); uint32_t baud = (freq/I2C_FREQ - 10 - freq*TIME_RISE/1000000000) / 2; si->BAUD.reg = baud; si->CTRLA.reg = areg | SERCOM_I2CM_CTRLA_ENABLE; while (si->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_ENABLE) ; // Go into idle mode si->STATUS.reg = SERCOM_I2CM_STATUS_BUSSTATE(1); while (si->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_SYSOP) ; }
void SERCOM::initMasterWIRE( uint32_t baudrate ) { // Initialize the peripheral clock and interruption initClockNVIC() ; resetWIRE() ; // Set master mode and enable SCL Clock Stretch mode (stretch after ACK bit) sercom->I2CM.CTRLA.reg = SERCOM_I2CM_CTRLA_MODE( I2C_MASTER_OPERATION )/* | SERCOM_I2CM_CTRLA_SCLSM*/ ; // Enable Smart mode and Quick Command //sercom->I2CM.CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN /*| SERCOM_I2CM_CTRLB_QCEN*/ ; // Enable all interrupts // sercom->I2CM.INTENSET.reg = SERCOM_I2CM_INTENSET_MB | SERCOM_I2CM_INTENSET_SB | SERCOM_I2CM_INTENSET_ERROR ; // Synchronous arithmetic baudrate sercom->I2CM.BAUD.bit.BAUD = SystemCoreClock / ( 2 * baudrate) - 1 ; }
/** * \brief Initializes the requested I<SUP>2</SUP>C hardware module * * Initializes the SERCOM I<SUP>2</SUP>C master device requested and sets the provided * software module struct. Run this function before any further use of * the driver. * * \param[out] module Pointer to software module struct * \param[in] hw Pointer to the hardware instance * \param[in] config Pointer to the configuration struct * * \return Status of initialization. * \retval STATUS_OK Module initiated correctly * \retval STATUS_ERR_DENIED If module is enabled * \retval STATUS_BUSY If module is busy resetting * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than * previously set * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible * with set GCLK frequency * */ enum status_code i2c_master_init( struct i2c_master_module *const module, Sercom *const hw, const struct i2c_master_config *const config) { /* Sanity check arguments. */ Assert(module); Assert(hw); Assert(config); /* Initialize software module */ module->hw = hw; SercomI2cm *const i2c_module = &(module->hw->I2CM); uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); #if (SAML21) uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; #else uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; #endif uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; /* Turn on module in PM */ system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); /* 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 = config->generator_source; system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_enable(gclk_index); sercom_set_gclk_generator(config->generator_source, false); /* Check if module is enabled. */ if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) { return STATUS_ERR_DENIED; } /* Check if reset is in progress. */ if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) { return STATUS_BUSY; } #if I2C_MASTER_CALLBACK_MODE == true /* Get sercom instance index and register callback. */ uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw); _sercom_set_handler(instance_index, _i2c_master_interrupt_handler); _sercom_instances[instance_index] = module; /* Initialize values in module. */ module->registered_callback = 0; module->enabled_callback = 0; module->buffer_length = 0; module->buffer_remaining = 0; module->status = STATUS_OK; module->buffer = NULL; #endif /* Set sercom module to operate in I2C master mode. */ i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE(0x5); /* Set config and return status. */ return _i2c_master_set_config(module, config); }