1 /*******************************************************************************
\r
2 * (c) Copyright 2007-2008 Actel Corporation. All rights reserved.
\r
4 * SmartFusion microcontroller subsystem I2C bare metal software driver
\r
7 * SVN $Revision: 2152 $
\r
8 * SVN $Date: 2010-02-11 14:44:11 +0000 (Thu, 11 Feb 2010) $
\r
11 #include "../../CMSIS/mss_assert.h"
\r
17 /*------------------------------------------------------------------------------
\r
18 * I2C transaction direction.
\r
23 /* -- TRANSACTIONS TYPES -- */
\r
24 #define NO_TRANSACTION 0
\r
25 #define MASTER_WRITE_TRANSACTION 1
\r
26 #define MASTER_READ_TRANSACTION 2
\r
27 #define MASTER_RANDOM_READ_TRANSACTION 3
\r
28 #define WRITE_SLAVE_TRANSACTION 4
\r
29 #define READ_SLAVE_TRANSACTION 5
\r
30 #define RANDOM_READ_SLAVE_TRANSACTION 6
\r
33 /* -- SMBUS H/W STATES -- */
\r
34 /* -- MASTER STATES -- */
\r
35 #define ST_START 0x08 /* start condition sent */
\r
36 #define ST_RESTART 0x10 /* repeated start */
\r
37 #define ST_SLAW_ACK 0x18 /* SLA+W sent, ack received */
\r
38 #define ST_SLAW_NACK 0x20 /* SLA+W sent, nack received */
\r
39 #define ST_TX_DATA_ACK 0x28 /* Data sent, ACK'ed */
\r
40 #define ST_TX_DATA_NACK 0x30 /* Data sent, NACK'ed */
\r
41 #define ST_LOST_ARB 0x38 /* Master lost arbitration */
\r
42 #define ST_SLAR_ACK 0x40 /* SLA+R sent, ACK'ed */
\r
43 #define ST_SLAR_NACK 0x48 /* SLA+R sent, NACK'ed */
\r
44 #define ST_RX_DATA_ACK 0x50 /* Data received, ACK sent */
\r
45 #define ST_RX_DATA_NACK 0x58 /* Data received, NACK sent */
\r
47 /* -- SLAVE STATES -- */
\r
48 #define ST_SLAVE_SLAW 0x60 /* SLA+W received */
\r
49 #define ST_SLAVE_SLAR_ACK 0xA8 /* SLA+R received, ACK returned */
\r
50 #define ST_SLV_LA 0x68 /* Slave lost arbitration */
\r
51 #define ST_GCA 0x70 /* GCA received */
\r
52 #define ST_GCA_LA 0x78 /* GCA lost arbitration */
\r
53 #define ST_RDATA 0x80 /* Data received */
\r
54 #define ST_SLA_NACK 0x88 /* Slave addressed, NACK returned */
\r
55 #define ST_GCA_ACK 0x90 /* Previously addresses with GCA, data ACKed */
\r
56 #define ST_GCA_NACK 0x98 /* GCA addressed, NACK returned */
\r
57 #define ST_RSTOP 0xA0 /* Stop received */
\r
58 #define ST_REPEAT 0xA0 /* Repeated start received */
\r
59 #define ST_SLAR_ACKS 0xA8 /* Slave read received, ACKed */
\r
60 #define ST_SLARW_LA 0xB0 /* Arbitration lost */
\r
61 #define ST_RACK 0xB8 /* Byte sent, ACK received */
\r
62 #define ST_SLAVE_RNACK 0xC0 /* Byte sent, NACK received */
\r
63 #define ST_FINAL 0xC8 /* Final byte sent, ACK received */
\r
64 #define ST_BERR 0x00 /* Error on the bus */
\r
65 #define ST_SLV_RST 0xD8 /* Slave reset state */
\r
67 /*------------------------------------------------------------------------------
\r
70 static uint32_t disable_interrupts( void );
\r
71 static void restore_interrupts( uint32_t primask );
\r
72 static void mss_i2c_isr( mss_i2c_instance_t * this_i2c );
\r
74 /*------------------------------------------------------------------------------
\r
76 *------------------------------------------------------------------------------
\r
79 mss_i2c_instance_t g_mss_i2c0;
\r
80 mss_i2c_instance_t g_mss_i2c1;
\r
82 /*------------------------------------------------------------------------------
\r
84 * See "mss_i2c.h" for details of how to use this function.
\r
88 mss_i2c_instance_t * this_i2c,
\r
89 uint8_t ser_address,
\r
90 mss_i2c_clock_divider_t ser_clock_speed
\r
93 uint_fast16_t clock_speed = ser_clock_speed;
\r
95 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
97 if ( this_i2c == &g_mss_i2c0 )
\r
99 this_i2c->irqn = I2C0_IRQn;
\r
100 this_i2c->hw_reg = I2C0;
\r
101 this_i2c->hw_reg_bit = I2C0_BITBAND;
\r
104 SYSREG->SOFT_RST_CR |= SYSREG_I2C0_SOFTRESET_MASK;
\r
105 /* Clear any previously pended I2C0 interrupt */
\r
106 NVIC_ClearPendingIRQ( I2C0_IRQn );
\r
107 /* Take I2C0 out of reset. */
\r
108 SYSREG->SOFT_RST_CR &= ~SYSREG_I2C0_SOFTRESET_MASK;
\r
112 this_i2c->irqn = I2C1_IRQn;
\r
113 this_i2c->hw_reg = I2C1;
\r
114 this_i2c->hw_reg_bit = I2C1_BITBAND;
\r
117 SYSREG->SOFT_RST_CR |= SYSREG_I2C1_SOFTRESET_MASK;
\r
118 /* Clear any previously pended I2C1 interrupt */
\r
119 NVIC_ClearPendingIRQ( I2C1_IRQn );
\r
120 /* Take I2C1 out of reset. */
\r
121 SYSREG->SOFT_RST_CR &= ~SYSREG_I2C1_SOFTRESET_MASK;
\r
124 this_i2c->transaction = NO_TRANSACTION;
\r
126 this_i2c->ser_address = ser_address;
\r
128 this_i2c->tx_buffer = 0;
\r
129 this_i2c->tx_size = 0;
\r
130 this_i2c->tx_idx = 0;
\r
132 this_i2c->rx_buffer = 0;
\r
133 this_i2c->rx_size = 0;
\r
134 this_i2c->rx_idx = 0;
\r
136 this_i2c->status = MSS_I2C_SUCCESS;
\r
138 this_i2c->random_read_addr = 0;
\r
140 this_i2c->slave_write_handler = 0;
\r
141 this_i2c->slave_mem_offset_length = 0;
\r
143 this_i2c->hw_reg_bit->CTRL_ENS1 = 0x01; /* set enable bit */
\r
144 this_i2c->hw_reg_bit->CTRL_CR2 = (clock_speed >> 2) & 0x01;
\r
145 this_i2c->hw_reg_bit->CTRL_CR1 = (clock_speed >> 1) & 0x01;
\r
146 this_i2c->hw_reg_bit->CTRL_CR0 = clock_speed & 0x01;
\r
147 this_i2c->hw_reg->ADDR = this_i2c->ser_address;
\r
150 /*------------------------------------------------------------------------------
\r
151 * MSS_I2C_set_slave_mem_offset_length()
\r
152 * See "mss_i2c.h" for details of how to use this function.
\r
154 void MSS_I2C_set_slave_mem_offset_length
\r
156 mss_i2c_instance_t * this_i2c,
\r
157 uint8_t offset_length
\r
160 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
162 this_i2c->slave_mem_offset_length = offset_length;
\r
165 /*------------------------------------------------------------------------------
\r
166 * MSS_I2C_register_write_handler()
\r
167 * See "mss_i2c.h" for details of how to use this function.
\r
169 void MSS_I2C_register_write_handler
\r
171 mss_i2c_instance_t * this_i2c,
\r
172 mss_i2c_slave_wr_handler_t handler
\r
175 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
177 this_i2c->slave_write_handler = handler;
\r
180 /*------------------------------------------------------------------------------
\r
182 * See "mss_i2c.h" for details of how to use this function.
\r
186 mss_i2c_instance_t * this_i2c,
\r
187 uint8_t serial_addr,
\r
188 const uint8_t * write_buffer,
\r
189 uint16_t write_size,
\r
193 volatile uint8_t stat_ctrl;
\r
194 uint8_t serial_interrupt;
\r
198 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
200 primask = disable_interrupts();
\r
202 this_i2c->transaction = MASTER_WRITE_TRANSACTION;
\r
204 this_i2c->target_addr = serial_addr;
\r
205 this_i2c->dir = WRITE_DIR;
\r
206 this_i2c->tx_buffer = write_buffer;
\r
207 this_i2c->tx_size = write_size;
\r
208 this_i2c->tx_idx = 0;
\r
210 this_i2c->status = MSS_I2C_IN_PROGRESS;
\r
211 this_i2c->options = options;
\r
213 /* Clear interrupts if required (depends on repeated starts).*/
\r
214 serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;
\r
215 this_i2c->hw_reg_bit->CTRL_STA = 0x01;
\r
217 if ( serial_interrupt != 0 )
\r
219 this_i2c->hw_reg_bit->CTRL_SI = 0x00;
\r
220 NVIC_ClearPendingIRQ( this_i2c->irqn );
\r
223 stat_ctrl = this_i2c->hw_reg->STATUS;
\r
225 NVIC_EnableIRQ( this_i2c->irqn );
\r
227 restore_interrupts( primask );
\r
230 /*------------------------------------------------------------------------------
\r
232 * See "mss_i2c.h" for details of how to use this function.
\r
236 mss_i2c_instance_t * this_i2c,
\r
237 uint8_t serial_addr,
\r
238 uint8_t * read_buffer,
\r
239 uint16_t read_size,
\r
245 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
247 if ( read_size > 0 )
\r
249 volatile uint8_t stat_ctrl;
\r
250 uint8_t serial_interrupt;
\r
252 primask = disable_interrupts();
\r
254 this_i2c->transaction = MASTER_READ_TRANSACTION;
\r
256 this_i2c->target_addr = serial_addr;
\r
257 this_i2c->dir = READ_DIR;
\r
258 this_i2c->rx_buffer = read_buffer;
\r
259 this_i2c->rx_size = read_size;
\r
260 this_i2c->rx_idx = 0;
\r
262 this_i2c->status = MSS_I2C_IN_PROGRESS;
\r
264 this_i2c->options = options;
\r
266 /* Clear interrupts if required (depends on repeated starts).*/
\r
267 serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;
\r
268 this_i2c->hw_reg_bit->CTRL_STA = 0x01;
\r
270 if ( serial_interrupt != 0 )
\r
272 this_i2c->hw_reg_bit->CTRL_SI = 0x00;
\r
273 NVIC_ClearPendingIRQ( this_i2c->irqn );
\r
276 stat_ctrl = this_i2c->hw_reg->STATUS;
\r
278 NVIC_EnableIRQ( this_i2c->irqn );
\r
280 restore_interrupts( primask );
\r
284 /*------------------------------------------------------------------------------
\r
285 * MSS_I2C_write_read()
\r
286 * See "mss_i2c.h" for details of how to use this function.
\r
288 void MSS_I2C_write_read
\r
290 mss_i2c_instance_t * this_i2c,
\r
291 uint8_t serial_addr,
\r
292 const uint8_t * addr_offset,
\r
293 uint16_t offset_size,
\r
294 uint8_t * read_buffer,
\r
295 uint16_t read_size,
\r
299 volatile uint8_t stat_ctrl;
\r
300 uint8_t serial_interrupt;
\r
303 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
305 primask = disable_interrupts();
\r
307 this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION;
\r
308 this_i2c->target_addr = serial_addr;
\r
309 this_i2c->dir = WRITE_DIR;
\r
310 this_i2c->tx_buffer = addr_offset;
\r
311 this_i2c->tx_size = offset_size;
\r
312 this_i2c->tx_idx = 0;
\r
314 this_i2c->rx_buffer = read_buffer;
\r
315 this_i2c->rx_size = read_size;
\r
316 this_i2c->rx_idx = 0;
\r
318 this_i2c->status = MSS_I2C_IN_PROGRESS;
\r
319 this_i2c->options = options;
\r
321 /* Clear interrupts if required (depends on repeated starts).*/
\r
322 serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;
\r
323 this_i2c->hw_reg_bit->CTRL_STA = 0x01;
\r
325 if ( serial_interrupt != 0 )
\r
327 this_i2c->hw_reg_bit->CTRL_SI = 0x00;
\r
328 NVIC_ClearPendingIRQ( this_i2c->irqn );
\r
331 stat_ctrl = this_i2c->hw_reg->STATUS;
\r
333 NVIC_EnableIRQ( this_i2c->irqn );
\r
335 restore_interrupts( primask );
\r
338 /*------------------------------------------------------------------------------
\r
339 * MSS_I2C_set_slave_rx_buffer()
\r
340 * See "mss_i2c.h" for details of how to use this function.
\r
342 void MSS_I2C_set_slave_rx_buffer
\r
344 mss_i2c_instance_t * this_i2c,
\r
345 uint8_t * rx_buffer,
\r
351 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
353 primask = disable_interrupts();
\r
355 this_i2c->rx_buffer = rx_buffer;
\r
356 this_i2c->rx_size = rx_size;
\r
357 this_i2c->rx_idx = 0;
\r
359 restore_interrupts( primask );
\r
363 /*------------------------------------------------------------------------------
\r
364 * MSS_I2C_get_status()
\r
365 * See "mss_i2c.h" for details of how to use this function.
\r
367 mss_i2c_status_t MSS_I2C_get_status
\r
369 mss_i2c_instance_t * this_i2c
\r
372 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
374 return this_i2c->status;
\r
377 /*------------------------------------------------------------------------------
\r
378 * MSS_I2C_set_slave_tx_buffer()
\r
379 * See "mss_i2c.h" for details of how to use this function.
\r
381 void MSS_I2C_set_slave_tx_buffer
\r
383 mss_i2c_instance_t * this_i2c,
\r
384 uint8_t * tx_buffer,
\r
390 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
392 primask = disable_interrupts();
\r
394 this_i2c->tx_buffer = tx_buffer;
\r
395 this_i2c->tx_size = tx_size;
\r
396 this_i2c->tx_idx = 0;
\r
398 restore_interrupts( primask );
\r
400 /* Set the assert acknowledge bit. */
\r
401 this_i2c->hw_reg_bit->CTRL_AA = 0x01;
\r
404 /*------------------------------------------------------------------------------
\r
405 * MSS_I2C_enable_slave_rx()
\r
406 * See "mss_i2c.h" for details of how to use this function.
\r
408 void MSS_I2C_enable_slave_rx
\r
410 mss_i2c_instance_t * this_i2c
\r
413 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
415 /* Set the assert acknowledge bit. */
\r
416 this_i2c->hw_reg_bit->CTRL_AA = 0x01;
\r
417 /* accept GC addressing. */
\r
418 this_i2c->hw_reg_bit->ADDR_GC = 0x01;
\r
420 NVIC_EnableIRQ( this_i2c->irqn );
\r
423 /*------------------------------------------------------------------------------
\r
424 * MSS_I2C_wait_complete()
\r
425 * See "mss_i2c.h" for details of how to use this function.
\r
427 mss_i2c_status_t MSS_I2C_wait_complete
\r
429 mss_i2c_instance_t * this_i2c
\r
432 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
434 while ( this_i2c->status == MSS_I2C_IN_PROGRESS )
\r
436 /* Wait for transaction to compltete.*/
\r
439 return this_i2c->status;
\r
442 /*------------------------------------------------------------------------------
\r
443 * MSS I2C interrupt service routine.
\r
444 *------------------------------------------------------------------------------
\r
447 * mss_i2c_instance_t * this_i2c:
\r
448 * Pointer to the mss_i2c_instance_t data structure holding all data related to
\r
449 * the MSS I2C instance that generated the interrupt.
\r
451 static void mss_i2c_isr
\r
453 mss_i2c_instance_t * this_i2c
\r
456 volatile uint8_t status;
\r
459 uint8_t clear_irq = 1;
\r
461 ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );
\r
463 status = this_i2c->hw_reg->STATUS;
\r
467 /************** MASTER TRANSMITTER / RECEIVER *******************/
\r
469 case ST_START: /* start has been xmt'd */
\r
470 case ST_RESTART: /* repeated start has been xmt'd */
\r
471 this_i2c->hw_reg_bit->CTRL_STA = 0x0;
\r
472 this_i2c->hw_reg->DATA = this_i2c->target_addr;
\r
473 this_i2c->hw_reg_bit->DATA_DIR = this_i2c->dir;
\r
475 this_i2c->tx_idx = 0;
\r
476 this_i2c->rx_idx = 0;
\r
480 /* Set start bit. Let's keep trying! Don't give up! */
\r
481 this_i2c->hw_reg_bit->CTRL_STA = 0x01;
\r
484 /******************* MASTER TRANSMITTER *************************/
\r
486 /* call address has been xmt'd with ACK, time to send data byte and increment index. */
\r
487 if ( this_i2c->tx_idx < this_i2c->tx_size )
\r
489 /* load data byte */
\r
490 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
\r
494 NVIC_DisableIRQ( this_i2c->irqn );
\r
500 /* SLA+W has been transmitted; not ACK has been received - let's stop. */
\r
501 this_i2c->hw_reg_bit->CTRL_STO = 0x01;
\r
502 this_i2c->status = MSS_I2C_FAILED;
\r
504 /* call address has been xmt'd with ACK, time to send data byte and increment index. */
\r
505 if ( this_i2c->tx_idx < this_i2c->tx_size )
\r
507 /* load data byte */
\r
508 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
\r
512 NVIC_DisableIRQ( this_i2c->irqn );
\r
516 case ST_TX_DATA_ACK:
\r
517 /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */
\r
518 if (this_i2c->tx_idx < this_i2c->tx_size)
\r
520 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
\r
522 else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )
\r
524 /* We are finished sending the address offset part of a random read transaction.
\r
525 * It is is time to send a restart in order to change direction. */
\r
526 this_i2c->dir = READ_DIR;
\r
527 this_i2c->hw_reg_bit->CTRL_STA = 0x01;
\r
529 else /* done sending. let's stop */
\r
531 hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;
\r
532 if ( hold_bus == 0 )
\r
534 this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */
\r
538 NVIC_DisableIRQ( this_i2c->irqn );
\r
541 this_i2c->status = MSS_I2C_SUCCESS;
\r
545 case ST_TX_DATA_NACK:
\r
547 /* data byte SENT, ACK to be received
\r
548 * In fact, this means we've received a NACK (This may not be
\r
549 * obvious, but if we've rec'd an ACK then we would be in state
\r
550 * 0x28!) hence, let's send a stop bit
\r
552 this_i2c->hw_reg_bit->CTRL_STO = 0x01;
\r
553 this_i2c->status = MSS_I2C_FAILED;
\r
555 /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */
\r
556 if (this_i2c->tx_idx < this_i2c->tx_size)
\r
558 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
\r
560 else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )
\r
562 /* We are finished sending the address offset part of a random read transaction.
\r
563 * It is is time to send a restart in order to change direction. */
\r
564 this_i2c->dir = READ_DIR;
\r
565 this_i2c->hw_reg_bit->CTRL_STA = 0x01;
\r
567 else /* done sending. let's stop */
\r
569 hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;
\r
570 if ( hold_bus == 0 )
\r
572 this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */
\r
576 NVIC_DisableIRQ( this_i2c->irqn );
\r
579 this_i2c->status = MSS_I2C_SUCCESS;
\r
583 /********************* MASTER (or slave?) RECEIVER *************************/
\r
585 /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */
\r
586 case ST_SLAR_ACK: /* SLA+R tx'ed. */
\r
587 /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless
\r
588 * the next byte is the last byte of the read transaction.
\r
590 if( this_i2c->rx_size > 1 )
\r
592 this_i2c->hw_reg_bit->CTRL_AA = 0x01;
\r
596 this_i2c->hw_reg_bit->CTRL_AA = 0x00;
\r
600 case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */
\r
601 this_i2c->hw_reg_bit->CTRL_STO = 0x01;
\r
602 this_i2c->status = MSS_I2C_FAILED;
\r
605 case ST_RX_DATA_ACK: /* Data byte received, ACK returned */
\r
606 /* First, get the data */
\r
607 this_i2c->rx_buffer[this_i2c->rx_idx++] = this_i2c->hw_reg->DATA;
\r
609 if( this_i2c->rx_idx >= this_i2c->rx_size - 1)
\r
611 /* If we're at the second last byte, let's set AA to 0 so
\r
612 * we return a NACK at the last byte. */
\r
613 this_i2c->hw_reg_bit->CTRL_AA = 0x00;
\r
617 case ST_RX_DATA_NACK: /* Data byte received, NACK returned */
\r
618 /* Get the data, then send a stop condition */
\r
619 this_i2c->rx_buffer[this_i2c->rx_idx++] = this_i2c->hw_reg->DATA;
\r
621 hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;
\r
622 if ( hold_bus == 0 )
\r
624 this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */
\r
628 NVIC_DisableIRQ( this_i2c->irqn );
\r
632 this_i2c->status = MSS_I2C_SUCCESS;
\r
635 /******************** SLAVE RECEIVER **************************/
\r
636 case ST_GCA_NACK: /* NACK after, GCA addressing */
\r
637 case ST_SLA_NACK: /* Get Data, but also re-enable AA (assert ack) bit for future transmissions */
\r
638 if ( this_i2c->rx_buffer != 0 )
\r
640 this_i2c->rx_buffer[this_i2c->rx_idx] = this_i2c->hw_reg->DATA;
\r
642 this_i2c->hw_reg_bit->CTRL_AA = 0x01;
\r
645 case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */
\r
646 this_i2c->transaction = WRITE_SLAVE_TRANSACTION;
\r
647 this_i2c->rx_idx = 0;
\r
648 this_i2c->random_read_addr = 0;
\r
649 #ifndef INCLUDE_SLA_IN_RX_PAYLOAD
\r
650 /* Only break from this case if the slave address must NOT be included at the
\r
651 * beginning of the received write data. */
\r
654 case ST_GCA_ACK: /* DATA received; ACK sent after GCA */
\r
655 case ST_RDATA: /* DATA received; must clear DATA register */
\r
656 if (this_i2c->rx_idx >= this_i2c->rx_size - 2)
\r
658 this_i2c->hw_reg_bit->CTRL_AA = 0x00; /* send a NACK when done (next reception) */
\r
660 data = this_i2c->hw_reg->DATA;
\r
661 this_i2c->rx_buffer[this_i2c->rx_idx++] = data;
\r
662 this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data;
\r
667 /* STOP or repeated START occured. */
\r
668 /* We cannot be sure if the transaction has actually completed as
\r
669 * this hardware state reports that either a STOP or repeated START
\r
670 * condition has occured. We assume that this is a repeated START
\r
671 * if the transaction was a write from the master to this point.*/
\r
672 if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION )
\r
674 if ( this_i2c->rx_idx == this_i2c->slave_mem_offset_length )
\r
676 this_i2c->transaction = RANDOM_READ_SLAVE_TRANSACTION;
\r
677 this_i2c->tx_idx = this_i2c->random_read_addr;
\r
681 /* Call the slave's write transaction handler if it exists. */
\r
682 if ( this_i2c->slave_write_handler != 0 )
\r
684 mss_i2c_slave_handler_ret_t h_ret;
\r
685 h_ret = this_i2c->slave_write_handler( this_i2c->rx_buffer, (uint16_t)this_i2c->rx_idx );
\r
686 if ( MSS_I2C_REENABLE_SLAVE_RX == h_ret )
\r
688 this_i2c->hw_reg_bit->CTRL_AA = 0x01;
\r
692 this_i2c->hw_reg_bit->CTRL_AA = 0x00;
\r
697 /* Mark any previous master write transaction as complete. */
\r
698 this_i2c->status = MSS_I2C_SUCCESS;
\r
701 case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */
\r
702 case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */
\r
703 case ST_GCA: /* General call address received, ACK returned */
\r
704 case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */
\r
708 /****************** SLAVE TRANSMITTER **************************/
\r
709 case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */
\r
710 case ST_SLARW_LA: /* Arbitration lost, and: */
\r
711 case ST_RACK: /* Data tx'ed, ACK received */
\r
712 if ( status == ST_SLAVE_SLAR_ACK )
\r
714 this_i2c->transaction = READ_SLAVE_TRANSACTION;
\r
715 this_i2c->random_read_addr = 0;
\r
717 /* Load the data, and determine if it is the last one */
\r
718 this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];
\r
719 if (this_i2c->tx_idx >= this_i2c->tx_size - 1) /* last byte? */
\r
721 this_i2c->hw_reg_bit->CTRL_AA = 0x00;
\r
722 /* Next read transaction will result in slave's transmit buffer
\r
723 * being sent from the first byte. */
\r
724 this_i2c->tx_idx = 0;
\r
728 case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */
\r
729 /* We assume that the transaction will be stopped by the master.
\r
730 * Reset tx_idx so that a subsequent read will result in the slave's
\r
731 * transmit buffer being sent from the first byte. */
\r
732 this_i2c->tx_idx = 0;
\r
735 case ST_FINAL: /* Last Data byte tx'ed, ACK recieved */
\r
743 /* clear interrupt. */
\r
744 this_i2c->hw_reg_bit->CTRL_SI = 0x00;
\r
747 /* Read the status register to ensure the last I2C registers write took place
\r
748 * in a system built around a bus making use of posted writes. */
\r
749 status = this_i2c->hw_reg->STATUS;
\r
752 /*------------------------------------------------------------------------------
\r
755 uint32_t disable_interrupts( void )
\r
758 primask = __get_PRIMASK();
\r
762 /*------------------------------------------------------------------------------
\r
765 void restore_interrupts( uint32_t primask )
\r
767 __set_PRIMASK( primask );
\r
770 /*------------------------------------------------------------------------------
\r
773 #if defined(__GNUC__)
\r
774 __attribute__((__interrupt__)) void I2C0_IRQHandler( void )
\r
776 void I2C0_IRQHandler( void )
\r
779 mss_i2c_isr( &g_mss_i2c0 );
\r
780 NVIC_ClearPendingIRQ( I2C0_IRQn );
\r
783 /*------------------------------------------------------------------------------
\r
786 #if defined(__GNUC__)
\r
787 __attribute__((__interrupt__)) void I2C1_IRQHandler( void )
\r
789 void I2C1_IRQHandler( void )
\r
792 mss_i2c_isr( &g_mss_i2c1 );
\r
793 NVIC_ClearPendingIRQ( I2C1_IRQn );
\r