]> git.sur5r.net Git - freertos/commitdiff
Add I2S driver to the StmartFusion demo.
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Thu, 14 Apr 2011 09:37:07 +0000 (09:37 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Thu, 14 Apr 2011 09:37:07 +0000 (09:37 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1358 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

Demo/CORTEX_A2F200_SoftConsole/MicroSemi_Code/drivers/I2C/i2c.c [new file with mode: 0644]
Demo/CORTEX_A2F200_SoftConsole/MicroSemi_Code/drivers/I2C/i2c.h [new file with mode: 0644]

diff --git a/Demo/CORTEX_A2F200_SoftConsole/MicroSemi_Code/drivers/I2C/i2c.c b/Demo/CORTEX_A2F200_SoftConsole/MicroSemi_Code/drivers/I2C/i2c.c
new file mode 100644 (file)
index 0000000..46dbf62
--- /dev/null
@@ -0,0 +1,798 @@
+/*******************************************************************************\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
diff --git a/Demo/CORTEX_A2F200_SoftConsole/MicroSemi_Code/drivers/I2C/i2c.h b/Demo/CORTEX_A2F200_SoftConsole/MicroSemi_Code/drivers/I2C/i2c.h
new file mode 100644 (file)
index 0000000..63220c3
--- /dev/null
@@ -0,0 +1,775 @@
+/*******************************************************************************\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