--- /dev/null
+/*******************************************************************************\r
+ * (c) Copyright 2007-2008 Actel Corporation. All rights reserved.\r
+ *\r
+ * SmartFusion microcontroller subsystem I2C bare metal software driver\r
+ * implementation.\r
+ *\r
+ * SVN $Revision: 2152 $\r
+ * SVN $Date: 2010-02-11 14:44:11 +0000 (Thu, 11 Feb 2010) $\r
+ */\r
+#include "i2c.h"\r
+#include "../../CMSIS/mss_assert.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/*------------------------------------------------------------------------------\r
+ * I2C transaction direction.\r
+ */\r
+#define WRITE_DIR 0\r
+#define READ_DIR 1\r
+\r
+/* -- TRANSACTIONS TYPES -- */\r
+#define NO_TRANSACTION 0\r
+#define MASTER_WRITE_TRANSACTION 1\r
+#define MASTER_READ_TRANSACTION 2\r
+#define MASTER_RANDOM_READ_TRANSACTION 3\r
+#define WRITE_SLAVE_TRANSACTION 4\r
+#define READ_SLAVE_TRANSACTION 5\r
+#define RANDOM_READ_SLAVE_TRANSACTION 6\r
+\r
+\r
+/* -- SMBUS H/W STATES -- */\r
+/* -- MASTER STATES -- */\r
+#define ST_START 0x08 /* start condition sent */\r
+#define ST_RESTART 0x10 /* repeated start */\r
+#define ST_SLAW_ACK 0x18 /* SLA+W sent, ack received */\r
+#define ST_SLAW_NACK 0x20 /* SLA+W sent, nack received */\r
+#define ST_TX_DATA_ACK 0x28 /* Data sent, ACK'ed */\r
+#define ST_TX_DATA_NACK 0x30 /* Data sent, NACK'ed */\r
+#define ST_LOST_ARB 0x38 /* Master lost arbitration */\r
+#define ST_SLAR_ACK 0x40 /* SLA+R sent, ACK'ed */\r
+#define ST_SLAR_NACK 0x48 /* SLA+R sent, NACK'ed */\r
+#define ST_RX_DATA_ACK 0x50 /* Data received, ACK sent */\r
+#define ST_RX_DATA_NACK 0x58 /* Data received, NACK sent */\r
+\r
+/* -- SLAVE STATES -- */\r
+#define ST_SLAVE_SLAW 0x60 /* SLA+W received */\r
+#define ST_SLAVE_SLAR_ACK 0xA8 /* SLA+R received, ACK returned */\r
+#define ST_SLV_LA 0x68 /* Slave lost arbitration */\r
+#define ST_GCA 0x70 /* GCA received */\r
+#define ST_GCA_LA 0x78 /* GCA lost arbitration */\r
+#define ST_RDATA 0x80 /* Data received */\r
+#define ST_SLA_NACK 0x88 /* Slave addressed, NACK returned */\r
+#define ST_GCA_ACK 0x90 /* Previously addresses with GCA, data ACKed */\r
+#define ST_GCA_NACK 0x98 /* GCA addressed, NACK returned */\r
+#define ST_RSTOP 0xA0 /* Stop received */\r
+#define ST_REPEAT 0xA0 /* Repeated start received */\r
+#define ST_SLAR_ACKS 0xA8 /* Slave read received, ACKed */\r
+#define ST_SLARW_LA 0xB0 /* Arbitration lost */\r
+#define ST_RACK 0xB8 /* Byte sent, ACK received */\r
+#define ST_SLAVE_RNACK 0xC0 /* Byte sent, NACK received */\r
+#define ST_FINAL 0xC8 /* Final byte sent, ACK received */\r
+#define ST_BERR 0x00 /* Error on the bus */\r
+#define ST_SLV_RST 0xD8 /* Slave reset state */\r
+\r
+/*------------------------------------------------------------------------------\r
+ *\r
+ */\r
+static uint32_t disable_interrupts( void );\r
+static void restore_interrupts( uint32_t primask );\r
+static void mss_i2c_isr( mss_i2c_instance_t * this_i2c );\r
+\r
+/*------------------------------------------------------------------------------\r
+ *\r
+ *------------------------------------------------------------------------------\r
+ *\r
+ */\r
+mss_i2c_instance_t g_mss_i2c0;\r
+mss_i2c_instance_t g_mss_i2c1;\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_init()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_init\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t ser_address,\r
+ mss_i2c_clock_divider_t ser_clock_speed\r
+)\r
+{\r
+ uint_fast16_t clock_speed = ser_clock_speed;\r
+\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ if ( this_i2c == &g_mss_i2c0 )\r
+ {\r
+ this_i2c->irqn = I2C0_IRQn;\r
+ this_i2c->hw_reg = I2C0;\r
+ this_i2c->hw_reg_bit = I2C0_BITBAND;\r
+\r
+ /* reset I2C0 */\r
+ SYSREG->SOFT_RST_CR |= SYSREG_I2C0_SOFTRESET_MASK;\r
+ /* Clear any previously pended I2C0 interrupt */\r
+ NVIC_ClearPendingIRQ( I2C0_IRQn );\r
+ /* Take I2C0 out of reset. */\r
+ SYSREG->SOFT_RST_CR &= ~SYSREG_I2C0_SOFTRESET_MASK;\r
+ }\r
+ else\r
+ {\r
+ this_i2c->irqn = I2C1_IRQn;\r
+ this_i2c->hw_reg = I2C1;\r
+ this_i2c->hw_reg_bit = I2C1_BITBAND;\r
+\r
+ /* reset I2C1 */\r
+ SYSREG->SOFT_RST_CR |= SYSREG_I2C1_SOFTRESET_MASK;\r
+ /* Clear any previously pended I2C1 interrupt */\r
+ NVIC_ClearPendingIRQ( I2C1_IRQn );\r
+ /* Take I2C1 out of reset. */\r
+ SYSREG->SOFT_RST_CR &= ~SYSREG_I2C1_SOFTRESET_MASK;\r
+ }\r
+\r
+ this_i2c->transaction = NO_TRANSACTION;\r
+\r
+ this_i2c->ser_address = ser_address;\r
+\r
+ this_i2c->tx_buffer = 0;\r
+ this_i2c->tx_size = 0;\r
+ this_i2c->tx_idx = 0;\r
+\r
+ this_i2c->rx_buffer = 0;\r
+ this_i2c->rx_size = 0;\r
+ this_i2c->rx_idx = 0;\r
+\r
+ this_i2c->status = MSS_I2C_SUCCESS;\r
+\r
+ this_i2c->random_read_addr = 0;\r
+\r
+ this_i2c->slave_write_handler = 0;\r
+ this_i2c->slave_mem_offset_length = 0;\r
+\r
+ this_i2c->hw_reg_bit->CTRL_ENS1 = 0x01; /* set enable bit */\r
+ this_i2c->hw_reg_bit->CTRL_CR2 = (clock_speed >> 2) & 0x01;\r
+ this_i2c->hw_reg_bit->CTRL_CR1 = (clock_speed >> 1) & 0x01;\r
+ this_i2c->hw_reg_bit->CTRL_CR0 = clock_speed & 0x01;\r
+ this_i2c->hw_reg->ADDR = this_i2c->ser_address;\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_set_slave_mem_offset_length()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_set_slave_mem_offset_length\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t offset_length\r
+)\r
+{\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ this_i2c->slave_mem_offset_length = offset_length;\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_register_write_handler()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_register_write_handler\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ mss_i2c_slave_wr_handler_t handler\r
+)\r
+{\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ this_i2c->slave_write_handler = handler;\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_write()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_write\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t serial_addr,\r
+ const uint8_t * write_buffer,\r
+ uint16_t write_size,\r
+ uint8_t options\r
+)\r
+{\r
+ volatile uint8_t stat_ctrl;\r
+ uint8_t serial_interrupt;\r
+\r
+ uint32_t primask;\r
+\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ primask = disable_interrupts();\r
+\r
+ this_i2c->transaction = MASTER_WRITE_TRANSACTION;\r
+\r
+ this_i2c->target_addr = serial_addr;\r
+ this_i2c->dir = WRITE_DIR;\r
+ this_i2c->tx_buffer = write_buffer;\r
+ this_i2c->tx_size = write_size;\r
+ this_i2c->tx_idx = 0;\r
+\r
+ this_i2c->status = MSS_I2C_IN_PROGRESS;\r
+ this_i2c->options = options;\r
+\r
+ /* Clear interrupts if required (depends on repeated starts).*/\r
+ serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;\r
+ this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
+\r
+ if ( serial_interrupt != 0 )\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_SI = 0x00;\r
+ NVIC_ClearPendingIRQ( this_i2c->irqn );\r
+ }\r
+\r
+ stat_ctrl = this_i2c->hw_reg->STATUS;\r
+\r
+ NVIC_EnableIRQ( this_i2c->irqn );\r
+\r
+ restore_interrupts( primask );\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_read()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_read\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t serial_addr,\r
+ uint8_t * read_buffer,\r
+ uint16_t read_size,\r
+ uint8_t options\r
+)\r
+{\r
+ uint32_t primask;\r
+\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ if ( read_size > 0 )\r
+ {\r
+ volatile uint8_t stat_ctrl;\r
+ uint8_t serial_interrupt;\r
+\r
+ primask = disable_interrupts();\r
+\r
+ this_i2c->transaction = MASTER_READ_TRANSACTION;\r
+\r
+ this_i2c->target_addr = serial_addr;\r
+ this_i2c->dir = READ_DIR;\r
+ this_i2c->rx_buffer = read_buffer;\r
+ this_i2c->rx_size = read_size;\r
+ this_i2c->rx_idx = 0;\r
+\r
+ this_i2c->status = MSS_I2C_IN_PROGRESS;\r
+\r
+ this_i2c->options = options;\r
+\r
+ /* Clear interrupts if required (depends on repeated starts).*/\r
+ serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;\r
+ this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
+\r
+ if ( serial_interrupt != 0 )\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_SI = 0x00;\r
+ NVIC_ClearPendingIRQ( this_i2c->irqn );\r
+ }\r
+\r
+ stat_ctrl = this_i2c->hw_reg->STATUS;\r
+\r
+ NVIC_EnableIRQ( this_i2c->irqn );\r
+\r
+ restore_interrupts( primask );\r
+ }\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_write_read()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_write_read\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t serial_addr,\r
+ const uint8_t * addr_offset,\r
+ uint16_t offset_size,\r
+ uint8_t * read_buffer,\r
+ uint16_t read_size,\r
+ uint8_t options\r
+)\r
+{\r
+ volatile uint8_t stat_ctrl;\r
+ uint8_t serial_interrupt;\r
+ uint32_t primask;\r
+\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ primask = disable_interrupts();\r
+\r
+ this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION;\r
+ this_i2c->target_addr = serial_addr;\r
+ this_i2c->dir = WRITE_DIR;\r
+ this_i2c->tx_buffer = addr_offset;\r
+ this_i2c->tx_size = offset_size;\r
+ this_i2c->tx_idx = 0;\r
+\r
+ this_i2c->rx_buffer = read_buffer;\r
+ this_i2c->rx_size = read_size;\r
+ this_i2c->rx_idx = 0;\r
+\r
+ this_i2c->status = MSS_I2C_IN_PROGRESS;\r
+ this_i2c->options = options;\r
+\r
+ /* Clear interrupts if required (depends on repeated starts).*/\r
+ serial_interrupt = this_i2c->hw_reg_bit->CTRL_SI;\r
+ this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
+\r
+ if ( serial_interrupt != 0 )\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_SI = 0x00;\r
+ NVIC_ClearPendingIRQ( this_i2c->irqn );\r
+ }\r
+\r
+ stat_ctrl = this_i2c->hw_reg->STATUS;\r
+\r
+ NVIC_EnableIRQ( this_i2c->irqn );\r
+\r
+ restore_interrupts( primask );\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_set_slave_rx_buffer()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_set_slave_rx_buffer\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t * rx_buffer,\r
+ uint16_t rx_size\r
+)\r
+{\r
+ uint32_t primask;\r
+\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ primask = disable_interrupts();\r
+\r
+ this_i2c->rx_buffer = rx_buffer;\r
+ this_i2c->rx_size = rx_size;\r
+ this_i2c->rx_idx = 0;\r
+\r
+ restore_interrupts( primask );\r
+}\r
+\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_get_status()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+mss_i2c_status_t MSS_I2C_get_status\r
+(\r
+ mss_i2c_instance_t * this_i2c\r
+)\r
+{\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ return this_i2c->status;\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_set_slave_tx_buffer()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_set_slave_tx_buffer\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t * tx_buffer,\r
+ uint16_t tx_size\r
+)\r
+{\r
+ uint32_t primask;\r
+\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ primask = disable_interrupts();\r
+\r
+ this_i2c->tx_buffer = tx_buffer;\r
+ this_i2c->tx_size = tx_size;\r
+ this_i2c->tx_idx = 0;\r
+\r
+ restore_interrupts( primask );\r
+\r
+ /* Set the assert acknowledge bit. */\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_enable_slave_rx()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+void MSS_I2C_enable_slave_rx\r
+(\r
+ mss_i2c_instance_t * this_i2c\r
+)\r
+{\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ /* Set the assert acknowledge bit. */\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
+ /* accept GC addressing. */\r
+ this_i2c->hw_reg_bit->ADDR_GC = 0x01;\r
+\r
+ NVIC_EnableIRQ( this_i2c->irqn );\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS_I2C_wait_complete()\r
+ * See "mss_i2c.h" for details of how to use this function.\r
+ */\r
+mss_i2c_status_t MSS_I2C_wait_complete\r
+(\r
+ mss_i2c_instance_t * this_i2c\r
+)\r
+{\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ while ( this_i2c->status == MSS_I2C_IN_PROGRESS )\r
+ {\r
+ /* Wait for transaction to compltete.*/\r
+ ;\r
+ }\r
+ return this_i2c->status;\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ * MSS I2C interrupt service routine.\r
+ *------------------------------------------------------------------------------\r
+ * Parameters:\r
+ *\r
+ * mss_i2c_instance_t * this_i2c:\r
+ * Pointer to the mss_i2c_instance_t data structure holding all data related to\r
+ * the MSS I2C instance that generated the interrupt.\r
+ */\r
+static void mss_i2c_isr\r
+(\r
+ mss_i2c_instance_t * this_i2c\r
+)\r
+{\r
+ volatile uint8_t status;\r
+ uint8_t data;\r
+ uint8_t hold_bus;\r
+ uint8_t clear_irq = 1;\r
+\r
+ ASSERT( (this_i2c == &g_mss_i2c0) || (this_i2c == &g_mss_i2c1) );\r
+\r
+ status = this_i2c->hw_reg->STATUS;\r
+\r
+ switch( status )\r
+ {\r
+ /************** MASTER TRANSMITTER / RECEIVER *******************/\r
+\r
+ case ST_START: /* start has been xmt'd */\r
+ case ST_RESTART: /* repeated start has been xmt'd */\r
+ this_i2c->hw_reg_bit->CTRL_STA = 0x0;\r
+ this_i2c->hw_reg->DATA = this_i2c->target_addr;\r
+ this_i2c->hw_reg_bit->DATA_DIR = this_i2c->dir;\r
+\r
+ this_i2c->tx_idx = 0;\r
+ this_i2c->rx_idx = 0;\r
+ break;\r
+\r
+ case ST_LOST_ARB:\r
+ /* Set start bit. Let's keep trying! Don't give up! */\r
+ this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
+ break;\r
+\r
+ /******************* MASTER TRANSMITTER *************************/\r
+ case ST_SLAW_ACK:\r
+ /* call address has been xmt'd with ACK, time to send data byte and increment index. */\r
+ if ( this_i2c->tx_idx < this_i2c->tx_size )\r
+ {\r
+ /* load data byte */\r
+ this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
+ }\r
+ else\r
+ {\r
+ NVIC_DisableIRQ( this_i2c->irqn );\r
+ }\r
+ break;\r
+\r
+ case ST_SLAW_NACK:\r
+#if 0\r
+ /* SLA+W has been transmitted; not ACK has been received - let's stop. */\r
+ this_i2c->hw_reg_bit->CTRL_STO = 0x01;\r
+ this_i2c->status = MSS_I2C_FAILED;\r
+#endif\r
+ /* call address has been xmt'd with ACK, time to send data byte and increment index. */\r
+ if ( this_i2c->tx_idx < this_i2c->tx_size )\r
+ {\r
+ /* load data byte */\r
+ this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
+ }\r
+ else\r
+ {\r
+ NVIC_DisableIRQ( this_i2c->irqn );\r
+ }\r
+ break;\r
+\r
+ case ST_TX_DATA_ACK:\r
+ /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */\r
+ if (this_i2c->tx_idx < this_i2c->tx_size)\r
+ {\r
+ this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
+ }\r
+ else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )\r
+ {\r
+ /* We are finished sending the address offset part of a random read transaction.\r
+ * It is is time to send a restart in order to change direction. */\r
+ this_i2c->dir = READ_DIR;\r
+ this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
+ }\r
+ else /* done sending. let's stop */\r
+ {\r
+ hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;\r
+ if ( hold_bus == 0 )\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */\r
+ }\r
+ else\r
+ {\r
+ NVIC_DisableIRQ( this_i2c->irqn );\r
+ clear_irq = 0;\r
+ }\r
+ this_i2c->status = MSS_I2C_SUCCESS;\r
+ }\r
+ break;\r
+\r
+ case ST_TX_DATA_NACK:\r
+#if 0\r
+ /* data byte SENT, ACK to be received\r
+ * In fact, this means we've received a NACK (This may not be\r
+ * obvious, but if we've rec'd an ACK then we would be in state\r
+ * 0x28!) hence, let's send a stop bit\r
+ */\r
+ this_i2c->hw_reg_bit->CTRL_STO = 0x01;\r
+ this_i2c->status = MSS_I2C_FAILED;\r
+#endif\r
+ /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */\r
+ if (this_i2c->tx_idx < this_i2c->tx_size)\r
+ {\r
+ this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
+ }\r
+ else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION )\r
+ {\r
+ /* We are finished sending the address offset part of a random read transaction.\r
+ * It is is time to send a restart in order to change direction. */\r
+ this_i2c->dir = READ_DIR;\r
+ this_i2c->hw_reg_bit->CTRL_STA = 0x01;\r
+ }\r
+ else /* done sending. let's stop */\r
+ {\r
+ hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;\r
+ if ( hold_bus == 0 )\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */\r
+ }\r
+ else\r
+ {\r
+ NVIC_DisableIRQ( this_i2c->irqn );\r
+ clear_irq = 0;\r
+ }\r
+ this_i2c->status = MSS_I2C_SUCCESS;\r
+ }\r
+ break;\r
+\r
+ /********************* MASTER (or slave?) RECEIVER *************************/\r
+\r
+ /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */\r
+ case ST_SLAR_ACK: /* SLA+R tx'ed. */\r
+ /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless\r
+ * the next byte is the last byte of the read transaction.\r
+ */\r
+ if( this_i2c->rx_size > 1 )\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
+ }\r
+ else\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x00;\r
+ }\r
+ break;\r
+\r
+ case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */\r
+ this_i2c->hw_reg_bit->CTRL_STO = 0x01;\r
+ this_i2c->status = MSS_I2C_FAILED;\r
+ break;\r
+\r
+ case ST_RX_DATA_ACK: /* Data byte received, ACK returned */\r
+ /* First, get the data */\r
+ this_i2c->rx_buffer[this_i2c->rx_idx++] = this_i2c->hw_reg->DATA;\r
+\r
+ if( this_i2c->rx_idx >= this_i2c->rx_size - 1)\r
+ {\r
+ /* If we're at the second last byte, let's set AA to 0 so\r
+ * we return a NACK at the last byte. */\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x00;\r
+ }\r
+ break;\r
+\r
+ case ST_RX_DATA_NACK: /* Data byte received, NACK returned */\r
+ /* Get the data, then send a stop condition */\r
+ this_i2c->rx_buffer[this_i2c->rx_idx++] = this_i2c->hw_reg->DATA;\r
+\r
+ hold_bus = this_i2c->options & MSS_I2C_HOLD_BUS;\r
+ if ( hold_bus == 0 )\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_STO = 0x01; /*xmt stop condition */\r
+ }\r
+ else\r
+ {\r
+ NVIC_DisableIRQ( this_i2c->irqn );\r
+ clear_irq = 0;\r
+ }\r
+\r
+ this_i2c->status = MSS_I2C_SUCCESS;\r
+ break;\r
+\r
+ /******************** SLAVE RECEIVER **************************/\r
+ case ST_GCA_NACK: /* NACK after, GCA addressing */\r
+ case ST_SLA_NACK: /* Get Data, but also re-enable AA (assert ack) bit for future transmissions */\r
+ if ( this_i2c->rx_buffer != 0 )\r
+ {\r
+ this_i2c->rx_buffer[this_i2c->rx_idx] = this_i2c->hw_reg->DATA;\r
+ }\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
+ break;\r
+\r
+ case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */\r
+ this_i2c->transaction = WRITE_SLAVE_TRANSACTION;\r
+ this_i2c->rx_idx = 0;\r
+ this_i2c->random_read_addr = 0;\r
+#ifndef INCLUDE_SLA_IN_RX_PAYLOAD\r
+ /* Only break from this case if the slave address must NOT be included at the\r
+ * beginning of the received write data. */\r
+ break;\r
+#endif\r
+ case ST_GCA_ACK: /* DATA received; ACK sent after GCA */\r
+ case ST_RDATA: /* DATA received; must clear DATA register */\r
+ if (this_i2c->rx_idx >= this_i2c->rx_size - 2)\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x00; /* send a NACK when done (next reception) */\r
+ }\r
+ data = this_i2c->hw_reg->DATA;\r
+ this_i2c->rx_buffer[this_i2c->rx_idx++] = data;\r
+ this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data;\r
+\r
+ break;\r
+\r
+ case ST_RSTOP:\r
+ /* STOP or repeated START occured. */\r
+ /* We cannot be sure if the transaction has actually completed as\r
+ * this hardware state reports that either a STOP or repeated START\r
+ * condition has occured. We assume that this is a repeated START\r
+ * if the transaction was a write from the master to this point.*/\r
+ if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION )\r
+ {\r
+ if ( this_i2c->rx_idx == this_i2c->slave_mem_offset_length )\r
+ {\r
+ this_i2c->transaction = RANDOM_READ_SLAVE_TRANSACTION;\r
+ this_i2c->tx_idx = this_i2c->random_read_addr;\r
+ }\r
+ else\r
+ {\r
+ /* Call the slave's write transaction handler if it exists. */\r
+ if ( this_i2c->slave_write_handler != 0 )\r
+ {\r
+ mss_i2c_slave_handler_ret_t h_ret;\r
+ h_ret = this_i2c->slave_write_handler( this_i2c->rx_buffer, (uint16_t)this_i2c->rx_idx );\r
+ if ( MSS_I2C_REENABLE_SLAVE_RX == h_ret )\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x01;\r
+ }\r
+ else\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x00;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ /* Mark any previous master write transaction as complete. */\r
+ this_i2c->status = MSS_I2C_SUCCESS;\r
+ break;\r
+\r
+ case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */\r
+ case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */\r
+ case ST_GCA: /* General call address received, ACK returned */\r
+ case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */\r
+ /* do nothing */\r
+ break;\r
+\r
+ /****************** SLAVE TRANSMITTER **************************/\r
+ case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */\r
+ case ST_SLARW_LA: /* Arbitration lost, and: */\r
+ case ST_RACK: /* Data tx'ed, ACK received */\r
+ if ( status == ST_SLAVE_SLAR_ACK )\r
+ {\r
+ this_i2c->transaction = READ_SLAVE_TRANSACTION;\r
+ this_i2c->random_read_addr = 0;\r
+ }\r
+ /* Load the data, and determine if it is the last one */\r
+ this_i2c->hw_reg->DATA = this_i2c->tx_buffer[this_i2c->tx_idx++];\r
+ if (this_i2c->tx_idx >= this_i2c->tx_size - 1) /* last byte? */\r
+ {\r
+ this_i2c->hw_reg_bit->CTRL_AA = 0x00;\r
+ /* Next read transaction will result in slave's transmit buffer\r
+ * being sent from the first byte. */\r
+ this_i2c->tx_idx = 0;\r
+ }\r
+ break;\r
+\r
+ case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */\r
+ /* We assume that the transaction will be stopped by the master.\r
+ * Reset tx_idx so that a subsequent read will result in the slave's\r
+ * transmit buffer being sent from the first byte. */\r
+ this_i2c->tx_idx = 0;\r
+ break;\r
+\r
+ case ST_FINAL: /* Last Data byte tx'ed, ACK recieved */\r
+ default:\r
+ /* do nothing */\r
+ break;\r
+ }\r
+\r
+ if ( clear_irq )\r
+ {\r
+ /* clear interrupt. */\r
+ this_i2c->hw_reg_bit->CTRL_SI = 0x00;\r
+ }\r
+\r
+ /* Read the status register to ensure the last I2C registers write took place\r
+ * in a system built around a bus making use of posted writes. */\r
+ status = this_i2c->hw_reg->STATUS;\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ *\r
+ */\r
+uint32_t disable_interrupts( void )\r
+{\r
+ uint32_t primask;\r
+ primask = __get_PRIMASK();\r
+ return primask;\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ *\r
+ */\r
+void restore_interrupts( uint32_t primask )\r
+{\r
+ __set_PRIMASK( primask );\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ *\r
+ */\r
+#if defined(__GNUC__)\r
+__attribute__((__interrupt__)) void I2C0_IRQHandler( void )\r
+#else\r
+void I2C0_IRQHandler( void )\r
+#endif\r
+{\r
+ mss_i2c_isr( &g_mss_i2c0 );\r
+ NVIC_ClearPendingIRQ( I2C0_IRQn );\r
+}\r
+\r
+/*------------------------------------------------------------------------------\r
+ *\r
+ */\r
+#if defined(__GNUC__)\r
+__attribute__((__interrupt__)) void I2C1_IRQHandler( void )\r
+#else\r
+void I2C1_IRQHandler( void )\r
+#endif\r
+{\r
+ mss_i2c_isr( &g_mss_i2c1 );\r
+ NVIC_ClearPendingIRQ( I2C1_IRQn );\r
+}\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
--- /dev/null
+/*******************************************************************************\r
+ * (c) Copyright 2007-2008 Actel Corporation. All rights reserved.\r
+ *\r
+ * SmartFusion microcontroller subsystem I2C bare metal software driver public\r
+ * API.\r
+ *\r
+ * SVN $Revision: 2150 $\r
+ * SVN $Date: 2010-02-11 14:39:24 +0000 (Thu, 11 Feb 2010) $\r
+ */\r
+/*=========================================================================*//**\r
+ @mainpage SmartFusion MSS I2C Bare Metal Driver.\r
+\r
+ @section intro_sec Introduction\r
+ The SmartFusion™ microcontroller subsystem (MSS) includes two I2C peripherals\r
+ for serial communication. This driver provides a set of functions for\r
+ controlling the MSS I2Cs as part of a bare metal system where no operating\r
+ system is available. These drivers can be adapted for use as part of an\r
+ operating system, but the implementation of the adaptation layer between this\r
+ driver and the operating system's driver model is outside the scope of this\r
+ driver.\r
+\r
+ @section hw_dependencies Hardware Flow Dependencies\r
+ The configuration of all features of the MSS I2Cs is covered by this driver\r
+ with the exception of the SmartFusion IOMUX configuration. SmartFusion allows\r
+ multiple non-concurrent uses of some external pins through IOMUX configuration.\r
+ This feature allows optimization of external pin usage by assigning external\r
+ pins for use by either the microcontroller subsystem or the FPGA fabric. The\r
+ MSS I2Cs serial signals are routed through IOMUXes to the SmartFusion device\r
+ external pins. These IOMUXes are automatically configured correctly by the MSS\r
+ configurator tool in the hardware flow when the MSS I2Cs are enabled in that\r
+ tool. You must ensure that the MSS I2Cs are enabled by the MSS configurator\r
+ tool in the hardware flow; otherwise the serial inputs and outputs will not be\r
+ connected to the chip's external pins. For more information on IOMUX, refer to\r
+ the IOMUX section of the SmartFusion Datasheet.\r
+ The base address, register addresses and interrupt number assignment for the\r
+ MSS I2C blocks are defined as constants in the SmartFusion CMSIS-PAL. You must\r
+ ensure that the SmartFusion CMSIS-PAL is either included in the software tool\r
+ chain used to build your project or is included in your project.\r
+\r
+ @section theory_op Theory of Operation\r
+ The MSS I2C driver functions are grouped into the following categories:\r
+ • Initialization and configuration functions\r
+ • Interrupt control\r
+ • I2C master operations – functions to handle write, read and write-read transactions\r
+ • I2C slave operations – functions to handle write, read and write-read transactions\r
+\r
+ Initialization and Configuration\r
+ The MSS I2C driver is initialized through a call to the MSS_I2C_init()\r
+ function. This function takes the MSS I2C's configuration as parameters. The\r
+ MSS_I2C_init() function must be called before any other MSS I2C driver\r
+ functions can be called. The first parameter of the MSS_I2C_init() function\r
+ is a pointer to one of two global data structures used by the driver to\r
+ store state information for each MSS I2C. A pointer to these data structures\r
+ is also used as first parameter to any of the driver functions to identify\r
+ which MSS I2C will be used by the called function. The names of these two\r
+ data structures are g_mss_i2c0 and g_mss_i2c1. Therefore any call to an MSS\r
+ I2C driver function should be of the form MSS_I2C_function_name( &g_mss_i2c0, ... )\r
+ or MSS_I2C_function_name( &g_mss_i2c1, ... ).\r
+ The MSS_I2C_init() function call for each MSS I2C also takes the I2C serial\r
+ address assigned to the MSS I2C and the serial clock divider to be used to\r
+ generate its I2C clock as configuration parameters.\r
+\r
+ Interrupt Control\r
+ The MSS I2C driver is interrupt driven and it enables and disables the\r
+ generation of interrupts by MSS I2C at various times when it is operating.\r
+ The driver automatically handles MSS I2C interrupts internally, including\r
+ enabling disabling and clearing MSS I2C interrupts in the Cortex-M3\r
+ interrupt controller when required.\r
+ The function MSS_I2C_register_write_handler() is used to register a write\r
+ handler function with the MSS I2C driver that it will call on completion of\r
+ an I2C write transaction by the MSS I2C slave. It is your responsibility to\r
+ create and register the implementation of this handler function that will\r
+ process or trigger the processing of the received data.\r
+ Transaction Types\r
+ The MSS I2C driver is designed to handle three types of I2C transaction:\r
+ • Write transactions\r
+ • Read transactions\r
+ • Write-read transactions\r
+\r
+ Write transaction\r
+ The master I2C device initiates a write transaction by sending a START bit\r
+ as soon as the bus becomes free. The START bit is followed by the 7-bit\r
+ serial address of the target slave device followed by the read/write bit\r
+ indicating the direction of the transaction. The slave acknowledges receipt\r
+ of it’s address with an acknowledge bit. The master sends data one byte at\r
+ a time to the slave, which must acknowledge receipt of each byte for the\r
+ next byte to be sent. The master sends a STOP bit to complete the transaction.\r
+ The slave can abort the transaction by replying with a non-acknowledge bit\r
+ instead of an acknowledge.\r
+ The application programmer can choose not to send a STOP bit at the end of\r
+ the transaction causing the next transaction to begin with a repeated START bit.\r
+\r
+ Read transaction\r
+ The master I2C device initiates a read transaction by sending a START bit\r
+ as soon as the bus becomes free. The START bit is followed by the 7-bit\r
+ serial address of the target slave device followed by the read/write bit\r
+ indicating the direction of the transaction. The slave acknowledges receipt\r
+ of it’s slave address with an acknowledge bit. The slave sends data one byte\r
+ at a time to the master, which must acknowledge receipt of each byte for the\r
+ next byte to be sent. The master sends a non-acknowledge bit following the\r
+ last byte it wishes to read followed by a STOP bit.\r
+ The application programmer can choose not to send a STOP bit at the end of\r
+ the transaction causing the next transaction to begin with a repeated START bit.\r
+\r
+ Write-read transaction\r
+ The write-read transaction is a combination of a write transaction\r
+ immediately followed by a read transaction. There is no STOP bit between\r
+ the write and read phases of a write-read transaction. A repeated START\r
+ bit is sent between the write and read phases.\r
+ The write-read transaction is typically used to send a command or offset\r
+ in the write transaction specifying the logical data to be transferred\r
+ during the read phase.\r
+ The application programmer can choose not to send a STOP bit at the end of\r
+ the transaction causing the next transaction to begin with a repeated START bit.\r
+\r
+ Master Operations\r
+ The application can use the MSS_I2C_write(), MSS_I2C_read() and MSS_I2C_write_read()\r
+ functions to initiate an I2C bus transaction. The application can then wait\r
+ for the transaction to complete using the MSS_I2C_wait_complete() function\r
+ or poll the status of the I2C transaction using the MSS_I2C_get_status()\r
+ function until it returns a value different from MSS_I2C_IN_PROGRESS.\r
+\r
+ Slave Operations\r
+ The configuration of the MSS I2C driver to operate as an I2C slave requires\r
+ the use of the following functions:\r
+ • MSS_I2C_set_slave_tx_buffer()\r
+ • MSS_I2C_set_slave_rx_buffer()\r
+ • MSS_I2C_set_slave_mem_offset_length()\r
+ • MSS_I2C_register_write_handler()\r
+ • MSS_I2C_enable_slave_rx()\r
+ Use of all functions is not required if the slave I2C does not need to support\r
+ all types of I2C read transactions. The subsequent sections list the functions\r
+ that must be used to support each transaction type.\r
+\r
+ Responding to read transactions\r
+ The following functions are used to configure the MSS I2C driver to respond\r
+ to I2C read transactions:\r
+ • MSS_I2C_set_slave_tx_buffer()\r
+ • MSS_I2C_enable_slave_rx()\r
+ The function MSS_I2C_set_slave_tx_buffer() specifies the data buffer that\r
+ will be transmitted when the I2C slave is the target of an I2C read\r
+ transaction. It is then up to the application to manage the content of that\r
+ buffer to control the data that will be transmitted to the I2C master as a\r
+ result of the read transaction.\r
+ The function MSS_I2C_enable_slave_rx() enables the MSS I2C hardware instance\r
+ to respond to I2C transactions. It must be called after the MSS I2C driver\r
+ has been configured to respond to the required transaction types.\r
+\r
+ Responding to write transactions\r
+ The following functions are used to configure the MSS I2C driver to respond\r
+ to I2C write transactions:\r
+ • MSS_I2C_set_slave_rx_buffer()\r
+ • MSS_I2C_register_write_handler()\r
+ • MSS_I2C_enable_slave_rx()\r
+ The function MSS_I2C_set_slave_rx_buffer() specifies the data buffer that\r
+ will be used to store the data received by the I2C slave when it is the\r
+ target an I2C write transaction.\r
+ The function MSS_I2C_register_write_handler() specifies the handler function\r
+ that must be called on completion of the I2C write transaction. It is this\r
+ handler function that will process or trigger the processing of the received\r
+ data.\r
+ The function MSS_I2C_enable_slave_rx() enables the MSS I2C hardware instance\r
+ to respond to I2C transactions. It must be called after the MSS I2C driver\r
+ has been configured to respond to the required transaction types.\r
+\r
+ Responding to write-read transactions\r
+ The following functions are used to configure the MSS I2C driver to respond\r
+ to write-read transactions:\r
+ • MSS_I2C_set_slave_tx_buffer()\r
+ • MSS_I2C_set_slave_rx_buffer()\r
+ • MSS_I2C_set_slave_mem_offset_length()\r
+ • MSS_I2C_enable_slave_rx()\r
+ The function MSS_I2C_set_slave_mem_offset_length() specifies the number of\r
+ bytes expected by the I2C slave during the write phase of the write-read\r
+ transaction.\r
+ The function MSS_I2C_set_slave_tx_buffer() specifies the data that will be\r
+ transmitted to the I2C master during the read phase of the write-read\r
+ transaction. The value received by the I2C slave during the write phase of\r
+ the transaction will be used as an index into the transmit buffer specified\r
+ by this function to decide which part of the transmit buffer will be\r
+ transmitted to the I2C master as part of the read phase of the write-read\r
+ transaction.\r
+ The function MSS_I2C_set_slave_rx_buffer() specifies the data buffer that\r
+ will be used to store the data received by the I2C slave during the write\r
+ phase of the write-read transaction. This buffer must be at least large\r
+ enough to accommodate the number of bytes specified through the\r
+ MSS_I2C_set_slave_mem_offset_length() function.\r
+ The function MSS_I2C_enable_slave_rx() enables the MSS I2C hardware\r
+ instance to respond to I2C transactions. It must be called after the MSS\r
+ I2C driver has been configured to respond to the required transaction types.\r
+ *//*=========================================================================*/\r
+#ifndef I2C_H_\r
+#define I2C_H_\r
+\r
+#include "../../CMSIS/a2fxxxm3.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ The mss_i2c_clock_divider_t type is used to specify the divider to be applied\r
+ to the MSS I2C BCLK signal in order to generate the I2C clock.\r
+ */\r
+typedef enum mss_i2c_clock_divider {\r
+ MSS_I2C_PCLK_DIV_256 = 0,\r
+ MSS_I2C_PCLK_DIV_224,\r
+ MSS_I2C_PCLK_DIV_192,\r
+ MSS_I2C_PCLK_DIV_160,\r
+ MSS_I2C_PCLK_DIV_960,\r
+ MSS_I2C_PCLK_DIV_120,\r
+ MSS_I2C_PCLK_DIV_60,\r
+ MSS_I2C_BCLK_DIV_8\r
+} mss_i2c_clock_divider_t;\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ The MSS_I2C_RELEASE_BUS constant is used to specify the options parameter to\r
+ functions MSS_I2C_read(), MSS_I2C_write() and MSS_I2C_write_read() to indicate\r
+ that a STOP bit must be generated at the end of the I2C transaction to release\r
+ the bus.\r
+ */\r
+#define MSS_I2C_RELEASE_BUS 0x00\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ The MSS_I2C_HOLD_BUS constant is used to specify the options parameter to\r
+ functions MSS_I2C_read(), MSS_I2C_write() and MSS_I2C_write_read() to indicate\r
+ that a STOP bit must not be generated at the end of the I2C transaction in\r
+ order to retain the bus ownership. This will cause the next transaction to\r
+ begin with a repeated START bit and no STOP bit between the transactions.\r
+ */\r
+#define MSS_I2C_HOLD_BUS 0x01\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ The mss_i2c_status_t type is used to report the status of I2C transactions.\r
+ */\r
+typedef enum mss_i2c_status\r
+{\r
+ MSS_I2C_SUCCESS = 0,\r
+ MSS_I2C_IN_PROGRESS,\r
+ MSS_I2C_FAILED\r
+} mss_i2c_status_t;\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ The mss_i2c_slave_handler_ret_t type is used by slave write handler functions\r
+ to indicate whether the received data buffer should be released or not.\r
+ */\r
+typedef enum mss_i2c_slave_handler_ret {\r
+ MSS_I2C_REENABLE_SLAVE_RX = 0,\r
+ MSS_I2C_PAUSE_SLAVE_RX = 1\r
+} mss_i2c_slave_handler_ret_t;\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ Slave write handler functions prototype.\r
+ ------------------------------------------------------------------------------\r
+ This defines the function prototype that must be followed by MSS I2C slave\r
+ write handler functions. These functions are registered with the MSS I2C driver\r
+ through the MSS_I2C_register_write_handler() function.\r
+\r
+ Declaring and Implementing Slave Write Handler Functions:\r
+ Slave write handler functions should follow the following prototype:\r
+ mss_i2c_slave_handler_ret_t write_handler( uint8_t * data, uint16_t size );\r
+\r
+ The data parameter is a pointer to a buffer (received data buffer) holding\r
+ the data written to the MSS I2C slave.\r
+ The size parameter is the number of bytes held in the received data buffer.\r
+ Handler functions must return one of the following values:\r
+ • MSS_I2C_REENABLE_SLAVE_RX\r
+ • MSS_I2C_PAUSE_SLAVE_RX.\r
+ If the handler function returns MSS_I2C_REENABLE_SLAVE_RX, the driver will\r
+ release the received data buffer and allow further I2C write transactions to\r
+ the MSS I2C slave to take place.\r
+ If the handler function returns MSS_I2C_PAUSE_SLAVE_RX, the MSS I2C slave\r
+ will respond to subsequent write requests with a non-acknowledge bit (NACK),\r
+ until the received data buffer content has been processed by some other part\r
+ of the software application.\r
+ A call to MSS_I2C_enable_slave_rx() is required at some point after\r
+ returning MSS_I2C_PAUSE_SLAVE_RX in order to release the received data\r
+ buffer so it can be used to store data received by subsequent I2C write\r
+ transactions.\r
+ */\r
+typedef mss_i2c_slave_handler_ret_t (*mss_i2c_slave_wr_handler_t)( uint8_t *, uint16_t );\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ mss_i2c_instance_t\r
+ ------------------------------------------------------------------------------\r
+ There is one instance of this structure for each of the microcontroller\r
+ subsystem's I2Cs. Instances of this structure are used to identify a specific\r
+ I2C. A pointer to an instance of the mss_i2c_instance_t structure is passed as\r
+ the first parameter to MSS I2C driver functions to identify which I2C should\r
+ perform the requested operation.\r
+ */\r
+typedef struct mss_i2c_instance\r
+{\r
+ uint_fast8_t ser_address;\r
+ /* Transmit related info:*/\r
+ uint_fast8_t target_addr;\r
+\r
+ /* Current transaction type (WRITE, READ, RANDOM_READ)*/\r
+ uint8_t transaction;\r
+\r
+ uint_fast16_t random_read_addr;\r
+\r
+ uint8_t options;\r
+\r
+ /* I2C hardware instance identification */\r
+ IRQn_Type irqn;\r
+ I2C_TypeDef * hw_reg;\r
+ I2C_BitBand_TypeDef * hw_reg_bit;\r
+\r
+ /* TX INFO: */\r
+ const uint8_t * tx_buffer;\r
+ uint_fast16_t tx_size;\r
+ uint_fast16_t tx_idx;\r
+ uint_fast8_t dir;\r
+\r
+ /* RX INFO: */\r
+ uint8_t * rx_buffer;\r
+ uint_fast16_t rx_size;\r
+ uint_fast16_t rx_idx;\r
+\r
+ /* status variable: */\r
+ volatile mss_i2c_status_t status;\r
+\r
+ /* Slave data: */\r
+ uint_fast8_t slave_mem_offset_length;\r
+ mss_i2c_slave_wr_handler_t slave_write_handler;\r
+\r
+} mss_i2c_instance_t;\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ This instance of mss_i2c_instance_t holds all data related to the operations\r
+ performed by MSS I2C 0. A pointer to g_mss_i2c0 is passed as the first\r
+ parameter to MSS I2C driver functions to indicate that MSS I2C 0 should\r
+ perform the requested operation.\r
+ */\r
+extern mss_i2c_instance_t g_mss_i2c0;\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ This instance of mss_i2c_instance_t holds all data related to the operations\r
+ performed by MSS I2C 1. A pointer to g_mss_i2c1 is passed as the first\r
+ parameter to MSS I2C driver functions to indicate that MSS I2C 1 should\r
+ perform the requested operation.\r
+ */\r
+extern mss_i2c_instance_t g_mss_i2c1;\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ MSS I2C initialisation routine.\r
+ ------------------------------------------------------------------------------\r
+ The MSS_I2C_init() function initializes and configures hardware and data\r
+ structures of one of the SmartFusion MSS I2Cs.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block to be initialized. There are two such\r
+ data structures, g_mss_i2c0 and g_mss_i2c1, associated with MSS I2C 0 and\r
+ MSS I2C 1 respectively. This parameter must point to either the g_mss_i2c0\r
+ or g_mss_i2c1 global data structure defined within the I2C driver.\r
+\r
+ @param ser_address:\r
+ This parameter sets the I2C serial address being initialized. It is the I2C\r
+ bus address to which the MSS I2C instance will respond. Any 8 bit address is\r
+ allowed.\r
+\r
+ @param ser_clock_speed:\r
+ This parameter sets the I2C serial clock frequency. It selects the divider\r
+ that will be used to generate the serial clock from the APB clock. It can be\r
+ one of the following:\r
+ • MSS_I2C_PCLK_DIV_256\r
+ • MSS_I2C_PCLK_DIV_224\r
+ • MSS_I2C_PCLK_DIV_192\r
+ • MSS_I2C_PCLK_DIV_160\r
+ • MSS_I2C_PCLK_DIV_960\r
+ • MSS_I2C_PCLK_DIV_120\r
+ • MSS_I2C_PCLK_DIV_60\r
+ • MSS_I2C_BCLK_DIV_8\r
+ */\r
+void MSS_I2C_init\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t ser_address,\r
+ mss_i2c_clock_divider_t ser_clock_speed\r
+);\r
+\r
+/*******************************************************************************\r
+ *******************************************************************************\r
+ *\r
+ * Master specific functions\r
+ *\r
+ * The following functions are only used within an I2C master's implementation.\r
+ */\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C master write function.\r
+ ------------------------------------------------------------------------------\r
+ This function initiates an I2C master write transaction. This function returns\r
+ immediately after initiating the transaction. The content of the write buffer\r
+ passed as parameter should not be modified until the write transaction\r
+ completes. It also means that the memory allocated for the write buffer should\r
+ not be freed or go out of scope before the write completes. You can check for\r
+ the write transaction completion using the MSS_I2C_status() function.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+\r
+ @param serial_addr:\r
+ This parameter specifies the serial address of the target I2C device.\r
+\r
+ @param write_buffer:\r
+ This parameter is a pointer to a buffer holding the data to be written to\r
+ the target I2C device.\r
+ Care must be taken not to release the memory used by this buffer before the\r
+ write transaction completes. For example, it is not appropriate to return\r
+ from a function allocating this buffer as an array variable before the write\r
+ transaction completes as this would result in the buffer's memory being\r
+ de-allocated from the stack when the function returns. This memory could\r
+ then be subsequently reused and modified causing unexpected data to be\r
+ written to the target I2C device.\r
+\r
+ @param write_size:\r
+ Number of bytes held in the write_buffer to be written to the target I2C\r
+ device.\r
+\r
+ @param options:\r
+ The options parameter is used to indicate if the I2C bus should be released\r
+ on completion of the write transaction. Using the MSS_I2C_RELEASE_BUS\r
+ constant for the options parameter causes a STOP bit to be generated at the\r
+ end of the write transaction causing the bus to be released for other I2C\r
+ devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter\r
+ prevents a STOP bit from being generated at the end of the write\r
+ transaction, preventing other I2C devices from initiating a bus transaction.\r
+ */\r
+void MSS_I2C_write\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t serial_addr,\r
+ const uint8_t * write_buffer,\r
+ uint16_t write_size,\r
+ uint8_t options\r
+);\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C master read.\r
+ ------------------------------------------------------------------------------\r
+ This function initiates an I2C master read transaction. This function returns\r
+ immediately after initiating the transaction.\r
+ The content of the read buffer passed as parameter should not be modified\r
+ until the read transaction completes. It also means that the memory allocated\r
+ for the read buffer should not be freed or go out of scope before the read\r
+ completes. You can check for the read transaction completion using the\r
+ MSS_I2C_status() function.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+\r
+ @param serial_addr:\r
+ This parameter specifies the serial address of the target I2C device.\r
+\r
+ @param read_buffer\r
+ Pointer to a buffer where the data received from the target device will be\r
+ stored.\r
+ Care must be taken not to release the memory used by this buffer before the\r
+ read transaction completes. For example, it is not appropriate to return\r
+ from a function allocating this buffer as an array variable before the read\r
+ transaction completes as this would result in the buffer's memory being\r
+ de-allocated from the stack when the function returns. This memory could\r
+ then be subsequently reallocated resulting in the read transaction\r
+ corrupting the newly allocated memory.\r
+\r
+ @param read_size:\r
+ This parameter is the number of bytes to read from the target device. This\r
+ size must not exceed the size of the read_buffer buffer.\r
+\r
+ @param options:\r
+ The options parameter is used to indicate if the I2C bus should be released\r
+ on completion of the read transaction. Using the MSS_I2C_RELEASE_BUS\r
+ constant for the options parameter causes a STOP bit to be generated at the\r
+ end of the read transaction causing the bus to be released for other I2C\r
+ devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter\r
+ prevents a STOP bit from being generated at the end of the read transaction,\r
+ preventing other I2C devices from initiating a bus transaction.\r
+ */\r
+void MSS_I2C_read\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t serial_addr,\r
+ uint8_t * read_buffer,\r
+ uint16_t read_size,\r
+ uint8_t options\r
+);\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C master write-read\r
+ ------------------------------------------------------------------------------\r
+ This function initiates an I2C write-read transaction where data is first\r
+ written to the target device before issuing a restart condition and changing\r
+ the direction of the I2C transaction in order to read from the target device.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+\r
+ @param serial_addr:\r
+ This parameter specifies the serial address of the target I2C device.\r
+\r
+ @param addr_offset:\r
+ This parameter is a pointer to the buffer containing the data that will be\r
+ sent to the slave during the write phase of the write-read transaction. This\r
+ data is typically used to specify an address offset specifying to the I2C\r
+ slave device what data it must return during the read phase of the\r
+ write-read transaction.\r
+\r
+ @param offset_size:\r
+ This parameter specifies the number of offset bytes to be written during the\r
+ write phase of the write-read transaction. This is typically the size of the\r
+ buffer pointed to by the addr_offset parameter.\r
+\r
+ @param read_buffer:\r
+ This parameter is a pointer to the buffer where the data read from the I2C\r
+ slave will be stored.\r
+\r
+ @param read_size:\r
+ This parameter specifies the number of bytes to read from the target I2C\r
+ slave device. This size must not exceed the size of the buffer pointed to by\r
+ the read_buffer parameter.\r
+\r
+ @param options:\r
+ The options parameter is used to indicate if the I2C bus should be released\r
+ on completion of the write-read transaction. Using the MSS_I2C_RELEASE_BUS\r
+ constant for the options parameter causes a STOP bit to be generated at the\r
+ end of the write-read transaction causing the bus to be released for other\r
+ I2C devices to use. Using the MSS_I2C_HOLD_BUS constant as options parameter\r
+ prevents a STOP bit from being generated at the end of the write-read\r
+ transaction, preventing other I2C devices from initiating a bus transaction.\r
+ */\r
+void MSS_I2C_write_read\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t serial_addr,\r
+ const uint8_t * addr_offset,\r
+ uint16_t offset_size,\r
+ uint8_t * read_buffer,\r
+ uint16_t read_size,\r
+ uint8_t options\r
+);\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C status\r
+ ------------------------------------------------------------------------------\r
+ This function indicates the current state of a MSS I2C instance.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+ ------------------------------------------------------------------------------\r
+ @return\r
+ The return value indicates the current state of a MSS I2C instance or the\r
+ outcome of the previous transaction if no transaction is in progress.\r
+ Possible return values are:\r
+ SUCCESS\r
+ The last I2C transaction has completed successfully.\r
+ IN_PROGRESS\r
+ There is an I2C transaction in progress.\r
+ FAILED\r
+ The last I2C transaction failed.\r
+\r
+ */\r
+mss_i2c_status_t MSS_I2C_get_status\r
+(\r
+ mss_i2c_instance_t * this_i2c\r
+);\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ Wait for I2C transaction completion.\r
+ ------------------------------------------------------------------------------\r
+ This function waits for the current I2C transaction to complete. The return\r
+ value indicates whether the last I2C transaction was successful, or is still\r
+ in progress, or failed.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+ ------------------------------------------------------------------------------\r
+ @return\r
+ The return value indicates the outcome of the last I2C transaction. It can\r
+ be one of the following:\r
+ MSS_I2C_SUCCESS\r
+ The last I2C transaction has completed successfully.\r
+ MSS_I2C_IN_PROGRESS\r
+ The current I2C transaction is still in progress.\r
+ MSS_I2C_FAILED\r
+ The last I2C transaction failed.\r
+ */\r
+mss_i2c_status_t MSS_I2C_wait_complete\r
+(\r
+ mss_i2c_instance_t * this_i2c\r
+);\r
+\r
+\r
+/*******************************************************************************\r
+ *******************************************************************************\r
+ *\r
+ * Slave specific functions\r
+ *\r
+ * The following functions are only used within the implementation of an I2C\r
+ * slave device.\r
+ */\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C slave transmit buffer configuration.\r
+ ------------------------------------------------------------------------------\r
+ This function specifies the memory buffer holding the data that will be sent\r
+ to the I2C master when this MSS I2C instance is the target of an I2C read or\r
+ write-read transaction.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+\r
+ @param tx_buffer:\r
+ This parameter is a pointer to the memory buffer holding the data to be\r
+ returned to the I2C master when this MSS I2C instance is the target of an\r
+ I2C read or write-read transaction.\r
+\r
+ @param tx_size:\r
+ Size of the transmit buffer pointed to by the tx_buffer parameter.\r
+ */\r
+void MSS_I2C_set_slave_tx_buffer\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t * tx_buffer,\r
+ uint16_t tx_size\r
+);\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C slave receive buffer configuration.\r
+ ------------------------------------------------------------------------------\r
+ This function specifies the memory buffer that will be used by the MSS I2C\r
+ instance to receive data when it is a slave. This buffer is the memory where\r
+ data will be stored when the MSS I2C is the target of an I2C master write\r
+ transaction (i.e. when it is the slave).\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+\r
+ @param rx_buffer:\r
+ This parameter is a pointer to the memory buffer allocated by the caller\r
+ software to be used as a slave receive buffer.\r
+\r
+ @param rx_size:\r
+ Size of the slave receive buffer. This is the amount of memory that is\r
+ allocated to the buffer pointed to by rx_buffer.\r
+ Note: This buffer size will indirectly specify the maximum I2C write\r
+ transaction length this MSS I2C instance can be the target of. This\r
+ is because this MSS I2C instance will respond to further received\r
+ bytes with a non-acknowledge bit (NACK) as soon as its receive\r
+ buffer is full. This will cause the write transaction to fail.\r
+ */\r
+void MSS_I2C_set_slave_rx_buffer\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t * rx_buffer,\r
+ uint16_t rx_size\r
+);\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C slave memory offset length configuration.\r
+ ------------------------------------------------------------------------------\r
+ This function is used as part of the configuration of a MSS I2C instance for\r
+ operation as a slave supporting write-read transactions. It specifies the\r
+ number of bytes expected as part of the write phase of a write-read\r
+ transaction. The bytes received during the write phase of a write-read\r
+ transaction will be interpreted as an offset into the slave’s transmit buffer.\r
+ This allows random access into the I2C slave transmit buffer from a remote\r
+ I2C master.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+\r
+ @param offset_length:\r
+ The offset_length parameter configures the number of bytes to be interpreted\r
+ by the MSS I2C slave as a memory offset value during the write phase of\r
+ write-read transactions.\r
+ */\r
+void MSS_I2C_set_slave_mem_offset_length\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ uint8_t offset_length\r
+);\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C write handler registration.\r
+ ------------------------------------------------------------------------------\r
+ Register the function that will be called to process the data written to this\r
+ MSS I2C instance when it is the slave in an I2C write transaction.\r
+ Note: The write handler is not called as a result of a write-read transaction.\r
+ The write data of a write read transaction is interpreted as an offset\r
+ into the slave’s transmit buffer and handled by the driver.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+\r
+ @param handler:\r
+ Pointer to the function that will process the I2C write request.\r
+ */\r
+void MSS_I2C_register_write_handler\r
+(\r
+ mss_i2c_instance_t * this_i2c,\r
+ mss_i2c_slave_wr_handler_t handler\r
+);\r
+\r
+/*-------------------------------------------------------------------------*//**\r
+ I2C slave receive enable.\r
+ ------------------------------------------------------------------------------\r
+ Enables the MSS I2C instance identified through the this_i2c parameter to\r
+ receive data when it is the target of an I2C write or write-read transaction.\r
+ ------------------------------------------------------------------------------\r
+ @param this_i2c:\r
+ The this_i2c parameter is a pointer to an mss_i2c_instance_t structure\r
+ identifying the MSS I2C hardware block that will perform the requested\r
+ function. There are two such data structures, g_mss_i2c0 and g_mss_i2c1,\r
+ associated with MSS I2C 0 and MSS I2C 1 respectively. This parameter must\r
+ point to either the g_mss_i2c0 or g_mss_i2c1 global data structure defined\r
+ within the I2C driver.\r
+ */\r
+void MSS_I2C_enable_slave_rx\r
+(\r
+ mss_i2c_instance_t * this_i2c\r
+);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /*MSS_I2C_H_*/\r