示例#1
0
/**
 * \internal
 * Handles interrupts as they occur, and it will run callback functions
 * which are registered and enabled.
 *
 * \param[in]  instance  ID of the SERCOM instance calling the interrupt
 *                       handler.
 */
void _usart_interrupt_handler(
		uint8_t instance)
{
	/* Temporary variables */
	uint16_t interrupt_status;
	uint16_t callback_status;
	uint8_t error_code;


	/* Get device instance from the look-up table */
	struct usart_module *module
		= (struct usart_module *)_sercom_instances[instance];

	/* Pointer to the hardware module instance */
	SercomUsart *const usart_hw
		= &(module->hw->USART);

	/* Wait for the synchronization to complete */
	_usart_wait_for_sync(module);

	/* Read and mask interrupt flag register */
	interrupt_status = usart_hw->INTFLAG.reg;
	interrupt_status &= usart_hw->INTENSET.reg;
	callback_status = module->callback_reg_mask &
			module->callback_enable_mask;

	/* Check if a DATA READY interrupt has occurred,
	 * and if there is more to transfer */
	if (interrupt_status & SERCOM_USART_INTFLAG_DRE) {
		if (module->remaining_tx_buffer_length) {
			/* Write value will be at least 8-bits long */
			uint16_t data_to_send = *(module->tx_buffer_ptr);
			/* Increment 8-bit pointer */
			(module->tx_buffer_ptr)++;

			if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
				data_to_send |= (*(module->tx_buffer_ptr) << 8);
				/* Increment 8-bit pointer */
				(module->tx_buffer_ptr)++;
			}
			/* Write the data to send */
			usart_hw->DATA.reg = (data_to_send & SERCOM_USART_DATA_MASK);

			if (--(module->remaining_tx_buffer_length) == 0) {
				/* Disable the Data Register Empty Interrupt */
				usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
				/* Enable Transmission Complete interrupt */
				usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_TXC;

			}
		} else {
			usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
		}

	/* Check if the Transmission Complete interrupt has occurred and
	 * that the transmit buffer is empty */
	}

	if (interrupt_status & SERCOM_USART_INTFLAG_TXC) {

		/* Disable TX Complete Interrupt, and set STATUS_OK */
		usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
		module->tx_status = STATUS_OK;

		/* Run callback if registered and enabled */
		if (callback_status & (1 << USART_CALLBACK_BUFFER_TRANSMITTED)) {
			(*(module->callback[USART_CALLBACK_BUFFER_TRANSMITTED]))(module);
		}

	/* Check if the Receive Complete interrupt has occurred, and that
	 * there's more data to receive */
	}

	if (interrupt_status & SERCOM_USART_INTFLAG_RXC) {

		if (module->remaining_rx_buffer_length) {
			/* Read out the status code and mask away all but the 4 LSBs*/
			error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
#if !SAMD20
			/* CTS status should not be considered as an error */
			if(error_code & SERCOM_USART_STATUS_CTS) {
				error_code &= ~SERCOM_USART_STATUS_CTS;
			}
#endif
			/* Check if an error has occurred during the receiving */
			if (error_code) {
				/* Check which error occurred */
				if (error_code & SERCOM_USART_STATUS_FERR) {
					/* Store the error code and clear flag by writing 1 to it */
					module->rx_status = STATUS_ERR_BAD_FORMAT;
					usart_hw->STATUS.reg |= SERCOM_USART_STATUS_FERR;
				} else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
					/* Store the error code and clear flag by writing 1 to it */
					module->rx_status = STATUS_ERR_OVERFLOW;
					usart_hw->STATUS.reg |= SERCOM_USART_STATUS_BUFOVF;
				} else if (error_code & SERCOM_USART_STATUS_PERR) {
					/* Store the error code and clear flag by writing 1 to it */
					module->rx_status = STATUS_ERR_BAD_DATA;
					usart_hw->STATUS.reg |= SERCOM_USART_STATUS_PERR;
				}
#ifdef FEATURE_USART_LIN_SLAVE
				else if (error_code & SERCOM_USART_STATUS_ISF) {
					/* Store the error code and clear flag by writing 1 to it */
					module->rx_status = STATUS_ERR_PROTOCOL;
					usart_hw->STATUS.reg |= SERCOM_USART_STATUS_ISF;
				}
#endif
#ifdef FEATURE_USART_COLLISION_DECTION
				else if (error_code & SERCOM_USART_STATUS_COLL) {
					/* Store the error code and clear flag by writing 1 to it */
					module->rx_status = STATUS_ERR_PACKET_COLLISION;
					usart_hw->STATUS.reg |= SERCOM_USART_STATUS_COLL;
				}
#endif

				/* Run callback if registered and enabled */
				if (callback_status
						& (1 << USART_CALLBACK_ERROR)) {
					(*(module->callback[USART_CALLBACK_ERROR]))(module);
				}

			} else {

				/* Read current packet from DATA register,
				 * increment buffer pointer and decrement buffer length */
				uint16_t received_data = (usart_hw->DATA.reg & SERCOM_USART_DATA_MASK);

				/* Read value will be at least 8-bits long */
				*(module->rx_buffer_ptr) = received_data;
				/* Increment 8-bit pointer */
				module->rx_buffer_ptr += 1;

				if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
					/* 9-bit data, write next received byte to the buffer */
					*(module->rx_buffer_ptr) = (received_data >> 8);
					/* Increment 8-bit pointer */
					module->rx_buffer_ptr += 1;
				}

				/* Check if the last character have been received */
				if(--(module->remaining_rx_buffer_length) == 0) {
					/* Disable RX Complete Interrupt,
					 * and set STATUS_OK */
					usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
					module->rx_status = STATUS_OK;

					/* Run callback if registered and enabled */
					if (callback_status
							& (1 << USART_CALLBACK_BUFFER_RECEIVED)) {
						(*(module->callback[USART_CALLBACK_BUFFER_RECEIVED]))(module);
					}
				}
			}
		} else {
示例#2
0
文件: usart.c 项目: Wiredhome/mbed
/**
 * \internal
 * Set Configuration of the USART module
 */
static enum status_code _usart_set_config(
    struct usart_module *const module,
    const struct usart_config *const config)
{
    /* Sanity check arguments */
    Assert(module);
    Assert(module->hw);

    /* Get a pointer to the hardware module instance */
    SercomUsart *const usart_hw = &(module->hw->USART);

    /* Index for generic clock */
    uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
    uint32_t gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;

    /* Cache new register values to minimize the number of register writes */
    uint32_t ctrla = 0;
    uint32_t ctrlb = 0;
    uint16_t baud  = 0;

    enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
    enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;

#ifdef FEATURE_USART_OVER_SAMPLE
    switch (config->sample_rate) {
        case USART_SAMPLE_RATE_16X_ARITHMETIC:
            mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
            sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
            break;
        case USART_SAMPLE_RATE_8X_ARITHMETIC:
            mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
            sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
            break;
        case USART_SAMPLE_RATE_3X_ARITHMETIC:
            mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
            sample_num = SERCOM_ASYNC_SAMPLE_NUM_3;
            break;
        case USART_SAMPLE_RATE_16X_FRACTIONAL:
            mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
            sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
            break;
        case USART_SAMPLE_RATE_8X_FRACTIONAL:
            mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
            sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
            break;
    }
#endif

    /* Set data order, internal muxing, and clock polarity */
    ctrla = (uint32_t)config->data_order |
            (uint32_t)config->mux_setting |
#ifdef FEATURE_USART_OVER_SAMPLE
            config->sample_adjustment |
            config->sample_rate |
#endif
#ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
            (config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) |
#endif
            (config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);

    enum status_code status_code = STATUS_OK;

    /* Get baud value from mode and clock */
    switch (config->transfer_mode) {
        case USART_TRANSFER_SYNCHRONOUSLY:
            if (!config->use_external_clock) {
                status_code = _sercom_get_sync_baud_val(config->baudrate,
                                                        system_gclk_chan_get_hz(gclk_index), &baud);
            }

            break;

        case USART_TRANSFER_ASYNCHRONOUSLY:
            if (config->use_external_clock) {
                status_code =
                    _sercom_get_async_baud_val(config->baudrate,
                                               config->ext_clock_freq, &baud, mode, sample_num);
            } else {
                status_code =
                    _sercom_get_async_baud_val(config->baudrate,
                                               system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num);
            }

            break;
    }

    /* Check if calculating the baudrate failed */
    if (status_code != STATUS_OK) {
        /* Abort */
        return status_code;
    }

#ifdef FEATURE_USART_IRDA
    if(config->encoding_format_enable) {
        usart_hw->RXPL.reg = config->receive_pulse_length;
    }
#endif

    /* Wait until synchronization is complete */
    _usart_wait_for_sync(module);

    /*Set baud val */
    usart_hw->BAUD.reg = baud;

    /* Set sample mode */
    ctrla |= config->transfer_mode;

    if (config->use_external_clock == false) {
        ctrla |= SERCOM_USART_CTRLA_MODE(0x1);
    } else {
        ctrla |= SERCOM_USART_CTRLA_MODE(0x0);
    }

    /* Set stopbits, character size and enable transceivers */
    ctrlb = (uint32_t)config->stopbits | (uint32_t)config->character_size |
#ifdef FEATURE_USART_IRDA
            (config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) |
#endif
#ifdef FEATURE_USART_START_FRAME_DECTION
            (config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) |
#endif
#ifdef FEATURE_USART_COLLISION_DECTION
            (config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) |
#endif
            (config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
            (config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);

    /* Check parity mode bits */
    if (config->parity != USART_PARITY_NONE) {
#ifdef FEATURE_USART_LIN_SLAVE
        if(config->lin_slave_enable) {
            ctrla |= SERCOM_USART_CTRLA_FORM(0x5);
        } else {
            ctrla |= SERCOM_USART_CTRLA_FORM(1);
        }
#else
        ctrla |= SERCOM_USART_CTRLA_FORM(1);
#endif
        ctrlb |= config->parity;
    } else {
#ifdef FEATURE_USART_LIN_SLAVE
        if(config->lin_slave_enable) {
            ctrla |= SERCOM_USART_CTRLA_FORM(0x4);
        } else {
            ctrla |= SERCOM_USART_CTRLA_FORM(0);
        }
#else
        ctrla |= SERCOM_USART_CTRLA_FORM(0);
#endif
    }

    /* Set whether module should run in standby. */
    if (config->run_in_standby || system_is_debugger_present()) {
        ctrla |= SERCOM_USART_CTRLA_RUNSTDBY;
    }

    /* Wait until synchronization is complete */
    _usart_wait_for_sync(module);

    /* Write configuration to CTRLB */
    usart_hw->CTRLB.reg = ctrlb;

    /* Wait until synchronization is complete */
    _usart_wait_for_sync(module);

    /* Write configuration to CTRLA */
    usart_hw->CTRLA.reg = ctrla;

    return STATUS_OK;
}
示例#3
0
/**
 * \internal
 * Set Configuration of the USART module
 */
static enum status_code _usart_set_config(
		struct usart_module *const module,
		const struct usart_config *const config)
{
	/* Sanity check arguments */
	Assert(module);
	Assert(module->hw);

	/* Get a pointer to the hardware module instance */
	SercomUsart *const usart_hw = &(module->hw->USART);

	/* Index for generic clock */
	uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
	uint32_t gclk_index   = sercom_index + SERCOM0_GCLK_ID_CORE;

	/* Cache new register values to minimize the number of register writes */
	uint32_t ctrla = 0;
	uint32_t ctrlb = 0;
#ifdef FEATURE_USART_ISO7816
	uint32_t ctrlc = 0;
#endif
	uint16_t baud  = 0;
	uint32_t transfer_mode;

	enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
	enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;

#ifdef FEATURE_USART_OVER_SAMPLE
	switch (config->sample_rate) {
		case USART_SAMPLE_RATE_16X_ARITHMETIC:
			mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
			sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
			break;
		case USART_SAMPLE_RATE_8X_ARITHMETIC:
			mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
			sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
			break;
		case USART_SAMPLE_RATE_3X_ARITHMETIC:
			mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
			sample_num = SERCOM_ASYNC_SAMPLE_NUM_3;
			break;
		case USART_SAMPLE_RATE_16X_FRACTIONAL:
			mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
			sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
			break;
		case USART_SAMPLE_RATE_8X_FRACTIONAL:
			mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
			sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
			break;
	}
#endif

	/* Set data order, internal muxing, and clock polarity */
	ctrla = (uint32_t)config->data_order |
		(uint32_t)config->mux_setting |
	#ifdef FEATURE_USART_OVER_SAMPLE
		config->sample_adjustment |
		config->sample_rate |
	#endif
	#ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
		(config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) |
	#endif
		(config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);

	enum status_code status_code = STATUS_OK;

	transfer_mode = (uint32_t)config->transfer_mode;
#ifdef FEATURE_USART_ISO7816
	if(config->iso7816_config.enabled) {
		transfer_mode = config->iso7816_config.protocol_t;
	}
#endif
	/* Get baud value from mode and clock */
#ifdef FEATURE_USART_ISO7816
	if(config->iso7816_config.enabled) {
		baud = config->baudrate;
	} else {
#endif
	switch (transfer_mode)
	{
		case USART_TRANSFER_SYNCHRONOUSLY:
			if (!config->use_external_clock) {
				status_code = _sercom_get_sync_baud_val(config->baudrate,
						system_gclk_chan_get_hz(gclk_index), &baud);
			}

			break;

		case USART_TRANSFER_ASYNCHRONOUSLY:
			if (config->use_external_clock) {
				status_code =
						_sercom_get_async_baud_val(config->baudrate,
							config->ext_clock_freq, &baud, mode, sample_num);
			} else {
				status_code =
						_sercom_get_async_baud_val(config->baudrate,
							system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num);
			}

			break;
	}

	/* Check if calculating the baudrate failed */
	if (status_code != STATUS_OK) {
		/* Abort */
		return status_code;
	}
#ifdef FEATURE_USART_ISO7816
	}
#endif

#ifdef FEATURE_USART_IRDA
	if(config->encoding_format_enable) {
		usart_hw->RXPL.reg = config->receive_pulse_length;
	}
#endif

	/* Wait until synchronization is complete */
	_usart_wait_for_sync(module);

	/*Set baud val */
	usart_hw->BAUD.reg = baud;

	/* Set sample mode */
	ctrla |= transfer_mode;

	if (config->use_external_clock == false) {
		ctrla |= SERCOM_USART_CTRLA_MODE(0x1);
	}
	else {
		ctrla |= SERCOM_USART_CTRLA_MODE(0x0);
	}

	/* Set stopbits and enable transceivers */
	ctrlb =  
		#ifdef FEATURE_USART_IRDA
			(config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) |
		#endif
		#ifdef FEATURE_USART_START_FRAME_DECTION
			(config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) |
		#endif
		#ifdef FEATURE_USART_COLLISION_DECTION
			(config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) |
		#endif
			(config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
			(config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);

#ifdef FEATURE_USART_ISO7816
	if(config->iso7816_config.enabled) {
		ctrla |= SERCOM_USART_CTRLA_FORM(0x07);
		if (config->iso7816_config.enable_inverse) {
			ctrla |= SERCOM_USART_CTRLA_TXINV | SERCOM_USART_CTRLA_RXINV;
		}
		ctrlb |=  USART_CHARACTER_SIZE_8BIT;
		
		switch(config->iso7816_config.protocol_t) {
			case ISO7816_PROTOCOL_T_0:
				ctrlb |= (uint32_t)config->stopbits;	
				ctrlc |= SERCOM_USART_CTRLC_GTIME(config->iso7816_config.guard_time) | \
						(config->iso7816_config.inhibit_nack) | \
						(config->iso7816_config.successive_recv_nack) | \
						SERCOM_USART_CTRLC_MAXITER(config->iso7816_config.max_iterations);
				break;	
			case ISO7816_PROTOCOL_T_1:
				ctrlb |= USART_STOPBITS_1;
				break;		
		}
	} else {
#endif
	ctrlb |= (uint32_t)config->character_size;
	/* Check parity mode bits */
	if (config->parity != USART_PARITY_NONE) {
		ctrla |= SERCOM_USART_CTRLA_FORM(1);
		ctrlb |= config->parity;
	} else {
#ifdef FEATURE_USART_LIN_SLAVE
		if(config->lin_slave_enable) {
			ctrla |= SERCOM_USART_CTRLA_FORM(0x4);
		} else {
			ctrla |= SERCOM_USART_CTRLA_FORM(0);
		}
#else
		ctrla |= SERCOM_USART_CTRLA_FORM(0);
#endif
	}
#ifdef FEATURE_USART_ISO7816
	}
#endif

#ifdef FEATURE_USART_LIN_MASTER
	usart_hw->CTRLC.reg = ((usart_hw->CTRLC.reg) & SERCOM_USART_CTRLC_GTIME_Msk)
						| config->lin_header_delay
						| config->lin_break_length;

	if (config->lin_node != LIN_INVALID_MODE) {
		ctrla &= ~(SERCOM_USART_CTRLA_FORM(0xf));
		ctrla |= config->lin_node;
	}
#endif

	/* Set whether module should run in standby. */
	if (config->run_in_standby || system_is_debugger_present()) {
		ctrla |= SERCOM_USART_CTRLA_RUNSTDBY;
	}

	/* Wait until synchronization is complete */
	_usart_wait_for_sync(module);

	/* Write configuration to CTRLB */
	usart_hw->CTRLB.reg = ctrlb;

	/* Wait until synchronization is complete */
	_usart_wait_for_sync(module);

	/* Write configuration to CTRLA */
	usart_hw->CTRLA.reg = ctrla;

#ifdef FEATURE_USART_RS485
	if ((usart_hw->CTRLA.reg & SERCOM_USART_CTRLA_FORM_Msk) != \
		SERCOM_USART_CTRLA_FORM(0x07)) {
		usart_hw->CTRLC.reg &= ~(SERCOM_USART_CTRLC_GTIME(0x7));
		usart_hw->CTRLC.reg |= SERCOM_USART_CTRLC_GTIME(config->rs485_guard_time);
	}
#endif

#ifdef FEATURE_USART_ISO7816
	if(config->iso7816_config.enabled) {
		_usart_wait_for_sync(module);
		usart_hw->CTRLC.reg = ctrlc;
	}
#endif

	return STATUS_OK;
}