void I2C_Master_read(uint8_t slave_address, uint32_t * rxBuffer , uint32_t rxlength)
{
	uint32_t rxCount;
	rxCount = rxlength;
	// Set Slave Address
	TWI1->TWI_MMR |= TWI_MMR_DADR(slave_address);
	// Set Master read
	TWI1->TWI_MMR |= TWI_MMR_MREAD;
	// Set Stop Bit prior to start if rxlength is equal to 1
	if(rxlength == 1)
		TWI1->TWI_CR |= TWI_CR_STOP;
	// Start Communication
	TWI1->TWI_CR |= TWI_CR_START;
	// Receive data until previous to last datum
	while(rxCount > 1)
	{
		// Wait until byte received
		while(!(TWI1->TWI_SR & TWI_SR_RXRDY));
		// store received data in rxBuffer
		*rxBuffer++ = TWI1->TWI_RHR;
		rxCount --;
	}
	// Set Stop Bit if rxlength was higher than 1 
	if(rxlength > 1)
		TWI1->TWI_CR |= TWI_CR_STOP;
	// Wait until last byte received
	while(!(TWI1->TWI_SR & TWI_SR_RXRDY));
	// store last datum in rxBuffer
	*rxBuffer++ = TWI1->TWI_RHR;
	while(!(TWI1->TWI_SR & TWI_SR_TXCOMP));
}
예제 #2
0
파일: i2c_lld_pdc.c 프로젝트: roby85/Viper
/**
 * @brief   Transmits data via the I2C bus as master.
 * @details Number of receiving bytes must be 0 or more than 1 on STM32F1x.
 *          This is hardware restriction.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address
 * @param[in] txbuf     pointer to the transmit buffer
 * @param[in] txbytes   number of bytes to be transmitted
 * @param[out] rxbuf    pointer to the receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The operation status.
 * @retval RDY_OK       if the function succeeded.
 * @retval RDY_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval RDY_TIMEOUT  if a timeout occurred before operation end. <b>After a
 *                      timeout the driver must be stopped and restarted
 *                      because the bus is in an uncertain state</b>.
 *
 * @notapi
 */
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                      const uint8_t *txbuf, size_t txbytes,
                                      uint8_t *rxbuf, size_t rxbytes,
                                      systime_t timeout) {

    (void)i2cp;
    (void)addr;
    (void)txbuf;
    (void)txbytes;
    (void)rxbuf;
    (void)rxbytes;
    (void)timeout;

    i2cdef_t i2c = i2cp->i2c;
    uint32_t status;

    /* Set write mode, slave address and 3 internal address byte lengths */
    i2c->TWI_MMR = 0;
    i2c->TWI_MMR = TWI_MMR_DADR(addr->chip) |
                   ((addr->len << TWI_MMR_IADRSZ_Pos) &
                    TWI_MMR_IADRSZ_Msk);

    /* Set internal address for remote chip */
    i2c->TWI_IADR = 0;
    i2c->TWI_IADR = twi_mk_addr(addr->addr, addr->len);

    /* Send all bytes */
    while (txbytes > 0) {
        status = i2c->TWI_SR;
        if (status & TWI_SR_NACK) {
            return RDY_RESET;
        }

        if (!(status & TWI_SR_TXRDY)) {
            continue;
        }
        i2c->TWI_THR = *txbuf++;

        txbytes--;
    }

    while (1) {
        status = i2c->TWI_SR;
        if (status & TWI_SR_NACK) {
            return RDY_RESET;
        }

        if (status & TWI_SR_TXRDY) {
            break;
        }
    }

    i2c->TWI_CR = TWI_CR_STOP;

    while (!(i2c->TWI_SR & TWI_SR_TXCOMP)) {
    }


    return RDY_OK;
}
예제 #3
0
void twi_send(Twi *this_twi, wbuff *nwb, uint32_t address)
{
	this_twi->TWI_MMR = TWI_MMR_DADR(address) | TWI_MMR_IADRSZ_1_BYTE;
	this_twi->TWI_IADR = TWI_IADR_IADR(nwb->buff[0]);
	this_twi->TWI_CR =  TWI_CR_MSEN;
	this_twi->TWI_THR = nwb->buff[1];
	this_twi->TWI_CR = TWI_CR_STOP;
}
예제 #4
0
파일: twi.c 프로젝트: roby85/Viper
/**
 * \brief Read multiple bytes from a TWI compatible slave device.
 *
 * \note This function will NOT return until all data has been read or error occurs.
 *
 * \param p_twi Pointer to a TWI instance.
 * \param p_packet Packet information and data (see \ref twi_packet_t).
 *
 * \return TWI_SUCCESS if all bytes were read, error code otherwise.
 */
