Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of mbed-src by
targets/hal/TARGET_NXP/TARGET_LPC15XX/i2c_api.c@641:be9b2017785a, 2016-07-13 (annotated)
- Committer:
- LancasterUniversity
- Date:
- Wed Jul 13 12:52:54 2016 +0100
- Revision:
- 641:be9b2017785a
- Parent:
- 257:9258cc0a200d
Synchronized with git rev 1fb8ab4c
Author: James Devine
mbed-classic: BUGFIX for timer when using wait_ms from interrupt context
Previously if a user used wait[_ms,_us] in interrupt context the device would
hang indefinitely. This was due to incrementing overflowCount from
interrupt context only.
This meant that if a user used wait[_ms,_us] in an ISR with
the same or greater interrupt priority, it would result in an infinite
loop as the overflowCount variable would never be incremented, and
wait[_ms,_us] would never return.
This patch simply applies a better solution for the race condition
mentioned in the previous commit. It instead disables the timer1
interrupt and increments the overflowCount variable, preventing
the race condition whilst supporting wait[_ms,_us] in interrupt
context.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mbed_official | 103:9b881da47c92 | 1 | /* mbed Microcontroller Library |
mbed_official | 103:9b881da47c92 | 2 | * Copyright (c) 2006-2013 ARM Limited |
mbed_official | 103:9b881da47c92 | 3 | * |
mbed_official | 103:9b881da47c92 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
mbed_official | 103:9b881da47c92 | 5 | * you may not use this file except in compliance with the License. |
mbed_official | 103:9b881da47c92 | 6 | * You may obtain a copy of the License at |
mbed_official | 103:9b881da47c92 | 7 | * |
mbed_official | 103:9b881da47c92 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
mbed_official | 103:9b881da47c92 | 9 | * |
mbed_official | 103:9b881da47c92 | 10 | * Unless required by applicable law or agreed to in writing, software |
mbed_official | 103:9b881da47c92 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
mbed_official | 103:9b881da47c92 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
mbed_official | 103:9b881da47c92 | 13 | * See the License for the specific language governing permissions and |
mbed_official | 103:9b881da47c92 | 14 | * limitations under the License. |
mbed_official | 103:9b881da47c92 | 15 | */ |
mbed_official | 227:7bd0639b8911 | 16 | #include "mbed_assert.h" |
mbed_official | 103:9b881da47c92 | 17 | #include "i2c_api.h" |
mbed_official | 103:9b881da47c92 | 18 | #include "cmsis.h" |
mbed_official | 103:9b881da47c92 | 19 | #include "pinmap.h" |
mbed_official | 103:9b881da47c92 | 20 | |
mbed_official | 103:9b881da47c92 | 21 | static uint8_t repeated_start = 0; |
mbed_official | 103:9b881da47c92 | 22 | |
mbed_official | 103:9b881da47c92 | 23 | #define I2C_STAT(x) ((LPC_I2C0->STAT >> 1) & (0x07)) |
mbed_official | 103:9b881da47c92 | 24 | |
mbed_official | 103:9b881da47c92 | 25 | static inline int i2c_status(i2c_t *obj) { |
mbed_official | 103:9b881da47c92 | 26 | return I2C_STAT(obj); |
mbed_official | 103:9b881da47c92 | 27 | } |
mbed_official | 103:9b881da47c92 | 28 | |
mbed_official | 103:9b881da47c92 | 29 | // Wait until the Serial Interrupt (SI) is set |
mbed_official | 103:9b881da47c92 | 30 | static int i2c_wait_SI(i2c_t *obj) { |
mbed_official | 117:e0a7df0a9a56 | 31 | volatile int timeout = 0; |
mbed_official | 103:9b881da47c92 | 32 | while (!(LPC_I2C0->STAT & (1 << 0))) { |
mbed_official | 103:9b881da47c92 | 33 | timeout++; |
mbed_official | 103:9b881da47c92 | 34 | if (timeout > 100000) return -1; |
mbed_official | 103:9b881da47c92 | 35 | } |
mbed_official | 103:9b881da47c92 | 36 | return 0; |
mbed_official | 103:9b881da47c92 | 37 | } |
mbed_official | 103:9b881da47c92 | 38 | |
mbed_official | 103:9b881da47c92 | 39 | static inline void i2c_interface_enable(i2c_t *obj) { |
mbed_official | 103:9b881da47c92 | 40 | LPC_I2C0->CFG |= (1 << 0); |
mbed_official | 103:9b881da47c92 | 41 | } |
mbed_official | 103:9b881da47c92 | 42 | |
mbed_official | 117:e0a7df0a9a56 | 43 | void i2c_init(i2c_t *obj, PinName sda, PinName scl) { |
mbed_official | 257:9258cc0a200d | 44 | MBED_ASSERT((sda == P0_23) && (scl == P0_22)); |
mbed_official | 117:e0a7df0a9a56 | 45 | |
mbed_official | 103:9b881da47c92 | 46 | // Enables clock for I2C0 |
mbed_official | 117:e0a7df0a9a56 | 47 | LPC_SYSCON->SYSAHBCLKCTRL1 |= (1 << 13); |
mbed_official | 103:9b881da47c92 | 48 | |
mbed_official | 117:e0a7df0a9a56 | 49 | LPC_SYSCON->PRESETCTRL1 |= (1 << 13); |
mbed_official | 117:e0a7df0a9a56 | 50 | LPC_SYSCON->PRESETCTRL1 &= ~(1 << 13); |
mbed_official | 103:9b881da47c92 | 51 | |
mbed_official | 103:9b881da47c92 | 52 | // pin enable |
mbed_official | 103:9b881da47c92 | 53 | LPC_SWM->PINENABLE1 &= ~(0x3 << 3); |
mbed_official | 117:e0a7df0a9a56 | 54 | |
mbed_official | 117:e0a7df0a9a56 | 55 | // set default frequency at 100kHz |
mbed_official | 103:9b881da47c92 | 56 | i2c_frequency(obj, 100000); |
mbed_official | 103:9b881da47c92 | 57 | i2c_interface_enable(obj); |
mbed_official | 103:9b881da47c92 | 58 | } |
mbed_official | 103:9b881da47c92 | 59 | |
mbed_official | 103:9b881da47c92 | 60 | inline int i2c_start(i2c_t *obj) { |
mbed_official | 103:9b881da47c92 | 61 | int status = 0; |
mbed_official | 103:9b881da47c92 | 62 | if (repeated_start) { |
mbed_official | 103:9b881da47c92 | 63 | LPC_I2C0->MSTCTL = (1 << 1) | (1 << 0); |
mbed_official | 103:9b881da47c92 | 64 | repeated_start = 0; |
mbed_official | 103:9b881da47c92 | 65 | } else { |
mbed_official | 103:9b881da47c92 | 66 | LPC_I2C0->MSTCTL = (1 << 1); |
mbed_official | 103:9b881da47c92 | 67 | } |
mbed_official | 103:9b881da47c92 | 68 | return status; |
mbed_official | 103:9b881da47c92 | 69 | } |
mbed_official | 103:9b881da47c92 | 70 | |
mbed_official | 103:9b881da47c92 | 71 | inline int i2c_stop(i2c_t *obj) { |
mbed_official | 117:e0a7df0a9a56 | 72 | volatile int timeout = 0; |
mbed_official | 103:9b881da47c92 | 73 | |
mbed_official | 103:9b881da47c92 | 74 | LPC_I2C0->MSTCTL = (1 << 2) | (1 << 0); |
mbed_official | 103:9b881da47c92 | 75 | while ((LPC_I2C0->STAT & ((1 << 0) | (7 << 1))) != ((1 << 0) | (0 << 1))) { |
mbed_official | 103:9b881da47c92 | 76 | timeout ++; |
mbed_official | 103:9b881da47c92 | 77 | if (timeout > 100000) return 1; |
mbed_official | 103:9b881da47c92 | 78 | } |
mbed_official | 103:9b881da47c92 | 79 | |
mbed_official | 103:9b881da47c92 | 80 | return 0; |
mbed_official | 103:9b881da47c92 | 81 | } |
mbed_official | 103:9b881da47c92 | 82 | |
mbed_official | 103:9b881da47c92 | 83 | |
mbed_official | 103:9b881da47c92 | 84 | static inline int i2c_do_write(i2c_t *obj, int value, uint8_t addr) { |
mbed_official | 103:9b881da47c92 | 85 | // write the data |
mbed_official | 103:9b881da47c92 | 86 | LPC_I2C0->MSTDAT = value; |
mbed_official | 103:9b881da47c92 | 87 | |
mbed_official | 103:9b881da47c92 | 88 | if (!addr) |
mbed_official | 103:9b881da47c92 | 89 | LPC_I2C0->MSTCTL = (1 << 0); |
mbed_official | 103:9b881da47c92 | 90 | |
mbed_official | 103:9b881da47c92 | 91 | // wait and return status |
mbed_official | 103:9b881da47c92 | 92 | i2c_wait_SI(obj); |
mbed_official | 103:9b881da47c92 | 93 | return i2c_status(obj); |
mbed_official | 103:9b881da47c92 | 94 | } |
mbed_official | 103:9b881da47c92 | 95 | |
mbed_official | 103:9b881da47c92 | 96 | static inline int i2c_do_read(i2c_t *obj, int last) { |
mbed_official | 103:9b881da47c92 | 97 | // wait for it to arrive |
mbed_official | 103:9b881da47c92 | 98 | i2c_wait_SI(obj); |
mbed_official | 103:9b881da47c92 | 99 | if (!last) |
mbed_official | 103:9b881da47c92 | 100 | LPC_I2C0->MSTCTL = (1 << 0); |
mbed_official | 103:9b881da47c92 | 101 | |
mbed_official | 103:9b881da47c92 | 102 | // return the data |
mbed_official | 103:9b881da47c92 | 103 | return (LPC_I2C0->MSTDAT & 0xFF); |
mbed_official | 103:9b881da47c92 | 104 | } |
mbed_official | 103:9b881da47c92 | 105 | |
mbed_official | 103:9b881da47c92 | 106 | void i2c_frequency(i2c_t *obj, int hz) { |
mbed_official | 103:9b881da47c92 | 107 | // No peripheral clock divider on the M0 |
mbed_official | 103:9b881da47c92 | 108 | uint32_t PCLK = SystemCoreClock; |
mbed_official | 103:9b881da47c92 | 109 | uint32_t clkdiv = PCLK / (hz * 4) - 1; |
mbed_official | 103:9b881da47c92 | 110 | |
mbed_official | 103:9b881da47c92 | 111 | LPC_I2C0->DIV = clkdiv; |
mbed_official | 103:9b881da47c92 | 112 | LPC_I2C0->MSTTIME = 0; |
mbed_official | 103:9b881da47c92 | 113 | } |
mbed_official | 103:9b881da47c92 | 114 | |
mbed_official | 103:9b881da47c92 | 115 | int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { |
mbed_official | 103:9b881da47c92 | 116 | int count, status; |
mbed_official | 103:9b881da47c92 | 117 | |
mbed_official | 103:9b881da47c92 | 118 | i2c_start(obj); |
mbed_official | 103:9b881da47c92 | 119 | |
mbed_official | 103:9b881da47c92 | 120 | LPC_I2C0->MSTDAT = (address | 0x01); |
mbed_official | 103:9b881da47c92 | 121 | LPC_I2C0->MSTCTL |= 0x20; |
mbed_official | 117:e0a7df0a9a56 | 122 | if (i2c_wait_SI(obj) == -1) |
mbed_official | 117:e0a7df0a9a56 | 123 | return -1; |
mbed_official | 117:e0a7df0a9a56 | 124 | |
mbed_official | 103:9b881da47c92 | 125 | status = ((LPC_I2C0->STAT >> 1) & (0x07)); |
mbed_official | 103:9b881da47c92 | 126 | if (status != 0x01) { |
mbed_official | 103:9b881da47c92 | 127 | i2c_stop(obj); |
mbed_official | 103:9b881da47c92 | 128 | return I2C_ERROR_NO_SLAVE; |
mbed_official | 103:9b881da47c92 | 129 | } |
mbed_official | 103:9b881da47c92 | 130 | |
mbed_official | 103:9b881da47c92 | 131 | // Read in all except last byte |
mbed_official | 103:9b881da47c92 | 132 | for (count = 0; count < (length - 1); count++) { |
mbed_official | 117:e0a7df0a9a56 | 133 | if (i2c_wait_SI(obj) == -1) |
mbed_official | 117:e0a7df0a9a56 | 134 | return -1; |
mbed_official | 117:e0a7df0a9a56 | 135 | LPC_I2C0->MSTCTL = (1 << 0); |
mbed_official | 117:e0a7df0a9a56 | 136 | data[count] = (LPC_I2C0->MSTDAT & 0xFF); |
mbed_official | 117:e0a7df0a9a56 | 137 | status = ((LPC_I2C0->STAT >> 1) & (0x07)); |
mbed_official | 182:242346c42295 | 138 | if (status != 0x01) { |
mbed_official | 103:9b881da47c92 | 139 | i2c_stop(obj); |
mbed_official | 103:9b881da47c92 | 140 | return count; |
mbed_official | 103:9b881da47c92 | 141 | } |
mbed_official | 103:9b881da47c92 | 142 | } |
mbed_official | 103:9b881da47c92 | 143 | |
mbed_official | 103:9b881da47c92 | 144 | // read in last byte |
mbed_official | 117:e0a7df0a9a56 | 145 | if (i2c_wait_SI(obj) == -1) |
mbed_official | 117:e0a7df0a9a56 | 146 | return -1; |
mbed_official | 117:e0a7df0a9a56 | 147 | |
mbed_official | 103:9b881da47c92 | 148 | data[count] = (LPC_I2C0->MSTDAT & 0xFF); |
mbed_official | 103:9b881da47c92 | 149 | status = i2c_status(obj); |
mbed_official | 103:9b881da47c92 | 150 | if (status != 0x01) { |
mbed_official | 103:9b881da47c92 | 151 | i2c_stop(obj); |
mbed_official | 103:9b881da47c92 | 152 | return length - 1; |
mbed_official | 103:9b881da47c92 | 153 | } |
mbed_official | 103:9b881da47c92 | 154 | // If not repeated start, send stop. |
mbed_official | 103:9b881da47c92 | 155 | if (stop) { |
mbed_official | 103:9b881da47c92 | 156 | i2c_stop(obj); |
mbed_official | 103:9b881da47c92 | 157 | } else { |
mbed_official | 103:9b881da47c92 | 158 | repeated_start = 1; |
mbed_official | 103:9b881da47c92 | 159 | } |
mbed_official | 103:9b881da47c92 | 160 | |
mbed_official | 103:9b881da47c92 | 161 | return length; |
mbed_official | 103:9b881da47c92 | 162 | } |
mbed_official | 103:9b881da47c92 | 163 | |
mbed_official | 103:9b881da47c92 | 164 | int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { |
mbed_official | 103:9b881da47c92 | 165 | int i, status; |
mbed_official | 103:9b881da47c92 | 166 | |
mbed_official | 103:9b881da47c92 | 167 | i2c_start(obj); |
mbed_official | 103:9b881da47c92 | 168 | |
mbed_official | 103:9b881da47c92 | 169 | LPC_I2C0->MSTDAT = (address & 0xFE); |
mbed_official | 103:9b881da47c92 | 170 | LPC_I2C0->MSTCTL |= 0x20; |
mbed_official | 117:e0a7df0a9a56 | 171 | if (i2c_wait_SI(obj) == -1) |
mbed_official | 117:e0a7df0a9a56 | 172 | return -1; |
mbed_official | 117:e0a7df0a9a56 | 173 | |
mbed_official | 103:9b881da47c92 | 174 | status = ((LPC_I2C0->STAT >> 1) & (0x07)); |
mbed_official | 103:9b881da47c92 | 175 | if (status != 0x02) { |
mbed_official | 103:9b881da47c92 | 176 | i2c_stop(obj); |
mbed_official | 103:9b881da47c92 | 177 | return I2C_ERROR_NO_SLAVE; |
mbed_official | 103:9b881da47c92 | 178 | } |
mbed_official | 103:9b881da47c92 | 179 | |
mbed_official | 103:9b881da47c92 | 180 | for (i=0; i<length; i++) { |
mbed_official | 103:9b881da47c92 | 181 | LPC_I2C0->MSTDAT = data[i]; |
mbed_official | 103:9b881da47c92 | 182 | LPC_I2C0->MSTCTL = (1 << 0); |
mbed_official | 117:e0a7df0a9a56 | 183 | if (i2c_wait_SI(obj) == -1) |
mbed_official | 117:e0a7df0a9a56 | 184 | return -1; |
mbed_official | 117:e0a7df0a9a56 | 185 | |
mbed_official | 117:e0a7df0a9a56 | 186 | status = ((LPC_I2C0->STAT >> 1) & (0x07)); |
mbed_official | 103:9b881da47c92 | 187 | if (status != 0x02) { |
mbed_official | 103:9b881da47c92 | 188 | i2c_stop(obj); |
mbed_official | 103:9b881da47c92 | 189 | return i; |
mbed_official | 103:9b881da47c92 | 190 | } |
mbed_official | 103:9b881da47c92 | 191 | } |
mbed_official | 103:9b881da47c92 | 192 | |
mbed_official | 103:9b881da47c92 | 193 | // If not repeated start, send stop. |
mbed_official | 103:9b881da47c92 | 194 | if (stop) { |
mbed_official | 103:9b881da47c92 | 195 | i2c_stop(obj); |
mbed_official | 103:9b881da47c92 | 196 | } else { |
mbed_official | 103:9b881da47c92 | 197 | repeated_start = 1; |
mbed_official | 103:9b881da47c92 | 198 | } |
mbed_official | 103:9b881da47c92 | 199 | |
mbed_official | 103:9b881da47c92 | 200 | return length; |
mbed_official | 103:9b881da47c92 | 201 | } |
mbed_official | 103:9b881da47c92 | 202 | |
mbed_official | 103:9b881da47c92 | 203 | void i2c_reset(i2c_t *obj) { |
mbed_official | 103:9b881da47c92 | 204 | i2c_stop(obj); |
mbed_official | 103:9b881da47c92 | 205 | } |
mbed_official | 103:9b881da47c92 | 206 | |
mbed_official | 103:9b881da47c92 | 207 | int i2c_byte_read(i2c_t *obj, int last) { |
mbed_official | 103:9b881da47c92 | 208 | return (i2c_do_read(obj, last) & 0xFF); |
mbed_official | 103:9b881da47c92 | 209 | } |
mbed_official | 103:9b881da47c92 | 210 | |
mbed_official | 103:9b881da47c92 | 211 | int i2c_byte_write(i2c_t *obj, int data) { |
mbed_official | 117:e0a7df0a9a56 | 212 | if (i2c_do_write(obj, (data & 0xFF), 0) == 2) { |
mbed_official | 117:e0a7df0a9a56 | 213 | return 1; |
mbed_official | 117:e0a7df0a9a56 | 214 | } else { |
mbed_official | 117:e0a7df0a9a56 | 215 | return 0; |
mbed_official | 103:9b881da47c92 | 216 | } |
mbed_official | 103:9b881da47c92 | 217 | } |