mbed library sources
Fork of mbed-src by
targets/hal/TARGET_Atmel/TARGET_SAM21/drivers/sercom/i2c/i2c_samd21_r21_d10_d11_l21/i2c_master.c@592:a274ee790e56, 2015-07-17 (annotated)
- Committer:
- mbed_official
- Date:
- Fri Jul 17 09:15:10 2015 +0100
- Revision:
- 592:a274ee790e56
- Parent:
- 579:53297373a894
Synchronized with git revision e7144f83a8d75df80c4877936b6ffe552b0be9e6
Full URL: https://github.com/mbedmicro/mbed/commit/e7144f83a8d75df80c4877936b6ffe552b0be9e6/
More API implementation for SAMR21
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mbed_official | 579:53297373a894 | 1 | #include "i2c_master.h" |
mbed_official | 579:53297373a894 | 2 | |
mbed_official | 579:53297373a894 | 3 | #if I2C_MASTER_CALLBACK_MODE == true |
mbed_official | 579:53297373a894 | 4 | # include "i2c_master_interrupt.h" |
mbed_official | 579:53297373a894 | 5 | #endif |
mbed_official | 579:53297373a894 | 6 | |
mbed_official | 579:53297373a894 | 7 | /* Forward declaration */ |
mbed_official | 579:53297373a894 | 8 | enum status_code _i2c_master_wait_for_bus( |
mbed_official | 579:53297373a894 | 9 | struct i2c_master_module *const module); |
mbed_official | 579:53297373a894 | 10 | |
mbed_official | 579:53297373a894 | 11 | enum status_code _i2c_master_address_response( |
mbed_official | 579:53297373a894 | 12 | struct i2c_master_module *const module); |
mbed_official | 579:53297373a894 | 13 | |
mbed_official | 579:53297373a894 | 14 | enum status_code _i2c_master_send_hs_master_code( |
mbed_official | 579:53297373a894 | 15 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 16 | uint8_t hs_master_code); |
mbed_official | 579:53297373a894 | 17 | |
mbed_official | 579:53297373a894 | 18 | #if !defined(__DOXYGEN__) |
mbed_official | 579:53297373a894 | 19 | |
mbed_official | 579:53297373a894 | 20 | /** |
mbed_official | 579:53297373a894 | 21 | * \internal Sets configurations to module |
mbed_official | 579:53297373a894 | 22 | * |
mbed_official | 579:53297373a894 | 23 | * \param[out] module Pointer to software module structure |
mbed_official | 579:53297373a894 | 24 | * \param[in] config Configuration structure with configurations to set |
mbed_official | 579:53297373a894 | 25 | * |
mbed_official | 579:53297373a894 | 26 | * \return Status of setting configuration. |
mbed_official | 579:53297373a894 | 27 | * \retval STATUS_OK If module was configured correctly |
mbed_official | 579:53297373a894 | 28 | * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than |
mbed_official | 579:53297373a894 | 29 | * previously set |
mbed_official | 579:53297373a894 | 30 | * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible |
mbed_official | 579:53297373a894 | 31 | * with set GCLK frequency |
mbed_official | 579:53297373a894 | 32 | */ |
mbed_official | 579:53297373a894 | 33 | static enum status_code _i2c_master_set_config( |
mbed_official | 579:53297373a894 | 34 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 35 | const struct i2c_master_config *const config) |
mbed_official | 579:53297373a894 | 36 | { |
mbed_official | 579:53297373a894 | 37 | /* Sanity check arguments. */ |
mbed_official | 579:53297373a894 | 38 | Assert(module); |
mbed_official | 579:53297373a894 | 39 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 40 | Assert(config); |
mbed_official | 579:53297373a894 | 41 | |
mbed_official | 579:53297373a894 | 42 | /* Temporary variables. */ |
mbed_official | 579:53297373a894 | 43 | uint32_t tmp_ctrla; |
mbed_official | 579:53297373a894 | 44 | int32_t tmp_baud; |
mbed_official | 579:53297373a894 | 45 | int32_t tmp_baud_hs; |
mbed_official | 579:53297373a894 | 46 | enum status_code tmp_status_code = STATUS_OK; |
mbed_official | 579:53297373a894 | 47 | |
mbed_official | 579:53297373a894 | 48 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 49 | Sercom *const sercom_hw = module->hw; |
mbed_official | 579:53297373a894 | 50 | |
mbed_official | 579:53297373a894 | 51 | uint8_t sercom_index = _sercom_get_sercom_inst_index(sercom_hw); |
mbed_official | 579:53297373a894 | 52 | |
mbed_official | 579:53297373a894 | 53 | /* Pin configuration */ |
mbed_official | 579:53297373a894 | 54 | struct system_pinmux_config pin_conf; |
mbed_official | 579:53297373a894 | 55 | system_pinmux_get_config_defaults(&pin_conf); |
mbed_official | 579:53297373a894 | 56 | |
mbed_official | 579:53297373a894 | 57 | uint32_t pad0 = config->pinmux_pad0; |
mbed_official | 579:53297373a894 | 58 | uint32_t pad1 = config->pinmux_pad1; |
mbed_official | 579:53297373a894 | 59 | |
mbed_official | 579:53297373a894 | 60 | /* SERCOM PAD0 - SDA */ |
mbed_official | 579:53297373a894 | 61 | if (pad0 == PINMUX_DEFAULT) { |
mbed_official | 579:53297373a894 | 62 | pad0 = _sercom_get_default_pad(sercom_hw, 0); |
mbed_official | 579:53297373a894 | 63 | } |
mbed_official | 579:53297373a894 | 64 | pin_conf.mux_position = pad0 & 0xFFFF; |
mbed_official | 579:53297373a894 | 65 | pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK; |
mbed_official | 579:53297373a894 | 66 | system_pinmux_pin_set_config(pad0 >> 16, &pin_conf); |
mbed_official | 579:53297373a894 | 67 | |
mbed_official | 579:53297373a894 | 68 | /* SERCOM PAD1 - SCL */ |
mbed_official | 579:53297373a894 | 69 | if (pad1 == PINMUX_DEFAULT) { |
mbed_official | 579:53297373a894 | 70 | pad1 = _sercom_get_default_pad(sercom_hw, 1); |
mbed_official | 579:53297373a894 | 71 | } |
mbed_official | 579:53297373a894 | 72 | pin_conf.mux_position = pad1 & 0xFFFF; |
mbed_official | 579:53297373a894 | 73 | pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT_WITH_READBACK; |
mbed_official | 579:53297373a894 | 74 | system_pinmux_pin_set_config(pad1 >> 16, &pin_conf); |
mbed_official | 579:53297373a894 | 75 | |
mbed_official | 579:53297373a894 | 76 | /* Save timeout on unknown bus state in software module. */ |
mbed_official | 579:53297373a894 | 77 | module->unknown_bus_state_timeout = config->unknown_bus_state_timeout; |
mbed_official | 579:53297373a894 | 78 | |
mbed_official | 579:53297373a894 | 79 | /* Save timeout on buffer write. */ |
mbed_official | 579:53297373a894 | 80 | module->buffer_timeout = config->buffer_timeout; |
mbed_official | 579:53297373a894 | 81 | |
mbed_official | 579:53297373a894 | 82 | /* Set whether module should run in standby. */ |
mbed_official | 579:53297373a894 | 83 | if (config->run_in_standby || system_is_debugger_present()) { |
mbed_official | 579:53297373a894 | 84 | tmp_ctrla = SERCOM_I2CM_CTRLA_RUNSTDBY; |
mbed_official | 579:53297373a894 | 85 | } else { |
mbed_official | 579:53297373a894 | 86 | tmp_ctrla = 0; |
mbed_official | 579:53297373a894 | 87 | } |
mbed_official | 579:53297373a894 | 88 | |
mbed_official | 579:53297373a894 | 89 | /* Check and set start data hold timeout. */ |
mbed_official | 579:53297373a894 | 90 | if (config->start_hold_time != I2C_MASTER_START_HOLD_TIME_DISABLED) { |
mbed_official | 579:53297373a894 | 91 | tmp_ctrla |= config->start_hold_time; |
mbed_official | 579:53297373a894 | 92 | } |
mbed_official | 579:53297373a894 | 93 | |
mbed_official | 579:53297373a894 | 94 | /* Check and set transfer speed */ |
mbed_official | 579:53297373a894 | 95 | tmp_ctrla |= config->transfer_speed; |
mbed_official | 579:53297373a894 | 96 | |
mbed_official | 579:53297373a894 | 97 | /* Check and set SCL low timeout. */ |
mbed_official | 579:53297373a894 | 98 | if (config->scl_low_timeout) { |
mbed_official | 579:53297373a894 | 99 | tmp_ctrla |= SERCOM_I2CM_CTRLA_LOWTOUTEN; |
mbed_official | 579:53297373a894 | 100 | } |
mbed_official | 579:53297373a894 | 101 | |
mbed_official | 579:53297373a894 | 102 | /* Check and set inactive bus timeout. */ |
mbed_official | 579:53297373a894 | 103 | if (config->inactive_timeout != I2C_MASTER_INACTIVE_TIMEOUT_DISABLED) { |
mbed_official | 579:53297373a894 | 104 | tmp_ctrla |= config->inactive_timeout; |
mbed_official | 579:53297373a894 | 105 | } |
mbed_official | 579:53297373a894 | 106 | |
mbed_official | 579:53297373a894 | 107 | /* Check and set SCL clock stretch mode. */ |
mbed_official | 579:53297373a894 | 108 | if (config->scl_stretch_only_after_ack_bit) { |
mbed_official | 579:53297373a894 | 109 | tmp_ctrla |= SERCOM_I2CM_CTRLA_SCLSM; |
mbed_official | 579:53297373a894 | 110 | } |
mbed_official | 579:53297373a894 | 111 | |
mbed_official | 579:53297373a894 | 112 | /* Check and set slave SCL low extend timeout. */ |
mbed_official | 579:53297373a894 | 113 | if (config->slave_scl_low_extend_timeout) { |
mbed_official | 579:53297373a894 | 114 | tmp_ctrla |= SERCOM_I2CM_CTRLA_SEXTTOEN; |
mbed_official | 579:53297373a894 | 115 | } |
mbed_official | 579:53297373a894 | 116 | |
mbed_official | 579:53297373a894 | 117 | /* Check and set master SCL low extend timeout. */ |
mbed_official | 579:53297373a894 | 118 | if (config->master_scl_low_extend_timeout) { |
mbed_official | 579:53297373a894 | 119 | tmp_ctrla |= SERCOM_I2CM_CTRLA_MEXTTOEN; |
mbed_official | 579:53297373a894 | 120 | } |
mbed_official | 579:53297373a894 | 121 | |
mbed_official | 579:53297373a894 | 122 | /* Write config to register CTRLA. */ |
mbed_official | 579:53297373a894 | 123 | i2c_module->CTRLA.reg |= tmp_ctrla; |
mbed_official | 579:53297373a894 | 124 | |
mbed_official | 579:53297373a894 | 125 | /* Set configurations in CTRLB. */ |
mbed_official | 579:53297373a894 | 126 | i2c_module->CTRLB.reg = SERCOM_I2CM_CTRLB_SMEN; |
mbed_official | 579:53297373a894 | 127 | |
mbed_official | 579:53297373a894 | 128 | /* Find and set baudrate. */ |
mbed_official | 579:53297373a894 | 129 | tmp_baud = (int32_t)(div_ceil( |
mbed_official | 579:53297373a894 | 130 | system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index), |
mbed_official | 579:53297373a894 | 131 | (2000*(config->baud_rate))) - 5); |
mbed_official | 579:53297373a894 | 132 | |
mbed_official | 579:53297373a894 | 133 | /* Check that baudrate is supported at current speed. */ |
mbed_official | 579:53297373a894 | 134 | if (tmp_baud > 255 || tmp_baud < 0) { |
mbed_official | 579:53297373a894 | 135 | /* Baud rate not supported. */ |
mbed_official | 579:53297373a894 | 136 | tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE; |
mbed_official | 579:53297373a894 | 137 | } else { |
mbed_official | 579:53297373a894 | 138 | /* Find baudrate for high speed */ |
mbed_official | 579:53297373a894 | 139 | tmp_baud_hs = (int32_t)(div_ceil( |
mbed_official | 579:53297373a894 | 140 | system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index), |
mbed_official | 579:53297373a894 | 141 | (2000*(config->baud_rate_high_speed))) - 1); |
mbed_official | 579:53297373a894 | 142 | |
mbed_official | 579:53297373a894 | 143 | /* Check that baudrate is supported at current speed. */ |
mbed_official | 579:53297373a894 | 144 | if (tmp_baud_hs > 255 || tmp_baud_hs < 0) { |
mbed_official | 579:53297373a894 | 145 | /* Baud rate not supported. */ |
mbed_official | 579:53297373a894 | 146 | tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE; |
mbed_official | 579:53297373a894 | 147 | } |
mbed_official | 579:53297373a894 | 148 | } |
mbed_official | 579:53297373a894 | 149 | if (tmp_status_code != STATUS_ERR_BAUDRATE_UNAVAILABLE) { |
mbed_official | 579:53297373a894 | 150 | /* Baud rate acceptable. */ |
mbed_official | 579:53297373a894 | 151 | i2c_module->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud) | |
mbed_official | 579:53297373a894 | 152 | SERCOM_I2CM_BAUD_HSBAUD(tmp_baud_hs); |
mbed_official | 579:53297373a894 | 153 | } |
mbed_official | 579:53297373a894 | 154 | |
mbed_official | 579:53297373a894 | 155 | return tmp_status_code; |
mbed_official | 579:53297373a894 | 156 | } |
mbed_official | 579:53297373a894 | 157 | #endif /* __DOXYGEN__ */ |
mbed_official | 579:53297373a894 | 158 | |
mbed_official | 579:53297373a894 | 159 | /** |
mbed_official | 579:53297373a894 | 160 | * \brief Initializes the requested I<SUP>2</SUP>C hardware module |
mbed_official | 579:53297373a894 | 161 | * |
mbed_official | 579:53297373a894 | 162 | * Initializes the SERCOM I<SUP>2</SUP>C master device requested and sets the provided |
mbed_official | 579:53297373a894 | 163 | * software module struct. Run this function before any further use of |
mbed_official | 579:53297373a894 | 164 | * the driver. |
mbed_official | 579:53297373a894 | 165 | * |
mbed_official | 579:53297373a894 | 166 | * \param[out] module Pointer to software module struct |
mbed_official | 579:53297373a894 | 167 | * \param[in] hw Pointer to the hardware instance |
mbed_official | 579:53297373a894 | 168 | * \param[in] config Pointer to the configuration struct |
mbed_official | 579:53297373a894 | 169 | * |
mbed_official | 579:53297373a894 | 170 | * \return Status of initialization. |
mbed_official | 579:53297373a894 | 171 | * \retval STATUS_OK Module initiated correctly |
mbed_official | 579:53297373a894 | 172 | * \retval STATUS_ERR_DENIED If module is enabled |
mbed_official | 579:53297373a894 | 173 | * \retval STATUS_BUSY If module is busy resetting |
mbed_official | 579:53297373a894 | 174 | * \retval STATUS_ERR_ALREADY_INITIALIZED If setting other GCLK generator than |
mbed_official | 579:53297373a894 | 175 | * previously set |
mbed_official | 579:53297373a894 | 176 | * \retval STATUS_ERR_BAUDRATE_UNAVAILABLE If given baudrate is not compatible |
mbed_official | 579:53297373a894 | 177 | * with set GCLK frequency |
mbed_official | 579:53297373a894 | 178 | * |
mbed_official | 579:53297373a894 | 179 | */ |
mbed_official | 579:53297373a894 | 180 | enum status_code i2c_master_init( |
mbed_official | 579:53297373a894 | 181 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 182 | Sercom *const hw, |
mbed_official | 579:53297373a894 | 183 | const struct i2c_master_config *const config) |
mbed_official | 579:53297373a894 | 184 | { |
mbed_official | 579:53297373a894 | 185 | /* Sanity check arguments. */ |
mbed_official | 579:53297373a894 | 186 | Assert(module); |
mbed_official | 579:53297373a894 | 187 | Assert(hw); |
mbed_official | 579:53297373a894 | 188 | Assert(config); |
mbed_official | 579:53297373a894 | 189 | |
mbed_official | 579:53297373a894 | 190 | /* Initialize software module */ |
mbed_official | 579:53297373a894 | 191 | module->hw = hw; |
mbed_official | 579:53297373a894 | 192 | |
mbed_official | 579:53297373a894 | 193 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 194 | |
mbed_official | 579:53297373a894 | 195 | uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); |
mbed_official | 579:53297373a894 | 196 | #if (SAML21) |
mbed_official | 579:53297373a894 | 197 | uint32_t pm_index = sercom_index + MCLK_APBCMASK_SERCOM0_Pos; |
mbed_official | 579:53297373a894 | 198 | #else |
mbed_official | 579:53297373a894 | 199 | uint32_t pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; |
mbed_official | 579:53297373a894 | 200 | #endif |
mbed_official | 579:53297373a894 | 201 | uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; |
mbed_official | 579:53297373a894 | 202 | |
mbed_official | 579:53297373a894 | 203 | /* Turn on module in PM */ |
mbed_official | 579:53297373a894 | 204 | system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); |
mbed_official | 579:53297373a894 | 205 | |
mbed_official | 579:53297373a894 | 206 | /* Set up the GCLK for the module */ |
mbed_official | 579:53297373a894 | 207 | struct system_gclk_chan_config gclk_chan_conf; |
mbed_official | 579:53297373a894 | 208 | system_gclk_chan_get_config_defaults(&gclk_chan_conf); |
mbed_official | 579:53297373a894 | 209 | gclk_chan_conf.source_generator = config->generator_source; |
mbed_official | 579:53297373a894 | 210 | system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); |
mbed_official | 579:53297373a894 | 211 | system_gclk_chan_enable(gclk_index); |
mbed_official | 579:53297373a894 | 212 | sercom_set_gclk_generator(config->generator_source, false); |
mbed_official | 579:53297373a894 | 213 | |
mbed_official | 579:53297373a894 | 214 | /* Check if module is enabled. */ |
mbed_official | 579:53297373a894 | 215 | if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_ENABLE) { |
mbed_official | 579:53297373a894 | 216 | return STATUS_ERR_DENIED; |
mbed_official | 579:53297373a894 | 217 | } |
mbed_official | 579:53297373a894 | 218 | |
mbed_official | 579:53297373a894 | 219 | /* Check if reset is in progress. */ |
mbed_official | 579:53297373a894 | 220 | if (i2c_module->CTRLA.reg & SERCOM_I2CM_CTRLA_SWRST) { |
mbed_official | 579:53297373a894 | 221 | return STATUS_BUSY; |
mbed_official | 579:53297373a894 | 222 | } |
mbed_official | 579:53297373a894 | 223 | |
mbed_official | 579:53297373a894 | 224 | #if I2C_MASTER_CALLBACK_MODE == true |
mbed_official | 579:53297373a894 | 225 | /* Get sercom instance index and register callback. */ |
mbed_official | 579:53297373a894 | 226 | uint8_t instance_index = _sercom_get_sercom_inst_index(module->hw); |
mbed_official | 579:53297373a894 | 227 | _sercom_set_handler(instance_index, _i2c_master_interrupt_handler); |
mbed_official | 579:53297373a894 | 228 | _sercom_instances[instance_index] = module; |
mbed_official | 579:53297373a894 | 229 | |
mbed_official | 579:53297373a894 | 230 | /* Initialize values in module. */ |
mbed_official | 579:53297373a894 | 231 | module->registered_callback = 0; |
mbed_official | 579:53297373a894 | 232 | module->enabled_callback = 0; |
mbed_official | 579:53297373a894 | 233 | module->buffer_length = 0; |
mbed_official | 579:53297373a894 | 234 | module->buffer_remaining = 0; |
mbed_official | 579:53297373a894 | 235 | |
mbed_official | 579:53297373a894 | 236 | module->status = STATUS_OK; |
mbed_official | 579:53297373a894 | 237 | module->buffer = NULL; |
mbed_official | 579:53297373a894 | 238 | #endif |
mbed_official | 579:53297373a894 | 239 | |
mbed_official | 579:53297373a894 | 240 | /* Set sercom module to operate in I2C master mode. */ |
mbed_official | 579:53297373a894 | 241 | i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_MODE(0x5); |
mbed_official | 579:53297373a894 | 242 | |
mbed_official | 579:53297373a894 | 243 | /* Set config and return status. */ |
mbed_official | 579:53297373a894 | 244 | return _i2c_master_set_config(module, config); |
mbed_official | 579:53297373a894 | 245 | } |
mbed_official | 579:53297373a894 | 246 | |
mbed_official | 579:53297373a894 | 247 | /** |
mbed_official | 579:53297373a894 | 248 | * \brief Resets the hardware module |
mbed_official | 579:53297373a894 | 249 | * |
mbed_official | 579:53297373a894 | 250 | * Reset the module to hardware defaults. |
mbed_official | 579:53297373a894 | 251 | * |
mbed_official | 579:53297373a894 | 252 | * \param[in,out] module Pointer to software module structure |
mbed_official | 579:53297373a894 | 253 | */ |
mbed_official | 579:53297373a894 | 254 | void i2c_master_reset(struct i2c_master_module *const module) |
mbed_official | 579:53297373a894 | 255 | { |
mbed_official | 579:53297373a894 | 256 | /* Sanity check arguments */ |
mbed_official | 579:53297373a894 | 257 | Assert(module); |
mbed_official | 579:53297373a894 | 258 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 259 | |
mbed_official | 579:53297373a894 | 260 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 261 | |
mbed_official | 579:53297373a894 | 262 | /* Wait for sync */ |
mbed_official | 579:53297373a894 | 263 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 264 | |
mbed_official | 579:53297373a894 | 265 | /* Disable module */ |
mbed_official | 579:53297373a894 | 266 | i2c_master_disable(module); |
mbed_official | 579:53297373a894 | 267 | |
mbed_official | 579:53297373a894 | 268 | #if I2C_MASTER_CALLBACK_MODE == true |
mbed_official | 579:53297373a894 | 269 | /* Clear all pending interrupts */ |
mbed_official | 579:53297373a894 | 270 | system_interrupt_enter_critical_section(); |
mbed_official | 579:53297373a894 | 271 | system_interrupt_clear_pending(_sercom_get_interrupt_vector(module->hw)); |
mbed_official | 579:53297373a894 | 272 | system_interrupt_leave_critical_section(); |
mbed_official | 579:53297373a894 | 273 | #endif |
mbed_official | 579:53297373a894 | 274 | |
mbed_official | 579:53297373a894 | 275 | /* Wait for sync */ |
mbed_official | 579:53297373a894 | 276 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 277 | |
mbed_official | 579:53297373a894 | 278 | /* Reset module */ |
mbed_official | 579:53297373a894 | 279 | i2c_module->CTRLA.reg = SERCOM_I2CM_CTRLA_SWRST; |
mbed_official | 579:53297373a894 | 280 | } |
mbed_official | 579:53297373a894 | 281 | |
mbed_official | 579:53297373a894 | 282 | #if !defined(__DOXYGEN__) |
mbed_official | 579:53297373a894 | 283 | /** |
mbed_official | 579:53297373a894 | 284 | * \internal |
mbed_official | 579:53297373a894 | 285 | * Address response. Called when address is answered or timed out. |
mbed_official | 579:53297373a894 | 286 | * |
mbed_official | 579:53297373a894 | 287 | * \param[in,out] module Pointer to software module structure |
mbed_official | 579:53297373a894 | 288 | * |
mbed_official | 579:53297373a894 | 289 | * \return Status of address response. |
mbed_official | 579:53297373a894 | 290 | * \retval STATUS_OK No error has occurred |
mbed_official | 579:53297373a894 | 291 | * \retval STATUS_ERR_DENIED If error on bus |
mbed_official | 579:53297373a894 | 292 | * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost |
mbed_official | 579:53297373a894 | 293 | * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave |
mbed_official | 579:53297373a894 | 294 | * acknowledged the address |
mbed_official | 579:53297373a894 | 295 | */ |
mbed_official | 579:53297373a894 | 296 | enum status_code _i2c_master_address_response( |
mbed_official | 579:53297373a894 | 297 | struct i2c_master_module *const module) |
mbed_official | 579:53297373a894 | 298 | { |
mbed_official | 579:53297373a894 | 299 | /* Sanity check arguments */ |
mbed_official | 579:53297373a894 | 300 | Assert(module); |
mbed_official | 579:53297373a894 | 301 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 302 | |
mbed_official | 579:53297373a894 | 303 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 304 | |
mbed_official | 579:53297373a894 | 305 | /* Check for error and ignore bus-error; workaround for BUSSTATE stuck in |
mbed_official | 579:53297373a894 | 306 | * BUSY */ |
mbed_official | 579:53297373a894 | 307 | if (i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB) { |
mbed_official | 579:53297373a894 | 308 | |
mbed_official | 579:53297373a894 | 309 | /* Clear write interrupt flag */ |
mbed_official | 579:53297373a894 | 310 | i2c_module->INTFLAG.reg = SERCOM_I2CM_INTFLAG_SB; |
mbed_official | 579:53297373a894 | 311 | |
mbed_official | 579:53297373a894 | 312 | /* Check arbitration. */ |
mbed_official | 579:53297373a894 | 313 | if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) { |
mbed_official | 579:53297373a894 | 314 | /* Return packet collision. */ |
mbed_official | 579:53297373a894 | 315 | return STATUS_ERR_PACKET_COLLISION; |
mbed_official | 579:53297373a894 | 316 | } |
mbed_official | 579:53297373a894 | 317 | /* Check that slave responded with ack. */ |
mbed_official | 579:53297373a894 | 318 | } else if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { |
mbed_official | 579:53297373a894 | 319 | /* Slave busy. Issue ack and stop command. */ |
mbed_official | 579:53297373a894 | 320 | i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); |
mbed_official | 579:53297373a894 | 321 | |
mbed_official | 579:53297373a894 | 322 | /* Return bad address value. */ |
mbed_official | 579:53297373a894 | 323 | return STATUS_ERR_BAD_ADDRESS; |
mbed_official | 579:53297373a894 | 324 | } |
mbed_official | 579:53297373a894 | 325 | |
mbed_official | 579:53297373a894 | 326 | return STATUS_OK; |
mbed_official | 579:53297373a894 | 327 | } |
mbed_official | 579:53297373a894 | 328 | |
mbed_official | 579:53297373a894 | 329 | /** |
mbed_official | 579:53297373a894 | 330 | * \internal |
mbed_official | 579:53297373a894 | 331 | * Waits for answer on bus. |
mbed_official | 579:53297373a894 | 332 | * |
mbed_official | 579:53297373a894 | 333 | * \param[in,out] module Pointer to software module structure |
mbed_official | 579:53297373a894 | 334 | * |
mbed_official | 579:53297373a894 | 335 | * \return Status of bus. |
mbed_official | 579:53297373a894 | 336 | * \retval STATUS_OK If given response from slave device |
mbed_official | 579:53297373a894 | 337 | * \retval STATUS_ERR_TIMEOUT If no response was given within specified timeout |
mbed_official | 579:53297373a894 | 338 | * period |
mbed_official | 579:53297373a894 | 339 | */ |
mbed_official | 579:53297373a894 | 340 | enum status_code _i2c_master_wait_for_bus( |
mbed_official | 579:53297373a894 | 341 | struct i2c_master_module *const module) |
mbed_official | 579:53297373a894 | 342 | { |
mbed_official | 579:53297373a894 | 343 | /* Sanity check arguments */ |
mbed_official | 579:53297373a894 | 344 | Assert(module); |
mbed_official | 579:53297373a894 | 345 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 346 | |
mbed_official | 579:53297373a894 | 347 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 348 | |
mbed_official | 579:53297373a894 | 349 | /* Wait for reply. */ |
mbed_official | 579:53297373a894 | 350 | uint16_t timeout_counter = 0; |
mbed_official | 579:53297373a894 | 351 | while (!(i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_MB) && |
mbed_official | 579:53297373a894 | 352 | !(i2c_module->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB)) { |
mbed_official | 579:53297373a894 | 353 | |
mbed_official | 579:53297373a894 | 354 | /* Check timeout condition. */ |
mbed_official | 579:53297373a894 | 355 | if (++timeout_counter >= module->buffer_timeout) { |
mbed_official | 579:53297373a894 | 356 | return STATUS_ERR_TIMEOUT; |
mbed_official | 579:53297373a894 | 357 | } |
mbed_official | 579:53297373a894 | 358 | } |
mbed_official | 579:53297373a894 | 359 | return STATUS_OK; |
mbed_official | 579:53297373a894 | 360 | } |
mbed_official | 579:53297373a894 | 361 | #endif /* __DOXYGEN__ */ |
mbed_official | 579:53297373a894 | 362 | |
mbed_official | 579:53297373a894 | 363 | /** |
mbed_official | 579:53297373a894 | 364 | * \internal |
mbed_official | 579:53297373a894 | 365 | * Send master code for high speed transfer. |
mbed_official | 579:53297373a894 | 366 | * |
mbed_official | 579:53297373a894 | 367 | * \param[in,out] module Pointer to software module structure |
mbed_official | 579:53297373a894 | 368 | * \param[in] hs_master_code 8-bit master code (0000 1XXX) |
mbed_official | 579:53297373a894 | 369 | * |
mbed_official | 579:53297373a894 | 370 | * \return Status of bus. |
mbed_official | 579:53297373a894 | 371 | * \retval STATUS_OK No error happen |
mbed_official | 579:53297373a894 | 372 | */ |
mbed_official | 579:53297373a894 | 373 | enum status_code _i2c_master_send_hs_master_code( |
mbed_official | 579:53297373a894 | 374 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 375 | uint8_t hs_master_code) |
mbed_official | 579:53297373a894 | 376 | { |
mbed_official | 579:53297373a894 | 377 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 378 | /* Return value. */ |
mbed_official | 579:53297373a894 | 379 | enum status_code tmp_status; |
mbed_official | 579:53297373a894 | 380 | |
mbed_official | 579:53297373a894 | 381 | /* Set NACK for high speed code */ |
mbed_official | 579:53297373a894 | 382 | i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 579:53297373a894 | 383 | /* Send high speed code */ |
mbed_official | 579:53297373a894 | 384 | i2c_module->ADDR.reg = hs_master_code; |
mbed_official | 579:53297373a894 | 385 | /* Wait for response on bus. */ |
mbed_official | 579:53297373a894 | 386 | tmp_status = _i2c_master_wait_for_bus(module); |
mbed_official | 579:53297373a894 | 387 | /* Clear write interrupt flag */ |
mbed_official | 579:53297373a894 | 388 | i2c_module->INTFLAG.reg = SERCOM_I2CM_INTENCLR_MB; |
mbed_official | 579:53297373a894 | 389 | |
mbed_official | 579:53297373a894 | 390 | return tmp_status; |
mbed_official | 579:53297373a894 | 391 | } |
mbed_official | 579:53297373a894 | 392 | |
mbed_official | 579:53297373a894 | 393 | |
mbed_official | 579:53297373a894 | 394 | /** |
mbed_official | 579:53297373a894 | 395 | * \internal |
mbed_official | 579:53297373a894 | 396 | * Starts blocking read operation. |
mbed_official | 579:53297373a894 | 397 | * |
mbed_official | 579:53297373a894 | 398 | * \param[in,out] module Pointer to software module struct |
mbed_official | 579:53297373a894 | 399 | * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer |
mbed_official | 579:53297373a894 | 400 | * |
mbed_official | 579:53297373a894 | 401 | * \return Status of reading packet. |
mbed_official | 579:53297373a894 | 402 | * \retval STATUS_OK The packet was read successfully |
mbed_official | 579:53297373a894 | 403 | * \retval STATUS_ERR_TIMEOUT If no response was given within |
mbed_official | 579:53297373a894 | 404 | * specified timeout period |
mbed_official | 579:53297373a894 | 405 | * \retval STATUS_ERR_DENIED If error on bus |
mbed_official | 579:53297373a894 | 406 | * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost |
mbed_official | 579:53297373a894 | 407 | * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave |
mbed_official | 579:53297373a894 | 408 | * acknowledged the address |
mbed_official | 579:53297373a894 | 409 | * |
mbed_official | 579:53297373a894 | 410 | */ |
mbed_official | 579:53297373a894 | 411 | static enum status_code _i2c_master_read_packet( |
mbed_official | 579:53297373a894 | 412 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 413 | struct i2c_master_packet *const packet) |
mbed_official | 579:53297373a894 | 414 | { |
mbed_official | 579:53297373a894 | 415 | /* Sanity check arguments */ |
mbed_official | 579:53297373a894 | 416 | Assert(module); |
mbed_official | 579:53297373a894 | 417 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 418 | Assert(packet); |
mbed_official | 579:53297373a894 | 419 | |
mbed_official | 579:53297373a894 | 420 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 421 | |
mbed_official | 579:53297373a894 | 422 | /* Return value. */ |
mbed_official | 579:53297373a894 | 423 | enum status_code tmp_status; |
mbed_official | 579:53297373a894 | 424 | uint16_t tmp_data_length = packet->data_length; |
mbed_official | 579:53297373a894 | 425 | |
mbed_official | 579:53297373a894 | 426 | /* Written buffer counter. */ |
mbed_official | 579:53297373a894 | 427 | uint16_t counter = 0; |
mbed_official | 579:53297373a894 | 428 | |
mbed_official | 579:53297373a894 | 429 | bool sclsm_flag = i2c_module->CTRLA.bit.SCLSM; |
mbed_official | 579:53297373a894 | 430 | |
mbed_official | 579:53297373a894 | 431 | /* Switch to high speed mode */ |
mbed_official | 579:53297373a894 | 432 | if (packet->high_speed) { |
mbed_official | 579:53297373a894 | 433 | _i2c_master_send_hs_master_code(module, packet->hs_master_code); |
mbed_official | 579:53297373a894 | 434 | } |
mbed_official | 579:53297373a894 | 435 | |
mbed_official | 579:53297373a894 | 436 | /* Set action to ACK. */ |
mbed_official | 579:53297373a894 | 437 | i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 579:53297373a894 | 438 | |
mbed_official | 579:53297373a894 | 439 | /* Set address and direction bit. Will send start command on bus. */ |
mbed_official | 579:53297373a894 | 440 | if (packet->ten_bit_address) { |
mbed_official | 579:53297373a894 | 441 | /* |
mbed_official | 579:53297373a894 | 442 | * Write ADDR.ADDR[10:1] with the 10-bit address. ADDR.TENBITEN must |
mbed_official | 579:53297373a894 | 443 | * be set and read/write bit (ADDR.ADDR[0]) equal to 0. |
mbed_official | 579:53297373a894 | 444 | */ |
mbed_official | 579:53297373a894 | 445 | i2c_module->ADDR.reg = (packet->address << 1) | |
mbed_official | 579:53297373a894 | 446 | (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | |
mbed_official | 579:53297373a894 | 447 | SERCOM_I2CM_ADDR_TENBITEN; |
mbed_official | 579:53297373a894 | 448 | |
mbed_official | 579:53297373a894 | 449 | /* Wait for response on bus. */ |
mbed_official | 579:53297373a894 | 450 | tmp_status = _i2c_master_wait_for_bus(module); |
mbed_official | 579:53297373a894 | 451 | |
mbed_official | 579:53297373a894 | 452 | /* Set action to ack. */ |
mbed_official | 579:53297373a894 | 453 | i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 579:53297373a894 | 454 | |
mbed_official | 579:53297373a894 | 455 | /* Check for address response error unless previous error is |
mbed_official | 579:53297373a894 | 456 | * detected. */ |
mbed_official | 579:53297373a894 | 457 | if (tmp_status == STATUS_OK) { |
mbed_official | 579:53297373a894 | 458 | tmp_status = _i2c_master_address_response(module); |
mbed_official | 579:53297373a894 | 459 | } |
mbed_official | 579:53297373a894 | 460 | |
mbed_official | 579:53297373a894 | 461 | if (tmp_status == STATUS_OK) { |
mbed_official | 579:53297373a894 | 462 | /* |
mbed_official | 579:53297373a894 | 463 | * Write ADDR[7:0] register to 鈥10 address[9:8] 1鈥 |
mbed_official | 579:53297373a894 | 464 | * ADDR.TENBITEN must be cleared |
mbed_official | 579:53297373a894 | 465 | */ |
mbed_official | 579:53297373a894 | 466 | i2c_module->ADDR.reg = (((packet->address >> 8) | 0x78) << 1) | |
mbed_official | 579:53297373a894 | 467 | (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | |
mbed_official | 579:53297373a894 | 468 | I2C_TRANSFER_READ; |
mbed_official | 579:53297373a894 | 469 | } else { |
mbed_official | 579:53297373a894 | 470 | return tmp_status; |
mbed_official | 579:53297373a894 | 471 | } |
mbed_official | 579:53297373a894 | 472 | } else { |
mbed_official | 579:53297373a894 | 473 | i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_READ | |
mbed_official | 579:53297373a894 | 474 | (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos); |
mbed_official | 579:53297373a894 | 475 | } |
mbed_official | 579:53297373a894 | 476 | |
mbed_official | 579:53297373a894 | 477 | /* Wait for response on bus. */ |
mbed_official | 579:53297373a894 | 478 | tmp_status = _i2c_master_wait_for_bus(module); |
mbed_official | 579:53297373a894 | 479 | |
mbed_official | 579:53297373a894 | 480 | /* Set action to ack. */ |
mbed_official | 579:53297373a894 | 481 | i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 579:53297373a894 | 482 | |
mbed_official | 579:53297373a894 | 483 | /* Check for address response error unless previous error is |
mbed_official | 579:53297373a894 | 484 | * detected. */ |
mbed_official | 579:53297373a894 | 485 | if (tmp_status == STATUS_OK) { |
mbed_official | 579:53297373a894 | 486 | tmp_status = _i2c_master_address_response(module); |
mbed_official | 579:53297373a894 | 487 | } |
mbed_official | 579:53297373a894 | 488 | |
mbed_official | 579:53297373a894 | 489 | /* Check that no error has occurred. */ |
mbed_official | 579:53297373a894 | 490 | if (tmp_status == STATUS_OK) { |
mbed_official | 579:53297373a894 | 491 | /* Read data buffer. */ |
mbed_official | 579:53297373a894 | 492 | while (tmp_data_length--) { |
mbed_official | 579:53297373a894 | 493 | /* Check that bus ownership is not lost. */ |
mbed_official | 579:53297373a894 | 494 | if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) { |
mbed_official | 579:53297373a894 | 495 | return STATUS_ERR_PACKET_COLLISION; |
mbed_official | 579:53297373a894 | 496 | } |
mbed_official | 579:53297373a894 | 497 | |
mbed_official | 579:53297373a894 | 498 | if (((!sclsm_flag) && (tmp_data_length == 0)) || |
mbed_official | 579:53297373a894 | 499 | ((sclsm_flag) && (tmp_data_length == 1))) { |
mbed_official | 579:53297373a894 | 500 | /* Set action to NACK */ |
mbed_official | 579:53297373a894 | 501 | i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 579:53297373a894 | 502 | } else { |
mbed_official | 579:53297373a894 | 503 | /* Save data to buffer. */ |
mbed_official | 579:53297373a894 | 504 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 505 | packet->data[counter++] = i2c_module->DATA.reg; |
mbed_official | 579:53297373a894 | 506 | /* Wait for response. */ |
mbed_official | 579:53297373a894 | 507 | tmp_status = _i2c_master_wait_for_bus(module); |
mbed_official | 579:53297373a894 | 508 | } |
mbed_official | 579:53297373a894 | 509 | |
mbed_official | 579:53297373a894 | 510 | /* Check for error. */ |
mbed_official | 579:53297373a894 | 511 | if (tmp_status != STATUS_OK) { |
mbed_official | 579:53297373a894 | 512 | break; |
mbed_official | 579:53297373a894 | 513 | } |
mbed_official | 579:53297373a894 | 514 | } |
mbed_official | 579:53297373a894 | 515 | |
mbed_official | 579:53297373a894 | 516 | if (module->send_stop) { |
mbed_official | 579:53297373a894 | 517 | /* Send stop command unless arbitration is lost. */ |
mbed_official | 579:53297373a894 | 518 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 519 | i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); |
mbed_official | 579:53297373a894 | 520 | } |
mbed_official | 579:53297373a894 | 521 | |
mbed_official | 579:53297373a894 | 522 | /* Save last data to buffer. */ |
mbed_official | 579:53297373a894 | 523 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 524 | packet->data[counter] = i2c_module->DATA.reg; |
mbed_official | 579:53297373a894 | 525 | } |
mbed_official | 579:53297373a894 | 526 | |
mbed_official | 579:53297373a894 | 527 | return tmp_status; |
mbed_official | 579:53297373a894 | 528 | } |
mbed_official | 579:53297373a894 | 529 | |
mbed_official | 579:53297373a894 | 530 | /** |
mbed_official | 579:53297373a894 | 531 | * \brief Reads data packet from slave |
mbed_official | 579:53297373a894 | 532 | * |
mbed_official | 579:53297373a894 | 533 | * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C |
mbed_official | 579:53297373a894 | 534 | * bus and sends a stop condition when finished. |
mbed_official | 579:53297373a894 | 535 | * |
mbed_official | 579:53297373a894 | 536 | * \note This will stall the device from any other operation. For |
mbed_official | 579:53297373a894 | 537 | * interrupt-driven operation, see \ref i2c_master_read_packet_job. |
mbed_official | 579:53297373a894 | 538 | * |
mbed_official | 579:53297373a894 | 539 | * \param[in,out] module Pointer to software module struct |
mbed_official | 579:53297373a894 | 540 | * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer |
mbed_official | 579:53297373a894 | 541 | * |
mbed_official | 579:53297373a894 | 542 | * \return Status of reading packet. |
mbed_official | 579:53297373a894 | 543 | * \retval STATUS_OK The packet was read successfully |
mbed_official | 579:53297373a894 | 544 | * \retval STATUS_ERR_TIMEOUT If no response was given within |
mbed_official | 579:53297373a894 | 545 | * specified timeout period |
mbed_official | 579:53297373a894 | 546 | * \retval STATUS_ERR_DENIED If error on bus |
mbed_official | 579:53297373a894 | 547 | * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost |
mbed_official | 579:53297373a894 | 548 | * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave |
mbed_official | 579:53297373a894 | 549 | * acknowledged the address |
mbed_official | 579:53297373a894 | 550 | */ |
mbed_official | 579:53297373a894 | 551 | enum status_code i2c_master_read_packet_wait( |
mbed_official | 579:53297373a894 | 552 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 553 | struct i2c_master_packet *const packet) |
mbed_official | 579:53297373a894 | 554 | { |
mbed_official | 579:53297373a894 | 555 | /* Sanity check */ |
mbed_official | 579:53297373a894 | 556 | Assert(module); |
mbed_official | 579:53297373a894 | 557 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 558 | Assert(packet); |
mbed_official | 579:53297373a894 | 559 | |
mbed_official | 579:53297373a894 | 560 | #if I2C_MASTER_CALLBACK_MODE == true |
mbed_official | 579:53297373a894 | 561 | /* Check if the I2C module is busy with a job. */ |
mbed_official | 579:53297373a894 | 562 | if (module->buffer_remaining > 0) { |
mbed_official | 579:53297373a894 | 563 | return STATUS_BUSY; |
mbed_official | 579:53297373a894 | 564 | } |
mbed_official | 579:53297373a894 | 565 | #endif |
mbed_official | 579:53297373a894 | 566 | |
mbed_official | 579:53297373a894 | 567 | module->send_stop = true; |
mbed_official | 579:53297373a894 | 568 | |
mbed_official | 579:53297373a894 | 569 | return _i2c_master_read_packet(module, packet); |
mbed_official | 579:53297373a894 | 570 | } |
mbed_official | 579:53297373a894 | 571 | |
mbed_official | 579:53297373a894 | 572 | /** |
mbed_official | 579:53297373a894 | 573 | * \brief Reads data packet from slave without sending a stop condition when done |
mbed_official | 579:53297373a894 | 574 | * |
mbed_official | 579:53297373a894 | 575 | * Reads a data packet from the specified slave address on the I<SUP>2</SUP>C |
mbed_official | 579:53297373a894 | 576 | * bus without sending a stop condition when done, thus retaining ownership of |
mbed_official | 579:53297373a894 | 577 | * the bus when done. To end the transaction, a |
mbed_official | 579:53297373a894 | 578 | * \ref i2c_master_read_packet_wait "read" or |
mbed_official | 579:53297373a894 | 579 | * \ref i2c_master_write_packet_wait "write" with stop condition must be |
mbed_official | 579:53297373a894 | 580 | * performed. |
mbed_official | 579:53297373a894 | 581 | * |
mbed_official | 579:53297373a894 | 582 | * \note This will stall the device from any other operation. For |
mbed_official | 579:53297373a894 | 583 | * interrupt-driven operation, see \ref i2c_master_read_packet_job. |
mbed_official | 579:53297373a894 | 584 | * |
mbed_official | 579:53297373a894 | 585 | * \param[in,out] module Pointer to software module struct |
mbed_official | 579:53297373a894 | 586 | * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer |
mbed_official | 579:53297373a894 | 587 | * |
mbed_official | 579:53297373a894 | 588 | * \return Status of reading packet. |
mbed_official | 579:53297373a894 | 589 | * \retval STATUS_OK The packet was read successfully |
mbed_official | 579:53297373a894 | 590 | * \retval STATUS_ERR_TIMEOUT If no response was given within |
mbed_official | 579:53297373a894 | 591 | * specified timeout period |
mbed_official | 579:53297373a894 | 592 | * \retval STATUS_ERR_DENIED If error on bus |
mbed_official | 579:53297373a894 | 593 | * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost |
mbed_official | 579:53297373a894 | 594 | * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave |
mbed_official | 579:53297373a894 | 595 | * acknowledged the address |
mbed_official | 579:53297373a894 | 596 | */ |
mbed_official | 579:53297373a894 | 597 | enum status_code i2c_master_read_packet_wait_no_stop( |
mbed_official | 579:53297373a894 | 598 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 599 | struct i2c_master_packet *const packet) |
mbed_official | 579:53297373a894 | 600 | { |
mbed_official | 579:53297373a894 | 601 | /* Sanity check */ |
mbed_official | 579:53297373a894 | 602 | Assert(module); |
mbed_official | 579:53297373a894 | 603 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 604 | Assert(packet); |
mbed_official | 579:53297373a894 | 605 | |
mbed_official | 579:53297373a894 | 606 | #if I2C_MASTER_CALLBACK_MODE == true |
mbed_official | 579:53297373a894 | 607 | /* Check if the I2C module is busy with a job. */ |
mbed_official | 579:53297373a894 | 608 | if (module->buffer_remaining > 0) { |
mbed_official | 579:53297373a894 | 609 | return STATUS_BUSY; |
mbed_official | 579:53297373a894 | 610 | } |
mbed_official | 579:53297373a894 | 611 | #endif |
mbed_official | 579:53297373a894 | 612 | |
mbed_official | 579:53297373a894 | 613 | module->send_stop = false; |
mbed_official | 579:53297373a894 | 614 | |
mbed_official | 579:53297373a894 | 615 | return _i2c_master_read_packet(module, packet); |
mbed_official | 579:53297373a894 | 616 | } |
mbed_official | 579:53297373a894 | 617 | |
mbed_official | 579:53297373a894 | 618 | /** |
mbed_official | 579:53297373a894 | 619 | * \internal |
mbed_official | 579:53297373a894 | 620 | * Starts blocking write operation. |
mbed_official | 579:53297373a894 | 621 | * |
mbed_official | 579:53297373a894 | 622 | * \param[in,out] module Pointer to software module struct |
mbed_official | 579:53297373a894 | 623 | * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer |
mbed_official | 579:53297373a894 | 624 | * |
mbed_official | 579:53297373a894 | 625 | * \return Status of reading packet. |
mbed_official | 579:53297373a894 | 626 | * \retval STATUS_OK The packet was read successfully |
mbed_official | 579:53297373a894 | 627 | * \retval STATUS_ERR_TIMEOUT If no response was given within |
mbed_official | 579:53297373a894 | 628 | * specified timeout period |
mbed_official | 579:53297373a894 | 629 | * \retval STATUS_ERR_DENIED If error on bus |
mbed_official | 579:53297373a894 | 630 | * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost |
mbed_official | 579:53297373a894 | 631 | * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave |
mbed_official | 579:53297373a894 | 632 | * acknowledged the address |
mbed_official | 579:53297373a894 | 633 | */ |
mbed_official | 579:53297373a894 | 634 | static enum status_code _i2c_master_write_packet( |
mbed_official | 579:53297373a894 | 635 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 636 | struct i2c_master_packet *const packet) |
mbed_official | 579:53297373a894 | 637 | { |
mbed_official | 579:53297373a894 | 638 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 639 | |
mbed_official | 579:53297373a894 | 640 | /* Return value. */ |
mbed_official | 579:53297373a894 | 641 | enum status_code tmp_status; |
mbed_official | 579:53297373a894 | 642 | uint16_t tmp_data_length = packet->data_length; |
mbed_official | 579:53297373a894 | 643 | |
mbed_official | 579:53297373a894 | 644 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 645 | |
mbed_official | 579:53297373a894 | 646 | /* Switch to high speed mode */ |
mbed_official | 579:53297373a894 | 647 | if (packet->high_speed) { |
mbed_official | 579:53297373a894 | 648 | _i2c_master_send_hs_master_code(module, packet->hs_master_code); |
mbed_official | 579:53297373a894 | 649 | } |
mbed_official | 579:53297373a894 | 650 | |
mbed_official | 579:53297373a894 | 651 | /* Set action to ACK. */ |
mbed_official | 579:53297373a894 | 652 | i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 579:53297373a894 | 653 | |
mbed_official | 579:53297373a894 | 654 | /* Set address and direction bit. Will send start command on bus. */ |
mbed_official | 579:53297373a894 | 655 | if (packet->ten_bit_address) { |
mbed_official | 579:53297373a894 | 656 | i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE | |
mbed_official | 579:53297373a894 | 657 | (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos) | |
mbed_official | 579:53297373a894 | 658 | SERCOM_I2CM_ADDR_TENBITEN; |
mbed_official | 579:53297373a894 | 659 | } else { |
mbed_official | 579:53297373a894 | 660 | i2c_module->ADDR.reg = (packet->address << 1) | I2C_TRANSFER_WRITE | |
mbed_official | 579:53297373a894 | 661 | (packet->high_speed << SERCOM_I2CM_ADDR_HS_Pos); |
mbed_official | 579:53297373a894 | 662 | } |
mbed_official | 579:53297373a894 | 663 | /* Wait for response on bus. */ |
mbed_official | 579:53297373a894 | 664 | tmp_status = _i2c_master_wait_for_bus(module); |
mbed_official | 579:53297373a894 | 665 | |
mbed_official | 579:53297373a894 | 666 | /* Check for address response error unless previous error is |
mbed_official | 579:53297373a894 | 667 | * detected. */ |
mbed_official | 579:53297373a894 | 668 | if (tmp_status == STATUS_OK) { |
mbed_official | 579:53297373a894 | 669 | tmp_status = _i2c_master_address_response(module); |
mbed_official | 579:53297373a894 | 670 | } |
mbed_official | 579:53297373a894 | 671 | |
mbed_official | 579:53297373a894 | 672 | /* Check that no error has occurred. */ |
mbed_official | 579:53297373a894 | 673 | if (tmp_status == STATUS_OK) { |
mbed_official | 579:53297373a894 | 674 | /* Buffer counter. */ |
mbed_official | 579:53297373a894 | 675 | uint16_t buffer_counter = 0; |
mbed_official | 579:53297373a894 | 676 | |
mbed_official | 579:53297373a894 | 677 | /* Write data buffer. */ |
mbed_official | 579:53297373a894 | 678 | while (tmp_data_length--) { |
mbed_official | 579:53297373a894 | 679 | /* Check that bus ownership is not lost. */ |
mbed_official | 579:53297373a894 | 680 | if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) { |
mbed_official | 579:53297373a894 | 681 | return STATUS_ERR_PACKET_COLLISION; |
mbed_official | 579:53297373a894 | 682 | } |
mbed_official | 579:53297373a894 | 683 | |
mbed_official | 579:53297373a894 | 684 | /* Write byte to slave. */ |
mbed_official | 579:53297373a894 | 685 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 686 | i2c_module->DATA.reg = packet->data[buffer_counter++]; |
mbed_official | 579:53297373a894 | 687 | |
mbed_official | 579:53297373a894 | 688 | /* Wait for response. */ |
mbed_official | 579:53297373a894 | 689 | tmp_status = _i2c_master_wait_for_bus(module); |
mbed_official | 579:53297373a894 | 690 | |
mbed_official | 579:53297373a894 | 691 | /* Check for error. */ |
mbed_official | 579:53297373a894 | 692 | if (tmp_status != STATUS_OK) { |
mbed_official | 579:53297373a894 | 693 | break; |
mbed_official | 579:53297373a894 | 694 | } |
mbed_official | 579:53297373a894 | 695 | |
mbed_official | 579:53297373a894 | 696 | /* Check for NACK from slave. */ |
mbed_official | 579:53297373a894 | 697 | if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { |
mbed_official | 579:53297373a894 | 698 | /* Return bad data value. */ |
mbed_official | 579:53297373a894 | 699 | tmp_status = STATUS_ERR_OVERFLOW; |
mbed_official | 579:53297373a894 | 700 | break; |
mbed_official | 579:53297373a894 | 701 | } |
mbed_official | 579:53297373a894 | 702 | } |
mbed_official | 579:53297373a894 | 703 | |
mbed_official | 579:53297373a894 | 704 | if (module->send_stop) { |
mbed_official | 579:53297373a894 | 705 | /* Stop command */ |
mbed_official | 579:53297373a894 | 706 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 707 | i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); |
mbed_official | 579:53297373a894 | 708 | } |
mbed_official | 579:53297373a894 | 709 | } |
mbed_official | 579:53297373a894 | 710 | |
mbed_official | 579:53297373a894 | 711 | return tmp_status; |
mbed_official | 579:53297373a894 | 712 | } |
mbed_official | 579:53297373a894 | 713 | |
mbed_official | 579:53297373a894 | 714 | /** |
mbed_official | 579:53297373a894 | 715 | * \brief Writes data packet to slave |
mbed_official | 579:53297373a894 | 716 | * |
mbed_official | 579:53297373a894 | 717 | * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C bus |
mbed_official | 579:53297373a894 | 718 | * and sends a stop condition when finished. |
mbed_official | 579:53297373a894 | 719 | * |
mbed_official | 579:53297373a894 | 720 | * \note This will stall the device from any other operation. For |
mbed_official | 579:53297373a894 | 721 | * interrupt-driven operation, see \ref i2c_master_read_packet_job. |
mbed_official | 579:53297373a894 | 722 | * |
mbed_official | 579:53297373a894 | 723 | * \param[in,out] module Pointer to software module struct |
mbed_official | 579:53297373a894 | 724 | * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer |
mbed_official | 579:53297373a894 | 725 | * |
mbed_official | 579:53297373a894 | 726 | * \return Status of reading packet. |
mbed_official | 579:53297373a894 | 727 | * \retval STATUS_OK If packet was read |
mbed_official | 579:53297373a894 | 728 | * \retval STATUS_BUSY If master module is busy with a job |
mbed_official | 579:53297373a894 | 729 | * \retval STATUS_ERR_DENIED If error on bus |
mbed_official | 579:53297373a894 | 730 | * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost |
mbed_official | 579:53297373a894 | 731 | * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave |
mbed_official | 579:53297373a894 | 732 | * acknowledged the address |
mbed_official | 579:53297373a894 | 733 | * \retval STATUS_ERR_TIMEOUT If timeout occurred |
mbed_official | 579:53297373a894 | 734 | * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent |
mbed_official | 579:53297373a894 | 735 | * data, indicating that slave does not |
mbed_official | 579:53297373a894 | 736 | * want more data and was not able to read |
mbed_official | 579:53297373a894 | 737 | * last data sent |
mbed_official | 579:53297373a894 | 738 | */ |
mbed_official | 579:53297373a894 | 739 | enum status_code i2c_master_write_packet_wait( |
mbed_official | 579:53297373a894 | 740 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 741 | struct i2c_master_packet *const packet) |
mbed_official | 579:53297373a894 | 742 | { |
mbed_official | 579:53297373a894 | 743 | /* Sanity check */ |
mbed_official | 579:53297373a894 | 744 | Assert(module); |
mbed_official | 579:53297373a894 | 745 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 746 | Assert(packet); |
mbed_official | 579:53297373a894 | 747 | |
mbed_official | 579:53297373a894 | 748 | #if I2C_MASTER_CALLBACK_MODE == true |
mbed_official | 579:53297373a894 | 749 | /* Check if the I2C module is busy with a job */ |
mbed_official | 579:53297373a894 | 750 | if (module->buffer_remaining > 0) { |
mbed_official | 579:53297373a894 | 751 | return STATUS_BUSY; |
mbed_official | 579:53297373a894 | 752 | } |
mbed_official | 579:53297373a894 | 753 | #endif |
mbed_official | 579:53297373a894 | 754 | |
mbed_official | 579:53297373a894 | 755 | module->send_stop = true; |
mbed_official | 579:53297373a894 | 756 | |
mbed_official | 579:53297373a894 | 757 | return _i2c_master_write_packet(module, packet); |
mbed_official | 579:53297373a894 | 758 | } |
mbed_official | 579:53297373a894 | 759 | |
mbed_official | 579:53297373a894 | 760 | /** |
mbed_official | 579:53297373a894 | 761 | * \brief Writes data packet to slave without sending a stop condition when done |
mbed_official | 579:53297373a894 | 762 | * |
mbed_official | 579:53297373a894 | 763 | * Writes a data packet to the specified slave address on the I<SUP>2</SUP>C bus |
mbed_official | 579:53297373a894 | 764 | * without sending a stop condition, thus retaining ownership of the bus when |
mbed_official | 579:53297373a894 | 765 | * done. To end the transaction, a \ref i2c_master_read_packet_wait "read" or |
mbed_official | 579:53297373a894 | 766 | * \ref i2c_master_write_packet_wait "write" with stop condition or sending a |
mbed_official | 579:53297373a894 | 767 | * stop with the \ref i2c_master_send_stop function must be performed. |
mbed_official | 579:53297373a894 | 768 | * |
mbed_official | 579:53297373a894 | 769 | * \note This will stall the device from any other operation. For |
mbed_official | 579:53297373a894 | 770 | * interrupt-driven operation, see \ref i2c_master_read_packet_job. |
mbed_official | 579:53297373a894 | 771 | * |
mbed_official | 579:53297373a894 | 772 | * \param[in,out] module Pointer to software module struct |
mbed_official | 579:53297373a894 | 773 | * \param[in,out] packet Pointer to I<SUP>2</SUP>C packet to transfer |
mbed_official | 579:53297373a894 | 774 | * |
mbed_official | 579:53297373a894 | 775 | * \return Status of reading packet. |
mbed_official | 579:53297373a894 | 776 | * \retval STATUS_OK If packet was read |
mbed_official | 579:53297373a894 | 777 | * \retval STATUS_BUSY If master module is busy |
mbed_official | 579:53297373a894 | 778 | * \retval STATUS_ERR_DENIED If error on bus |
mbed_official | 579:53297373a894 | 779 | * \retval STATUS_ERR_PACKET_COLLISION If arbitration is lost |
mbed_official | 579:53297373a894 | 780 | * \retval STATUS_ERR_BAD_ADDRESS If slave is busy, or no slave |
mbed_official | 579:53297373a894 | 781 | * acknowledged the address |
mbed_official | 579:53297373a894 | 782 | * \retval STATUS_ERR_TIMEOUT If timeout occurred |
mbed_official | 579:53297373a894 | 783 | * \retval STATUS_ERR_OVERFLOW If slave did not acknowledge last sent |
mbed_official | 579:53297373a894 | 784 | * data, indicating that slave do not want |
mbed_official | 579:53297373a894 | 785 | * more data |
mbed_official | 579:53297373a894 | 786 | */ |
mbed_official | 579:53297373a894 | 787 | enum status_code i2c_master_write_packet_wait_no_stop( |
mbed_official | 579:53297373a894 | 788 | struct i2c_master_module *const module, |
mbed_official | 579:53297373a894 | 789 | struct i2c_master_packet *const packet) |
mbed_official | 579:53297373a894 | 790 | { |
mbed_official | 579:53297373a894 | 791 | /* Sanity check */ |
mbed_official | 579:53297373a894 | 792 | Assert(module); |
mbed_official | 579:53297373a894 | 793 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 794 | Assert(packet); |
mbed_official | 579:53297373a894 | 795 | |
mbed_official | 579:53297373a894 | 796 | #if I2C_MASTER_CALLBACK_MODE == true |
mbed_official | 579:53297373a894 | 797 | /* Check if the I2C module is busy with a job */ |
mbed_official | 579:53297373a894 | 798 | if (module->buffer_remaining > 0) { |
mbed_official | 579:53297373a894 | 799 | return STATUS_BUSY; |
mbed_official | 579:53297373a894 | 800 | } |
mbed_official | 579:53297373a894 | 801 | #endif |
mbed_official | 579:53297373a894 | 802 | |
mbed_official | 579:53297373a894 | 803 | module->send_stop = false; |
mbed_official | 579:53297373a894 | 804 | |
mbed_official | 579:53297373a894 | 805 | return _i2c_master_write_packet(module, packet); |
mbed_official | 579:53297373a894 | 806 | } |
mbed_official | 579:53297373a894 | 807 | |
mbed_official | 579:53297373a894 | 808 | /** |
mbed_official | 579:53297373a894 | 809 | * \brief Sends stop condition on bus |
mbed_official | 579:53297373a894 | 810 | * |
mbed_official | 579:53297373a894 | 811 | * Sends a stop condition on bus. |
mbed_official | 579:53297373a894 | 812 | * |
mbed_official | 579:53297373a894 | 813 | * \note This function can only be used after the |
mbed_official | 579:53297373a894 | 814 | * \ref i2c_master_write_packet_wait_no_stop function. If a stop condition |
mbed_official | 579:53297373a894 | 815 | * is to be sent after a read, the \ref i2c_master_read_packet_wait |
mbed_official | 579:53297373a894 | 816 | * function must be used. |
mbed_official | 579:53297373a894 | 817 | * |
mbed_official | 579:53297373a894 | 818 | * \param[in] module Pointer to the software instance struct |
mbed_official | 579:53297373a894 | 819 | */ |
mbed_official | 579:53297373a894 | 820 | void i2c_master_send_stop(struct i2c_master_module *const module) |
mbed_official | 579:53297373a894 | 821 | { |
mbed_official | 579:53297373a894 | 822 | /* Sanity check */ |
mbed_official | 579:53297373a894 | 823 | Assert(module); |
mbed_official | 579:53297373a894 | 824 | Assert(module->hw); |
mbed_official | 579:53297373a894 | 825 | |
mbed_official | 579:53297373a894 | 826 | SercomI2cm *const i2c_module = &(module->hw->I2CM); |
mbed_official | 579:53297373a894 | 827 | |
mbed_official | 579:53297373a894 | 828 | /* Send stop command */ |
mbed_official | 579:53297373a894 | 829 | _i2c_master_wait_for_sync(module); |
mbed_official | 579:53297373a894 | 830 | i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); |
mbed_official | 579:53297373a894 | 831 | } |