uint32_t twi_master_read(Twi *p_twi, twi_packet_t *p_packet)
{
	uint32_t status;
	uint32_t cnt = p_packet->length;
	uint8_t *buffer = p_packet->buffer;
	uint8_t stop_sent = 0;
	
	/* Check argument */
	if (cnt == 0) {
		return TWI_INVALID_ARGUMENT;
	}

	/* Set read mode, slave address and 3 internal address byte lengths */
	p_twi->TWI_MMR = 0;
	p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(p_packet->chip) |
			((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
			TWI_MMR_IADRSZ_Msk);

	/* Set internal address for remote chip */
	p_twi->TWI_IADR = 0;
	p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);

	/* Send a START condition */
	if (cnt == 1) {
		p_twi->TWI_CR = TWI_CR_START | TWI_CR_STOP;
		stop_sent = 1;
	} else {
		p_twi->TWI_CR = TWI_CR_START;
		stop_sent = 0;
	}

	while (cnt > 0) {
		status = p_twi->TWI_SR;
		if (status & TWI_SR_NACK) {
			return TWI_RECEIVE_NACK;
		}

		/* Last byte ? */
		if (cnt == 1  && !stop_sent) {
			p_twi->TWI_CR = TWI_CR_STOP;
			stop_sent = 1;
		}

		if (!(status & TWI_SR_RXRDY)) {
			continue;
		}
		*buffer++ = p_twi->TWI_RHR;

		cnt--;
	}

	while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
	}

	p_twi->TWI_SR;

	return TWI_SUCCESS;
}
예제 #5
0
/**
 * \brief Write multiple bytes to a TWI compatible slave device.
 *
 * \note This function will NOT return until all data has been written or error occurred.
 *
 * \param p_twi Pointer to a TWI instance.
 * \param p_packet Packet information and data (see \ref twi_packet_t).
 *
 * \return TWI_SUCCESS if all bytes were written, error code otherwise.
 */
