added prescaler for 16 bit pwm in LPC1347 target
Fork of mbed-dev by
targets/hal/TARGET_Atmel/TARGET_SAM_CortexM0P/i2c_api.c@15:a81a8d6c1dfe, 2015-11-04 (annotated)
- Committer:
- mbed_official
- Date:
- Wed Nov 04 16:30:11 2015 +0000
- Revision:
- 15:a81a8d6c1dfe
- Child:
- 64:41a834223ea3
Synchronized with git revision 46af745ef4405614c3fa49abbd9a706a362ea514
Full URL: https://github.com/mbedmicro/mbed/commit/46af745ef4405614c3fa49abbd9a706a362ea514/
Renamed TARGET_SAM_CortexM0+ to TARGET_SAM_CortexM0P for compatiblity with online compiler
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mbed_official | 15:a81a8d6c1dfe | 1 | /* mbed Microcontroller Library |
mbed_official | 15:a81a8d6c1dfe | 2 | * Copyright (c) 2006-2015 ARM Limited |
mbed_official | 15:a81a8d6c1dfe | 3 | * |
mbed_official | 15:a81a8d6c1dfe | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
mbed_official | 15:a81a8d6c1dfe | 5 | * you may not use this file except in compliance with the License. |
mbed_official | 15:a81a8d6c1dfe | 6 | * You may obtain a copy of the License at |
mbed_official | 15:a81a8d6c1dfe | 7 | * |
mbed_official | 15:a81a8d6c1dfe | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
mbed_official | 15:a81a8d6c1dfe | 9 | * |
mbed_official | 15:a81a8d6c1dfe | 10 | * Unless required by applicable law or agreed to in writing, software |
mbed_official | 15:a81a8d6c1dfe | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
mbed_official | 15:a81a8d6c1dfe | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
mbed_official | 15:a81a8d6c1dfe | 13 | * See the License for the specific language governing permissions and |
mbed_official | 15:a81a8d6c1dfe | 14 | * limitations under the License. |
mbed_official | 15:a81a8d6c1dfe | 15 | */ |
mbed_official | 15:a81a8d6c1dfe | 16 | #include "mbed_assert.h" |
mbed_official | 15:a81a8d6c1dfe | 17 | #include "i2c_api.h" |
mbed_official | 15:a81a8d6c1dfe | 18 | |
mbed_official | 15:a81a8d6c1dfe | 19 | #include <math.h> |
mbed_official | 15:a81a8d6c1dfe | 20 | |
mbed_official | 15:a81a8d6c1dfe | 21 | #include "cmsis.h" |
mbed_official | 15:a81a8d6c1dfe | 22 | #include "pinmap.h" |
mbed_official | 15:a81a8d6c1dfe | 23 | #include "sercom.h" |
mbed_official | 15:a81a8d6c1dfe | 24 | #include "i2c_master.h" |
mbed_official | 15:a81a8d6c1dfe | 25 | #include "i2c_slave.h" |
mbed_official | 15:a81a8d6c1dfe | 26 | |
mbed_official | 15:a81a8d6c1dfe | 27 | #include "pinmap_function.h" |
mbed_official | 15:a81a8d6c1dfe | 28 | |
mbed_official | 15:a81a8d6c1dfe | 29 | #if DEVICE_I2C_ASYNCH |
mbed_official | 15:a81a8d6c1dfe | 30 | #include "i2c_master_interrupt.h" |
mbed_official | 15:a81a8d6c1dfe | 31 | #endif |
mbed_official | 15:a81a8d6c1dfe | 32 | |
mbed_official | 15:a81a8d6c1dfe | 33 | |
mbed_official | 15:a81a8d6c1dfe | 34 | #if DEVICE_I2C_ASYNCH |
mbed_official | 15:a81a8d6c1dfe | 35 | #define pI2C_S(obj) (&obj->i2c) |
mbed_official | 15:a81a8d6c1dfe | 36 | #else |
mbed_official | 15:a81a8d6c1dfe | 37 | #define pI2C_S(obj) obj |
mbed_official | 15:a81a8d6c1dfe | 38 | #endif |
mbed_official | 15:a81a8d6c1dfe | 39 | |
mbed_official | 15:a81a8d6c1dfe | 40 | #define I2C_MASTER_DEFAULT_BAUD 100000 |
mbed_official | 15:a81a8d6c1dfe | 41 | |
mbed_official | 15:a81a8d6c1dfe | 42 | /** |
mbed_official | 15:a81a8d6c1dfe | 43 | * \brief I2C modes enum |
mbed_official | 15:a81a8d6c1dfe | 44 | * |
mbed_official | 15:a81a8d6c1dfe | 45 | * I2C mode selection. |
mbed_official | 15:a81a8d6c1dfe | 46 | */ |
mbed_official | 15:a81a8d6c1dfe | 47 | enum i2c_mode { |
mbed_official | 15:a81a8d6c1dfe | 48 | /** Master mode. */ |
mbed_official | 15:a81a8d6c1dfe | 49 | I2C_MODE_MASTER = 0x5, |
mbed_official | 15:a81a8d6c1dfe | 50 | /** Slave mode. */ |
mbed_official | 15:a81a8d6c1dfe | 51 | I2C_MODE_SLAVE = 0x4, |
mbed_official | 15:a81a8d6c1dfe | 52 | }; |
mbed_official | 15:a81a8d6c1dfe | 53 | |
mbed_official | 15:a81a8d6c1dfe | 54 | /* Extern Variables */ |
mbed_official | 15:a81a8d6c1dfe | 55 | extern uint8_t g_sys_init; |
mbed_official | 15:a81a8d6c1dfe | 56 | |
mbed_official | 15:a81a8d6c1dfe | 57 | typedef void (*I2CHandler)(void); |
mbed_official | 15:a81a8d6c1dfe | 58 | |
mbed_official | 15:a81a8d6c1dfe | 59 | #if DEVICE_I2C_ASYNCH |
mbed_official | 15:a81a8d6c1dfe | 60 | #define _SERCOM_INTERRUPT_HANDLERS(n, unused) (uint32_t)SERCOM##n##_Handler, |
mbed_official | 15:a81a8d6c1dfe | 61 | |
mbed_official | 15:a81a8d6c1dfe | 62 | /* To save the i2c objects */ |
mbed_official | 15:a81a8d6c1dfe | 63 | static uint32_t i2c_instances[SERCOM_INST_NUM] = {0}; |
mbed_official | 15:a81a8d6c1dfe | 64 | const uint32_t sercom_irq_handlers[SERCOM_INST_NUM] = { |
mbed_official | 15:a81a8d6c1dfe | 65 | MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_HANDLERS, ~) |
mbed_official | 15:a81a8d6c1dfe | 66 | }; |
mbed_official | 15:a81a8d6c1dfe | 67 | #endif |
mbed_official | 15:a81a8d6c1dfe | 68 | |
mbed_official | 15:a81a8d6c1dfe | 69 | /* Forward declaration */ |
mbed_official | 15:a81a8d6c1dfe | 70 | enum status_code _i2c_master_wait_for_bus( |
mbed_official | 15:a81a8d6c1dfe | 71 | struct i2c_master_module *const module); |
mbed_official | 15:a81a8d6c1dfe | 72 | |
mbed_official | 15:a81a8d6c1dfe | 73 | enum status_code _i2c_master_address_response( |
mbed_official | 15:a81a8d6c1dfe | 74 | struct i2c_master_module *const module); |
mbed_official | 15:a81a8d6c1dfe | 75 | |
mbed_official | 15:a81a8d6c1dfe | 76 | enum status_code _i2c_master_send_hs_master_code( |
mbed_official | 15:a81a8d6c1dfe | 77 | struct i2c_master_module *const module, |
mbed_official | 15:a81a8d6c1dfe | 78 | uint8_t hs_master_code); |
mbed_official | 15:a81a8d6c1dfe | 79 | |
mbed_official | 15:a81a8d6c1dfe | 80 | /* Adding function from ASF for compatibility */ |
mbed_official | 15:a81a8d6c1dfe | 81 | static enum status_code _i2c_slave_wait_for_bus( |
mbed_official | 15:a81a8d6c1dfe | 82 | struct i2c_slave_module *const module) |
mbed_official | 15:a81a8d6c1dfe | 83 | { |
mbed_official | 15:a81a8d6c1dfe | 84 | /* Sanity check arguments. */ |
mbed_official | 15:a81a8d6c1dfe | 85 | MBED_ASSERT(module); |
mbed_official | 15:a81a8d6c1dfe | 86 | MBED_ASSERT(module->hw); |
mbed_official | 15:a81a8d6c1dfe | 87 | |
mbed_official | 15:a81a8d6c1dfe | 88 | SercomI2cs *const i2c_hw = &(module->hw->I2CS); |
mbed_official | 15:a81a8d6c1dfe | 89 | |
mbed_official | 15:a81a8d6c1dfe | 90 | /* Wait for reply. */ |
mbed_official | 15:a81a8d6c1dfe | 91 | uint16_t timeout_counter = 0; |
mbed_official | 15:a81a8d6c1dfe | 92 | while ((!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_DRDY)) && |
mbed_official | 15:a81a8d6c1dfe | 93 | (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC)) && |
mbed_official | 15:a81a8d6c1dfe | 94 | (!(i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH))) { |
mbed_official | 15:a81a8d6c1dfe | 95 | |
mbed_official | 15:a81a8d6c1dfe | 96 | /* Check timeout condition. */ |
mbed_official | 15:a81a8d6c1dfe | 97 | if (++timeout_counter >= module->buffer_timeout) { |
mbed_official | 15:a81a8d6c1dfe | 98 | return STATUS_ERR_TIMEOUT; |
mbed_official | 15:a81a8d6c1dfe | 99 | } |
mbed_official | 15:a81a8d6c1dfe | 100 | } |
mbed_official | 15:a81a8d6c1dfe | 101 | return STATUS_OK; |
mbed_official | 15:a81a8d6c1dfe | 102 | } |
mbed_official | 15:a81a8d6c1dfe | 103 | |
mbed_official | 15:a81a8d6c1dfe | 104 | /** Initialize the I2C peripheral |
mbed_official | 15:a81a8d6c1dfe | 105 | * |
mbed_official | 15:a81a8d6c1dfe | 106 | * Configures the pins used by I2C, sets a default format and frequency, and enables the peripheral |
mbed_official | 15:a81a8d6c1dfe | 107 | * @param[out] obj The I2C object to initialize |
mbed_official | 15:a81a8d6c1dfe | 108 | * @param[in] sda The pin to use for SDA |
mbed_official | 15:a81a8d6c1dfe | 109 | * @param[in] scl The pin to use for SCL |
mbed_official | 15:a81a8d6c1dfe | 110 | * @return void |
mbed_official | 15:a81a8d6c1dfe | 111 | */ |
mbed_official | 15:a81a8d6c1dfe | 112 | void i2c_init(i2c_t *obj, PinName sda, PinName scl) |
mbed_official | 15:a81a8d6c1dfe | 113 | { |
mbed_official | 15:a81a8d6c1dfe | 114 | Sercom* hw; |
mbed_official | 15:a81a8d6c1dfe | 115 | uint32_t mux_func; |
mbed_official | 15:a81a8d6c1dfe | 116 | struct i2c_master_config config_i2c_master; |
mbed_official | 15:a81a8d6c1dfe | 117 | |
mbed_official | 15:a81a8d6c1dfe | 118 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 119 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 120 | MBED_ASSERT(sda != NC); |
mbed_official | 15:a81a8d6c1dfe | 121 | MBED_ASSERT(scl != NC); |
mbed_official | 15:a81a8d6c1dfe | 122 | |
mbed_official | 15:a81a8d6c1dfe | 123 | if (g_sys_init == 0) { |
mbed_official | 15:a81a8d6c1dfe | 124 | system_init(); |
mbed_official | 15:a81a8d6c1dfe | 125 | g_sys_init = 1; |
mbed_official | 15:a81a8d6c1dfe | 126 | } |
mbed_official | 15:a81a8d6c1dfe | 127 | |
mbed_official | 15:a81a8d6c1dfe | 128 | pI2C_S(obj)->pins[0] = sda; |
mbed_official | 15:a81a8d6c1dfe | 129 | pI2C_S(obj)->pins[1] = scl; |
mbed_official | 15:a81a8d6c1dfe | 130 | |
mbed_official | 15:a81a8d6c1dfe | 131 | /* Calculate SERCOM instance from pins */ |
mbed_official | 15:a81a8d6c1dfe | 132 | uint32_t sercom_index = pinmap_merge_sercom(sda, scl); |
mbed_official | 15:a81a8d6c1dfe | 133 | if (sercom_index == (uint32_t)NC) { |
mbed_official | 15:a81a8d6c1dfe | 134 | return; |
mbed_official | 15:a81a8d6c1dfe | 135 | } |
mbed_official | 15:a81a8d6c1dfe | 136 | hw = (Sercom*)pinmap_peripheral_sercom(NC, sercom_index); |
mbed_official | 15:a81a8d6c1dfe | 137 | |
mbed_official | 15:a81a8d6c1dfe | 138 | i2c_master_get_config_defaults(&config_i2c_master); |
mbed_official | 15:a81a8d6c1dfe | 139 | |
mbed_official | 15:a81a8d6c1dfe | 140 | /* SERCOM PAD0 - SDA */ |
mbed_official | 15:a81a8d6c1dfe | 141 | mux_func = pinmap_function_sercom(sda, sercom_index); |
mbed_official | 15:a81a8d6c1dfe | 142 | if (mux_func == (uint32_t)NC) return; |
mbed_official | 15:a81a8d6c1dfe | 143 | config_i2c_master.pinmux_pad0 = (sda << 16) | (mux_func & 0xFFFF); |
mbed_official | 15:a81a8d6c1dfe | 144 | |
mbed_official | 15:a81a8d6c1dfe | 145 | /* SERCOM PAD1 - SCL */ |
mbed_official | 15:a81a8d6c1dfe | 146 | mux_func = pinmap_function_sercom(scl, sercom_index); |
mbed_official | 15:a81a8d6c1dfe | 147 | if (mux_func == (uint32_t)NC) return; |
mbed_official | 15:a81a8d6c1dfe | 148 | config_i2c_master.pinmux_pad1 = (scl << 16) | (mux_func & 0xFFFF); |
mbed_official | 15:a81a8d6c1dfe | 149 | |
mbed_official | 15:a81a8d6c1dfe | 150 | /* Default baud rate is set to 100kHz */ |
mbed_official | 15:a81a8d6c1dfe | 151 | pI2C_S(obj)->baud_rate = I2C_MASTER_DEFAULT_BAUD; |
mbed_official | 15:a81a8d6c1dfe | 152 | config_i2c_master.baud_rate = pI2C_S(obj)->baud_rate / 1000; |
mbed_official | 15:a81a8d6c1dfe | 153 | |
mbed_official | 15:a81a8d6c1dfe | 154 | while(i2c_master_init(&pI2C_S(obj)->master, hw, &config_i2c_master) != STATUS_OK); |
mbed_official | 15:a81a8d6c1dfe | 155 | pI2C_S(obj)->mode = I2C_MODE_MASTER; |
mbed_official | 15:a81a8d6c1dfe | 156 | |
mbed_official | 15:a81a8d6c1dfe | 157 | #if DEVICE_I2C_ASYNCH |
mbed_official | 15:a81a8d6c1dfe | 158 | /* Save the i2c object */ |
mbed_official | 15:a81a8d6c1dfe | 159 | i2c_instances[sercom_index] = (uint32_t)obj; |
mbed_official | 15:a81a8d6c1dfe | 160 | #endif |
mbed_official | 15:a81a8d6c1dfe | 161 | |
mbed_official | 15:a81a8d6c1dfe | 162 | i2c_master_enable(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 163 | } |
mbed_official | 15:a81a8d6c1dfe | 164 | |
mbed_official | 15:a81a8d6c1dfe | 165 | /** Configure the I2C frequency. |
mbed_official | 15:a81a8d6c1dfe | 166 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 167 | * @param hz Frequency in Hz |
mbed_official | 15:a81a8d6c1dfe | 168 | */ |
mbed_official | 15:a81a8d6c1dfe | 169 | void i2c_frequency(i2c_t *obj, int hz) |
mbed_official | 15:a81a8d6c1dfe | 170 | { |
mbed_official | 15:a81a8d6c1dfe | 171 | /* Temporary variables. */ |
mbed_official | 15:a81a8d6c1dfe | 172 | int32_t baud_rate; |
mbed_official | 15:a81a8d6c1dfe | 173 | int32_t tmp_baud; |
mbed_official | 15:a81a8d6c1dfe | 174 | int32_t tmp_baud_hs; |
mbed_official | 15:a81a8d6c1dfe | 175 | enum status_code tmp_status_code; |
mbed_official | 15:a81a8d6c1dfe | 176 | |
mbed_official | 15:a81a8d6c1dfe | 177 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 178 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 179 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 180 | |
mbed_official | 15:a81a8d6c1dfe | 181 | /* Return if in Slave mode, slave do not have any baud to set */ |
mbed_official | 15:a81a8d6c1dfe | 182 | if (pI2C_S(obj)->mode != I2C_MODE_MASTER) return; |
mbed_official | 15:a81a8d6c1dfe | 183 | |
mbed_official | 15:a81a8d6c1dfe | 184 | SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM); |
mbed_official | 15:a81a8d6c1dfe | 185 | |
mbed_official | 15:a81a8d6c1dfe | 186 | /* Disable I2C Module */ |
mbed_official | 15:a81a8d6c1dfe | 187 | i2c_master_disable(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 188 | |
mbed_official | 15:a81a8d6c1dfe | 189 | baud_rate = hz / 1000; /* To kHz */ |
mbed_official | 15:a81a8d6c1dfe | 190 | |
mbed_official | 15:a81a8d6c1dfe | 191 | /* Give a dummy supported value */ |
mbed_official | 15:a81a8d6c1dfe | 192 | pI2C_S(obj)->baud_rate_high_speed = I2C_MASTER_BAUD_RATE_3400KHZ; |
mbed_official | 15:a81a8d6c1dfe | 193 | |
mbed_official | 15:a81a8d6c1dfe | 194 | uint32_t sercom_index = _sercom_get_sercom_inst_index(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 195 | |
mbed_official | 15:a81a8d6c1dfe | 196 | /* Find and set baudrate. */ |
mbed_official | 15:a81a8d6c1dfe | 197 | tmp_baud = (int32_t)(div_ceil( |
mbed_official | 15:a81a8d6c1dfe | 198 | system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index), (2000*(baud_rate))) - 5); |
mbed_official | 15:a81a8d6c1dfe | 199 | |
mbed_official | 15:a81a8d6c1dfe | 200 | /* Check that baudrate is supported at current speed. */ |
mbed_official | 15:a81a8d6c1dfe | 201 | if (tmp_baud > 255 || tmp_baud < 0) { |
mbed_official | 15:a81a8d6c1dfe | 202 | /* Baud rate not supported. */ |
mbed_official | 15:a81a8d6c1dfe | 203 | tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE; |
mbed_official | 15:a81a8d6c1dfe | 204 | } else { |
mbed_official | 15:a81a8d6c1dfe | 205 | /* Find baudrate for high speed */ |
mbed_official | 15:a81a8d6c1dfe | 206 | tmp_baud_hs = (int32_t)(div_ceil( |
mbed_official | 15:a81a8d6c1dfe | 207 | system_gclk_chan_get_hz(SERCOM0_GCLK_ID_CORE + sercom_index), |
mbed_official | 15:a81a8d6c1dfe | 208 | (2000*(pI2C_S(obj)->baud_rate_high_speed))) - 1); |
mbed_official | 15:a81a8d6c1dfe | 209 | |
mbed_official | 15:a81a8d6c1dfe | 210 | /* Check that baudrate is supported at current speed. */ |
mbed_official | 15:a81a8d6c1dfe | 211 | if (tmp_baud_hs > 255 || tmp_baud_hs < 0) { |
mbed_official | 15:a81a8d6c1dfe | 212 | /* Baud rate not supported. */ |
mbed_official | 15:a81a8d6c1dfe | 213 | tmp_status_code = STATUS_ERR_BAUDRATE_UNAVAILABLE; |
mbed_official | 15:a81a8d6c1dfe | 214 | } |
mbed_official | 15:a81a8d6c1dfe | 215 | } |
mbed_official | 15:a81a8d6c1dfe | 216 | if (tmp_status_code != STATUS_ERR_BAUDRATE_UNAVAILABLE) { |
mbed_official | 15:a81a8d6c1dfe | 217 | /* Baud rate acceptable. */ |
mbed_official | 15:a81a8d6c1dfe | 218 | i2c_module->BAUD.reg = SERCOM_I2CM_BAUD_BAUD(tmp_baud) | SERCOM_I2CM_BAUD_HSBAUD(tmp_baud_hs); |
mbed_official | 15:a81a8d6c1dfe | 219 | pI2C_S(obj)->baud_rate = hz; |
mbed_official | 15:a81a8d6c1dfe | 220 | } |
mbed_official | 15:a81a8d6c1dfe | 221 | |
mbed_official | 15:a81a8d6c1dfe | 222 | /* Enable back the I2C Module */ |
mbed_official | 15:a81a8d6c1dfe | 223 | i2c_master_enable(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 224 | } |
mbed_official | 15:a81a8d6c1dfe | 225 | |
mbed_official | 15:a81a8d6c1dfe | 226 | /** Send START command. |
mbed_official | 15:a81a8d6c1dfe | 227 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 228 | */ |
mbed_official | 15:a81a8d6c1dfe | 229 | int i2c_start(i2c_t *obj) |
mbed_official | 15:a81a8d6c1dfe | 230 | { |
mbed_official | 15:a81a8d6c1dfe | 231 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 232 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 233 | |
mbed_official | 15:a81a8d6c1dfe | 234 | if (pI2C_S(obj)->mode == I2C_MODE_MASTER) { |
mbed_official | 15:a81a8d6c1dfe | 235 | pI2C_S(obj)->start_pending = 1; |
mbed_official | 15:a81a8d6c1dfe | 236 | } |
mbed_official | 15:a81a8d6c1dfe | 237 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 238 | } |
mbed_official | 15:a81a8d6c1dfe | 239 | |
mbed_official | 15:a81a8d6c1dfe | 240 | /** Send STOP command. |
mbed_official | 15:a81a8d6c1dfe | 241 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 242 | */ |
mbed_official | 15:a81a8d6c1dfe | 243 | int i2c_stop(i2c_t *obj) |
mbed_official | 15:a81a8d6c1dfe | 244 | { |
mbed_official | 15:a81a8d6c1dfe | 245 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 246 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 247 | |
mbed_official | 15:a81a8d6c1dfe | 248 | if (pI2C_S(obj)->mode == I2C_MODE_MASTER) { |
mbed_official | 15:a81a8d6c1dfe | 249 | /* Send STOP command */ |
mbed_official | 15:a81a8d6c1dfe | 250 | i2c_master_send_stop(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 251 | } else { |
mbed_official | 15:a81a8d6c1dfe | 252 | SercomI2cs *const i2c_hw = &(pI2C_S(obj)->slave.hw->I2CS); |
mbed_official | 15:a81a8d6c1dfe | 253 | /* Release line and wait for next start condition */ |
mbed_official | 15:a81a8d6c1dfe | 254 | i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x2); |
mbed_official | 15:a81a8d6c1dfe | 255 | } |
mbed_official | 15:a81a8d6c1dfe | 256 | |
mbed_official | 15:a81a8d6c1dfe | 257 | pI2C_S(obj)->start_pending = 0; |
mbed_official | 15:a81a8d6c1dfe | 258 | |
mbed_official | 15:a81a8d6c1dfe | 259 | /* TODO: Wait till STOP is send */ |
mbed_official | 15:a81a8d6c1dfe | 260 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 261 | } |
mbed_official | 15:a81a8d6c1dfe | 262 | |
mbed_official | 15:a81a8d6c1dfe | 263 | /** Blocking reading data. |
mbed_official | 15:a81a8d6c1dfe | 264 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 265 | * @param address 7-bit address (last bit is 1) |
mbed_official | 15:a81a8d6c1dfe | 266 | * @param data The buffer for receiving |
mbed_official | 15:a81a8d6c1dfe | 267 | * @param length Number of bytes to read |
mbed_official | 15:a81a8d6c1dfe | 268 | * @param stop Stop to be generated after the transfer is done |
mbed_official | 15:a81a8d6c1dfe | 269 | * @return Number of read bytes |
mbed_official | 15:a81a8d6c1dfe | 270 | */ |
mbed_official | 15:a81a8d6c1dfe | 271 | int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) |
mbed_official | 15:a81a8d6c1dfe | 272 | { |
mbed_official | 15:a81a8d6c1dfe | 273 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 274 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 275 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 276 | |
mbed_official | 15:a81a8d6c1dfe | 277 | enum status_code tmp_status; |
mbed_official | 15:a81a8d6c1dfe | 278 | |
mbed_official | 15:a81a8d6c1dfe | 279 | #if DEVICE_I2C_ASYNCH |
mbed_official | 15:a81a8d6c1dfe | 280 | if (i2c_active(obj)) { |
mbed_official | 15:a81a8d6c1dfe | 281 | /* I2C is busy with a job */ |
mbed_official | 15:a81a8d6c1dfe | 282 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 283 | } |
mbed_official | 15:a81a8d6c1dfe | 284 | #endif |
mbed_official | 15:a81a8d6c1dfe | 285 | |
mbed_official | 15:a81a8d6c1dfe | 286 | struct i2c_master_packet packet; |
mbed_official | 15:a81a8d6c1dfe | 287 | packet.address = (address & 0xFF) >> 1; |
mbed_official | 15:a81a8d6c1dfe | 288 | packet.data_length = length; |
mbed_official | 15:a81a8d6c1dfe | 289 | packet.data = (uint8_t*)data; |
mbed_official | 15:a81a8d6c1dfe | 290 | packet.ten_bit_address = false; |
mbed_official | 15:a81a8d6c1dfe | 291 | packet.high_speed = false; |
mbed_official | 15:a81a8d6c1dfe | 292 | |
mbed_official | 15:a81a8d6c1dfe | 293 | if (stop) { |
mbed_official | 15:a81a8d6c1dfe | 294 | tmp_status = i2c_master_read_packet_wait(&pI2C_S(obj)->master, &packet); |
mbed_official | 15:a81a8d6c1dfe | 295 | } else { |
mbed_official | 15:a81a8d6c1dfe | 296 | tmp_status = i2c_master_read_packet_wait_no_stop(&pI2C_S(obj)->master, &packet); |
mbed_official | 15:a81a8d6c1dfe | 297 | } |
mbed_official | 15:a81a8d6c1dfe | 298 | |
mbed_official | 15:a81a8d6c1dfe | 299 | if (tmp_status == STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 300 | return length; |
mbed_official | 15:a81a8d6c1dfe | 301 | } else { |
mbed_official | 15:a81a8d6c1dfe | 302 | /* Currently, no way to track no of bytes received, so return 0 if fail */ |
mbed_official | 15:a81a8d6c1dfe | 303 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 304 | } |
mbed_official | 15:a81a8d6c1dfe | 305 | } |
mbed_official | 15:a81a8d6c1dfe | 306 | |
mbed_official | 15:a81a8d6c1dfe | 307 | /** Blocking sending data. |
mbed_official | 15:a81a8d6c1dfe | 308 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 309 | * @param address 7-bit address (last bit is 0) |
mbed_official | 15:a81a8d6c1dfe | 310 | * @param data The buffer for sending |
mbed_official | 15:a81a8d6c1dfe | 311 | * @param length Number of bytes to write |
mbed_official | 15:a81a8d6c1dfe | 312 | * @param stop Stop to be generated after the transfer is done |
mbed_official | 15:a81a8d6c1dfe | 313 | * @return Number of written bytes |
mbed_official | 15:a81a8d6c1dfe | 314 | */ |
mbed_official | 15:a81a8d6c1dfe | 315 | int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) |
mbed_official | 15:a81a8d6c1dfe | 316 | { |
mbed_official | 15:a81a8d6c1dfe | 317 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 318 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 319 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 320 | |
mbed_official | 15:a81a8d6c1dfe | 321 | enum status_code tmp_status; |
mbed_official | 15:a81a8d6c1dfe | 322 | |
mbed_official | 15:a81a8d6c1dfe | 323 | #if DEVICE_I2C_ASYNCH |
mbed_official | 15:a81a8d6c1dfe | 324 | if (i2c_active(obj)) { |
mbed_official | 15:a81a8d6c1dfe | 325 | /* I2C is busy with a job */ |
mbed_official | 15:a81a8d6c1dfe | 326 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 327 | } |
mbed_official | 15:a81a8d6c1dfe | 328 | #endif |
mbed_official | 15:a81a8d6c1dfe | 329 | |
mbed_official | 15:a81a8d6c1dfe | 330 | struct i2c_master_packet packet; |
mbed_official | 15:a81a8d6c1dfe | 331 | packet.address = (address & 0xFF) >> 1; |
mbed_official | 15:a81a8d6c1dfe | 332 | packet.data_length = length; |
mbed_official | 15:a81a8d6c1dfe | 333 | packet.data = data; |
mbed_official | 15:a81a8d6c1dfe | 334 | packet.ten_bit_address = false; |
mbed_official | 15:a81a8d6c1dfe | 335 | packet.high_speed = false; |
mbed_official | 15:a81a8d6c1dfe | 336 | |
mbed_official | 15:a81a8d6c1dfe | 337 | if (stop) { |
mbed_official | 15:a81a8d6c1dfe | 338 | tmp_status = i2c_master_write_packet_wait(&pI2C_S(obj)->master, &packet); |
mbed_official | 15:a81a8d6c1dfe | 339 | } else { |
mbed_official | 15:a81a8d6c1dfe | 340 | tmp_status = i2c_master_write_packet_wait_no_stop(&pI2C_S(obj)->master, &packet); |
mbed_official | 15:a81a8d6c1dfe | 341 | } |
mbed_official | 15:a81a8d6c1dfe | 342 | |
mbed_official | 15:a81a8d6c1dfe | 343 | if (tmp_status == STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 344 | return length; |
mbed_official | 15:a81a8d6c1dfe | 345 | } else { |
mbed_official | 15:a81a8d6c1dfe | 346 | /* Currently, no way to track no of bytes transmitted, so return 0 if fail */ |
mbed_official | 15:a81a8d6c1dfe | 347 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 348 | } |
mbed_official | 15:a81a8d6c1dfe | 349 | } |
mbed_official | 15:a81a8d6c1dfe | 350 | |
mbed_official | 15:a81a8d6c1dfe | 351 | /** Reset I2C peripheral. |
mbed_official | 15:a81a8d6c1dfe | 352 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 353 | */ |
mbed_official | 15:a81a8d6c1dfe | 354 | void i2c_reset(i2c_t *obj) |
mbed_official | 15:a81a8d6c1dfe | 355 | { |
mbed_official | 15:a81a8d6c1dfe | 356 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 357 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 358 | |
mbed_official | 15:a81a8d6c1dfe | 359 | /* Send STOP */ |
mbed_official | 15:a81a8d6c1dfe | 360 | i2c_stop(obj); |
mbed_official | 15:a81a8d6c1dfe | 361 | |
mbed_official | 15:a81a8d6c1dfe | 362 | pI2C_S(obj)->start_pending = 0; |
mbed_official | 15:a81a8d6c1dfe | 363 | } |
mbed_official | 15:a81a8d6c1dfe | 364 | |
mbed_official | 15:a81a8d6c1dfe | 365 | /** Write address preceded by START condition. |
mbed_official | 15:a81a8d6c1dfe | 366 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 367 | * @param address Address to be placed |
mbed_official | 15:a81a8d6c1dfe | 368 | * @param rw_flag read or write flag |
mbed_official | 15:a81a8d6c1dfe | 369 | * @return 1 if NAK was received, 0 if ACK was received, 2 for timeout. |
mbed_official | 15:a81a8d6c1dfe | 370 | */ |
mbed_official | 15:a81a8d6c1dfe | 371 | int i2c_write_address(i2c_t *obj, int address, int rw_flag) |
mbed_official | 15:a81a8d6c1dfe | 372 | { |
mbed_official | 15:a81a8d6c1dfe | 373 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 374 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 375 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 376 | |
mbed_official | 15:a81a8d6c1dfe | 377 | enum status_code tmp_status; |
mbed_official | 15:a81a8d6c1dfe | 378 | SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM); |
mbed_official | 15:a81a8d6c1dfe | 379 | |
mbed_official | 15:a81a8d6c1dfe | 380 | _i2c_master_wait_for_sync(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 381 | |
mbed_official | 15:a81a8d6c1dfe | 382 | /* Set action to ACK. */ |
mbed_official | 15:a81a8d6c1dfe | 383 | i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 15:a81a8d6c1dfe | 384 | |
mbed_official | 15:a81a8d6c1dfe | 385 | /* Write 7-bit address + read/write flag */ |
mbed_official | 15:a81a8d6c1dfe | 386 | i2c_module->ADDR.reg = ((address & 0x7F) << 1) | (rw_flag & 0x01) | (0 << SERCOM_I2CM_ADDR_HS_Pos); |
mbed_official | 15:a81a8d6c1dfe | 387 | |
mbed_official | 15:a81a8d6c1dfe | 388 | /* Wait for response on bus. */ |
mbed_official | 15:a81a8d6c1dfe | 389 | tmp_status = _i2c_master_wait_for_bus(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 390 | /* Check for error. */ |
mbed_official | 15:a81a8d6c1dfe | 391 | if (tmp_status != STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 392 | return I2C_ERROR_BUS_BUSY; |
mbed_official | 15:a81a8d6c1dfe | 393 | } |
mbed_official | 15:a81a8d6c1dfe | 394 | /* Check for address response error unless previous error is detected. */ |
mbed_official | 15:a81a8d6c1dfe | 395 | tmp_status = _i2c_master_address_response(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 396 | if (tmp_status != STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 397 | return I2C_ERROR_NO_SLAVE; |
mbed_official | 15:a81a8d6c1dfe | 398 | } |
mbed_official | 15:a81a8d6c1dfe | 399 | |
mbed_official | 15:a81a8d6c1dfe | 400 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 401 | } |
mbed_official | 15:a81a8d6c1dfe | 402 | |
mbed_official | 15:a81a8d6c1dfe | 403 | /** Read one byte. |
mbed_official | 15:a81a8d6c1dfe | 404 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 405 | * @param last Acknowledge |
mbed_official | 15:a81a8d6c1dfe | 406 | * @return The read byte |
mbed_official | 15:a81a8d6c1dfe | 407 | */ |
mbed_official | 15:a81a8d6c1dfe | 408 | int i2c_byte_read(i2c_t *obj, int last) |
mbed_official | 15:a81a8d6c1dfe | 409 | { |
mbed_official | 15:a81a8d6c1dfe | 410 | int data = -1; |
mbed_official | 15:a81a8d6c1dfe | 411 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 412 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 413 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 414 | |
mbed_official | 15:a81a8d6c1dfe | 415 | enum status_code tmp_status; |
mbed_official | 15:a81a8d6c1dfe | 416 | |
mbed_official | 15:a81a8d6c1dfe | 417 | if (pI2C_S(obj)->mode == I2C_MODE_MASTER) { |
mbed_official | 15:a81a8d6c1dfe | 418 | SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM); |
mbed_official | 15:a81a8d6c1dfe | 419 | |
mbed_official | 15:a81a8d6c1dfe | 420 | if (last) { |
mbed_official | 15:a81a8d6c1dfe | 421 | /* Set action to nack. */ |
mbed_official | 15:a81a8d6c1dfe | 422 | i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 15:a81a8d6c1dfe | 423 | } else { |
mbed_official | 15:a81a8d6c1dfe | 424 | /* Set action to ack. */ |
mbed_official | 15:a81a8d6c1dfe | 425 | i2c_module->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 15:a81a8d6c1dfe | 426 | } |
mbed_official | 15:a81a8d6c1dfe | 427 | |
mbed_official | 15:a81a8d6c1dfe | 428 | /* Check that bus ownership is not lost. */ |
mbed_official | 15:a81a8d6c1dfe | 429 | if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) { |
mbed_official | 15:a81a8d6c1dfe | 430 | return -1; /* Return invalid data*/ |
mbed_official | 15:a81a8d6c1dfe | 431 | } |
mbed_official | 15:a81a8d6c1dfe | 432 | |
mbed_official | 15:a81a8d6c1dfe | 433 | /* Save data to buffer. */ |
mbed_official | 15:a81a8d6c1dfe | 434 | _i2c_master_wait_for_sync(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 435 | data = i2c_module->DATA.reg; |
mbed_official | 15:a81a8d6c1dfe | 436 | /* Wait for response. */ |
mbed_official | 15:a81a8d6c1dfe | 437 | tmp_status = _i2c_master_wait_for_bus(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 438 | |
mbed_official | 15:a81a8d6c1dfe | 439 | /* Check for error. */ |
mbed_official | 15:a81a8d6c1dfe | 440 | if (tmp_status != STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 441 | return -1; /* Return invalid data*/ |
mbed_official | 15:a81a8d6c1dfe | 442 | } |
mbed_official | 15:a81a8d6c1dfe | 443 | |
mbed_official | 15:a81a8d6c1dfe | 444 | } else { |
mbed_official | 15:a81a8d6c1dfe | 445 | #if DEVICE_I2CSLAVE |
mbed_official | 15:a81a8d6c1dfe | 446 | SercomI2cs *const i2c_hw = &(pI2C_S(obj)->slave.hw->I2CS); |
mbed_official | 15:a81a8d6c1dfe | 447 | |
mbed_official | 15:a81a8d6c1dfe | 448 | /* Check direction */ |
mbed_official | 15:a81a8d6c1dfe | 449 | if (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_DIR) { |
mbed_official | 15:a81a8d6c1dfe | 450 | /* Write request from master, send NACK and return */ |
mbed_official | 15:a81a8d6c1dfe | 451 | i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_ACKACT; |
mbed_official | 15:a81a8d6c1dfe | 452 | i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3); |
mbed_official | 15:a81a8d6c1dfe | 453 | return -1; /* Return invalid data*/ |
mbed_official | 15:a81a8d6c1dfe | 454 | } |
mbed_official | 15:a81a8d6c1dfe | 455 | |
mbed_official | 15:a81a8d6c1dfe | 456 | if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) { |
mbed_official | 15:a81a8d6c1dfe | 457 | /* Request from master, Address not yet acknowledged */ |
mbed_official | 15:a81a8d6c1dfe | 458 | i2c_hw->CTRLB.reg &= ~SERCOM_I2CS_CTRLB_ACKACT; |
mbed_official | 15:a81a8d6c1dfe | 459 | i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3); |
mbed_official | 15:a81a8d6c1dfe | 460 | i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_AMATCH; |
mbed_official | 15:a81a8d6c1dfe | 461 | } |
mbed_official | 15:a81a8d6c1dfe | 462 | if (last) { |
mbed_official | 15:a81a8d6c1dfe | 463 | /* Set action to nack. */ |
mbed_official | 15:a81a8d6c1dfe | 464 | i2c_hw->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 15:a81a8d6c1dfe | 465 | } else { |
mbed_official | 15:a81a8d6c1dfe | 466 | /* Set action to ack. */ |
mbed_official | 15:a81a8d6c1dfe | 467 | i2c_hw->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; |
mbed_official | 15:a81a8d6c1dfe | 468 | } |
mbed_official | 15:a81a8d6c1dfe | 469 | |
mbed_official | 15:a81a8d6c1dfe | 470 | /* Wait for next byte or stop condition */ |
mbed_official | 15:a81a8d6c1dfe | 471 | tmp_status = _i2c_slave_wait_for_bus(&pI2C_S(obj)->slave); |
mbed_official | 15:a81a8d6c1dfe | 472 | if (tmp_status != STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 473 | /* Timeout, return */ |
mbed_official | 15:a81a8d6c1dfe | 474 | return -1; |
mbed_official | 15:a81a8d6c1dfe | 475 | } |
mbed_official | 15:a81a8d6c1dfe | 476 | |
mbed_official | 15:a81a8d6c1dfe | 477 | if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_PREC) { |
mbed_official | 15:a81a8d6c1dfe | 478 | /* Master sent stop condition, or repeated start, read done */ |
mbed_official | 15:a81a8d6c1dfe | 479 | /* Clear stop flag */ |
mbed_official | 15:a81a8d6c1dfe | 480 | i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_PREC; |
mbed_official | 15:a81a8d6c1dfe | 481 | return -1; |
mbed_official | 15:a81a8d6c1dfe | 482 | } |
mbed_official | 15:a81a8d6c1dfe | 483 | |
mbed_official | 15:a81a8d6c1dfe | 484 | /* Read data */ |
mbed_official | 15:a81a8d6c1dfe | 485 | _i2c_slave_wait_for_sync(&pI2C_S(obj)->slave); |
mbed_official | 15:a81a8d6c1dfe | 486 | data = i2c_hw->DATA.reg; |
mbed_official | 15:a81a8d6c1dfe | 487 | #endif |
mbed_official | 15:a81a8d6c1dfe | 488 | } |
mbed_official | 15:a81a8d6c1dfe | 489 | |
mbed_official | 15:a81a8d6c1dfe | 490 | return data; |
mbed_official | 15:a81a8d6c1dfe | 491 | } |
mbed_official | 15:a81a8d6c1dfe | 492 | |
mbed_official | 15:a81a8d6c1dfe | 493 | /** Write one byte. |
mbed_official | 15:a81a8d6c1dfe | 494 | * @param obj The i2c object |
mbed_official | 15:a81a8d6c1dfe | 495 | * @param data Byte to be written |
mbed_official | 15:a81a8d6c1dfe | 496 | * @return 1 if NAK was received, 0 if ACK was received, 2 for timeout. |
mbed_official | 15:a81a8d6c1dfe | 497 | */ |
mbed_official | 15:a81a8d6c1dfe | 498 | int i2c_byte_write(i2c_t *obj, int data) |
mbed_official | 15:a81a8d6c1dfe | 499 | { |
mbed_official | 15:a81a8d6c1dfe | 500 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 501 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 502 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 503 | |
mbed_official | 15:a81a8d6c1dfe | 504 | enum status_code tmp_status; |
mbed_official | 15:a81a8d6c1dfe | 505 | |
mbed_official | 15:a81a8d6c1dfe | 506 | data = data & 0xFF; |
mbed_official | 15:a81a8d6c1dfe | 507 | |
mbed_official | 15:a81a8d6c1dfe | 508 | if (pI2C_S(obj)->mode == I2C_MODE_MASTER) { |
mbed_official | 15:a81a8d6c1dfe | 509 | SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM); |
mbed_official | 15:a81a8d6c1dfe | 510 | |
mbed_official | 15:a81a8d6c1dfe | 511 | if (pI2C_S(obj)->start_pending) { |
mbed_official | 15:a81a8d6c1dfe | 512 | pI2C_S(obj)->start_pending = 0; |
mbed_official | 15:a81a8d6c1dfe | 513 | /* Write address */ |
mbed_official | 15:a81a8d6c1dfe | 514 | return i2c_write_address(obj, (data >> 1), (data & 0x01)); |
mbed_official | 15:a81a8d6c1dfe | 515 | } else { |
mbed_official | 15:a81a8d6c1dfe | 516 | /* Write data */ |
mbed_official | 15:a81a8d6c1dfe | 517 | /* Check that bus ownership is not lost. */ |
mbed_official | 15:a81a8d6c1dfe | 518 | if (!(i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE(2))) { |
mbed_official | 15:a81a8d6c1dfe | 519 | return I2C_ERROR_NO_SLAVE; |
mbed_official | 15:a81a8d6c1dfe | 520 | } |
mbed_official | 15:a81a8d6c1dfe | 521 | |
mbed_official | 15:a81a8d6c1dfe | 522 | /* Write byte to slave. */ |
mbed_official | 15:a81a8d6c1dfe | 523 | _i2c_master_wait_for_sync(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 524 | i2c_module->DATA.reg = data; |
mbed_official | 15:a81a8d6c1dfe | 525 | |
mbed_official | 15:a81a8d6c1dfe | 526 | /* Wait for response. */ |
mbed_official | 15:a81a8d6c1dfe | 527 | tmp_status = _i2c_master_wait_for_bus(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 528 | /* Check for error. */ |
mbed_official | 15:a81a8d6c1dfe | 529 | if (tmp_status != STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 530 | return I2C_ERROR_BUS_BUSY; |
mbed_official | 15:a81a8d6c1dfe | 531 | } |
mbed_official | 15:a81a8d6c1dfe | 532 | |
mbed_official | 15:a81a8d6c1dfe | 533 | /* Check for NACK from slave. */ |
mbed_official | 15:a81a8d6c1dfe | 534 | if (i2c_module->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { |
mbed_official | 15:a81a8d6c1dfe | 535 | /* Return bad data value. */ |
mbed_official | 15:a81a8d6c1dfe | 536 | return I2C_ERROR_NO_SLAVE; |
mbed_official | 15:a81a8d6c1dfe | 537 | } |
mbed_official | 15:a81a8d6c1dfe | 538 | } |
mbed_official | 15:a81a8d6c1dfe | 539 | } else { |
mbed_official | 15:a81a8d6c1dfe | 540 | #if DEVICE_I2CSLAVE |
mbed_official | 15:a81a8d6c1dfe | 541 | SercomI2cs *const i2c_hw = &(pI2C_S(obj)->slave.hw->I2CS); |
mbed_official | 15:a81a8d6c1dfe | 542 | |
mbed_official | 15:a81a8d6c1dfe | 543 | if (i2c_hw->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) { |
mbed_official | 15:a81a8d6c1dfe | 544 | /* Read request from master, Address not yet acknowledged */ |
mbed_official | 15:a81a8d6c1dfe | 545 | i2c_hw->CTRLB.reg &= ~SERCOM_I2CS_CTRLB_ACKACT; |
mbed_official | 15:a81a8d6c1dfe | 546 | i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x3); |
mbed_official | 15:a81a8d6c1dfe | 547 | i2c_hw->INTFLAG.reg = SERCOM_I2CS_INTFLAG_AMATCH; |
mbed_official | 15:a81a8d6c1dfe | 548 | } |
mbed_official | 15:a81a8d6c1dfe | 549 | |
mbed_official | 15:a81a8d6c1dfe | 550 | /* Write data */ |
mbed_official | 15:a81a8d6c1dfe | 551 | _i2c_slave_wait_for_sync(&pI2C_S(obj)->slave); |
mbed_official | 15:a81a8d6c1dfe | 552 | i2c_hw->DATA.reg = data; |
mbed_official | 15:a81a8d6c1dfe | 553 | |
mbed_official | 15:a81a8d6c1dfe | 554 | /* Wait for response from master */ |
mbed_official | 15:a81a8d6c1dfe | 555 | tmp_status = _i2c_slave_wait_for_bus(&pI2C_S(obj)->slave); |
mbed_official | 15:a81a8d6c1dfe | 556 | |
mbed_official | 15:a81a8d6c1dfe | 557 | if (tmp_status != STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 558 | /* Timeout, return */ |
mbed_official | 15:a81a8d6c1dfe | 559 | return I2C_ERROR_BUS_BUSY; |
mbed_official | 15:a81a8d6c1dfe | 560 | } |
mbed_official | 15:a81a8d6c1dfe | 561 | |
mbed_official | 15:a81a8d6c1dfe | 562 | if (i2c_hw->STATUS.reg & SERCOM_I2CS_STATUS_RXNACK) { |
mbed_official | 15:a81a8d6c1dfe | 563 | /* NACK from master, abort */ |
mbed_official | 15:a81a8d6c1dfe | 564 | /* Release line */ |
mbed_official | 15:a81a8d6c1dfe | 565 | i2c_hw->CTRLB.reg |= SERCOM_I2CS_CTRLB_CMD(0x02); |
mbed_official | 15:a81a8d6c1dfe | 566 | |
mbed_official | 15:a81a8d6c1dfe | 567 | return I2C_ERROR_NO_SLAVE; |
mbed_official | 15:a81a8d6c1dfe | 568 | } |
mbed_official | 15:a81a8d6c1dfe | 569 | #endif |
mbed_official | 15:a81a8d6c1dfe | 570 | } |
mbed_official | 15:a81a8d6c1dfe | 571 | |
mbed_official | 15:a81a8d6c1dfe | 572 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 573 | } |
mbed_official | 15:a81a8d6c1dfe | 574 | |
mbed_official | 15:a81a8d6c1dfe | 575 | |
mbed_official | 15:a81a8d6c1dfe | 576 | #if DEVICE_I2CSLAVE |
mbed_official | 15:a81a8d6c1dfe | 577 | |
mbed_official | 15:a81a8d6c1dfe | 578 | /** |
mbed_official | 15:a81a8d6c1dfe | 579 | * \defgroup SynchI2C Synchronous I2C Hardware Abstraction Layer for slave |
mbed_official | 15:a81a8d6c1dfe | 580 | * @{ |
mbed_official | 15:a81a8d6c1dfe | 581 | */ |
mbed_official | 15:a81a8d6c1dfe | 582 | |
mbed_official | 15:a81a8d6c1dfe | 583 | /** Configure I2C as slave or master. |
mbed_official | 15:a81a8d6c1dfe | 584 | * @param obj The I2C object |
mbed_official | 15:a81a8d6c1dfe | 585 | * @param enable_slave configure I2C in slave mode or not |
mbed_official | 15:a81a8d6c1dfe | 586 | * @return void |
mbed_official | 15:a81a8d6c1dfe | 587 | */ |
mbed_official | 15:a81a8d6c1dfe | 588 | void i2c_slave_mode(i2c_t *obj, int enable_slave) |
mbed_official | 15:a81a8d6c1dfe | 589 | { |
mbed_official | 15:a81a8d6c1dfe | 590 | int i; |
mbed_official | 15:a81a8d6c1dfe | 591 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 592 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 593 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 594 | |
mbed_official | 15:a81a8d6c1dfe | 595 | uint32_t mux_func[2]; |
mbed_official | 15:a81a8d6c1dfe | 596 | uint32_t sercom_index = _sercom_get_sercom_inst_index(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 597 | for (i=0; i<2; i++) { |
mbed_official | 15:a81a8d6c1dfe | 598 | mux_func[i] = pinmap_function_sercom(pI2C_S(obj)->pins[0], sercom_index); |
mbed_official | 15:a81a8d6c1dfe | 599 | if (mux_func[i] == NC) return; |
mbed_official | 15:a81a8d6c1dfe | 600 | } |
mbed_official | 15:a81a8d6c1dfe | 601 | |
mbed_official | 15:a81a8d6c1dfe | 602 | if (enable_slave) { |
mbed_official | 15:a81a8d6c1dfe | 603 | /* Disable I2C Master module if active */ |
mbed_official | 15:a81a8d6c1dfe | 604 | i2c_master_disable(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 605 | |
mbed_official | 15:a81a8d6c1dfe | 606 | struct i2c_slave_config config_i2c_slave; |
mbed_official | 15:a81a8d6c1dfe | 607 | i2c_slave_get_config_defaults(&config_i2c_slave); |
mbed_official | 15:a81a8d6c1dfe | 608 | |
mbed_official | 15:a81a8d6c1dfe | 609 | /* SERCOM PAD0 - SDA */ |
mbed_official | 15:a81a8d6c1dfe | 610 | config_i2c_slave.pinmux_pad0 = (pI2C_S(obj)->pins[0] << 16) | (mux_func[0] & 0xFFFF); |
mbed_official | 15:a81a8d6c1dfe | 611 | /* SERCOM PAD1 - SCL */ |
mbed_official | 15:a81a8d6c1dfe | 612 | config_i2c_slave.pinmux_pad1 = (pI2C_S(obj)->pins[1] << 16) | (mux_func[1] & 0xFFFF); |
mbed_official | 15:a81a8d6c1dfe | 613 | |
mbed_official | 15:a81a8d6c1dfe | 614 | i2c_slave_init(&pI2C_S(obj)->slave, pI2C_S(obj)->master.hw, &config_i2c_slave); |
mbed_official | 15:a81a8d6c1dfe | 615 | |
mbed_official | 15:a81a8d6c1dfe | 616 | pI2C_S(obj)->mode = I2C_MODE_SLAVE; |
mbed_official | 15:a81a8d6c1dfe | 617 | |
mbed_official | 15:a81a8d6c1dfe | 618 | i2c_slave_enable(&pI2C_S(obj)->slave); |
mbed_official | 15:a81a8d6c1dfe | 619 | } else { |
mbed_official | 15:a81a8d6c1dfe | 620 | if ((pI2C_S(obj)->master.hw) && (pI2C_S(obj)->mode == I2C_MODE_MASTER)) { |
mbed_official | 15:a81a8d6c1dfe | 621 | /* Already configured, enable and return */ |
mbed_official | 15:a81a8d6c1dfe | 622 | i2c_master_enable(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 623 | return; |
mbed_official | 15:a81a8d6c1dfe | 624 | } else if ((pI2C_S(obj)->slave.hw) && (pI2C_S(obj)->mode == I2C_MODE_SLAVE)) { |
mbed_official | 15:a81a8d6c1dfe | 625 | /* Disable slave */ |
mbed_official | 15:a81a8d6c1dfe | 626 | i2c_slave_disable(&pI2C_S(obj)->slave); |
mbed_official | 15:a81a8d6c1dfe | 627 | } |
mbed_official | 15:a81a8d6c1dfe | 628 | |
mbed_official | 15:a81a8d6c1dfe | 629 | struct i2c_master_config config_i2c_master; |
mbed_official | 15:a81a8d6c1dfe | 630 | /* SERCOM PAD0 - SDA */ |
mbed_official | 15:a81a8d6c1dfe | 631 | config_i2c_master.pinmux_pad0 = (pI2C_S(obj)->pins[0] << 16) | (mux_func[0] & 0xFFFF); |
mbed_official | 15:a81a8d6c1dfe | 632 | /* SERCOM PAD1 - SCL */ |
mbed_official | 15:a81a8d6c1dfe | 633 | config_i2c_master.pinmux_pad1 = (pI2C_S(obj)->pins[1] << 16) | (mux_func[1] & 0xFFFF); |
mbed_official | 15:a81a8d6c1dfe | 634 | /* Baud rate */ |
mbed_official | 15:a81a8d6c1dfe | 635 | config_i2c_master.baud_rate = pI2C_S(obj)->baud_rate / 1000; |
mbed_official | 15:a81a8d6c1dfe | 636 | |
mbed_official | 15:a81a8d6c1dfe | 637 | while(i2c_master_init(&pI2C_S(obj)->master, pI2C_S(obj)->master.hw, &config_i2c_master) != STATUS_OK); |
mbed_official | 15:a81a8d6c1dfe | 638 | pI2C_S(obj)->mode = I2C_MODE_MASTER; |
mbed_official | 15:a81a8d6c1dfe | 639 | |
mbed_official | 15:a81a8d6c1dfe | 640 | i2c_master_enable(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 641 | } |
mbed_official | 15:a81a8d6c1dfe | 642 | } |
mbed_official | 15:a81a8d6c1dfe | 643 | |
mbed_official | 15:a81a8d6c1dfe | 644 | /** Check to see if the I2C slave has been addressed. |
mbed_official | 15:a81a8d6c1dfe | 645 | * @param obj The I2C object |
mbed_official | 15:a81a8d6c1dfe | 646 | * @return The status - 1 - read addresses, 2 - write to all slaves, |
mbed_official | 15:a81a8d6c1dfe | 647 | * 3 write addressed, 0 - the slave has not been addressed |
mbed_official | 15:a81a8d6c1dfe | 648 | */ |
mbed_official | 15:a81a8d6c1dfe | 649 | int i2c_slave_receive(i2c_t *obj) |
mbed_official | 15:a81a8d6c1dfe | 650 | { |
mbed_official | 15:a81a8d6c1dfe | 651 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 652 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 653 | MBED_ASSERT(pI2C_S(obj)->slave.hw); |
mbed_official | 15:a81a8d6c1dfe | 654 | |
mbed_official | 15:a81a8d6c1dfe | 655 | SercomI2cs *const i2c_module = &(pI2C_S(obj)->slave.hw->I2CS); |
mbed_official | 15:a81a8d6c1dfe | 656 | |
mbed_official | 15:a81a8d6c1dfe | 657 | if (i2c_module->INTFLAG.reg & SERCOM_I2CS_INTFLAG_AMATCH) { |
mbed_official | 15:a81a8d6c1dfe | 658 | if (i2c_module->STATUS.reg & SERCOM_I2CS_STATUS_DIR) { |
mbed_official | 15:a81a8d6c1dfe | 659 | /* Slave is read addressed */ |
mbed_official | 15:a81a8d6c1dfe | 660 | return 1; |
mbed_official | 15:a81a8d6c1dfe | 661 | } else { |
mbed_official | 15:a81a8d6c1dfe | 662 | if (!(i2c_module->DATA.reg & 0xFF)) { |
mbed_official | 15:a81a8d6c1dfe | 663 | /* General call address detected */ |
mbed_official | 15:a81a8d6c1dfe | 664 | return 2; |
mbed_official | 15:a81a8d6c1dfe | 665 | } else { |
mbed_official | 15:a81a8d6c1dfe | 666 | /* Slave is write addressed */ |
mbed_official | 15:a81a8d6c1dfe | 667 | return 3; |
mbed_official | 15:a81a8d6c1dfe | 668 | } |
mbed_official | 15:a81a8d6c1dfe | 669 | } |
mbed_official | 15:a81a8d6c1dfe | 670 | } |
mbed_official | 15:a81a8d6c1dfe | 671 | |
mbed_official | 15:a81a8d6c1dfe | 672 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 673 | } |
mbed_official | 15:a81a8d6c1dfe | 674 | |
mbed_official | 15:a81a8d6c1dfe | 675 | /** Blocking reading data. |
mbed_official | 15:a81a8d6c1dfe | 676 | * @param obj The i2c slave object |
mbed_official | 15:a81a8d6c1dfe | 677 | * @param data The buffer for receiving |
mbed_official | 15:a81a8d6c1dfe | 678 | * @param length Number of bytes to read |
mbed_official | 15:a81a8d6c1dfe | 679 | * @return Number of read bytes |
mbed_official | 15:a81a8d6c1dfe | 680 | */ |
mbed_official | 15:a81a8d6c1dfe | 681 | int i2c_slave_read(i2c_t *obj, char *data, int length) |
mbed_official | 15:a81a8d6c1dfe | 682 | { |
mbed_official | 15:a81a8d6c1dfe | 683 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 684 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 685 | MBED_ASSERT(pI2C_S(obj)->slave.hw); |
mbed_official | 15:a81a8d6c1dfe | 686 | |
mbed_official | 15:a81a8d6c1dfe | 687 | if (!data || !length) return 0; |
mbed_official | 15:a81a8d6c1dfe | 688 | |
mbed_official | 15:a81a8d6c1dfe | 689 | enum status_code tmp_status; |
mbed_official | 15:a81a8d6c1dfe | 690 | |
mbed_official | 15:a81a8d6c1dfe | 691 | struct i2c_slave_packet packet; |
mbed_official | 15:a81a8d6c1dfe | 692 | packet.data_length = length; |
mbed_official | 15:a81a8d6c1dfe | 693 | packet.data = (uint8_t*)data; |
mbed_official | 15:a81a8d6c1dfe | 694 | |
mbed_official | 15:a81a8d6c1dfe | 695 | tmp_status = i2c_slave_read_packet_wait(&pI2C_S(obj)->slave, &packet); |
mbed_official | 15:a81a8d6c1dfe | 696 | |
mbed_official | 15:a81a8d6c1dfe | 697 | if (tmp_status == STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 698 | return length; |
mbed_official | 15:a81a8d6c1dfe | 699 | } else { |
mbed_official | 15:a81a8d6c1dfe | 700 | /* Currently, no way to track no of bytes transmitted, so return 0 */ |
mbed_official | 15:a81a8d6c1dfe | 701 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 702 | } |
mbed_official | 15:a81a8d6c1dfe | 703 | |
mbed_official | 15:a81a8d6c1dfe | 704 | } |
mbed_official | 15:a81a8d6c1dfe | 705 | |
mbed_official | 15:a81a8d6c1dfe | 706 | /** Blocking writing data. |
mbed_official | 15:a81a8d6c1dfe | 707 | * @param obj The i2c slave object |
mbed_official | 15:a81a8d6c1dfe | 708 | * @param data The buffer for transmitting |
mbed_official | 15:a81a8d6c1dfe | 709 | * @param length Number of bytes to write |
mbed_official | 15:a81a8d6c1dfe | 710 | * @return Number of bytes written |
mbed_official | 15:a81a8d6c1dfe | 711 | */ |
mbed_official | 15:a81a8d6c1dfe | 712 | int i2c_slave_write(i2c_t *obj, const char *data, int length) |
mbed_official | 15:a81a8d6c1dfe | 713 | { |
mbed_official | 15:a81a8d6c1dfe | 714 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 715 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 716 | MBED_ASSERT(pI2C_S(obj)->slave.hw); |
mbed_official | 15:a81a8d6c1dfe | 717 | |
mbed_official | 15:a81a8d6c1dfe | 718 | if (!data || !length) return 0; |
mbed_official | 15:a81a8d6c1dfe | 719 | |
mbed_official | 15:a81a8d6c1dfe | 720 | enum status_code tmp_status; |
mbed_official | 15:a81a8d6c1dfe | 721 | |
mbed_official | 15:a81a8d6c1dfe | 722 | struct i2c_slave_packet packet; |
mbed_official | 15:a81a8d6c1dfe | 723 | packet.data_length = length; |
mbed_official | 15:a81a8d6c1dfe | 724 | packet.data = data; |
mbed_official | 15:a81a8d6c1dfe | 725 | |
mbed_official | 15:a81a8d6c1dfe | 726 | tmp_status = i2c_slave_write_packet_wait(&pI2C_S(obj)->slave, &packet); |
mbed_official | 15:a81a8d6c1dfe | 727 | |
mbed_official | 15:a81a8d6c1dfe | 728 | if (tmp_status == STATUS_OK) { |
mbed_official | 15:a81a8d6c1dfe | 729 | return length; |
mbed_official | 15:a81a8d6c1dfe | 730 | } else { |
mbed_official | 15:a81a8d6c1dfe | 731 | /* Currently, no way to track no of bytes transmitted, so return 0 */ |
mbed_official | 15:a81a8d6c1dfe | 732 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 733 | } |
mbed_official | 15:a81a8d6c1dfe | 734 | } |
mbed_official | 15:a81a8d6c1dfe | 735 | |
mbed_official | 15:a81a8d6c1dfe | 736 | /** Configure I2C slave address. |
mbed_official | 15:a81a8d6c1dfe | 737 | * @param obj The I2C object |
mbed_official | 15:a81a8d6c1dfe | 738 | * @param idx Currently not used |
mbed_official | 15:a81a8d6c1dfe | 739 | * @param address The address to be set |
mbed_official | 15:a81a8d6c1dfe | 740 | * @param mask Currently not used |
mbed_official | 15:a81a8d6c1dfe | 741 | */ |
mbed_official | 15:a81a8d6c1dfe | 742 | void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) |
mbed_official | 15:a81a8d6c1dfe | 743 | { |
mbed_official | 15:a81a8d6c1dfe | 744 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 745 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 746 | MBED_ASSERT(pI2C_S(obj)->slave.hw); |
mbed_official | 15:a81a8d6c1dfe | 747 | |
mbed_official | 15:a81a8d6c1dfe | 748 | /* Disable I2C Module */ |
mbed_official | 15:a81a8d6c1dfe | 749 | i2c_slave_disable(&pI2C_S(obj)->slave); |
mbed_official | 15:a81a8d6c1dfe | 750 | |
mbed_official | 15:a81a8d6c1dfe | 751 | SercomI2cs *const i2c_hw = &(pI2C_S(obj)->slave.hw->I2CS); |
mbed_official | 15:a81a8d6c1dfe | 752 | |
mbed_official | 15:a81a8d6c1dfe | 753 | address = (address & 0xFF) >> 1; |
mbed_official | 15:a81a8d6c1dfe | 754 | if (!mask) { |
mbed_official | 15:a81a8d6c1dfe | 755 | mask = (0xFE >> 1); |
mbed_official | 15:a81a8d6c1dfe | 756 | } |
mbed_official | 15:a81a8d6c1dfe | 757 | /* Set the address and address mask */ |
mbed_official | 15:a81a8d6c1dfe | 758 | i2c_hw->ADDR.reg = (address << SERCOM_I2CS_ADDR_ADDR_Pos) | |
mbed_official | 15:a81a8d6c1dfe | 759 | (mask << SERCOM_I2CS_ADDR_ADDRMASK_Pos) | |
mbed_official | 15:a81a8d6c1dfe | 760 | (0 << SERCOM_I2CS_ADDR_TENBITEN_Pos) | |
mbed_official | 15:a81a8d6c1dfe | 761 | (1 << SERCOM_I2CS_ADDR_GENCEN_Pos); |
mbed_official | 15:a81a8d6c1dfe | 762 | |
mbed_official | 15:a81a8d6c1dfe | 763 | /* Enable I2C Module */ |
mbed_official | 15:a81a8d6c1dfe | 764 | i2c_slave_enable(&pI2C_S(obj)->slave); |
mbed_official | 15:a81a8d6c1dfe | 765 | } |
mbed_official | 15:a81a8d6c1dfe | 766 | |
mbed_official | 15:a81a8d6c1dfe | 767 | #endif /* DEVICE_I2CSLAVE */ |
mbed_official | 15:a81a8d6c1dfe | 768 | |
mbed_official | 15:a81a8d6c1dfe | 769 | /**@}*/ |
mbed_official | 15:a81a8d6c1dfe | 770 | |
mbed_official | 15:a81a8d6c1dfe | 771 | #if DEVICE_I2C_ASYNCH |
mbed_official | 15:a81a8d6c1dfe | 772 | |
mbed_official | 15:a81a8d6c1dfe | 773 | /** |
mbed_official | 15:a81a8d6c1dfe | 774 | * \defgroup AsynchI2C Asynchronous I2C Hardware Abstraction Layer |
mbed_official | 15:a81a8d6c1dfe | 775 | * @{ |
mbed_official | 15:a81a8d6c1dfe | 776 | */ |
mbed_official | 15:a81a8d6c1dfe | 777 | |
mbed_official | 15:a81a8d6c1dfe | 778 | /** |
mbed_official | 15:a81a8d6c1dfe | 779 | * \internal |
mbed_official | 15:a81a8d6c1dfe | 780 | * Callback for transfer finish. |
mbed_official | 15:a81a8d6c1dfe | 781 | * |
mbed_official | 15:a81a8d6c1dfe | 782 | * \param[in,out] module Pointer to SPI software instance struct |
mbed_official | 15:a81a8d6c1dfe | 783 | */ |
mbed_official | 15:a81a8d6c1dfe | 784 | void i2c_transfer_complete_callback(struct i2c_master_module *const module) |
mbed_official | 15:a81a8d6c1dfe | 785 | { |
mbed_official | 15:a81a8d6c1dfe | 786 | uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); |
mbed_official | 15:a81a8d6c1dfe | 787 | |
mbed_official | 15:a81a8d6c1dfe | 788 | if (sercom_index >= SERCOM_INST_NUM) { |
mbed_official | 15:a81a8d6c1dfe | 789 | /* TODO: Abort operation */ |
mbed_official | 15:a81a8d6c1dfe | 790 | return; |
mbed_official | 15:a81a8d6c1dfe | 791 | } |
mbed_official | 15:a81a8d6c1dfe | 792 | |
mbed_official | 15:a81a8d6c1dfe | 793 | i2c_t *obj = (i2c_t*)i2c_instances[sercom_index]; |
mbed_official | 15:a81a8d6c1dfe | 794 | |
mbed_official | 15:a81a8d6c1dfe | 795 | i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_WRITE_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 796 | i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_READ_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 797 | i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_ERROR); |
mbed_official | 15:a81a8d6c1dfe | 798 | |
mbed_official | 15:a81a8d6c1dfe | 799 | /* Call the handler function */ |
mbed_official | 15:a81a8d6c1dfe | 800 | if (pI2C_S(obj)->handler) { |
mbed_official | 15:a81a8d6c1dfe | 801 | ((I2CHandler)pI2C_S(obj)->handler)(); |
mbed_official | 15:a81a8d6c1dfe | 802 | } |
mbed_official | 15:a81a8d6c1dfe | 803 | } |
mbed_official | 15:a81a8d6c1dfe | 804 | |
mbed_official | 15:a81a8d6c1dfe | 805 | /** |
mbed_official | 15:a81a8d6c1dfe | 806 | * \internal |
mbed_official | 15:a81a8d6c1dfe | 807 | * Callback for write complete. Initiate read from here. |
mbed_official | 15:a81a8d6c1dfe | 808 | * |
mbed_official | 15:a81a8d6c1dfe | 809 | * \param[in,out] module Pointer to SPI software instance struct |
mbed_official | 15:a81a8d6c1dfe | 810 | */ |
mbed_official | 15:a81a8d6c1dfe | 811 | void i2c_write_complete_callback(struct i2c_master_module *const module) |
mbed_official | 15:a81a8d6c1dfe | 812 | { |
mbed_official | 15:a81a8d6c1dfe | 813 | uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw); |
mbed_official | 15:a81a8d6c1dfe | 814 | |
mbed_official | 15:a81a8d6c1dfe | 815 | if (sercom_index >= SERCOM_INST_NUM) { |
mbed_official | 15:a81a8d6c1dfe | 816 | /* TODO: Abort operation */ |
mbed_official | 15:a81a8d6c1dfe | 817 | return; |
mbed_official | 15:a81a8d6c1dfe | 818 | } |
mbed_official | 15:a81a8d6c1dfe | 819 | |
mbed_official | 15:a81a8d6c1dfe | 820 | i2c_t *obj = (i2c_t*)i2c_instances[sercom_index]; |
mbed_official | 15:a81a8d6c1dfe | 821 | |
mbed_official | 15:a81a8d6c1dfe | 822 | if (!(pI2C_S(obj)->rd_packet.data) || (pI2C_S(obj)->rd_packet.data_length == 0)) { |
mbed_official | 15:a81a8d6c1dfe | 823 | /* Call the handler function */ |
mbed_official | 15:a81a8d6c1dfe | 824 | i2c_transfer_complete_callback(module); |
mbed_official | 15:a81a8d6c1dfe | 825 | } else { |
mbed_official | 15:a81a8d6c1dfe | 826 | i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_WRITE_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 827 | |
mbed_official | 15:a81a8d6c1dfe | 828 | /* Register read complete callback */ |
mbed_official | 15:a81a8d6c1dfe | 829 | i2c_master_register_callback(&pI2C_S(obj)->master, i2c_transfer_complete_callback, I2C_MASTER_CALLBACK_READ_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 830 | i2c_master_enable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_READ_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 831 | |
mbed_official | 15:a81a8d6c1dfe | 832 | /* Initiate read operation */ |
mbed_official | 15:a81a8d6c1dfe | 833 | if (pI2C_S(obj)->master.send_stop) { |
mbed_official | 15:a81a8d6c1dfe | 834 | i2c_master_read_packet_job(&pI2C_S(obj)->master,&pI2C_S(obj)->rd_packet); |
mbed_official | 15:a81a8d6c1dfe | 835 | } else { |
mbed_official | 15:a81a8d6c1dfe | 836 | i2c_master_read_packet_job_no_stop(&pI2C_S(obj)->master, &pI2C_S(obj)->rd_packet); |
mbed_official | 15:a81a8d6c1dfe | 837 | } |
mbed_official | 15:a81a8d6c1dfe | 838 | } |
mbed_official | 15:a81a8d6c1dfe | 839 | } |
mbed_official | 15:a81a8d6c1dfe | 840 | |
mbed_official | 15:a81a8d6c1dfe | 841 | /** Start i2c asynchronous transfer. |
mbed_official | 15:a81a8d6c1dfe | 842 | * @param obj The I2C object |
mbed_official | 15:a81a8d6c1dfe | 843 | * @param tx The buffer to send |
mbed_official | 15:a81a8d6c1dfe | 844 | * @param tx_length The number of words to transmit |
mbed_official | 15:a81a8d6c1dfe | 845 | * @param rx The buffer to receive |
mbed_official | 15:a81a8d6c1dfe | 846 | * @param rx_length The number of words to receive |
mbed_official | 15:a81a8d6c1dfe | 847 | * @param address The address to be set - 7bit or 9 bit |
mbed_official | 15:a81a8d6c1dfe | 848 | * @param stop If true, stop will be generated after the transfer is done |
mbed_official | 15:a81a8d6c1dfe | 849 | * @param handler The I2C IRQ handler to be set |
mbed_official | 15:a81a8d6c1dfe | 850 | * @param hint DMA hint usage |
mbed_official | 15:a81a8d6c1dfe | 851 | */ |
mbed_official | 15:a81a8d6c1dfe | 852 | void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx, size_t rx_length, uint32_t address, uint32_t stop, uint32_t handler, uint32_t event, DMAUsage hint) |
mbed_official | 15:a81a8d6c1dfe | 853 | { |
mbed_official | 15:a81a8d6c1dfe | 854 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 855 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 856 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 857 | |
mbed_official | 15:a81a8d6c1dfe | 858 | /* Return if in Slave mode */ |
mbed_official | 15:a81a8d6c1dfe | 859 | if (pI2C_S(obj)->mode != I2C_MODE_MASTER) return; |
mbed_official | 15:a81a8d6c1dfe | 860 | |
mbed_official | 15:a81a8d6c1dfe | 861 | uint32_t sercom_index = _sercom_get_sercom_inst_index(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 862 | |
mbed_official | 15:a81a8d6c1dfe | 863 | /* Init i2c packet. */ |
mbed_official | 15:a81a8d6c1dfe | 864 | pI2C_S(obj)->wr_packet.address = address >> 1; |
mbed_official | 15:a81a8d6c1dfe | 865 | pI2C_S(obj)->wr_packet.data_length = tx_length; |
mbed_official | 15:a81a8d6c1dfe | 866 | pI2C_S(obj)->wr_packet.data = tx; |
mbed_official | 15:a81a8d6c1dfe | 867 | |
mbed_official | 15:a81a8d6c1dfe | 868 | pI2C_S(obj)->rd_packet.address = address >> 1; |
mbed_official | 15:a81a8d6c1dfe | 869 | pI2C_S(obj)->rd_packet.data_length = rx_length; |
mbed_official | 15:a81a8d6c1dfe | 870 | pI2C_S(obj)->rd_packet.data = rx; |
mbed_official | 15:a81a8d6c1dfe | 871 | |
mbed_official | 15:a81a8d6c1dfe | 872 | /* Save event mask and handler function pointer */ |
mbed_official | 15:a81a8d6c1dfe | 873 | pI2C_S(obj)->events = event; |
mbed_official | 15:a81a8d6c1dfe | 874 | pI2C_S(obj)->handler = handler; |
mbed_official | 15:a81a8d6c1dfe | 875 | |
mbed_official | 15:a81a8d6c1dfe | 876 | /* TODO: Current implementation is interrupt based only */ |
mbed_official | 15:a81a8d6c1dfe | 877 | |
mbed_official | 15:a81a8d6c1dfe | 878 | /* Set interrupt handler to default handler of ASF */ |
mbed_official | 15:a81a8d6c1dfe | 879 | /* Enable interrupt */ |
mbed_official | 15:a81a8d6c1dfe | 880 | NVIC_SetVector((SERCOM0_IRQn + sercom_index), sercom_irq_handlers[sercom_index]); |
mbed_official | 15:a81a8d6c1dfe | 881 | NVIC_EnableIRQ(SERCOM0_IRQn + sercom_index); |
mbed_official | 15:a81a8d6c1dfe | 882 | |
mbed_official | 15:a81a8d6c1dfe | 883 | /* Register callbacks */ |
mbed_official | 15:a81a8d6c1dfe | 884 | i2c_master_register_callback(&pI2C_S(obj)->master, i2c_transfer_complete_callback, I2C_MASTER_CALLBACK_ERROR); |
mbed_official | 15:a81a8d6c1dfe | 885 | i2c_master_enable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_ERROR); |
mbed_official | 15:a81a8d6c1dfe | 886 | if (tx && tx_length) { |
mbed_official | 15:a81a8d6c1dfe | 887 | i2c_master_register_callback(&pI2C_S(obj)->master, i2c_write_complete_callback, I2C_MASTER_CALLBACK_WRITE_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 888 | i2c_master_enable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_WRITE_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 889 | |
mbed_official | 15:a81a8d6c1dfe | 890 | /* Start I2C write */ |
mbed_official | 15:a81a8d6c1dfe | 891 | if (stop) { |
mbed_official | 15:a81a8d6c1dfe | 892 | i2c_master_write_packet_job(&pI2C_S(obj)->master, &pI2C_S(obj)->wr_packet); |
mbed_official | 15:a81a8d6c1dfe | 893 | } else { |
mbed_official | 15:a81a8d6c1dfe | 894 | i2c_master_write_packet_job_no_stop(&pI2C_S(obj)->master, &pI2C_S(obj)->wr_packet); |
mbed_official | 15:a81a8d6c1dfe | 895 | } |
mbed_official | 15:a81a8d6c1dfe | 896 | } else if (rx && rx_length) { |
mbed_official | 15:a81a8d6c1dfe | 897 | i2c_master_register_callback(&pI2C_S(obj)->master, i2c_transfer_complete_callback, I2C_MASTER_CALLBACK_READ_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 898 | i2c_master_enable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_READ_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 899 | |
mbed_official | 15:a81a8d6c1dfe | 900 | /* Start I2C read */ |
mbed_official | 15:a81a8d6c1dfe | 901 | if (stop) { |
mbed_official | 15:a81a8d6c1dfe | 902 | i2c_master_read_packet_job(&pI2C_S(obj)->master,&pI2C_S(obj)->rd_packet); |
mbed_official | 15:a81a8d6c1dfe | 903 | } else { |
mbed_official | 15:a81a8d6c1dfe | 904 | i2c_master_read_packet_job_no_stop(&pI2C_S(obj)->master, &pI2C_S(obj)->rd_packet); |
mbed_official | 15:a81a8d6c1dfe | 905 | } |
mbed_official | 15:a81a8d6c1dfe | 906 | } else { |
mbed_official | 15:a81a8d6c1dfe | 907 | /* Nothing to transfer, invoke callback */ |
mbed_official | 15:a81a8d6c1dfe | 908 | i2c_transfer_complete_callback(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 909 | } |
mbed_official | 15:a81a8d6c1dfe | 910 | } |
mbed_official | 15:a81a8d6c1dfe | 911 | |
mbed_official | 15:a81a8d6c1dfe | 912 | /** The asynchronous IRQ handler |
mbed_official | 15:a81a8d6c1dfe | 913 | * @param obj The I2C object which holds the transfer information |
mbed_official | 15:a81a8d6c1dfe | 914 | * @return event flags if a transfer termination condition was met or 0 otherwise. |
mbed_official | 15:a81a8d6c1dfe | 915 | */ |
mbed_official | 15:a81a8d6c1dfe | 916 | uint32_t i2c_irq_handler_asynch(i2c_t *obj) |
mbed_official | 15:a81a8d6c1dfe | 917 | { |
mbed_official | 15:a81a8d6c1dfe | 918 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 919 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 920 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 921 | |
mbed_official | 15:a81a8d6c1dfe | 922 | uint32_t event_mask = pI2C_S(obj)->events; |
mbed_official | 15:a81a8d6c1dfe | 923 | |
mbed_official | 15:a81a8d6c1dfe | 924 | /* TODO: Current implementation is interrupt based only */ |
mbed_official | 15:a81a8d6c1dfe | 925 | |
mbed_official | 15:a81a8d6c1dfe | 926 | switch (pI2C_S(obj)->master.status) { |
mbed_official | 15:a81a8d6c1dfe | 927 | case STATUS_OK: |
mbed_official | 15:a81a8d6c1dfe | 928 | /* Transfer is complete */ |
mbed_official | 15:a81a8d6c1dfe | 929 | return (I2C_EVENT_TRANSFER_COMPLETE & event_mask); |
mbed_official | 15:a81a8d6c1dfe | 930 | break; |
mbed_official | 15:a81a8d6c1dfe | 931 | case STATUS_ERR_BAD_ADDRESS: |
mbed_official | 15:a81a8d6c1dfe | 932 | /* Received a NACK */ |
mbed_official | 15:a81a8d6c1dfe | 933 | return (I2C_EVENT_ERROR_NO_SLAVE & event_mask); |
mbed_official | 15:a81a8d6c1dfe | 934 | break; |
mbed_official | 15:a81a8d6c1dfe | 935 | case STATUS_ERR_PACKET_COLLISION: |
mbed_official | 15:a81a8d6c1dfe | 936 | /* An error occurred in between transfer */ |
mbed_official | 15:a81a8d6c1dfe | 937 | return (I2C_EVENT_ERROR & event_mask); |
mbed_official | 15:a81a8d6c1dfe | 938 | break; |
mbed_official | 15:a81a8d6c1dfe | 939 | default: |
mbed_official | 15:a81a8d6c1dfe | 940 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 941 | } |
mbed_official | 15:a81a8d6c1dfe | 942 | |
mbed_official | 15:a81a8d6c1dfe | 943 | return 0; |
mbed_official | 15:a81a8d6c1dfe | 944 | } |
mbed_official | 15:a81a8d6c1dfe | 945 | |
mbed_official | 15:a81a8d6c1dfe | 946 | /** Attempts to determine if I2C peripheral is already in use. |
mbed_official | 15:a81a8d6c1dfe | 947 | * @param obj The I2C object |
mbed_official | 15:a81a8d6c1dfe | 948 | * @return non-zero if the I2C module is active or zero if it is not |
mbed_official | 15:a81a8d6c1dfe | 949 | */ |
mbed_official | 15:a81a8d6c1dfe | 950 | uint8_t i2c_active(i2c_t *obj) |
mbed_official | 15:a81a8d6c1dfe | 951 | { |
mbed_official | 15:a81a8d6c1dfe | 952 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 953 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 954 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 955 | |
mbed_official | 15:a81a8d6c1dfe | 956 | return (pI2C_S(obj)->master.status == STATUS_BUSY); |
mbed_official | 15:a81a8d6c1dfe | 957 | } |
mbed_official | 15:a81a8d6c1dfe | 958 | |
mbed_official | 15:a81a8d6c1dfe | 959 | /** Abort ongoing asynchronous transaction. |
mbed_official | 15:a81a8d6c1dfe | 960 | * @param obj The I2C object |
mbed_official | 15:a81a8d6c1dfe | 961 | */ |
mbed_official | 15:a81a8d6c1dfe | 962 | void i2c_abort_asynch(i2c_t *obj) |
mbed_official | 15:a81a8d6c1dfe | 963 | { |
mbed_official | 15:a81a8d6c1dfe | 964 | /* Sanity check arguments */ |
mbed_official | 15:a81a8d6c1dfe | 965 | MBED_ASSERT(obj); |
mbed_official | 15:a81a8d6c1dfe | 966 | MBED_ASSERT(pI2C_S(obj)->master.hw); |
mbed_official | 15:a81a8d6c1dfe | 967 | |
mbed_official | 15:a81a8d6c1dfe | 968 | /* Pointer to the hardware module instance */ |
mbed_official | 15:a81a8d6c1dfe | 969 | SercomI2cm *const i2c_module = &(pI2C_S(obj)->master.hw->I2CM); |
mbed_official | 15:a81a8d6c1dfe | 970 | |
mbed_official | 15:a81a8d6c1dfe | 971 | /* Abort ongoing job */ |
mbed_official | 15:a81a8d6c1dfe | 972 | |
mbed_official | 15:a81a8d6c1dfe | 973 | /* Stop packet operation */ |
mbed_official | 15:a81a8d6c1dfe | 974 | i2c_module->INTENCLR.reg = SERCOM_I2CM_INTENCLR_MB | SERCOM_I2CM_INTENCLR_SB; |
mbed_official | 15:a81a8d6c1dfe | 975 | |
mbed_official | 15:a81a8d6c1dfe | 976 | pI2C_S(obj)->master.buffer_length = 0; |
mbed_official | 15:a81a8d6c1dfe | 977 | pI2C_S(obj)->master.buffer_remaining = 0; |
mbed_official | 15:a81a8d6c1dfe | 978 | |
mbed_official | 15:a81a8d6c1dfe | 979 | /* Send nack and stop command unless arbitration is lost */ |
mbed_official | 15:a81a8d6c1dfe | 980 | if ((pI2C_S(obj)->master.status != STATUS_ERR_PACKET_COLLISION) && pI2C_S(obj)->master.send_stop) { |
mbed_official | 15:a81a8d6c1dfe | 981 | _i2c_master_wait_for_sync(&pI2C_S(obj)->master); |
mbed_official | 15:a81a8d6c1dfe | 982 | i2c_module->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT | SERCOM_I2CM_CTRLB_CMD(3); |
mbed_official | 15:a81a8d6c1dfe | 983 | } |
mbed_official | 15:a81a8d6c1dfe | 984 | |
mbed_official | 15:a81a8d6c1dfe | 985 | /* Disable any registered callback */ |
mbed_official | 15:a81a8d6c1dfe | 986 | i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_WRITE_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 987 | i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_READ_COMPLETE); |
mbed_official | 15:a81a8d6c1dfe | 988 | i2c_master_disable_callback(&pI2C_S(obj)->master, I2C_MASTER_CALLBACK_ERROR); |
mbed_official | 15:a81a8d6c1dfe | 989 | |
mbed_official | 15:a81a8d6c1dfe | 990 | pI2C_S(obj)->master.status = STATUS_ABORTED; |
mbed_official | 15:a81a8d6c1dfe | 991 | } |
mbed_official | 15:a81a8d6c1dfe | 992 | |
mbed_official | 15:a81a8d6c1dfe | 993 | #endif |