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