uint32_t twi_master_write(Twi *p_twi, twi_packet_t *p_packet)
{
	uint32_t status;
	uint32_t cnt = p_packet->length;
	uint8_t *buffer = p_packet->buffer;

	/* Check argument */
	if (cnt == 0) {
		return TWI_INVALID_ARGUMENT;
	}

	/* Set write mode, slave address and 3 internal address byte lengths */
	p_twi->TWI_MMR = 0;
	p_twi->TWI_MMR = TWI_MMR_DADR(p_packet->chip) |
			((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
			TWI_MMR_IADRSZ_Msk);

	/* Set internal address for remote chip */
	p_twi->TWI_IADR = 0;
	p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);

	/* Send all bytes */
	while (cnt > 0) {
		status = p_twi->TWI_SR;
		if (status & TWI_SR_NACK) {
			return TWI_RECEIVE_NACK;
		}

		if (!(status & TWI_SR_TXRDY)) {
			continue;
		}
		p_twi->TWI_THR = *buffer++;

		cnt--;
	}

	while (1) {
		status = p_twi->TWI_SR;
		if (status & TWI_SR_NACK) {
			return TWI_RECEIVE_NACK;
		}

		if (status & TWI_SR_TXRDY) {
			break;
		}
	}

	p_twi->TWI_CR = TWI_CR_STOP;

	while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
	}

	return TWI_SUCCESS;
}
예제 #6
0
static void write_msg_start(Twi *const twi, struct twi_msg *msg, u8_t daddr)
{
	/* Set slave address and number of internal address bytes. */
	twi->TWI_MMR = TWI_MMR_DADR(daddr);

	/* Write first data byte on I2C bus */
	twi->TWI_THR = msg->buf[msg->idx++];

	/* Enable Transmit Ready and Transmission Completed interrupts */
	twi->TWI_IER = TWI_IER_TXRDY | TWI_IER_TXCOMP | TWI_IER_NACK;
}
예제 #7
0
파일: i2c_lld_pdc.c 프로젝트: roby85/Viper
/**
 * @brief   Receives data via the I2C bus as master.
 * @details Number of receiving bytes must be more than 1 on STM32F1x. This is
 *          hardware restriction.
 *
 * @param[in] i2cp      pointer to the @p I2CDriver object
 * @param[in] addr      slave device address
 * @param[out] rxbuf    pointer to the receive buffer
 * @param[in] rxbytes   number of bytes to be received
 * @param[in] timeout   the number of ticks before the operation timeouts,
 *                      the following special values are allowed:
 *                      - @a TIME_INFINITE no timeout.
 *                      .
 * @return              The operation status.
 * @retval RDY_OK       if the function succeeded.
 * @retval RDY_RESET    if one or more I2C errors occurred, the errors can
 *                      be retrieved using @p i2cGetErrors().
 * @retval RDY_TIMEOUT  if a timeout occurred before operation end. <b>After a
 *                      timeout the driver must be stopped and restarted
 *                      because the bus is in an uncertain state</b>.
 *
 * @notapi
 */
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
                                     uint8_t *rxbuf, size_t rxbytes,
                                     systime_t timeout) {

    (void)i2cp;
    (void)addr;
    (void)rxbuf;
    (void)rxbytes;
    (void)timeout;
    uint32_t status;
    uint32_t stop_sent;
    i2cdef_t i2c = i2cp->i2c;

    /* Set read mode, slave address and 3 internal address byte lengths */
    i2c->TWI_MMR = 0;
    i2c->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(addr->chip) | ((addr->len << TWI_MMR_IADRSZ_Pos) & TWI_MMR_IADRSZ_Msk);

    /* Set internal address for remote chip */
    i2c->TWI_IADR = 0;
    i2c->TWI_IADR = twi_mk_addr(addr->addr, addr->len);




    /* Send a START condition */
    if (rxbytes = 1) {
        i2c->TWI_CR = TWI_CR_START | TWI_CR_STOP;
        while (!(i2c->TWI_SR & TWI_SR_RXRDY));
        *rxbuf = i2c->TWI_RHR;

    } else {
        i2c->TWI_PTCR = TWI_PTCR_RXTDIS | TWI_PTCR_TXTDIS;


        i2c->TWI_IER = TWI_IER_ENDRX | TWI_IER_NACK | TWI_IER_OVRE;

        chSysLock();
        i2cp->thread = chThdSelf();
        i2c->TWI_RNPR = 0;
        i2c->TWI_RNCR = 0;
        i2c->TWI_RPR = (uint32_t) rxbuf;
        i2c->TWI_RCR = rxbytes - 2;
        i2c->TWI_PTCR = TWI_PTCR_RXTEN;
        i2cp->curbuf = rxbuf + (rxbytes - 2);

        i2c->TWI_CR = TWI_CR_START;
        chSchGoSleepS(THD_STATE_SUSPENDED);

        return chThdSelf()->p_u.rdymsg;
    }

    return RDY_OK;
}
예제 #8
0
/*************************************************************************
 Issues a start condition and sends address and transfer direction.
 If device is busy, use ack polling to wait until device is ready

 Input:   address and transfer direction of I2C device
*************************************************************************/
void HAL::i2cStartWait(unsigned char address_and_direction)
{
     uint32_t twiDirection = address_and_direction & 1;
    uint32_t address = address_and_direction >> 1;

    while(!(TWI_INTERFACE->TWI_SR & TWI_SR_TXCOMP));

    // set to master mode
    TWI_INTERFACE->TWI_CR = TWI_CR_MSEN | TWI_CR_SVDIS;

    // set master mode register with no internal address
    TWI_INTERFACE->TWI_MMR = 0;
    TWI_INTERFACE->TWI_MMR = (twiDirection << 12) | TWI_MMR_IADRSZ_NONE |  
         TWI_MMR_DADR(address);
}
예제 #9
0
static void read_msg_start(Twi *const twi, struct twi_msg *msg, u8_t daddr)
{
	u32_t twi_cr_stop;

	/* Set slave address and number of internal address bytes */
	twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(daddr);

	/* In single data byte read the START and STOP must both be set */
	twi_cr_stop = (msg->len == 1) ? TWI_CR_STOP : 0;
	/* Start the transfer by sending START condition */
	twi->TWI_CR = TWI_CR_START | twi_cr_stop;

	/* Enable Receive Ready and Transmission Completed interrupts */
	twi->TWI_IER = TWI_IER_RXRDY | TWI_IER_TXCOMP | TWI_IER_NACK;
}
예제 #10
0
/*************************************************************************
  Issues a start condition and sends address and transfer direction.
  return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char HAL::i2cStart(unsigned char address_and_direction)
{
  uint32_t twiDirection = address_and_direction & 1;
  uint32_t address = address_and_direction >> 1;

  // set master mode register with no internal address
  TWI_INTERFACE->TWI_MMR = 0;
  TWI_INTERFACE->TWI_MMR = (twiDirection << 12) | TWI_MMR_IADRSZ_NONE |
                           TWI_MMR_DADR(address);
  TWI_INTERFACE->TWI_CR = TWI_CR_MSEN | TWI_CR_SVDIS; //set master mode disable slave mode
  if (twiDirection)  TWI_INTERFACE->TWI_CR = TWI_CR_START; //send Start Bit for receiving data
  // returning readiness to send/recieve not device accessibility
  // return value not used in code anyway
  return !(TWI_INTERFACE->TWI_SR & TWI_SR_TXCOMP);
}
예제 #11
0
static int
eeprom_read(uint32_t EE_DEV_ADDR, uint32_t ee_off, void * buf, uint32_t size)
{
	uint8_t *bufptr = (uint8_t *)buf;
	uint32_t status;
	uint32_t count;

	/* Clean out any old status and received byte. */
	status = RD4HW(AT91RM92_TWI_BASE, TWI_SR);
	status = RD4HW(AT91RM92_TWI_BASE, TWI_RHR);

	/* Set the TWI Master Mode Register */
	WR4HW(AT91RM92_TWI_BASE, TWI_MMR,
	    TWI_MMR_DADR(EE_DEV_ADDR) | TWI_MMR_IADRSZ(2) | TWI_MMR_MREAD);

	/* Set TWI Internal Address Register */
	WR4HW(AT91RM92_TWI_BASE, TWI_IADR, ee_off);

	/* Start transfer */
	WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_START);

	status = RD4HW(AT91RM92_TWI_BASE, TWI_SR);

	while (size-- > 1){
		/* Wait until Receive Holding Register is full */
		count = 1000000;
		while (!(RD4HW(AT91RM92_TWI_BASE, TWI_SR) & TWI_SR_RXRDY) && 
		    --count != 0)
			continue;
		if (count <= 0)
			return -1;
		/* Read and store byte */
		*bufptr++ = (uint8_t)RD4HW(AT91RM92_TWI_BASE, TWI_RHR);
	}
	WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_STOP);

	status = RD4HW(AT91RM92_TWI_BASE, TWI_SR);

	/* Wait until transfer is finished */
	while (!(RD4HW(AT91RM92_TWI_BASE, TWI_SR) & TWI_SR_TXCOMP))
		continue;

	/* Read last byte */
	*bufptr = (uint8_t)RD4HW(AT91RM92_TWI_BASE, TWI_RHR);

	return 0;
}
예제 #12
0
/*************************************************************************
 Issues a start condition and sends address and transfer direction.
 If device is busy, use ack polling to wait until device is ready

 Input:   address and transfer direction of I2C device
*************************************************************************/
void HAL::i2cStartWait(unsigned char address_and_direction)
{
  uint32_t twiDirection = address_and_direction & 1;
  uint32_t address = address_and_direction >> 1;

  while (!(TWI_INTERFACE->TWI_SR & TWI_SR_TXCOMP));

  // set master mode register with no internal address

  TWI_INTERFACE->TWI_MMR = 0;
  TWI_INTERFACE->TWI_MMR = (twiDirection << 12) | TWI_MMR_IADRSZ_NONE |
                           TWI_MMR_DADR(address);
  
  TWI_INTERFACE->TWI_CR = TWI_CR_MSEN | TWI_CR_SVDIS; //set master mode disable slave mode

  if (twiDirection)  TWI_INTERFACE->TWI_CR = TWI_CR_START;//send Start Bit for receiving data
}
void I2C_Master_write(uint8_t slave_address, uint32_t * txBuffer , uint32_t txlength, uint8_t stop_enable)
{
	uint32_t txCount;
	txCount = txlength;
	// Set Slave Address
	TWI1->TWI_MMR |= TWI_MMR_DADR(slave_address);
	// Set Master write
	TWI1->TWI_MMR &= ~(TWI_MMR_MREAD);
	while (txCount)
	{
		// Wait until TWI ready to transmit
		while(!(TWI1->TWI_SR & TWI_SR_TXRDY));
		// store received data in rxBuffer
		TWI1->TWI_THR = * txBuffer++ ;
		txCount --;
	}
	// Set Stop Bit if enabled
	if (stop_enable)
	{
		TWI1->TWI_CR |= TWI_CR_STOP;
		while(!(TWI1->TWI_SR & TWI_SR_TXCOMP));
	}
}
예제 #14
0
{
#if EEPROM_AVAILABLE == EEPROM_I2C
  uint32_t twiDirection = address_and_direction & 1;
  uint32_t address = address_and_direction >> 1;

  // if 1 byte address, eeprom uses lower address bits for pos > 255
  if (EEPROM_ADDRSZ_BYTES == TWI_MMR_IADRSZ_1_BYTE)
  {
    address |= pos >> 8;
    pos &= 0xFF;
  }

  // set master mode register with internal address
  TWI_INTERFACE->TWI_MMR = 0;
  TWI_INTERFACE->TWI_MMR = (twiDirection << 12) | EEPROM_ADDRSZ_BYTES |
                           TWI_MMR_DADR(address);

  // write internal address register
  TWI_INTERFACE->TWI_IADR = 0;
  TWI_INTERFACE->TWI_IADR = TWI_IADR_IADR(pos);

  if (twiDirection) TWI_INTERFACE->TWI_CR = TWI_CR_START;//send Start Bit for receiving data
#endif  
}

