Example #1
0
void
PX4IO_serial_f4::_do_interrupt()
{
	uint32_t sr = rSR;	/* get UART status register */
	(void)rDR;		/* read DR to clear status */

	if (sr & (USART_SR_ORE |	/* overrun error - packet was too big for DMA or DMA was too slow */
		  USART_SR_NE |		/* noise error - we have lost a byte due to noise */
		  USART_SR_FE)) {		/* framing error - start/stop bit lost or line break */

		/*
		 * If we are in the process of listening for something, these are all fatal;
		 * abort the DMA with an error.
		 */
		if (_rx_dma_status == _dma_status_waiting) {
			_abort_dma();

			perf_count(_pc_uerrs);
			/* complete DMA as though in error */
			_do_rx_dma_callback(DMA_STATUS_TEIF);

			return;
		}

		/* XXX we might want to use FE / line break as an out-of-band handshake ... handle it here */

		/* don't attempt to handle IDLE if it's set - things went bad */
		return;
	}

	if (sr & USART_SR_IDLE) {

		/* if there is DMA reception going on, this is a short packet */
		if (_rx_dma_status == _dma_status_waiting) {

			/* verify that the received packet is complete */
			size_t length = sizeof(*_current_packet) - stm32_dmaresidual(_rx_dma);

			if ((length < 1) || (length < PKT_SIZE(*_current_packet))) {
				perf_count(_pc_badidle);

				/* stop the receive DMA */
				stm32_dmastop(_rx_dma);

				/* complete the short reception */
				_do_rx_dma_callback(DMA_STATUS_TEIF);
				return;
			}

			perf_count(_pc_idle);

			/* stop the receive DMA */
			stm32_dmastop(_rx_dma);

			/* complete the short reception */
			_do_rx_dma_callback(DMA_STATUS_TCIF);
		}
	}
}
Example #2
0
static void
i2c_tx_complete(void)
{
    tx_count = tx_len - stm32_dmaresidual(tx_dma);
    stm32_dmastop(tx_dma);

    /* for debug purposes, save the length of the last transmit as seen by the DMA */

    /* leave tx_buf/tx_len alone, so that a retry will see the same data */

    /* prepare for the next transaction */
    i2c_tx_setup();
}
Example #3
0
static void
i2c_rx_complete(void)
{
    rx_len = sizeof(rx_buf) - stm32_dmaresidual(rx_dma);
    stm32_dmastop(rx_dma);

    if (rx_len >= 2) {
        selected_page = rx_buf[0];
        selected_offset = rx_buf[1];

        /* work out how many registers are being written */
        unsigned count = (rx_len - 2) / 2;

        if (count > 0) {
            registers_set(selected_page, selected_offset, (const uint16_t *)&rx_buf[2], count);

        } else {
            /* no registers written, must be an address cycle */
            uint16_t *regs;
            unsigned reg_count;

            /* work out which registers are being addressed */
            int ret = registers_get(selected_page, selected_offset, &regs, &reg_count);

            if (ret == 0) {
                tx_buf = (uint8_t *)regs;
                tx_len = reg_count * 2;

            } else {
                tx_buf = junk_buf;
                tx_len = sizeof(junk_buf);
            }

            /* disable interrupts while reconfiguring DMA for the selected registers */
            irqstate_t flags = irqsave();

            stm32_dmastop(tx_dma);
            i2c_tx_setup();

            irqrestore(flags);
        }
    }

    /* prepare for the next transaction */
    i2c_rx_setup();
}
Example #4
0
static int
serial_interrupt(int irq, void *context, FAR void *arg)
{
	static bool abort_on_idle = false;

	uint32_t sr = rSR;	/* get UART status register */
	(void)rDR;		/* required to clear any of the interrupt status that brought us here */

	if (sr & (USART_SR_ORE |	/* overrun error - packet was too big for DMA or DMA was too slow */
		  USART_SR_NE |		/* noise error - we have lost a byte due to noise */
		  USART_SR_FE)) {		/* framing error - start/stop bit lost or line break */

		perf_count(pc_errors);

		if (sr & USART_SR_ORE) {
			perf_count(pc_ore);
		}

		if (sr & USART_SR_NE) {
			perf_count(pc_ne);
		}

		if (sr & USART_SR_FE) {
			perf_count(pc_fe);
		}

		/* send a line break - this will abort transmission/reception on the other end */
		rCR1 |= USART_CR1_SBK;

		/* when the line goes idle, abort rather than look at the packet */
		abort_on_idle = true;
	}

	if (sr & USART_SR_IDLE) {

		/*
		 * If we saw an error, don't bother looking at the packet - it should have
		 * been aborted by the sender and will definitely be bad. Get the DMA reconfigured
		 * ready for their retry.
		 */
		if (abort_on_idle) {

			abort_on_idle = false;
			dma_reset();
			return 0;
		}

		/*
		 * The sender has stopped sending - this is probably the end of a packet.
		 * Check the received length against the length in the header to see if
		 * we have something that looks like a packet.
		 */
		unsigned length = sizeof(dma_packet) - stm32_dmaresidual(rx_dma);

		if ((length < 1) || (length < PKT_SIZE(dma_packet))) {

			/* it was too short - possibly truncated */
			perf_count(pc_badidle);
			dma_reset();
			return 0;
		}

		/*
		 * Looks like we received a packet. Stop the DMA and go process the
		 * packet.
		 */
		perf_count(pc_idle);
		stm32_dmastop(rx_dma);
		rx_dma_callback(rx_dma, DMA_STATUS_TCIF, NULL);
	}

	return 0;
}