blob: a7dcdfdd815e7f0c55f307effd42496aeb6b5f86 [file] [log] [blame]
Christina Quast8be71e42014-12-02 13:06:01 +01001/* ----------------------------------------------------------------------------
2 * ATMEL Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2009, Atmel Corporation
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the disclaimer below.
13 *
14 * Atmel's name may not be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * ----------------------------------------------------------------------------
28 */
29
30
31/*----------------------------------------------------------------------------
32 * Headers
33 *----------------------------------------------------------------------------*/
34#include "chip.h"
35
36#include <assert.h>
37
38/*----------------------------------------------------------------------------
39 * Definition
40 *----------------------------------------------------------------------------*/
41#define TWITIMEOUTMAX 50000
42
43/*----------------------------------------------------------------------------
44 * Types
45 *----------------------------------------------------------------------------*/
46
47/** TWI driver callback function.*/
48typedef void (*TwiCallback)(Async *);
49
50/** \brief TWI asynchronous transfer descriptor.*/
51typedef struct _AsyncTwi {
52
53 /** Asynchronous transfer status. */
54 volatile uint8_t status;
55 // Callback function to invoke when transfer completes or fails.*/
56 TwiCallback callback;
57 /** Pointer to the data buffer.*/
58 uint8_t *pData;
59 /** Total number of bytes to transfer.*/
60 uint32_t num;
61 /** Number of already transferred bytes.*/
62 uint32_t transferred;
63
64} AsyncTwi;
65
66/*----------------------------------------------------------------------------
67 * Global functions
68 *----------------------------------------------------------------------------*/
69/**
70 * \brief Initializes a TWI driver instance, using the given TWI peripheral.
71 * \note The peripheral must have been initialized properly before calling this function.
72 * \param pTwid Pointer to the Twid instance to initialize.
73 * \param pTwi Pointer to the TWI peripheral to use.
74 */
75void TWID_Initialize(Twid *pTwid, Twi *pTwi)
76{
77 TRACE_DEBUG( "TWID_Initialize()\n\r" ) ;
78 assert( pTwid != NULL ) ;
79 assert( pTwi != NULL ) ;
80
81 /* Initialize driver. */
82 pTwid->pTwi = pTwi;
83 pTwid->pTransfer = 0;
84}
85
86
87/**
88 * \brief Interrupt handler for a TWI peripheral. Manages asynchronous transfer
89 * occuring on the bus. This function MUST be called by the interrupt service
90 * routine of the TWI peripheral if asynchronous read/write are needed.
91 * \param pTwid Pointer to a Twid instance.
92 */
93void TWID_Handler( Twid *pTwid )
94{
95 uint8_t status;
96 AsyncTwi *pTransfer ;
97 Twi *pTwi ;
98
99 assert( pTwid != NULL ) ;
100
101 pTransfer = (AsyncTwi*)pTwid->pTransfer ;
102 assert( pTransfer != NULL ) ;
103 pTwi = pTwid->pTwi ;
104 assert( pTwi != NULL ) ;
105
106 /* Retrieve interrupt status */
107 status = TWI_GetMaskedStatus(pTwi);
108
109 /* Byte received */
110 if (TWI_STATUS_RXRDY(status)) {
111
112 pTransfer->pData[pTransfer->transferred] = TWI_ReadByte(pTwi);
113 pTransfer->transferred++;
114
115 /* check for transfer finish */
116 if (pTransfer->transferred == pTransfer->num) {
117
118 TWI_DisableIt(pTwi, TWI_IDR_RXRDY);
119 TWI_EnableIt(pTwi, TWI_IER_TXCOMP);
120 }
121 /* Last byte? */
122 else if (pTransfer->transferred == (pTransfer->num - 1)) {
123
124 TWI_Stop(pTwi);
125 }
126 }
127 /* Byte sent*/
128 else if (TWI_STATUS_TXRDY(status)) {
129
130 /* Transfer finished ? */
131 if (pTransfer->transferred == pTransfer->num) {
132
133 TWI_DisableIt(pTwi, TWI_IDR_TXRDY);
134 TWI_EnableIt(pTwi, TWI_IER_TXCOMP);
135 TWI_SendSTOPCondition(pTwi);
136 }
137 /* Bytes remaining */
138 else {
139
140 TWI_WriteByte(pTwi, pTransfer->pData[pTransfer->transferred]);
141 pTransfer->transferred++;
142 }
143 }
144 /* Transfer complete*/
145 else if (TWI_STATUS_TXCOMP(status)) {
146
147 TWI_DisableIt(pTwi, TWI_IDR_TXCOMP);
148 pTransfer->status = 0;
149 if (pTransfer->callback) {
150
151 pTransfer->callback((Async *) pTransfer);
152 }
153 pTwid->pTransfer = 0;
154 }
155}
156
157/**
158 * \brief Asynchronously reads data from a slave on the TWI bus. An optional
159 * callback function is triggered when the transfer is complete.
160 * \param pTwid Pointer to a Twid instance.
161 * \param address TWI slave address.
162 * \param iaddress Optional slave internal address.
163 * \param isize Internal address size in bytes.
164 * \param pData Data buffer for storing received bytes.
165 * \param num Number of bytes to read.
166 * \param pAsync Asynchronous transfer descriptor.
167 * \return 0 if the transfer has been started; otherwise returns a TWI error code.
168 */
169uint8_t TWID_Read(
170 Twid *pTwid,
171 uint8_t address,
172 uint32_t iaddress,
173 uint8_t isize,
174 uint8_t *pData,
175 uint32_t num,
176 Async *pAsync)
177{
178 Twi *pTwi;
179 AsyncTwi *pTransfer;
180 uint32_t timeout;
181
182 assert( pTwid != NULL ) ;
183 pTwi = pTwid->pTwi;
184 pTransfer = (AsyncTwi *) pTwid->pTransfer;
185
186 assert( (address & 0x80) == 0 ) ;
187 assert( (iaddress & 0xFF000000) == 0 ) ;
188 assert( isize < 4 ) ;
189
190 /* Check that no transfer is already pending*/
191 if (pTransfer) {
192
193 TRACE_ERROR("TWID_Read: A transfer is already pending\n\r");
194 return TWID_ERROR_BUSY;
195 }
196
197 /* Set STOP signal if only one byte is sent*/
198 if (num == 1) {
199
200 TWI_Stop(pTwi);
201 }
202
203 /* Asynchronous transfer*/
204 if (pAsync) {
205
206 /* Update the transfer descriptor */
207 pTwid->pTransfer = pAsync;
208 pTransfer = (AsyncTwi *) pAsync;
209 pTransfer->status = ASYNC_STATUS_PENDING;
210 pTransfer->pData = pData;
211 pTransfer->num = num;
212 pTransfer->transferred = 0;
213
214 /* Enable read interrupt and start the transfer */
215 TWI_EnableIt(pTwi, TWI_IER_RXRDY);
216 TWI_StartRead(pTwi, address, iaddress, isize);
217 }
218 /* Synchronous transfer*/
219 else {
220
221 /* Start read*/
222 TWI_StartRead(pTwi, address, iaddress, isize);
223
224 /* Read all bytes, setting STOP before the last byte*/
225 while (num > 0) {
226
227 /* Last byte ?*/
228 if (num == 1) {
229
230 TWI_Stop(pTwi);
231 }
232
233 /* Wait for byte then read and store it*/
234 timeout = 0;
235 while( !TWI_ByteReceived(pTwi) && (++timeout<TWITIMEOUTMAX) );
236 if (timeout == TWITIMEOUTMAX) {
237 TRACE_ERROR("TWID Timeout BR\n\r");
238 }
239 *pData++ = TWI_ReadByte(pTwi);
240 num--;
241 }
242
243 /* Wait for transfer to be complete */
244 timeout = 0;
245 while( !TWI_TransferComplete(pTwi) && (++timeout<TWITIMEOUTMAX) );
246 if (timeout == TWITIMEOUTMAX) {
247 TRACE_ERROR("TWID Timeout TC\n\r");
248 }
249 }
250
251 return 0;
252}
253
254/**
255 * \brief Asynchronously sends data to a slave on the TWI bus. An optional callback
256 * function is invoked whenever the transfer is complete.
257 * \param pTwid Pointer to a Twid instance.
258 * \param address TWI slave address.
259 * \param iaddress Optional slave internal address.
260 * \param isize Number of internal address bytes.
261 * \param pData Data buffer for storing received bytes.
262 * \param num Data buffer to send.
263 * \param pAsync Asynchronous transfer descriptor.
264 * \return 0 if the transfer has been started; otherwise returns a TWI error code.
265 */
266uint8_t TWID_Write(
267 Twid *pTwid,
268 uint8_t address,
269 uint32_t iaddress,
270 uint8_t isize,
271 uint8_t *pData,
272 uint32_t num,
273 Async *pAsync)
274{
275 Twi *pTwi = pTwid->pTwi;
276 AsyncTwi *pTransfer = (AsyncTwi *) pTwid->pTransfer;
277 uint32_t timeout;
278
279 assert( pTwi != NULL ) ;
280 assert( (address & 0x80) == 0 ) ;
281 assert( (iaddress & 0xFF000000) == 0 ) ;
282 assert( isize < 4 ) ;
283
284 /* Check that no transfer is already pending */
285 if (pTransfer) {
286
287 TRACE_ERROR("TWI_Write: A transfer is already pending\n\r");
288 return TWID_ERROR_BUSY;
289 }
290
291 /* Asynchronous transfer */
292 if (pAsync) {
293
294 /* Update the transfer descriptor */
295 pTwid->pTransfer = pAsync;
296 pTransfer = (AsyncTwi *) pAsync;
297 pTransfer->status = ASYNC_STATUS_PENDING;
298 pTransfer->pData = pData;
299 pTransfer->num = num;
300 pTransfer->transferred = 1;
301
302 /* Enable write interrupt and start the transfer */
303 TWI_StartWrite(pTwi, address, iaddress, isize, *pData);
304 TWI_EnableIt(pTwi, TWI_IER_TXRDY);
305 }
306 /* Synchronous transfer*/
307 else {
308
309 // Start write
310 TWI_StartWrite(pTwi, address, iaddress, isize, *pData++);
311 num--;
312
313 /* Send all bytes */
314 while (num > 0) {
315
316 /* Wait before sending the next byte */
317 timeout = 0;
318 while( !TWI_ByteSent(pTwi) && (++timeout<TWITIMEOUTMAX) );
319 if (timeout == TWITIMEOUTMAX) {
320 TRACE_ERROR("TWID Timeout BS\n\r");
321 }
322
323 TWI_WriteByte(pTwi, *pData++);
324 num--;
325 }
326
327 /* Wait for actual end of transfer */
328 timeout = 0;
329
330 /* Send a STOP condition */
331 TWI_SendSTOPCondition(pTwi);
332
333 while( !TWI_TransferComplete(pTwi) && (++timeout<TWITIMEOUTMAX) );
334 if (timeout == TWITIMEOUTMAX) {
335 TRACE_ERROR("TWID Timeout TC2\n\r");
336 }
337
338 }
339
340 return 0;
341}
342