/*************************************************************************
 Terminates the data transfer and releases the I2C bus
*************************************************************************/
void HAL::i2cStop(void)
{
  while ( (TWI_INTERFACE->TWI_SR & TWI_SR_TXRDY) != TWI_SR_TXRDY);//wait for transmission finished
예제 #15
0
static int
at91_twi_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
{
	struct at91_twi_softc *sc;
	int i, len, err;
	uint32_t rdwr;
	uint8_t *buf;
	uint32_t sr;

	sc = device_get_softc(dev);
	err = 0;
	AT91_TWI_LOCK(sc);
	for (i = 0; i < nmsgs; i++) {
		/*
		 * The linux atmel driver doesn't use the internal device
		 * address feature of twi.  A separate i2c message needs to
		 * be written to use this.
		 * See http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html
		 * for details.  Upon reflection, we could use this as an
		 * optimization, but it is unclear the code bloat will
		 * result in faster/better operations.
		 */
		rdwr = (msgs[i].flags & IIC_M_RD) ? TWI_MMR_MREAD : 0;
		WR4(sc, TWI_MMR, TWI_MMR_DADR(msgs[i].slave) | rdwr);
		len = msgs[i].len;
		buf = msgs[i].buf;
		/* zero byte transfers aren't allowed */
		if (len == 0 || buf == NULL) {
			err = EINVAL;
			goto out;
		}
		if (len == 1 && msgs[i].flags & IIC_M_RD)
			WR4(sc, TWI_CR, TWI_CR_START | TWI_CR_STOP);
		else
			WR4(sc, TWI_CR, TWI_CR_START);
		if (msgs[i].flags & IIC_M_RD) {
			sr = RD4(sc, TWI_SR);
			while (!(sr & TWI_SR_TXCOMP)) {
				if ((sr = RD4(sc, TWI_SR)) & TWI_SR_RXRDY) {
					len--;
					*buf++ = RD4(sc, TWI_RHR) & 0xff;
					if (len == 1)
						WR4(sc, TWI_CR, TWI_CR_STOP);
				}
			}
			if (len > 0 || (sr & TWI_SR_NACK)) {
				err = ENXIO;		// iic nack convention
				goto out;
			}
		} else {
			while (len--) {
				if ((err = at91_twi_wait(sc, TWI_SR_TXRDY)))
					goto out;
				WR4(sc, TWI_THR, *buf++);
			}
			WR4(sc, TWI_CR, TWI_CR_STOP);
		}
		if ((err = at91_twi_wait(sc, TWI_SR_TXCOMP)))
			break;
	}
out:
	if (err) {
		WR4(sc, TWI_CR, TWI_CR_SWRST);
		WR4(sc, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS);
		WR4(sc, TWI_CWGR, sc->cwgr);
	}
	AT91_TWI_UNLOCK(sc);
	return (err);
}
예제 #16
0
/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte write operation on a TWI
 * peripheral.
 *
 * freertos_twi_write_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the TWI peripheral DMA controller (PDC) to transmit data on the
 * TWI port, then returns.  freertos_twi_write_packet_async() does not wait for
 * the transmission to complete before returning.
 *
 * The FreeRTOS TWI driver is initialized using a call to
 * freertos_twi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_twi_write_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_TX_COMPLETE bit clear. It can also only be used if packet
 * length is more than 1.
 *
 * freertos_twi_write_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_twi_write_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_twi    The handle to the TWI peripheral returned by the
 *     freertos_twi_master_init() call used to initialise the peripheral.
 * \param p_packet    Structure that defines the TWI transfer parameters, such
 *     as the I2C chip being addressed, the source data location, and the number
 *     of bytes to transmit.  twi_packet_t is a standard ASF type (it is not
 *     FreeRTOS specific).
 * \param block_time_ticks    The FreeRTOS ASF TWI driver is initialized using a
 *     call to freertos_twi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_TX_ACCESS_MUTEX bit
 *     set, then the driver will only write to the TWI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the write operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the transmit
 *     function exits the transmit function as soon as the transmission starts.
 *     The data being transmitted by the PDC must not be modified until after
 *     the transmission has completed.  The PDC interrupt (handled internally by
 *     the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has finished accessing the data.
 *     The calling task can call standard FreeRTOS functions to block on the
 *     semaphore until the PDC interrupt occurs.  Other RTOS tasks will execute
 *     while the the calling task is in the Blocked state.  The semaphore must
 *     be created using the FreeRTOS vSemaphoreCreateBinary() API function
 *     before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the TWI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the TWI write operation.
 */
status_code_t freertos_twi_write_packet_async(freertos_twi_if p_twi,
		twi_packet_t *p_packet, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE twi_index;
	Twi *twi_base;
	uint32_t internal_address = 0;

	twi_base = (Twi *) p_twi;
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) twi_base);

	/* Don't do anything unless a valid TWI pointer was used. */
	if ((twi_index < MAX_TWIS) && (p_packet->length > 0)) {
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[twi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Set write mode and slave address. */
			twi_base->TWI_MMR = 0;
			twi_base->TWI_MMR = TWI_MMR_DADR(p_packet->chip) |
					((p_packet->addr_length <<
					TWI_MMR_IADRSZ_Pos) &
					TWI_MMR_IADRSZ_Msk);

			/* Set internal address if any. */
			if (p_packet->addr_length > 0) {
				internal_address = p_packet->addr[0];
				if (p_packet->addr_length > 1) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[1];
				}

				if (p_packet->addr_length > 2) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[2];
				}
			}
			twi_base->TWI_IADR = internal_address;

			if (p_packet->length == 1) {
				uint32_t status;
				uint32_t timeout_counter = 0;
				/* Do not handle errors for short packets in interrupt handler */
				twi_disable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Send start condition */
				twi_base->TWI_THR = *((uint8_t*)(p_packet->buffer));
				while (1) {
					status = twi_base->TWI_SR;
					if (status & TWI_SR_NACK) {
						/* Re-enable interrupts */
						twi_enable_interrupt(
								all_twi_definitions[twi_index].peripheral_base_address,
								IER_ERROR_INTERRUPTS);
						/* Release semaphore */
						xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
						return ERR_BUSY;
					}
					if (status & TWI_SR_TXRDY) {
						break;
					}
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}
				twi_base->TWI_CR = TWI_CR_STOP;
				/* Wait for TX complete */
				while (!(twi_base->TWI_SR & TWI_SR_TXCOMP)) {
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}

				/* Re-enable interrupts */
				twi_enable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Release semaphores */
				xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
				if (return_value != ERR_TIMEOUT) {
					if (tx_dma_control[twi_index].transaction_complete_notification_semaphore != NULL) {
						xSemaphoreGive(tx_dma_control[twi_index].transaction_complete_notification_semaphore);
					}
				}

			} else {

				twis[twi_index].buffer = p_packet->buffer;
				twis[twi_index].length = p_packet->length;

				freertos_start_pdc_tx(&(tx_dma_control[twi_index]),
						p_packet->buffer, p_packet->length - 1,
						all_twi_definitions[twi_index].pdc_base_address,
						notification_semaphore);

				/* Catch the end of transmission so the access mutex can be
				returned, and the task notified (if it supplied a notification
				semaphore).  The interrupt can be enabled here because the ENDTX
				signal from the PDC to the peripheral will have been de-asserted when
				the next transfer was configured. */
				twi_enable_interrupt(twi_base, TWI_IER_ENDTX);

				return_value = freertos_optionally_wait_transfer_completion(
						&(tx_dma_control[twi_index]),
						notification_semaphore,
						block_time_ticks);
			}
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}
예제 #17
0
/**
 * \ingroup freertos_twi_peripheral_control_group
 * \brief Initiate a completely asynchronous multi-byte read operation on an TWI
 * peripheral.
 *
 * freertos_twi_read_packet_async() is an ASF specific FreeRTOS driver function.
 * It configures the TWI peripheral DMA controller (PDC) to read data from the
 * TWI port, then returns.  freertos_twi_read_packet_async() does not wait for
 * the reception to complete before returning.
 *
 * The FreeRTOS ASF TWI driver is initialized using a call to
 * freertos_twi_master_init().  The freertos_driver_parameters.options_flags
 * parameter passed into the initialization function defines the driver behavior.
 * freertos_twi_read_packet_async() can only be used if the
 * freertos_driver_parameters.options_flags parameter passed to the initialization
 * function had the WAIT_RX_COMPLETE bit clear. The function can also only be used
 * if the length of the packet is more that two. If less, it will block until the
 * transfer is done.
 *
 * freertos_twi_read_packet_async() is an advanced function and readers are
 * recommended to also reference the application note and examples that
 * accompany the FreeRTOS ASF drivers.  freertos_twi_read_packet() is a version
 * that does not exit until the PDC transfer is complete, but still allows other
 * RTOS tasks to execute while the transmission is in progress.
 *
 * The FreeRTOS ASF driver both installs and handles the TWI PDC interrupts.
 * Users do not need to concern themselves with interrupt handling, and must
 * not install their own interrupt handler.
 *
 * \param p_twi    The handle to the TWI port returned by the
 *     freertos_twi_master_init() call used to initialise the port.
 * \param p_packet    Structure that defines the TWI transfer parameters, such
 *     as the I2C chip being addressed, the destination for the data being read,
 *     and the number of bytes to read.  twi_packet_t is a standard ASF type (it
 *     is not FreeRTOS specific).
 * \param block_time_ticks    The FreeRTOS ASF TWI driver is initialized using a
 *     call to freertos_twi_master_init().  The
 *     freertos_driver_parameters.options_flags parameter passed to the
 *     initialization function defines the driver behavior.  If
 *     freertos_driver_parameters.options_flags had the USE_RX_ACCESS_MUTEX bit
 *     set, then the driver will only read from the TWI peripheral if it has
 *     first gained exclusive access to it.  block_time_ticks specifies the
 *     maximum amount of time the driver will wait to get exclusive access
 *     before aborting the read operation.  Other tasks will execute during any
 *     waiting time.  block_time_ticks is specified in RTOS tick periods.  To
 *     specify a block time in milliseconds, divide the milliseconds value by
 *     portTICK_RATE_MS, and pass the result in block_time_ticks.
 *     portTICK_RATE_MS is defined by FreeRTOS.
 * \param notification_semaphore    The RTOS task that calls the receive
 *     function exits the receive function as soon as the reception starts.
 *     The data being received by the PDC cannot normally be processed until
 *     after the reception has completed.  The PDC interrupt (handled internally
 *     by the FreeRTOS ASF driver) 'gives' the semaphore when the PDC transfer
 *     completes.  The notification_semaphore therefore provides a mechanism for
 *     the calling task to know when the PDC has read the requested number of
 *     bytes.  The calling task can call standard FreeRTOS functions to block on
 *     the semaphore until the PDC interrupt occurs.  Other RTOS tasks will
 *     execute while the the calling task is in the Blocked state.  The
 *     semaphore must be created using the FreeRTOS vSemaphoreCreateBinary() API
 *     function before it is used as a parameter.
 *
 * \return     ERR_INVALID_ARG is returned if an input parameter is invalid.
 *     ERR_TIMEOUT is returned if block_time_ticks passed before exclusive
 *     access to the TWI peripheral could be obtained.  STATUS_OK is returned if
 *     the PDC was successfully configured to perform the TWI read operation.
 */
