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