mirror of https://github.com/ARMmbed/mbed-os.git
620 lines
19 KiB
C
620 lines
19 KiB
C
/* mbed Microcontroller Library
|
|
* Copyright (c) 2019 ARM Limited
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/* Low-level implementation of I2C functionality for MSP432.
|
|
* This implementation does also support DEVICE_I2CSLAVE and DEVICE_I2C_ASYNCH.
|
|
*/
|
|
|
|
|
|
#if DEVICE_I2C
|
|
|
|
#include "i2c_api.h"
|
|
#include "mbed_assert.h"
|
|
|
|
/* With I2C_ASYNCH, our type i2c_s is embedded
|
|
* into a bigger structure (see i2c_api.h). So we
|
|
* need a macro to extract the i2c_s object.
|
|
*/
|
|
#if DEVICE_I2C_ASYNCH
|
|
#define I2C_S(obj) (&((obj)->i2c))
|
|
#else
|
|
#define I2C_S(obj) (obj)
|
|
#endif
|
|
|
|
#if DEVICE_I2C_ASYNCH
|
|
// Array with object pointers for ISR
|
|
i2c_t *i2c_objects[4] = {0};
|
|
#endif
|
|
|
|
/** Initialize the I2C peripheral. It sets the default parameters for I2C
|
|
* peripheral, and configures its specifieds pins.
|
|
*
|
|
* @param obj The I2C object
|
|
* @param sda The sda pin
|
|
* @param scl The scl pin
|
|
*/
|
|
void i2c_init(i2c_t *obj, PinName sda, PinName scl)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
|
|
/* Check if the pins support I2C */
|
|
I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
|
|
I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
|
|
objs->i2c = (I2CName)pinmap_merge(i2c_sda, i2c_scl);
|
|
MBED_ASSERT(objs->i2c != (I2CName)NC);
|
|
|
|
/* Configure I2C pins */
|
|
pinmap_pinout(sda, PinMap_I2C_SDA);
|
|
pinmap_pinout(scl, PinMap_I2C_SCL);
|
|
pin_mode(sda, GET_DATA_MODE(pinmap_function(sda, PinMap_I2C_SDA)));
|
|
pin_mode(scl, GET_DATA_MODE(pinmap_function(scl, PinMap_I2C_SCL)));
|
|
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Put EUSCI to reset state */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_SWRST_OFS) = 1;
|
|
/* Configure I2C mode */
|
|
EUSCI->CTLW0 |= EUSCI_B_CTLW0_MST | /* master mode */
|
|
EUSCI_B_CTLW0_MODE_3 | /* I2C mode */
|
|
EUSCI_B_CTLW0_SSEL__SMCLK; /* SMCLK */
|
|
EUSCI->CTLW1 = 0;
|
|
/* Set i2c clock to default 100 kHz */
|
|
i2c_frequency(obj, 100000);
|
|
/* Disable and clear interrupts */
|
|
EUSCI->IE = 0;
|
|
EUSCI->IFG = 0;
|
|
/* Clear the EUSCI reset state (enable module)*/
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_SWRST_OFS) = 0;
|
|
#if DEVICE_I2C_ASYNCH
|
|
// Store the object pointer for the ISR
|
|
int index = (((uint32_t)(objs->i2c)) >> 10) & 0x3;
|
|
i2c_objects[index] = obj;
|
|
objs->active = false;
|
|
/* Enable the NVIC irq for this I2C module */
|
|
NVIC_EnableIRQ((IRQn_Type)(EUSCIB0_IRQn + index));
|
|
#endif
|
|
}
|
|
|
|
/** Configure the I2C frequency
|
|
*
|
|
* @param obj The I2C object
|
|
* @param hz Frequency in Hz
|
|
*/
|
|
void i2c_frequency(i2c_t *obj, int hz)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Set I2C speed */
|
|
EUSCI->BRW = SubsystemMasterClock / hz;
|
|
}
|
|
|
|
/** Send START command
|
|
* This method will also send the I2C address, along
|
|
* with the R/W bit!
|
|
*
|
|
* @param obj The I2C object
|
|
*/
|
|
int i2c_start(i2c_t *obj)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Trigger a START condition */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTT_OFS) = 1;
|
|
/* Wait until START condition and device address has been sent */
|
|
while (BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTT_OFS)) ;
|
|
return 0;
|
|
}
|
|
|
|
/** Send STOP command
|
|
*
|
|
* @param obj The I2C object
|
|
*/
|
|
int i2c_stop(i2c_t *obj)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Trigger a STOP condition */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTP_OFS) = 1;
|
|
/* Wait until STOP condition has been sent */
|
|
while (BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTP_OFS)) ;
|
|
return 0;
|
|
}
|
|
|
|
/** Blocking reading data
|
|
*
|
|
* @param obj The I2C object
|
|
* @param address 7-bit address (last bit is 1)
|
|
* @param data The buffer for receiving
|
|
* @param length Number of bytes to read
|
|
* @param stop Stop to be generated after the transfer is done
|
|
* @return Number of read bytes
|
|
*/
|
|
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
|
|
{
|
|
/* This I2C implementation does not support a missing STOP
|
|
* condition after a master read operation. To send the final
|
|
* NACK, we will always have to trigger a STOP condition! */
|
|
MBED_ASSERT(stop);
|
|
/* Get the I2C base */
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Clear interrupt status and set slave address */
|
|
EUSCI->IFG = 0;
|
|
EUSCI->I2CSA = address >> 1;
|
|
/* Set receiver mode and send START condition */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TR_OFS) = 0;
|
|
i2c_start(obj);
|
|
int i;
|
|
for (i = 0; i < length; ++i) {
|
|
// Check if last byte to receive
|
|
if (i + 1 == length) {
|
|
// We have to trigger a STOP condition to
|
|
// send the final NACK so the slave knows
|
|
// we do not want any more data.
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTP_OFS) = 1;
|
|
}
|
|
// Wait until data is available
|
|
while (!BITBAND_PERI(EUSCI->IFG, EUSCI_B_IFG_RXIFG0_OFS));
|
|
// read the data
|
|
data[i] = EUSCI->RXBUF;
|
|
}
|
|
if (!length) {
|
|
i2c_stop(obj);
|
|
}
|
|
return length;
|
|
}
|
|
|
|
/** Blocking sending data
|
|
*
|
|
* @param obj The I2C object
|
|
* @param address 7-bit address (last bit is 0)
|
|
* @param data The buffer for sending
|
|
* @param length Number of bytes to write
|
|
* @param stop Stop to be generated after the transfer is done
|
|
* @return
|
|
* zero or non-zero - Number of written bytes
|
|
* negative - I2C_ERROR_XXX status
|
|
*/
|
|
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
|
|
{
|
|
/* Get the I2C base */
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Clear interrupt status and set slave address */
|
|
EUSCI->IFG = 0;
|
|
EUSCI->I2CSA = address >> 1;
|
|
/* Set transmitter mode and send START condition */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TR_OFS) = 1;
|
|
i2c_start(obj);
|
|
int i;
|
|
for (i = 0; i < length; ++i) {
|
|
// Fill transmit buffer
|
|
EUSCI->TXBUF = data[i];
|
|
// Wait until data is available or NACK
|
|
while (!(EUSCI->IFG & (EUSCI_B_IFG_TXIFG0 | EUSCI_B_IFG_NACKIFG)));
|
|
// Check NACK condition
|
|
if (BITBAND_PERI(EUSCI->IFG, EUSCI_B_IFG_NACKIFG_OFS)) {
|
|
// Generate STOP condition if requested
|
|
if (stop) {
|
|
i2c_stop(obj);
|
|
}
|
|
return i ? i - 1 : I2C_ERROR_NO_SLAVE;
|
|
}
|
|
}
|
|
/* Generate STOP condition if requested */
|
|
if (stop) {
|
|
i2c_stop(obj);
|
|
}
|
|
return length;
|
|
}
|
|
|
|
/** Reset I2C peripheral. TODO: The action here. Most of the implementation sends stop()
|
|
*
|
|
* @param obj The I2C object
|
|
*/
|
|
void i2c_reset(i2c_t *obj)
|
|
{
|
|
i2c_stop(obj);
|
|
}
|
|
|
|
/** Read one byte
|
|
*
|
|
* @param obj The I2C object
|
|
* @param last Acknoledge
|
|
* @return The read byte
|
|
*/
|
|
int i2c_byte_read(i2c_t *obj, int last)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Trigger STOP if we receive the last byte */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTP_OFS) = last;
|
|
/* Wait until data is available */
|
|
while (!BITBAND_PERI(EUSCI->IFG, EUSCI_B_IFG_RXIFG0_OFS));
|
|
// Return byte
|
|
return EUSCI->RXBUF;
|
|
}
|
|
|
|
/** Write one byte
|
|
*
|
|
* @param obj The I2C object
|
|
* @param data Byte to be written
|
|
* @return 0 if NAK was received, 1 if ACK was received, 2 for timeout.
|
|
*/
|
|
int i2c_byte_write(i2c_t *obj, int data)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Place character in buffer */
|
|
EUSCI->TXBUF = data;
|
|
// Wait until byte has been sent or NACK
|
|
while (!(EUSCI->IFG & (EUSCI_B_IFG_TXIFG0 | EUSCI_B_IFG_NACKIFG)));
|
|
// return 1 if write was successfull
|
|
return BITBAND_PERI(EUSCI->IFG, EUSCI_B_IFG_NACKIFG_OFS) ? 0 : 1;
|
|
}
|
|
|
|
/** Get the pins that support I2C SDA
|
|
*
|
|
* Return a PinMap array of pins that support I2C SDA in
|
|
* master mode. The array is terminated with {NC, NC, 0}.
|
|
*
|
|
* @return PinMap array
|
|
*/
|
|
const PinMap *i2c_master_sda_pinmap(void)
|
|
{
|
|
return PinMap_I2C_SDA;
|
|
}
|
|
|
|
/** Get the pins that support I2C SCL
|
|
*
|
|
* Return a PinMap array of pins that support I2C SCL in
|
|
* master mode. The array is terminated with {NC, NC, 0}.
|
|
*
|
|
* @return PinMap array
|
|
*/
|
|
const PinMap *i2c_master_scl_pinmap(void)
|
|
{
|
|
return PinMap_I2C_SCL;
|
|
}
|
|
|
|
#if DEVICE_I2CSLAVE
|
|
|
|
/** Configure I2C as slave or master.
|
|
* @param obj The I2C object
|
|
* @param enable_slave Enable i2c hardware so you can receive events with ::i2c_slave_receive
|
|
* @return non-zero if a value is available
|
|
*/
|
|
void i2c_slave_mode(i2c_t *obj, int enable_slave)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Set master/slave mode */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_MST_OFS) = !enable_slave;
|
|
}
|
|
|
|
/** Check to see if the I2C slave has been addressed.
|
|
* @param obj The I2C object
|
|
* @return The status - 1 - read addresses, 2 - write to all slaves,
|
|
* 3 write addressed, 0 - the slave has not been addressed
|
|
*/
|
|
int i2c_slave_receive(i2c_t *obj)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Check irq flags */
|
|
if (EUSCI->IFG & EUSCI_B_IFG_TXIFG0) {
|
|
/* master wants to read, slave has to transmit */
|
|
return 1;
|
|
}
|
|
if (EUSCI->IFG & EUSCI_B_IFG_RXIFG0) {
|
|
/* master has written, slave has to receive */
|
|
return 3;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/** I2C slave reads data from master.
|
|
* @param obj The I2C object
|
|
* @param data The buffer for receiving
|
|
* @param length Number of bytes to read
|
|
* @return non-zero if a value is available
|
|
*/
|
|
int i2c_slave_read(i2c_t *obj, char *data, int length)
|
|
{
|
|
/* Get the I2C base */
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
int i;
|
|
for (i = 0; i < length; ++i) {
|
|
// Wait until data is available
|
|
while (!BITBAND_PERI(EUSCI->IFG, EUSCI_B_IFG_RXIFG0_OFS));
|
|
// read the data
|
|
data[i] = EUSCI->RXBUF;
|
|
}
|
|
return length;
|
|
}
|
|
|
|
/** I2C slave writes data to master.
|
|
* @param obj The I2C object
|
|
* @param data The buffer for sending
|
|
* @param length Number of bytes to write
|
|
* @return non-zero if a value is available
|
|
*/
|
|
int i2c_slave_write(i2c_t *obj, const char *data, int length)
|
|
{
|
|
/* Get the I2C base */
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
int i;
|
|
for (i = 0; i < length; ++i) {
|
|
// Wait until data may be sent
|
|
while (!BITBAND_PERI(EUSCI->IFG, EUSCI_B_IFG_TXIFG0_OFS));
|
|
// Fill transmit buffer
|
|
EUSCI->TXBUF = data[i];
|
|
}
|
|
// Discard the next TXIFG, which is automatically triggered
|
|
// after sending the last byte. Without doing this, the
|
|
// receive()-method would detect a false slave-write!
|
|
while (!BITBAND_PERI(EUSCI->IFG, EUSCI_B_IFG_TXIFG0_OFS));
|
|
BITBAND_PERI(EUSCI->IFG, EUSCI_B_IFG_TXIFG0_OFS) = 0;
|
|
return length;
|
|
}
|
|
|
|
/** Configure I2C address.
|
|
* @param obj The I2C object
|
|
* @param idx Currently not used
|
|
* @param address The address to be set
|
|
* @param mask Currently not used
|
|
*/
|
|
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
/* Put EUSCI to reset state */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_SWRST_OFS) = 1;
|
|
/* Set own address. The EUSCI in I2C mode could
|
|
* also support multiple addresses (idx parameter)
|
|
* and an address mask, but this is currently not
|
|
* used by mbed-os drivers. */
|
|
EUSCI->I2COA0 = (address >> 1) | EUSCI_B_I2COA0_OAEN;
|
|
/* Clear EUSCI reset state) */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_SWRST_OFS) = 0;
|
|
}
|
|
|
|
/** Get the pins that support I2C SDA as slave
|
|
*
|
|
* Return a PinMap array of pins that support I2C SDA in
|
|
* slave mode. The array is terminated with {NC, NC, 0}.
|
|
*
|
|
* @return PinMap array
|
|
*/
|
|
const PinMap *i2c_slave_sda_pinmap(void)
|
|
{
|
|
return PinMap_I2C_SDA;
|
|
}
|
|
|
|
/** Get the pins that support I2C SCL as slave
|
|
*
|
|
* Return a PinMap array of pins that support I2C SCL in
|
|
* slave mode. The array is terminated with {NC, NC, 0}.
|
|
*
|
|
* @return PinMap array
|
|
*/
|
|
const PinMap *i2c_slave_scl_pinmap(void)
|
|
{
|
|
return PinMap_I2C_SCL;
|
|
}
|
|
|
|
#endif /* DEVICE_I2CSLAVE */
|
|
|
|
|
|
#if DEVICE_I2C_ASYNCH
|
|
|
|
/** Start I2C asynchronous transfer
|
|
*
|
|
* @param obj The I2C object
|
|
* @param tx The transmit buffer
|
|
* @param tx_length The number of bytes to transmit
|
|
* @param rx The receive buffer
|
|
* @param rx_length The number of bytes to receive
|
|
* @param address The address to be set - 7bit or 9bit
|
|
* @param stop If true, stop will be generated after the transfer is done
|
|
* @param handler The I2C IRQ handler to be set
|
|
* @param event Event mask for the transfer. See \ref hal_I2CEvents
|
|
* @param hint DMA hint usage
|
|
*/
|
|
void i2c_transfer_asynch(i2c_t *obj,
|
|
const void *tx, size_t tx_length,
|
|
void *rx, size_t rx_length,
|
|
uint32_t address, uint32_t stop,
|
|
uint32_t handler, uint32_t event,
|
|
DMAUsage hint)
|
|
{
|
|
// We ignore DMA for now
|
|
(void) hint;
|
|
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
/* Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
|
|
// Update object
|
|
obj->tx_buff.buffer = (void *)tx;
|
|
obj->tx_buff.length = tx_length;
|
|
obj->tx_buff.pos = 0;
|
|
obj->tx_buff.width = 8;
|
|
|
|
obj->rx_buff.buffer = (void *)rx;
|
|
obj->rx_buff.length = rx_length;
|
|
obj->rx_buff.pos = 0;
|
|
obj->rx_buff.width = 8;
|
|
|
|
objs->send_stop = stop;
|
|
objs->handler = (void (*)(void))handler;
|
|
objs->event = 0;
|
|
objs->available_events = event;
|
|
|
|
/* Clear interrupt status and set slave address */
|
|
EUSCI->IFG = 0;
|
|
EUSCI->I2CSA = address >> 1;
|
|
|
|
// Start the ball rolling by either enabling TX or RX interrupts
|
|
if (tx_length) {
|
|
objs->active = true;
|
|
/* Set transmitter mode and send START condition */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TR_OFS) = 1;
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTT_OFS) = 1;
|
|
EUSCI->IE = EUSCI_B_IE_TXIE | EUSCI_B_IE_NACKIE;
|
|
} else if (rx_length) {
|
|
objs->active = true;
|
|
/* Set receiver mode and send START condition */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TR_OFS) = 0;
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTT_OFS) = 1;
|
|
EUSCI->IE = EUSCI_B_IE_RXIE;
|
|
}
|
|
}
|
|
|
|
/** The asynchronous IRQ handler
|
|
*
|
|
* @param obj The I2C object which holds the transfer information
|
|
* @return Event flags if a transfer termination condition was met, otherwise return 0.
|
|
*/
|
|
uint32_t i2c_irq_handler_asynch(i2c_t *obj)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
return (objs->event & objs->available_events);
|
|
}
|
|
|
|
/** Attempts to determine if the I2C peripheral is already in use
|
|
*
|
|
* @param obj The I2C object
|
|
* @return Non-zero if the I2C module is active or zero if it is not
|
|
*/
|
|
uint8_t i2c_active(i2c_t *obj)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
return objs->active;
|
|
}
|
|
|
|
/** Abort asynchronous transfer
|
|
*
|
|
* This function does not perform any check - that should happen in upper layers.
|
|
* @param obj The I2C object
|
|
*/
|
|
void i2c_abort_asynch(i2c_t *obj)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
// Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
EUSCI->IE = 0;
|
|
EUSCI->IFG = 0;
|
|
objs->active = false;
|
|
}
|
|
|
|
/*************************/
|
|
/* I2C interrupt handler */
|
|
/*************************/
|
|
void handle_I2C_Interrupt(i2c_t *obj)
|
|
{
|
|
struct i2c_s *objs = I2C_S(obj);
|
|
// Get the I2C base */
|
|
EUSCI_B_Type *EUSCI = (EUSCI_B_Type *)objs->i2c;
|
|
uint16_t vector = EUSCI->IV;
|
|
switch (vector) {
|
|
/* UCNACKIFG */
|
|
case 0x04: {
|
|
objs->event = I2C_EVENT_TRANSFER_EARLY_NACK;
|
|
objs->handler();
|
|
break;
|
|
}
|
|
/* UCRXIFG0 */
|
|
case 0x16: {
|
|
struct buffer_s *rx_buff = &obj->rx_buff;
|
|
if (rx_buff->pos < rx_buff->length) {
|
|
((uint8_t *)rx_buff->buffer)[rx_buff->pos] = EUSCI->RXBUF;
|
|
rx_buff->pos++;
|
|
}
|
|
if (rx_buff->pos + 1 == rx_buff->length) {
|
|
EUSCI->CTLW0 |= EUSCI_B_CTLW0_TXSTP;
|
|
}
|
|
if (rx_buff->pos == rx_buff->length) {
|
|
BITBAND_PERI(EUSCI->IE, EUSCI_B_IE_TXIE_OFS) = 0;
|
|
objs->active = false;
|
|
objs->event = I2C_EVENT_TRANSFER_COMPLETE;
|
|
objs->handler();
|
|
}
|
|
break;
|
|
}
|
|
/* UCTXIFG0 */
|
|
case 0x18: {
|
|
struct buffer_s *tx_buff = &obj->tx_buff;
|
|
if (tx_buff->pos < tx_buff->length) {
|
|
EUSCI->TXBUF = ((uint8_t *)tx_buff->buffer)[tx_buff->pos];
|
|
tx_buff->pos++;
|
|
} else {
|
|
if (objs->send_stop) {
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTP_OFS) = 1;
|
|
}
|
|
// Disable interrupts
|
|
EUSCI->IE = 0;
|
|
// Check if we have to receive data
|
|
if (obj->rx_buff.length) {
|
|
/* Set transmitter mode and send START condition */
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TR_OFS) = 0;
|
|
BITBAND_PERI(EUSCI->CTLW0, EUSCI_B_CTLW0_TXSTT_OFS) = 1;
|
|
// Enable the RX interrupts
|
|
EUSCI->IE = EUSCI_B_IE_RXIE;
|
|
} else {
|
|
objs->active = false;
|
|
objs->event = I2C_EVENT_TRANSFER_COMPLETE;
|
|
objs->handler();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void EUSCIB0_I2C_IRQHandler(void)
|
|
{
|
|
handle_I2C_Interrupt(i2c_objects[0]);
|
|
}
|
|
void EUSCIB1_I2C_IRQHandler(void)
|
|
{
|
|
handle_I2C_Interrupt(i2c_objects[1]);
|
|
}
|
|
void EUSCIB2_I2C_IRQHandler(void)
|
|
{
|
|
handle_I2C_Interrupt(i2c_objects[2]);
|
|
}
|
|
void EUSCIB3_I2C_IRQHandler(void)
|
|
{
|
|
handle_I2C_Interrupt(i2c_objects[3]);
|
|
}
|
|
|
|
#endif // DEVICE_I2C_ASYNCH
|
|
|
|
#endif // DEVICE_I2C
|
|
|