status_code_t freertos_twi_read_packet_async(freertos_twi_if p_twi,
		twi_packet_t *p_packet, portTickType block_time_ticks,
		xSemaphoreHandle notification_semaphore)
{
	status_code_t return_value;
	portBASE_TYPE twi_index;
	Twi *twi_base;
	uint32_t internal_address = 0;

	twi_base = (Twi *) p_twi;
	twi_index = get_pdc_peripheral_details(all_twi_definitions, MAX_TWIS,
			(void *) twi_base);

	/* Don't do anything unless a valid TWI pointer was used. */
	if ((twi_index < MAX_TWIS) && (p_packet->length > 0)) {
		/* Because the peripheral is half duplex, there is only one access mutex
		and the rx uses the tx mutex. */
		return_value = freertos_obtain_peripheral_access_mutex(
				&(tx_dma_control[twi_index]), &block_time_ticks);

		if (return_value == STATUS_OK) {
			/* Ensure Rx is already empty. */
			twi_read_byte(twi_base);

			/* Set read mode and slave address. */
			twi_base->TWI_MMR = 0;
			twi_base->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(
					p_packet->chip) |
					((p_packet->addr_length <<
					TWI_MMR_IADRSZ_Pos) &
					TWI_MMR_IADRSZ_Msk);

			/* Set internal address if any. */
			if (p_packet->addr_length) {
				internal_address = p_packet->addr [0];
				if (p_packet->addr_length > 1) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[1];
				}

				if (p_packet->addr_length > 2) {
					internal_address <<= 8;
					internal_address |= p_packet->addr[2];
				}
			}
			twi_base->TWI_IADR = internal_address;

			if (p_packet->length <= 2) {
				/* Do not handle errors for short packets in interrupt handler */
				twi_disable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);

				/* Cannot use PDC transfer, use normal transfer */
				uint8_t stop_sent = 0;
				uint32_t cnt = p_packet->length;
				uint32_t status;
				uint8_t *buffer = p_packet->buffer;
				uint32_t timeout_counter = 0;

				/* Start the transfer. */
				if (cnt == 1) {
					twi_base->TWI_CR = TWI_CR_START | TWI_CR_STOP;
					stop_sent = 1;
				} else {
					twi_base->TWI_CR = TWI_CR_START;
				}

				while (cnt > 0) {
					status = twi_base->TWI_SR;
					if (status & TWI_SR_NACK) {
						/* Re-enable interrupts */
						twi_enable_interrupt(
								all_twi_definitions[twi_index].peripheral_base_address,
								IER_ERROR_INTERRUPTS);
						/* Release semaphore */
						xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
						return ERR_BUSY;
					}
					/* Last byte ? */
					if (cnt == 1 && !stop_sent) {
						twi_base->TWI_CR = TWI_CR_STOP;
						stop_sent = 1;
					}
					if (!(status & TWI_SR_RXRDY)) {
						if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
							return_value = ERR_TIMEOUT;
							break;
						}
						continue;
					}
					*buffer++ = twi_base->TWI_RHR;
					cnt--;
					timeout_counter = 0;
				}

				timeout_counter = 0;
				/* Wait for stop to be sent */
				while (!(twi_base->TWI_SR & TWI_SR_TXCOMP)) {
					/* Check timeout condition. */
					if (++timeout_counter >= TWI_TIMEOUT_COUNTER) {
						return_value = ERR_TIMEOUT;
						break;
					}
				}
				/* Re-enable interrupts */
				twi_enable_interrupt(
						all_twi_definitions[twi_index].peripheral_base_address,
						IER_ERROR_INTERRUPTS);
				/* Release semaphores */
				xSemaphoreGive(tx_dma_control[twi_index].peripheral_access_mutex);
				if (return_value != ERR_TIMEOUT) {
					if (rx_dma_control[twi_index].transaction_complete_notification_semaphore != NULL) {
						xSemaphoreGive(rx_dma_control[twi_index].transaction_complete_notification_semaphore);
					}
				}
			} else {
				/* Start the PDC reception. */
				twis[twi_index].buffer = p_packet->buffer;
				twis[twi_index].length = p_packet->length;
				freertos_start_pdc_rx(&(rx_dma_control[twi_index]),
						p_packet->buffer, (p_packet->length)-2,
						all_twi_definitions[twi_index].pdc_base_address,
						notification_semaphore);

				/* Start the transfer. */
				twi_base->TWI_CR = TWI_CR_START;

				/* Catch the end of reception so the access mutex can be returned,
				and the task notified (if it supplied a notification semaphore).
				The interrupt can be enabled here because the ENDRX	signal from the
				PDC to the peripheral will have been de-asserted when the next
				transfer was configured. */
				twi_enable_interrupt(twi_base, TWI_IER_ENDRX);

				return_value = freertos_optionally_wait_transfer_completion(
						&(rx_dma_control[twi_index]),
						notification_semaphore,
						block_time_ticks);
			}
		}
	} else {
		return_value = ERR_INVALID_ARG;
	}

	return return_value;
}
예제 #18
0
int32_t i2c_send_sequence(
	uint8_t ch,
	uint16_t *sequence,
	uint32_t sequence_length,
	uint8_t *received_data,
	void ( *callback_fn )( void* ),
	void *user_data
) {
	int32_t result = 0;

	volatile I2C_Channel *channel = &( i2c_channels[ch - ISSI_I2C_FirstBus_define] );
	uint8_t address;

#if defined(_kinetis_)
	uint8_t status;
	volatile uint8_t *I2C_C1  = (uint8_t*)(&I2C0_C1) + i2c_offset[ch];
	volatile uint8_t *I2C_S   = (uint8_t*)(&I2C0_S) + i2c_offset[ch];
	volatile uint8_t *I2C_D   = (uint8_t*)(&I2C0_D) + i2c_offset[ch];
#elif defined(_sam_)
	Twi *twi_dev = twi_devs[ch];
#endif

	if ( channel->status == I2C_BUSY )
	{
		return -1;
	}

	// Check if there are back-to-back errors
	// in succession
	if ( channel->last_error > 5 )
	{
		warn_msg("I2C Bus Error: ");
		printInt8( ch );
		print(" errors: ");
		printInt32( channel->error_count );
		print( NL );
	}

	// Debug
	/*
	for ( uint8_t c = 0; c < sequence_length; c++ )
	{
		printHex( sequence[c] );
		print(" ");
	}
	print(NL);
	*/

	channel->sequence = sequence;
	channel->sequence_end = sequence + sequence_length;
	channel->received_data = received_data;
	channel->status = I2C_BUSY;
	channel->txrx = I2C_WRITING;
	channel->callback_fn = callback_fn;
	channel->user_data = user_data;

	// reads_ahead does not need to be initialized

#if defined(_kinetis_)
	// Acknowledge the interrupt request, just in case
	*I2C_S |= I2C_S_IICIF;
	*I2C_C1 = ( I2C_C1_IICEN | I2C_C1_IICIE );

	// Generate a start condition and prepare for transmitting.
	*I2C_C1 |= ( I2C_C1_MST | I2C_C1_TX );

	status = *I2C_S;
	if ( status & I2C_S_ARBL )
	{
		warn_print("Arbitration lost");
		result = -1;
		goto i2c_send_sequence_cleanup;
	}

	// Write the first (address) byte.
	address = *channel->sequence++;
	*I2C_D = address;

	// Everything is OK.
	return result;

i2c_send_sequence_cleanup:
	// Record error, and reset last error counter
	channel->error_count++;
	channel->last_error++;

	// Generate STOP and disable further interrupts.
	*I2C_C1 &= ~( I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX );
	channel->status = I2C_ERROR;

#elif defined(_sam_)
	// Convert 8 bit address to 7bit + RW
	address = *channel->sequence++;
	//print("Address: ");
	//printHex( address );
	//print( NL );

	uint8_t mread = address & 1;
	address >>= 1;

	// Set slave address
	twi_dev->TWI_MMR = TWI_MMR_DADR(address) | (mread ? TWI_MMR_MREAD : 0);

	// Enable interrupts
	twi_dev->TWI_IER = TWI_IER_RXRDY | TWI_IER_TXRDY | TWI_IER_TXCOMP | TWI_IER_ARBLST;
	//twi_dev->TWI_IDR = 0xFFFFFFFF;

	// Generate a start condition
	twi_dev->TWI_CR |= TWI_CR_START;

	// Fire off the first read or write.
	// The first (address) byte is automatically trasmitted before any data
	// Arbitration errors will be handled in the isr
	i2c_isr(ch);

	// Everything is OK.
	return result;
#endif

	return result;
}