mbed library sources. Supersedes mbed-src.
Dependents: Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more
targets/TARGET_Cypress/TARGET_PSOC6/i2c_api.c@189:f392fc9709a3, 2019-02-20 (annotated)
- Committer:
- AnnaBridge
- Date:
- Wed Feb 20 22:31:08 2019 +0000
- Revision:
- 189:f392fc9709a3
- Parent:
- 188:bcfe06ba3d64
mbed library release version 165
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
AnnaBridge | 188:bcfe06ba3d64 | 1 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 2 | * mbed Microcontroller Library |
AnnaBridge | 188:bcfe06ba3d64 | 3 | * Copyright (c) 2017-2018 Future Electronics |
AnnaBridge | 189:f392fc9709a3 | 4 | * Copyright (c) 2018-2019 Cypress Semiconductor Corporation |
AnnaBridge | 189:f392fc9709a3 | 5 | * SPDX-License-Identifier: Apache-2.0 |
AnnaBridge | 188:bcfe06ba3d64 | 6 | * |
AnnaBridge | 188:bcfe06ba3d64 | 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
AnnaBridge | 188:bcfe06ba3d64 | 8 | * you may not use this file except in compliance with the License. |
AnnaBridge | 188:bcfe06ba3d64 | 9 | * You may obtain a copy of the License at |
AnnaBridge | 188:bcfe06ba3d64 | 10 | * |
AnnaBridge | 188:bcfe06ba3d64 | 11 | * http://www.apache.org/licenses/LICENSE-2.0 |
AnnaBridge | 188:bcfe06ba3d64 | 12 | * |
AnnaBridge | 188:bcfe06ba3d64 | 13 | * Unless required by applicable law or agreed to in writing, software |
AnnaBridge | 188:bcfe06ba3d64 | 14 | * distributed under the License is distributed on an "AS IS" BASIS, |
AnnaBridge | 188:bcfe06ba3d64 | 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
AnnaBridge | 188:bcfe06ba3d64 | 16 | * See the License for the specific language governing permissions and |
AnnaBridge | 188:bcfe06ba3d64 | 17 | * limitations under the License. |
AnnaBridge | 188:bcfe06ba3d64 | 18 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 19 | |
AnnaBridge | 188:bcfe06ba3d64 | 20 | #include "cmsis.h" |
AnnaBridge | 188:bcfe06ba3d64 | 21 | #include "mbed_assert.h" |
AnnaBridge | 188:bcfe06ba3d64 | 22 | #include "mbed_error.h" |
AnnaBridge | 188:bcfe06ba3d64 | 23 | #include "PeripheralPins.h" |
AnnaBridge | 188:bcfe06ba3d64 | 24 | #include "pinmap.h" |
AnnaBridge | 188:bcfe06ba3d64 | 25 | #include "i2c_api.h" |
AnnaBridge | 188:bcfe06ba3d64 | 26 | #include "psoc6_utils.h" |
AnnaBridge | 188:bcfe06ba3d64 | 27 | |
AnnaBridge | 189:f392fc9709a3 | 28 | #include "cy_sysclk.h" |
AnnaBridge | 189:f392fc9709a3 | 29 | #include "cy_gpio.h" |
AnnaBridge | 189:f392fc9709a3 | 30 | #include "cy_scb_i2c.h" |
AnnaBridge | 189:f392fc9709a3 | 31 | #include "cy_sysint.h" |
AnnaBridge | 188:bcfe06ba3d64 | 32 | |
AnnaBridge | 188:bcfe06ba3d64 | 33 | #define I2C_DEFAULT_SPEED 100000 |
AnnaBridge | 188:bcfe06ba3d64 | 34 | #define NUM_I2C_PORTS 8 |
AnnaBridge | 188:bcfe06ba3d64 | 35 | #define I2C_DEFAULT_IRQ_PRIORITY 3 |
AnnaBridge | 188:bcfe06ba3d64 | 36 | #define I2C_NUM_DIVIDERS 3 |
AnnaBridge | 188:bcfe06ba3d64 | 37 | #define MIN_I2C_CLOCK_FREQUENCY CY_SCB_I2C_SLAVE_STD_CLK_MIN |
AnnaBridge | 188:bcfe06ba3d64 | 38 | // Default timeout in milliseconds. |
AnnaBridge | 188:bcfe06ba3d64 | 39 | #define I2C_DEFAULT_TIMEOUT 1000 |
AnnaBridge | 188:bcfe06ba3d64 | 40 | |
AnnaBridge | 188:bcfe06ba3d64 | 41 | #define PENDING_NONE 0 |
AnnaBridge | 188:bcfe06ba3d64 | 42 | #define PENDING_RX 1 |
AnnaBridge | 188:bcfe06ba3d64 | 43 | #define PENDING_TX 2 |
AnnaBridge | 188:bcfe06ba3d64 | 44 | #define PENDING_TX_RX 3 |
AnnaBridge | 188:bcfe06ba3d64 | 45 | |
AnnaBridge | 188:bcfe06ba3d64 | 46 | typedef enum { |
AnnaBridge | 188:bcfe06ba3d64 | 47 | I2C_DIVIDER_LOW = 0, |
AnnaBridge | 188:bcfe06ba3d64 | 48 | I2C_DIVIDER_MID, |
AnnaBridge | 188:bcfe06ba3d64 | 49 | I2C_DIVIDER_HIGH, |
AnnaBridge | 188:bcfe06ba3d64 | 50 | I2C_INVALID_DIVIDER = 0xff |
AnnaBridge | 188:bcfe06ba3d64 | 51 | } I2cDividerType; |
AnnaBridge | 188:bcfe06ba3d64 | 52 | |
AnnaBridge | 188:bcfe06ba3d64 | 53 | |
AnnaBridge | 188:bcfe06ba3d64 | 54 | typedef struct { |
AnnaBridge | 188:bcfe06ba3d64 | 55 | uint32_t div_num; |
AnnaBridge | 188:bcfe06ba3d64 | 56 | cy_en_divider_types_t div_type; |
AnnaBridge | 188:bcfe06ba3d64 | 57 | uint32_t clk_frequency; |
AnnaBridge | 188:bcfe06ba3d64 | 58 | } I2cDividerInfo; |
AnnaBridge | 188:bcfe06ba3d64 | 59 | |
AnnaBridge | 188:bcfe06ba3d64 | 60 | |
AnnaBridge | 188:bcfe06ba3d64 | 61 | static const cy_stc_scb_i2c_config_t default_i2c_config = { |
AnnaBridge | 188:bcfe06ba3d64 | 62 | .i2cMode = CY_SCB_I2C_MASTER, |
AnnaBridge | 188:bcfe06ba3d64 | 63 | .useRxFifo = true, |
AnnaBridge | 188:bcfe06ba3d64 | 64 | .useTxFifo = true, |
AnnaBridge | 188:bcfe06ba3d64 | 65 | .slaveAddress = 0, |
AnnaBridge | 188:bcfe06ba3d64 | 66 | .slaveAddressMask = 0, |
AnnaBridge | 188:bcfe06ba3d64 | 67 | .acceptAddrInFifo = false, |
AnnaBridge | 188:bcfe06ba3d64 | 68 | .ackGeneralAddr = false, |
AnnaBridge | 188:bcfe06ba3d64 | 69 | .enableWakeFromSleep = false |
AnnaBridge | 188:bcfe06ba3d64 | 70 | }; |
AnnaBridge | 188:bcfe06ba3d64 | 71 | |
AnnaBridge | 188:bcfe06ba3d64 | 72 | |
AnnaBridge | 188:bcfe06ba3d64 | 73 | static I2cDividerInfo i2c_dividers[I2C_NUM_DIVIDERS] = { |
AnnaBridge | 189:f392fc9709a3 | 74 | { I2C_INVALID_DIVIDER, CY_SYSCLK_DIV_8_BIT, CY_SCB_I2C_SLAVE_STD_CLK_MIN }, // Low divider uses lowest possible frequency. |
AnnaBridge | 189:f392fc9709a3 | 75 | { I2C_INVALID_DIVIDER, CY_SYSCLK_DIV_8_BIT, CY_SCB_I2C_SLAVE_FST_CLK_MIN }, |
AnnaBridge | 189:f392fc9709a3 | 76 | { I2C_INVALID_DIVIDER, CY_SYSCLK_DIV_8_BIT, CY_SCB_I2C_SLAVE_FSTP_CLK_MIN } |
AnnaBridge | 188:bcfe06ba3d64 | 77 | }; |
AnnaBridge | 188:bcfe06ba3d64 | 78 | |
AnnaBridge | 189:f392fc9709a3 | 79 | |
AnnaBridge | 188:bcfe06ba3d64 | 80 | typedef struct i2c_s i2c_obj_t; |
AnnaBridge | 188:bcfe06ba3d64 | 81 | |
AnnaBridge | 188:bcfe06ba3d64 | 82 | #if DEVICE_I2C_ASYNCH |
AnnaBridge | 188:bcfe06ba3d64 | 83 | #define OBJ_P(in) (&(in->i2c)) |
AnnaBridge | 188:bcfe06ba3d64 | 84 | #else |
AnnaBridge | 188:bcfe06ba3d64 | 85 | #define OBJ_P(in) (in) |
AnnaBridge | 188:bcfe06ba3d64 | 86 | #endif |
AnnaBridge | 188:bcfe06ba3d64 | 87 | |
AnnaBridge | 188:bcfe06ba3d64 | 88 | |
AnnaBridge | 188:bcfe06ba3d64 | 89 | #if DEVICE_I2C_ASYNCH |
AnnaBridge | 188:bcfe06ba3d64 | 90 | |
AnnaBridge | 188:bcfe06ba3d64 | 91 | static IRQn_Type i2c_irq_allocate_channel(i2c_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 92 | { |
AnnaBridge | 188:bcfe06ba3d64 | 93 | #if defined (TARGET_MCU_PSOC6_M0) |
AnnaBridge | 188:bcfe06ba3d64 | 94 | obj->cm0p_irq_src = scb_0_interrupt_IRQn + obj->i2c_id; |
AnnaBridge | 188:bcfe06ba3d64 | 95 | return cy_m0_nvic_allocate_channel(CY_SERIAL_IRQN_ID + obj->i2c_id); |
AnnaBridge | 188:bcfe06ba3d64 | 96 | #else |
AnnaBridge | 189:f392fc9709a3 | 97 | return (IRQn_Type)(scb_0_interrupt_IRQn + obj->i2c_id); |
AnnaBridge | 189:f392fc9709a3 | 98 | #endif /* (TARGET_MCU_PSOC6_M0) */ |
AnnaBridge | 188:bcfe06ba3d64 | 99 | } |
AnnaBridge | 188:bcfe06ba3d64 | 100 | |
AnnaBridge | 188:bcfe06ba3d64 | 101 | static int i2c_irq_setup_channel(i2c_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 102 | { |
AnnaBridge | 188:bcfe06ba3d64 | 103 | cy_stc_sysint_t irq_config; |
AnnaBridge | 188:bcfe06ba3d64 | 104 | |
AnnaBridge | 188:bcfe06ba3d64 | 105 | if (obj->irqn == unconnected_IRQn) { |
AnnaBridge | 188:bcfe06ba3d64 | 106 | IRQn_Type irqn = i2c_irq_allocate_channel(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 107 | if (irqn < 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 108 | return (-1); |
AnnaBridge | 188:bcfe06ba3d64 | 109 | } |
AnnaBridge | 188:bcfe06ba3d64 | 110 | // Configure NVIC |
AnnaBridge | 188:bcfe06ba3d64 | 111 | irq_config.intrPriority = I2C_DEFAULT_IRQ_PRIORITY; |
AnnaBridge | 188:bcfe06ba3d64 | 112 | irq_config.intrSrc = irqn; |
AnnaBridge | 188:bcfe06ba3d64 | 113 | #if defined (TARGET_MCU_PSOC6_M0) |
AnnaBridge | 188:bcfe06ba3d64 | 114 | irq_config.cm0pSrc = obj->cm0p_irq_src; |
AnnaBridge | 188:bcfe06ba3d64 | 115 | #endif |
AnnaBridge | 188:bcfe06ba3d64 | 116 | if (Cy_SysInt_Init(&irq_config, (cy_israddress)(obj->handler)) != CY_SYSINT_SUCCESS) { |
AnnaBridge | 189:f392fc9709a3 | 117 | return (-1); |
AnnaBridge | 188:bcfe06ba3d64 | 118 | } |
AnnaBridge | 188:bcfe06ba3d64 | 119 | |
AnnaBridge | 188:bcfe06ba3d64 | 120 | obj->irqn = irqn; |
AnnaBridge | 188:bcfe06ba3d64 | 121 | NVIC_EnableIRQ(irqn); |
AnnaBridge | 188:bcfe06ba3d64 | 122 | } |
AnnaBridge | 188:bcfe06ba3d64 | 123 | return 0; |
AnnaBridge | 188:bcfe06ba3d64 | 124 | } |
AnnaBridge | 188:bcfe06ba3d64 | 125 | |
AnnaBridge | 188:bcfe06ba3d64 | 126 | #endif // DEVICE_I2C_ASYNCH |
AnnaBridge | 188:bcfe06ba3d64 | 127 | |
AnnaBridge | 188:bcfe06ba3d64 | 128 | static int allocate_divider(I2cDividerType divider) |
AnnaBridge | 188:bcfe06ba3d64 | 129 | { |
AnnaBridge | 188:bcfe06ba3d64 | 130 | I2cDividerInfo *p_div = &i2c_dividers[divider]; |
AnnaBridge | 188:bcfe06ba3d64 | 131 | |
AnnaBridge | 188:bcfe06ba3d64 | 132 | if (p_div->div_num == CY_INVALID_DIVIDER) { |
AnnaBridge | 188:bcfe06ba3d64 | 133 | p_div->div_num = cy_clk_allocate_divider(CY_SYSCLK_DIV_8_BIT); |
AnnaBridge | 188:bcfe06ba3d64 | 134 | if (p_div->div_num != CY_INVALID_DIVIDER) { |
AnnaBridge | 188:bcfe06ba3d64 | 135 | p_div->div_type = CY_SYSCLK_DIV_8_BIT; |
AnnaBridge | 188:bcfe06ba3d64 | 136 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 137 | p_div->div_num = cy_clk_allocate_divider(CY_SYSCLK_DIV_16_BIT); |
AnnaBridge | 188:bcfe06ba3d64 | 138 | if (p_div->div_num != CY_INVALID_DIVIDER) { |
AnnaBridge | 188:bcfe06ba3d64 | 139 | p_div->div_type = CY_SYSCLK_DIV_16_BIT; |
AnnaBridge | 188:bcfe06ba3d64 | 140 | } |
AnnaBridge | 188:bcfe06ba3d64 | 141 | } |
AnnaBridge | 188:bcfe06ba3d64 | 142 | } |
AnnaBridge | 188:bcfe06ba3d64 | 143 | |
AnnaBridge | 188:bcfe06ba3d64 | 144 | if (p_div->div_num != CY_INVALID_DIVIDER) { |
AnnaBridge | 188:bcfe06ba3d64 | 145 | // Set up proper frequency; |
AnnaBridge | 189:f392fc9709a3 | 146 | uint32_t div_value = cy_PeriClkFreqHz / p_div->clk_frequency; |
AnnaBridge | 189:f392fc9709a3 | 147 | p_div->clk_frequency = cy_PeriClkFreqHz / div_value; |
AnnaBridge | 188:bcfe06ba3d64 | 148 | if (Cy_SysClk_PeriphSetDivider(p_div->div_type, p_div->div_num, div_value) == CY_SYSCLK_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 149 | Cy_SysClk_PeriphEnableDivider(p_div->div_type, p_div->div_num); |
AnnaBridge | 188:bcfe06ba3d64 | 150 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 151 | p_div->div_num = CY_INVALID_DIVIDER; |
AnnaBridge | 188:bcfe06ba3d64 | 152 | } |
AnnaBridge | 188:bcfe06ba3d64 | 153 | } |
AnnaBridge | 188:bcfe06ba3d64 | 154 | |
AnnaBridge | 189:f392fc9709a3 | 155 | return (p_div->div_num == CY_INVALID_DIVIDER) ? -1 : 0; |
AnnaBridge | 188:bcfe06ba3d64 | 156 | } |
AnnaBridge | 188:bcfe06ba3d64 | 157 | |
AnnaBridge | 188:bcfe06ba3d64 | 158 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 159 | * Select one of the 3 dividers used depending on the required frequency. |
AnnaBridge | 188:bcfe06ba3d64 | 160 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 161 | static I2cDividerType select_divider(uint32_t frequency) |
AnnaBridge | 188:bcfe06ba3d64 | 162 | { |
AnnaBridge | 188:bcfe06ba3d64 | 163 | if (frequency <= (MIN_I2C_CLOCK_FREQUENCY / CY_SCB_I2C_DUTY_CYCLE_MAX)) { |
AnnaBridge | 188:bcfe06ba3d64 | 164 | // Required speed lower than min supported. |
AnnaBridge | 188:bcfe06ba3d64 | 165 | return I2C_INVALID_DIVIDER; |
AnnaBridge | 188:bcfe06ba3d64 | 166 | } else if (frequency <= CY_SCB_I2C_STD_DATA_RATE) { |
AnnaBridge | 188:bcfe06ba3d64 | 167 | return I2C_DIVIDER_LOW; |
AnnaBridge | 188:bcfe06ba3d64 | 168 | } else if (frequency <= CY_SCB_I2C_FST_DATA_RATE) { |
AnnaBridge | 188:bcfe06ba3d64 | 169 | return I2C_DIVIDER_MID; |
AnnaBridge | 188:bcfe06ba3d64 | 170 | } else if (frequency <= CY_SCB_I2C_FSTP_DATA_RATE) { |
AnnaBridge | 188:bcfe06ba3d64 | 171 | return I2C_DIVIDER_HIGH; |
AnnaBridge | 188:bcfe06ba3d64 | 172 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 173 | // Required speed too high; |
AnnaBridge | 188:bcfe06ba3d64 | 174 | return I2C_INVALID_DIVIDER; |
AnnaBridge | 188:bcfe06ba3d64 | 175 | } |
AnnaBridge | 188:bcfe06ba3d64 | 176 | } |
AnnaBridge | 188:bcfe06ba3d64 | 177 | |
AnnaBridge | 188:bcfe06ba3d64 | 178 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 179 | * Initializes i2c clock for the required speed |
AnnaBridge | 188:bcfe06ba3d64 | 180 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 181 | static cy_en_sysclk_status_t i2c_init_clock(i2c_obj_t *obj, uint32_t speed) |
AnnaBridge | 188:bcfe06ba3d64 | 182 | { |
AnnaBridge | 188:bcfe06ba3d64 | 183 | I2cDividerInfo *p_div = NULL; |
AnnaBridge | 188:bcfe06ba3d64 | 184 | cy_en_sysclk_status_t status = CY_SYSCLK_INVALID_STATE; |
AnnaBridge | 188:bcfe06ba3d64 | 185 | I2cDividerType divider = select_divider(speed); |
AnnaBridge | 188:bcfe06ba3d64 | 186 | |
AnnaBridge | 188:bcfe06ba3d64 | 187 | if (divider == I2C_INVALID_DIVIDER) { |
AnnaBridge | 189:f392fc9709a3 | 188 | error("I2C: required speed/frequency is out of valid range."); |
AnnaBridge | 188:bcfe06ba3d64 | 189 | } |
AnnaBridge | 188:bcfe06ba3d64 | 190 | |
AnnaBridge | 188:bcfe06ba3d64 | 191 | if (allocate_divider(divider) < 0) { |
AnnaBridge | 189:f392fc9709a3 | 192 | error("I2C: cannot allocate clock divider."); |
AnnaBridge | 188:bcfe06ba3d64 | 193 | } |
AnnaBridge | 188:bcfe06ba3d64 | 194 | |
AnnaBridge | 188:bcfe06ba3d64 | 195 | obj->divider = divider; |
AnnaBridge | 188:bcfe06ba3d64 | 196 | p_div = &i2c_dividers[divider]; |
AnnaBridge | 188:bcfe06ba3d64 | 197 | |
AnnaBridge | 188:bcfe06ba3d64 | 198 | status = Cy_SysClk_PeriphAssignDivider(obj->clock, p_div->div_type, p_div->div_num); |
AnnaBridge | 188:bcfe06ba3d64 | 199 | if (status != CY_SYSCLK_SUCCESS) { |
AnnaBridge | 189:f392fc9709a3 | 200 | error("I2C: cannot assign clock divider."); |
AnnaBridge | 188:bcfe06ba3d64 | 201 | } |
AnnaBridge | 188:bcfe06ba3d64 | 202 | |
AnnaBridge | 188:bcfe06ba3d64 | 203 | /* Set desired speed/frequency */ |
AnnaBridge | 188:bcfe06ba3d64 | 204 | obj->actual_speed = Cy_SCB_I2C_SetDataRate(obj->base, speed, p_div->clk_frequency); |
AnnaBridge | 189:f392fc9709a3 | 205 | return (obj->actual_speed != 0) ? CY_SYSCLK_SUCCESS : CY_SYSCLK_BAD_PARAM; |
AnnaBridge | 188:bcfe06ba3d64 | 206 | } |
AnnaBridge | 188:bcfe06ba3d64 | 207 | |
AnnaBridge | 188:bcfe06ba3d64 | 208 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 209 | * Initializes i/o pins for i2c sda/scl. |
AnnaBridge | 188:bcfe06ba3d64 | 210 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 211 | static void i2c_init_pins(i2c_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 212 | { |
AnnaBridge | 189:f392fc9709a3 | 213 | /* MBED driver reserves pins for I2C as Ditigal IO while doing I2C error |
AnnaBridge | 189:f392fc9709a3 | 214 | * recovery in constructor. |
AnnaBridge | 189:f392fc9709a3 | 215 | */ |
AnnaBridge | 189:f392fc9709a3 | 216 | pin_function(obj->pin_sda, pinmap_function(obj->pin_sda, PinMap_I2C_SDA)); |
AnnaBridge | 189:f392fc9709a3 | 217 | pin_function(obj->pin_scl, pinmap_function(obj->pin_scl, PinMap_I2C_SCL)); |
AnnaBridge | 188:bcfe06ba3d64 | 218 | } |
AnnaBridge | 188:bcfe06ba3d64 | 219 | |
AnnaBridge | 188:bcfe06ba3d64 | 220 | |
AnnaBridge | 188:bcfe06ba3d64 | 221 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 222 | * Initializes and enables I2C/SCB. |
AnnaBridge | 188:bcfe06ba3d64 | 223 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 224 | static void i2c_init_peripheral(i2c_obj_t *obj) |
AnnaBridge | 188:bcfe06ba3d64 | 225 | { |
AnnaBridge | 188:bcfe06ba3d64 | 226 | cy_stc_scb_i2c_config_t i2c_config = default_i2c_config; |
AnnaBridge | 188:bcfe06ba3d64 | 227 | I2cDividerInfo *p_div = &i2c_dividers[obj->divider]; |
AnnaBridge | 188:bcfe06ba3d64 | 228 | |
AnnaBridge | 188:bcfe06ba3d64 | 229 | Cy_SCB_I2C_Init(obj->base, &i2c_config, &obj->context); |
AnnaBridge | 189:f392fc9709a3 | 230 | Cy_SCB_I2C_SetDataRate(obj->base, obj->actual_speed, p_div->clk_frequency); |
AnnaBridge | 188:bcfe06ba3d64 | 231 | Cy_SCB_I2C_Enable(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 232 | } |
AnnaBridge | 188:bcfe06ba3d64 | 233 | |
AnnaBridge | 188:bcfe06ba3d64 | 234 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 235 | * Coverts PDL status into Mbed status. |
AnnaBridge | 188:bcfe06ba3d64 | 236 | */ |
AnnaBridge | 188:bcfe06ba3d64 | 237 | static int i2c_convert_status(cy_en_scb_i2c_status_t status) |
AnnaBridge | 188:bcfe06ba3d64 | 238 | { |
AnnaBridge | 188:bcfe06ba3d64 | 239 | switch (status) { |
AnnaBridge | 188:bcfe06ba3d64 | 240 | case CY_SCB_I2C_MASTER_NOT_READY: |
AnnaBridge | 188:bcfe06ba3d64 | 241 | case CY_SCB_I2C_MASTER_MANUAL_ARB_LOST: |
AnnaBridge | 188:bcfe06ba3d64 | 242 | case CY_SCB_I2C_MASTER_MANUAL_BUS_ERR: |
AnnaBridge | 188:bcfe06ba3d64 | 243 | case CY_SCB_I2C_MASTER_MANUAL_ABORT_START: |
AnnaBridge | 188:bcfe06ba3d64 | 244 | return I2C_ERROR_BUS_BUSY; |
AnnaBridge | 188:bcfe06ba3d64 | 245 | |
AnnaBridge | 188:bcfe06ba3d64 | 246 | case CY_SCB_I2C_MASTER_MANUAL_TIMEOUT: |
AnnaBridge | 188:bcfe06ba3d64 | 247 | case CY_SCB_I2C_MASTER_MANUAL_ADDR_NAK: |
AnnaBridge | 188:bcfe06ba3d64 | 248 | case CY_SCB_I2C_MASTER_MANUAL_NAK: |
AnnaBridge | 188:bcfe06ba3d64 | 249 | return I2C_ERROR_NO_SLAVE; |
AnnaBridge | 188:bcfe06ba3d64 | 250 | |
AnnaBridge | 188:bcfe06ba3d64 | 251 | case CY_SCB_I2C_SUCCESS: |
AnnaBridge | 188:bcfe06ba3d64 | 252 | case CY_SCB_I2C_BAD_PARAM: |
AnnaBridge | 188:bcfe06ba3d64 | 253 | default: |
AnnaBridge | 188:bcfe06ba3d64 | 254 | return 0; |
AnnaBridge | 188:bcfe06ba3d64 | 255 | } |
AnnaBridge | 188:bcfe06ba3d64 | 256 | } |
AnnaBridge | 188:bcfe06ba3d64 | 257 | |
AnnaBridge | 188:bcfe06ba3d64 | 258 | /* |
AnnaBridge | 188:bcfe06ba3d64 | 259 | * Callback function to handle into and out of deep sleep state transitions. |
AnnaBridge | 188:bcfe06ba3d64 | 260 | */ |
AnnaBridge | 189:f392fc9709a3 | 261 | #if DEVICE_SLEEP && DEVICE_LPTICKER |
AnnaBridge | 189:f392fc9709a3 | 262 | static cy_en_syspm_status_t i2c_pm_callback(cy_stc_syspm_callback_params_t *callback_params, cy_en_syspm_callback_mode_t mode) |
AnnaBridge | 188:bcfe06ba3d64 | 263 | { |
AnnaBridge | 188:bcfe06ba3d64 | 264 | cy_stc_syspm_callback_params_t params = *callback_params; |
AnnaBridge | 188:bcfe06ba3d64 | 265 | i2c_obj_t *obj = (i2c_obj_t *)params.context; |
AnnaBridge | 188:bcfe06ba3d64 | 266 | params.context = &obj->context; |
AnnaBridge | 188:bcfe06ba3d64 | 267 | |
AnnaBridge | 189:f392fc9709a3 | 268 | return Cy_SCB_I2C_DeepSleepCallback(¶ms, mode); |
AnnaBridge | 188:bcfe06ba3d64 | 269 | } |
AnnaBridge | 189:f392fc9709a3 | 270 | #endif // DEVICE_SLEEP && DEVICE_LPTICKER |
AnnaBridge | 188:bcfe06ba3d64 | 271 | |
AnnaBridge | 188:bcfe06ba3d64 | 272 | |
AnnaBridge | 188:bcfe06ba3d64 | 273 | void i2c_init(i2c_t *obj_in, PinName sda, PinName scl) |
AnnaBridge | 188:bcfe06ba3d64 | 274 | { |
AnnaBridge | 188:bcfe06ba3d64 | 275 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 276 | |
AnnaBridge | 188:bcfe06ba3d64 | 277 | uint32_t i2c = pinmap_peripheral(sda, PinMap_I2C_SDA); |
AnnaBridge | 188:bcfe06ba3d64 | 278 | i2c = pinmap_merge(i2c, pinmap_peripheral(scl, PinMap_I2C_SCL)); |
AnnaBridge | 189:f392fc9709a3 | 279 | |
AnnaBridge | 189:f392fc9709a3 | 280 | if (i2c != (uint32_t) NC) { |
AnnaBridge | 189:f392fc9709a3 | 281 | /* Initialize configuration */ |
AnnaBridge | 189:f392fc9709a3 | 282 | obj->base = (CySCB_Type *) i2c; |
AnnaBridge | 189:f392fc9709a3 | 283 | obj->i2c_id = ((I2CName) i2c - I2C_0) / (I2C_1 - I2C_0); |
AnnaBridge | 189:f392fc9709a3 | 284 | obj->clock = CY_PIN_CLOCK(pinmap_function(scl, PinMap_I2C_SCL)); |
AnnaBridge | 189:f392fc9709a3 | 285 | obj->divider = I2C_INVALID_DIVIDER; |
AnnaBridge | 189:f392fc9709a3 | 286 | obj->already_reserved = (0 != cy_reserve_scb(obj->i2c_id)); |
AnnaBridge | 188:bcfe06ba3d64 | 287 | obj->pin_sda = sda; |
AnnaBridge | 188:bcfe06ba3d64 | 288 | obj->pin_scl = scl; |
AnnaBridge | 189:f392fc9709a3 | 289 | |
AnnaBridge | 189:f392fc9709a3 | 290 | obj->mode = CY_SCB_I2C_MASTER; |
AnnaBridge | 188:bcfe06ba3d64 | 291 | obj->timeout = I2C_DEFAULT_TIMEOUT; |
AnnaBridge | 189:f392fc9709a3 | 292 | |
AnnaBridge | 188:bcfe06ba3d64 | 293 | #if DEVICE_I2C_ASYNCH |
AnnaBridge | 189:f392fc9709a3 | 294 | obj->irqn = unconnected_IRQn; |
AnnaBridge | 188:bcfe06ba3d64 | 295 | obj->pending = PENDING_NONE; |
AnnaBridge | 189:f392fc9709a3 | 296 | obj->events = 0; |
AnnaBridge | 189:f392fc9709a3 | 297 | #endif /* DEVICE_I2C_ASYNCH */ |
AnnaBridge | 189:f392fc9709a3 | 298 | |
AnnaBridge | 189:f392fc9709a3 | 299 | /* Check if resource severed */ |
AnnaBridge | 189:f392fc9709a3 | 300 | if (obj->already_reserved) { |
AnnaBridge | 189:f392fc9709a3 | 301 | |
AnnaBridge | 189:f392fc9709a3 | 302 | /* SCB pins and clocks are connected */ |
AnnaBridge | 189:f392fc9709a3 | 303 | |
AnnaBridge | 189:f392fc9709a3 | 304 | /* Disable block and get it into the default state */ |
AnnaBridge | 189:f392fc9709a3 | 305 | Cy_SCB_I2C_Disable(obj->base, &obj->context); |
AnnaBridge | 189:f392fc9709a3 | 306 | Cy_SCB_I2C_DeInit(obj->base); |
AnnaBridge | 189:f392fc9709a3 | 307 | |
AnnaBridge | 189:f392fc9709a3 | 308 | /* The proper clock will be connected by i2c_init_clock(obj, I2C_DEFAULT_SPEED) */ |
AnnaBridge | 189:f392fc9709a3 | 309 | obj->divider = I2C_DIVIDER_LOW; |
AnnaBridge | 189:f392fc9709a3 | 310 | } else { |
AnnaBridge | 189:f392fc9709a3 | 311 | #if DEVICE_SLEEP && DEVICE_LPTICKER |
AnnaBridge | 189:f392fc9709a3 | 312 | /* Register callback once */ |
AnnaBridge | 189:f392fc9709a3 | 313 | obj->pm_callback_handler.callback = i2c_pm_callback; |
AnnaBridge | 189:f392fc9709a3 | 314 | obj->pm_callback_handler.type = CY_SYSPM_DEEPSLEEP; |
AnnaBridge | 189:f392fc9709a3 | 315 | obj->pm_callback_handler.skipMode = 0; |
AnnaBridge | 189:f392fc9709a3 | 316 | obj->pm_callback_handler.callbackParams = &obj->pm_callback_params; |
AnnaBridge | 189:f392fc9709a3 | 317 | obj->pm_callback_params.base = obj->base; |
AnnaBridge | 189:f392fc9709a3 | 318 | obj->pm_callback_params.context = obj; |
AnnaBridge | 189:f392fc9709a3 | 319 | if (!Cy_SysPm_RegisterCallback(&obj->pm_callback_handler)) { |
AnnaBridge | 189:f392fc9709a3 | 320 | error("PM callback registration failed!"); |
AnnaBridge | 189:f392fc9709a3 | 321 | } |
AnnaBridge | 189:f392fc9709a3 | 322 | #endif /* DEVICE_SLEEP && DEVICE_LPTICKER */ |
AnnaBridge | 189:f392fc9709a3 | 323 | } |
AnnaBridge | 189:f392fc9709a3 | 324 | |
AnnaBridge | 189:f392fc9709a3 | 325 | /* Configure hardware resources */ |
AnnaBridge | 188:bcfe06ba3d64 | 326 | i2c_init_clock(obj, I2C_DEFAULT_SPEED); |
AnnaBridge | 188:bcfe06ba3d64 | 327 | i2c_init_pins(obj); |
AnnaBridge | 188:bcfe06ba3d64 | 328 | i2c_init_peripheral(obj); |
AnnaBridge | 189:f392fc9709a3 | 329 | |
AnnaBridge | 188:bcfe06ba3d64 | 330 | } else { |
AnnaBridge | 189:f392fc9709a3 | 331 | error("I2C pinout mismatch. Requested pins SDA and SCL can't be used for the same I2C communication."); |
AnnaBridge | 188:bcfe06ba3d64 | 332 | } |
AnnaBridge | 188:bcfe06ba3d64 | 333 | } |
AnnaBridge | 188:bcfe06ba3d64 | 334 | |
AnnaBridge | 188:bcfe06ba3d64 | 335 | void i2c_frequency(i2c_t *obj_in, int hz) |
AnnaBridge | 188:bcfe06ba3d64 | 336 | { |
AnnaBridge | 188:bcfe06ba3d64 | 337 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 338 | Cy_SCB_I2C_Disable(obj->base, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 339 | i2c_init_clock(obj, hz); |
AnnaBridge | 188:bcfe06ba3d64 | 340 | Cy_SCB_I2C_Enable(obj->base); |
AnnaBridge | 188:bcfe06ba3d64 | 341 | } |
AnnaBridge | 188:bcfe06ba3d64 | 342 | |
AnnaBridge | 188:bcfe06ba3d64 | 343 | int i2c_start(i2c_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 344 | { |
AnnaBridge | 189:f392fc9709a3 | 345 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 346 | |
AnnaBridge | 189:f392fc9709a3 | 347 | if (CY_SCB_I2C_IDLE == obj->context.state) { |
AnnaBridge | 189:f392fc9709a3 | 348 | /* Set the read or write direction */ |
AnnaBridge | 189:f392fc9709a3 | 349 | obj->context.state = CY_SCB_I2C_MASTER_ADDR; |
AnnaBridge | 189:f392fc9709a3 | 350 | |
AnnaBridge | 189:f392fc9709a3 | 351 | /* Clean up the hardware before a transfer. Note RX FIFO is empty at here */ |
AnnaBridge | 189:f392fc9709a3 | 352 | Cy_SCB_ClearMasterInterrupt(obj->base, CY_SCB_I2C_MASTER_INTR_ALL); |
AnnaBridge | 189:f392fc9709a3 | 353 | Cy_SCB_ClearRxInterrupt(obj->base, CY_SCB_RX_INTR_NOT_EMPTY); |
AnnaBridge | 189:f392fc9709a3 | 354 | Cy_SCB_ClearTxFifo(obj->base); |
AnnaBridge | 189:f392fc9709a3 | 355 | |
AnnaBridge | 189:f392fc9709a3 | 356 | /* Generate a Start and send address byte */ |
AnnaBridge | 189:f392fc9709a3 | 357 | SCB_I2C_M_CMD(obj->base) = SCB_I2C_M_CMD_M_START_ON_IDLE_Msk; |
AnnaBridge | 189:f392fc9709a3 | 358 | |
AnnaBridge | 189:f392fc9709a3 | 359 | /* Wait until Start is generated */ |
AnnaBridge | 189:f392fc9709a3 | 360 | while (0 != (SCB_I2C_M_CMD(obj->base) & SCB_I2C_M_CMD_M_START_ON_IDLE_Msk)) { |
AnnaBridge | 189:f392fc9709a3 | 361 | } |
AnnaBridge | 189:f392fc9709a3 | 362 | |
AnnaBridge | 189:f392fc9709a3 | 363 | return 0; |
AnnaBridge | 189:f392fc9709a3 | 364 | } |
AnnaBridge | 189:f392fc9709a3 | 365 | |
AnnaBridge | 189:f392fc9709a3 | 366 | return (-1); |
AnnaBridge | 188:bcfe06ba3d64 | 367 | } |
AnnaBridge | 188:bcfe06ba3d64 | 368 | |
AnnaBridge | 188:bcfe06ba3d64 | 369 | int i2c_stop(i2c_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 370 | { |
AnnaBridge | 189:f392fc9709a3 | 371 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 372 | cy_en_scb_i2c_status_t status = Cy_SCB_I2C_MasterSendStop(obj->base, obj->timeout, &obj->context); |
AnnaBridge | 189:f392fc9709a3 | 373 | |
AnnaBridge | 189:f392fc9709a3 | 374 | return i2c_convert_status(status); |
AnnaBridge | 188:bcfe06ba3d64 | 375 | } |
AnnaBridge | 188:bcfe06ba3d64 | 376 | |
AnnaBridge | 188:bcfe06ba3d64 | 377 | int i2c_read(i2c_t *obj_in, int address, char *data, int length, int stop) |
AnnaBridge | 188:bcfe06ba3d64 | 378 | { |
AnnaBridge | 188:bcfe06ba3d64 | 379 | cy_en_scb_i2c_status_t status = CY_SCB_I2C_SUCCESS; |
AnnaBridge | 188:bcfe06ba3d64 | 380 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 381 | cy_en_scb_i2c_command_t ack = CY_SCB_I2C_ACK; |
AnnaBridge | 188:bcfe06ba3d64 | 382 | int byte_count = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 383 | address >>= 1; |
AnnaBridge | 188:bcfe06ba3d64 | 384 | |
AnnaBridge | 188:bcfe06ba3d64 | 385 | // Start transaction, send address. |
AnnaBridge | 188:bcfe06ba3d64 | 386 | if (obj->context.state == CY_SCB_I2C_IDLE) { |
AnnaBridge | 188:bcfe06ba3d64 | 387 | status = Cy_SCB_I2C_MasterSendStart(obj->base, address, CY_SCB_I2C_READ_XFER, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 388 | } |
AnnaBridge | 188:bcfe06ba3d64 | 389 | if (status == CY_SCB_I2C_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 390 | while (length > 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 391 | if (length == 1) { |
AnnaBridge | 188:bcfe06ba3d64 | 392 | ack = CY_SCB_I2C_NAK; |
AnnaBridge | 188:bcfe06ba3d64 | 393 | } |
AnnaBridge | 188:bcfe06ba3d64 | 394 | status = Cy_SCB_I2C_MasterReadByte(obj->base, ack, (uint8_t *)data, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 395 | if (status != CY_SCB_I2C_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 396 | break; |
AnnaBridge | 188:bcfe06ba3d64 | 397 | } |
AnnaBridge | 188:bcfe06ba3d64 | 398 | ++byte_count; |
AnnaBridge | 188:bcfe06ba3d64 | 399 | --length; |
AnnaBridge | 188:bcfe06ba3d64 | 400 | ++data; |
AnnaBridge | 188:bcfe06ba3d64 | 401 | } |
AnnaBridge | 188:bcfe06ba3d64 | 402 | // SCB in I2C mode is very time sensitive. In practice we have to request STOP after |
AnnaBridge | 188:bcfe06ba3d64 | 403 | // each block, otherwise it may break the transmission. |
AnnaBridge | 188:bcfe06ba3d64 | 404 | Cy_SCB_I2C_MasterSendStop(obj->base, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 405 | } |
AnnaBridge | 188:bcfe06ba3d64 | 406 | |
AnnaBridge | 188:bcfe06ba3d64 | 407 | if (status != CY_SCB_I2C_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 408 | Cy_SCB_I2C_MasterSendStop(obj->base, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 409 | byte_count = i2c_convert_status(status); |
AnnaBridge | 188:bcfe06ba3d64 | 410 | } |
AnnaBridge | 188:bcfe06ba3d64 | 411 | |
AnnaBridge | 188:bcfe06ba3d64 | 412 | return byte_count; |
AnnaBridge | 188:bcfe06ba3d64 | 413 | } |
AnnaBridge | 188:bcfe06ba3d64 | 414 | |
AnnaBridge | 188:bcfe06ba3d64 | 415 | int i2c_write(i2c_t *obj_in, int address, const char *data, int length, int stop) |
AnnaBridge | 188:bcfe06ba3d64 | 416 | { |
AnnaBridge | 188:bcfe06ba3d64 | 417 | cy_en_scb_i2c_status_t status = CY_SCB_I2C_SUCCESS; |
AnnaBridge | 188:bcfe06ba3d64 | 418 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 419 | int byte_count = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 420 | address >>= 1; |
AnnaBridge | 188:bcfe06ba3d64 | 421 | |
AnnaBridge | 188:bcfe06ba3d64 | 422 | // Start transaction, send address. |
AnnaBridge | 188:bcfe06ba3d64 | 423 | if (obj->context.state == CY_SCB_I2C_IDLE) { |
AnnaBridge | 188:bcfe06ba3d64 | 424 | status = Cy_SCB_I2C_MasterSendStart(obj->base, address, CY_SCB_I2C_WRITE_XFER, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 425 | } |
AnnaBridge | 188:bcfe06ba3d64 | 426 | if (status == CY_SCB_I2C_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 427 | while (length > 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 428 | status = Cy_SCB_I2C_MasterWriteByte(obj->base, *data, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 429 | if (status != CY_SCB_I2C_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 430 | break;; |
AnnaBridge | 188:bcfe06ba3d64 | 431 | } |
AnnaBridge | 188:bcfe06ba3d64 | 432 | ++byte_count; |
AnnaBridge | 188:bcfe06ba3d64 | 433 | --length; |
AnnaBridge | 188:bcfe06ba3d64 | 434 | ++data; |
AnnaBridge | 188:bcfe06ba3d64 | 435 | } |
AnnaBridge | 188:bcfe06ba3d64 | 436 | // SCB in I2C mode is very time sensitive. In practice we have to request STOP after |
AnnaBridge | 188:bcfe06ba3d64 | 437 | // each block, otherwise it may break the transmission. |
AnnaBridge | 188:bcfe06ba3d64 | 438 | Cy_SCB_I2C_MasterSendStop(obj->base, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 439 | } |
AnnaBridge | 188:bcfe06ba3d64 | 440 | |
AnnaBridge | 188:bcfe06ba3d64 | 441 | if (status != CY_SCB_I2C_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 442 | Cy_SCB_I2C_MasterSendStop(obj->base, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 443 | byte_count = i2c_convert_status(status); |
AnnaBridge | 188:bcfe06ba3d64 | 444 | } |
AnnaBridge | 188:bcfe06ba3d64 | 445 | |
AnnaBridge | 188:bcfe06ba3d64 | 446 | return byte_count; |
AnnaBridge | 188:bcfe06ba3d64 | 447 | } |
AnnaBridge | 188:bcfe06ba3d64 | 448 | |
AnnaBridge | 188:bcfe06ba3d64 | 449 | void i2c_reset(i2c_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 450 | { |
AnnaBridge | 189:f392fc9709a3 | 451 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 452 | |
AnnaBridge | 189:f392fc9709a3 | 453 | /* Back block into default state */ |
AnnaBridge | 189:f392fc9709a3 | 454 | Cy_SCB_FwBlockReset(obj->base); |
AnnaBridge | 189:f392fc9709a3 | 455 | obj->context.state = CY_SCB_I2C_IDLE; |
AnnaBridge | 188:bcfe06ba3d64 | 456 | } |
AnnaBridge | 188:bcfe06ba3d64 | 457 | |
AnnaBridge | 188:bcfe06ba3d64 | 458 | int i2c_byte_read(i2c_t *obj_in, int last) |
AnnaBridge | 188:bcfe06ba3d64 | 459 | { |
AnnaBridge | 188:bcfe06ba3d64 | 460 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 461 | uint8_t tmp_byte = 0; |
AnnaBridge | 189:f392fc9709a3 | 462 | cy_en_scb_i2c_command_t ack = last ? CY_SCB_I2C_NAK : CY_SCB_I2C_ACK; |
AnnaBridge | 189:f392fc9709a3 | 463 | |
AnnaBridge | 189:f392fc9709a3 | 464 | /* i2c_start and i2c_byte_write was called. Update state to receive data */ |
AnnaBridge | 189:f392fc9709a3 | 465 | if (CY_SCB_I2C_MASTER_TX == obj->context.state) { |
AnnaBridge | 189:f392fc9709a3 | 466 | obj->context.state = CY_SCB_I2C_MASTER_RX0; |
AnnaBridge | 189:f392fc9709a3 | 467 | } |
AnnaBridge | 189:f392fc9709a3 | 468 | |
AnnaBridge | 188:bcfe06ba3d64 | 469 | cy_en_scb_i2c_status_t status = Cy_SCB_I2C_MasterReadByte(obj->base, ack, &tmp_byte, obj->timeout, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 470 | |
AnnaBridge | 188:bcfe06ba3d64 | 471 | if (status == CY_SCB_I2C_SUCCESS) { |
AnnaBridge | 188:bcfe06ba3d64 | 472 | return tmp_byte; |
AnnaBridge | 188:bcfe06ba3d64 | 473 | } else { |
AnnaBridge | 189:f392fc9709a3 | 474 | return (-1); |
AnnaBridge | 188:bcfe06ba3d64 | 475 | } |
AnnaBridge | 188:bcfe06ba3d64 | 476 | } |
AnnaBridge | 188:bcfe06ba3d64 | 477 | |
AnnaBridge | 188:bcfe06ba3d64 | 478 | int i2c_byte_write(i2c_t *obj_in, int data) |
AnnaBridge | 188:bcfe06ba3d64 | 479 | { |
AnnaBridge | 188:bcfe06ba3d64 | 480 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 481 | |
AnnaBridge | 189:f392fc9709a3 | 482 | /* i2c_start was called update state to receive data */ |
AnnaBridge | 189:f392fc9709a3 | 483 | if (CY_SCB_I2C_MASTER_ADDR == obj->context.state) { |
AnnaBridge | 189:f392fc9709a3 | 484 | obj->context.state = CY_SCB_I2C_MASTER_TX; |
AnnaBridge | 189:f392fc9709a3 | 485 | } |
AnnaBridge | 189:f392fc9709a3 | 486 | |
AnnaBridge | 188:bcfe06ba3d64 | 487 | cy_en_scb_i2c_status_t status = Cy_SCB_I2C_MasterWriteByte(obj->base, (uint8_t)data, obj->timeout, &obj->context); |
AnnaBridge | 189:f392fc9709a3 | 488 | |
AnnaBridge | 188:bcfe06ba3d64 | 489 | switch (status) { |
AnnaBridge | 188:bcfe06ba3d64 | 490 | case CY_SCB_I2C_MASTER_MANUAL_TIMEOUT: |
AnnaBridge | 188:bcfe06ba3d64 | 491 | return 2; |
AnnaBridge | 188:bcfe06ba3d64 | 492 | case CY_SCB_I2C_MASTER_MANUAL_ADDR_NAK: |
AnnaBridge | 188:bcfe06ba3d64 | 493 | case CY_SCB_I2C_MASTER_MANUAL_NAK: |
AnnaBridge | 188:bcfe06ba3d64 | 494 | return 0; |
AnnaBridge | 188:bcfe06ba3d64 | 495 | case CY_SCB_I2C_SUCCESS: |
AnnaBridge | 188:bcfe06ba3d64 | 496 | return 1; |
AnnaBridge | 188:bcfe06ba3d64 | 497 | default: |
AnnaBridge | 189:f392fc9709a3 | 498 | /* Error has occurred */ |
AnnaBridge | 188:bcfe06ba3d64 | 499 | return (-1); |
AnnaBridge | 188:bcfe06ba3d64 | 500 | } |
AnnaBridge | 188:bcfe06ba3d64 | 501 | } |
AnnaBridge | 188:bcfe06ba3d64 | 502 | |
AnnaBridge | 188:bcfe06ba3d64 | 503 | #if DEVICE_I2C_ASYNCH |
AnnaBridge | 188:bcfe06ba3d64 | 504 | |
AnnaBridge | 188:bcfe06ba3d64 | 505 | void i2c_transfer_asynch(i2c_t *obj_in, |
AnnaBridge | 188:bcfe06ba3d64 | 506 | const void *tx, |
AnnaBridge | 188:bcfe06ba3d64 | 507 | size_t tx_length, |
AnnaBridge | 188:bcfe06ba3d64 | 508 | void *rx, size_t rx_length, |
AnnaBridge | 188:bcfe06ba3d64 | 509 | uint32_t address, |
AnnaBridge | 188:bcfe06ba3d64 | 510 | uint32_t stop, |
AnnaBridge | 188:bcfe06ba3d64 | 511 | uint32_t handler, |
AnnaBridge | 188:bcfe06ba3d64 | 512 | uint32_t event, |
AnnaBridge | 188:bcfe06ba3d64 | 513 | DMAUsage hint) |
AnnaBridge | 188:bcfe06ba3d64 | 514 | { |
AnnaBridge | 188:bcfe06ba3d64 | 515 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 516 | |
AnnaBridge | 188:bcfe06ba3d64 | 517 | (void)hint; // At the moment we do not support DMA transfers, so this parameter gets ignored. |
AnnaBridge | 188:bcfe06ba3d64 | 518 | |
AnnaBridge | 188:bcfe06ba3d64 | 519 | if (obj->pending != PENDING_NONE) { |
AnnaBridge | 188:bcfe06ba3d64 | 520 | return; |
AnnaBridge | 188:bcfe06ba3d64 | 521 | } |
AnnaBridge | 188:bcfe06ba3d64 | 522 | |
AnnaBridge | 188:bcfe06ba3d64 | 523 | obj->rx_config.slaveAddress = address >> 1; |
AnnaBridge | 188:bcfe06ba3d64 | 524 | obj->tx_config.slaveAddress = address >> 1; |
AnnaBridge | 188:bcfe06ba3d64 | 525 | obj->events = event; |
AnnaBridge | 188:bcfe06ba3d64 | 526 | obj->handler = handler; |
AnnaBridge | 188:bcfe06ba3d64 | 527 | if (i2c_irq_setup_channel(obj) < 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 528 | return; |
AnnaBridge | 188:bcfe06ba3d64 | 529 | } |
AnnaBridge | 188:bcfe06ba3d64 | 530 | |
AnnaBridge | 188:bcfe06ba3d64 | 531 | obj->rx_config.buffer = rx; |
AnnaBridge | 188:bcfe06ba3d64 | 532 | obj->rx_config.bufferSize = rx_length; |
AnnaBridge | 188:bcfe06ba3d64 | 533 | obj->rx_config.xferPending = !stop; |
AnnaBridge | 188:bcfe06ba3d64 | 534 | |
AnnaBridge | 189:f392fc9709a3 | 535 | obj->tx_config.buffer = (void *)tx; |
AnnaBridge | 188:bcfe06ba3d64 | 536 | obj->tx_config.bufferSize = tx_length; |
AnnaBridge | 188:bcfe06ba3d64 | 537 | obj->tx_config.xferPending = rx_length || !stop; |
AnnaBridge | 188:bcfe06ba3d64 | 538 | |
AnnaBridge | 188:bcfe06ba3d64 | 539 | if (tx_length) { |
AnnaBridge | 188:bcfe06ba3d64 | 540 | // Write first, then read, or write only. |
AnnaBridge | 188:bcfe06ba3d64 | 541 | if (rx_length > 0) { |
AnnaBridge | 188:bcfe06ba3d64 | 542 | obj->pending = PENDING_TX_RX; |
AnnaBridge | 188:bcfe06ba3d64 | 543 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 544 | obj->pending = PENDING_TX; |
AnnaBridge | 188:bcfe06ba3d64 | 545 | } |
AnnaBridge | 188:bcfe06ba3d64 | 546 | Cy_SCB_I2C_MasterWrite(obj->base, &obj->tx_config, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 547 | } else if (rx_length) { |
AnnaBridge | 188:bcfe06ba3d64 | 548 | // Read transaction; |
AnnaBridge | 188:bcfe06ba3d64 | 549 | obj->pending = PENDING_RX; |
AnnaBridge | 188:bcfe06ba3d64 | 550 | Cy_SCB_I2C_MasterRead(obj->base, &obj->rx_config, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 551 | } |
AnnaBridge | 188:bcfe06ba3d64 | 552 | } |
AnnaBridge | 188:bcfe06ba3d64 | 553 | |
AnnaBridge | 189:f392fc9709a3 | 554 | |
AnnaBridge | 189:f392fc9709a3 | 555 | static void i2c_gen_stop(i2c_t *obj_in) |
AnnaBridge | 189:f392fc9709a3 | 556 | { |
AnnaBridge | 189:f392fc9709a3 | 557 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 558 | |
AnnaBridge | 189:f392fc9709a3 | 559 | // Enable master interrupts and generate Stop |
AnnaBridge | 189:f392fc9709a3 | 560 | Cy_SCB_SetMasterInterruptMask(obj->base, CY_SCB_I2C_MASTER_INTR); |
AnnaBridge | 189:f392fc9709a3 | 561 | SCB_I2C_M_CMD(obj->base) = (SCB_I2C_M_CMD_M_STOP_Msk | SCB_I2C_M_CMD_M_NACK_Msk); |
AnnaBridge | 189:f392fc9709a3 | 562 | } |
AnnaBridge | 189:f392fc9709a3 | 563 | |
AnnaBridge | 189:f392fc9709a3 | 564 | |
AnnaBridge | 188:bcfe06ba3d64 | 565 | uint32_t i2c_irq_handler_asynch(i2c_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 566 | { |
AnnaBridge | 188:bcfe06ba3d64 | 567 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 568 | uint32_t event = 0; |
AnnaBridge | 188:bcfe06ba3d64 | 569 | // Process actual interrupt. |
AnnaBridge | 188:bcfe06ba3d64 | 570 | Cy_SCB_I2C_Interrupt(obj->base, &obj->context); |
AnnaBridge | 189:f392fc9709a3 | 571 | |
AnnaBridge | 189:f392fc9709a3 | 572 | if (false == (CY_SCB_I2C_MASTER_BUSY & obj->context.masterStatus)) { |
AnnaBridge | 189:f392fc9709a3 | 573 | // Transfer was completed |
AnnaBridge | 189:f392fc9709a3 | 574 | event = I2C_EVENT_TRANSFER_COMPLETE; |
AnnaBridge | 189:f392fc9709a3 | 575 | |
AnnaBridge | 189:f392fc9709a3 | 576 | // Parse results of single transfer |
AnnaBridge | 189:f392fc9709a3 | 577 | if (CY_SCB_I2C_MASTER_ERR & obj->context.masterStatus) { |
AnnaBridge | 189:f392fc9709a3 | 578 | if (CY_SCB_I2C_MASTER_ADDR_NAK & obj->context.masterStatus) { |
AnnaBridge | 189:f392fc9709a3 | 579 | event |= I2C_EVENT_ERROR_NO_SLAVE; |
AnnaBridge | 189:f392fc9709a3 | 580 | } else if (CY_SCB_I2C_MASTER_DATA_NAK & obj->context.masterStatus) { |
AnnaBridge | 189:f392fc9709a3 | 581 | event |= I2C_EVENT_TRANSFER_EARLY_NACK; |
AnnaBridge | 188:bcfe06ba3d64 | 582 | } else { |
AnnaBridge | 189:f392fc9709a3 | 583 | // CY_SCB_I2C_MASTER_ARB_LOST || CY_SCB_I2C_MASTER_BUS_ERR || CY_SCB_I2C_MASTER_ABORT_START |
AnnaBridge | 189:f392fc9709a3 | 584 | event |= I2C_EVENT_ERROR; |
AnnaBridge | 189:f392fc9709a3 | 585 | } |
AnnaBridge | 189:f392fc9709a3 | 586 | } |
AnnaBridge | 189:f392fc9709a3 | 587 | |
AnnaBridge | 189:f392fc9709a3 | 588 | // Check if a read phase is pending after write. |
AnnaBridge | 189:f392fc9709a3 | 589 | if (obj->pending == PENDING_TX_RX) { |
AnnaBridge | 189:f392fc9709a3 | 590 | obj->pending = PENDING_RX; |
AnnaBridge | 189:f392fc9709a3 | 591 | |
AnnaBridge | 189:f392fc9709a3 | 592 | if (event == I2C_EVENT_TRANSFER_COMPLETE) { |
AnnaBridge | 189:f392fc9709a3 | 593 | // Send ReStart and continue with RX transfer |
AnnaBridge | 189:f392fc9709a3 | 594 | event = 0; |
AnnaBridge | 189:f392fc9709a3 | 595 | Cy_SCB_I2C_MasterRead(obj->base, &obj->rx_config, &obj->context); |
AnnaBridge | 189:f392fc9709a3 | 596 | } else { |
AnnaBridge | 189:f392fc9709a3 | 597 | // NACK - generate Stop (do not execute RX transfer) |
AnnaBridge | 189:f392fc9709a3 | 598 | // Error - do not execute RX transfer and report transfer complete |
AnnaBridge | 189:f392fc9709a3 | 599 | if (false == (event & I2C_EVENT_ERROR)) { |
AnnaBridge | 189:f392fc9709a3 | 600 | // Report events after Stop generation |
AnnaBridge | 189:f392fc9709a3 | 601 | event = 0; |
AnnaBridge | 189:f392fc9709a3 | 602 | obj->context.state = CY_SCB_I2C_MASTER_WAIT_STOP; |
AnnaBridge | 189:f392fc9709a3 | 603 | obj->context.masterPause = false; |
AnnaBridge | 189:f392fc9709a3 | 604 | |
AnnaBridge | 189:f392fc9709a3 | 605 | i2c_gen_stop(obj_in); |
AnnaBridge | 189:f392fc9709a3 | 606 | } |
AnnaBridge | 188:bcfe06ba3d64 | 607 | } |
AnnaBridge | 188:bcfe06ba3d64 | 608 | } else { |
AnnaBridge | 189:f392fc9709a3 | 609 | obj->pending = PENDING_NONE; |
AnnaBridge | 188:bcfe06ba3d64 | 610 | } |
AnnaBridge | 188:bcfe06ba3d64 | 611 | } |
AnnaBridge | 189:f392fc9709a3 | 612 | |
AnnaBridge | 189:f392fc9709a3 | 613 | return (event & obj->events); |
AnnaBridge | 188:bcfe06ba3d64 | 614 | } |
AnnaBridge | 188:bcfe06ba3d64 | 615 | |
AnnaBridge | 188:bcfe06ba3d64 | 616 | uint8_t i2c_active(i2c_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 617 | { |
AnnaBridge | 188:bcfe06ba3d64 | 618 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 619 | return (obj->pending != PENDING_NONE); |
AnnaBridge | 188:bcfe06ba3d64 | 620 | } |
AnnaBridge | 188:bcfe06ba3d64 | 621 | |
AnnaBridge | 188:bcfe06ba3d64 | 622 | void i2c_abort_asynch(i2c_t *obj_in) |
AnnaBridge | 188:bcfe06ba3d64 | 623 | { |
AnnaBridge | 188:bcfe06ba3d64 | 624 | i2c_obj_t *obj = OBJ_P(obj_in); |
AnnaBridge | 188:bcfe06ba3d64 | 625 | if (obj->pending != PENDING_NONE) { |
AnnaBridge | 188:bcfe06ba3d64 | 626 | if (obj->pending == PENDING_RX) { |
AnnaBridge | 188:bcfe06ba3d64 | 627 | Cy_SCB_I2C_MasterAbortRead(obj->base, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 628 | } else { |
AnnaBridge | 188:bcfe06ba3d64 | 629 | Cy_SCB_I2C_MasterAbortWrite(obj->base, &obj->context); |
AnnaBridge | 188:bcfe06ba3d64 | 630 | } |
AnnaBridge | 188:bcfe06ba3d64 | 631 | } |
AnnaBridge | 188:bcfe06ba3d64 | 632 | } |
AnnaBridge | 188:bcfe06ba3d64 | 633 | |
AnnaBridge | 188:bcfe06ba3d64 | 634 | #endif // DEVICE_ASYNCH |