* updated with ASYNCH api support for Serial.

pull/1214/head
akhilpanayamparambil 2015-06-25 19:13:51 +05:30 committed by Karthik Purushothaman
parent 6fd1a45011
commit a582b9f6a6
2 changed files with 180 additions and 40 deletions

View File

@ -52,6 +52,9 @@ struct serial_s {
uint32_t pinmux_pad1;
uint32_t pinmux_pad2;
uint32_t pinmux_pad3;
#if DEVICE_SERIAL_ASYNCH
uint32_t events;
#endif
};
/*
struct pwmout_s {

View File

@ -467,19 +467,6 @@ static inline void uart_irq(SercomUsart *const usart, uint32_t index)
usart->INTFLAG.reg = SERCOM_USART_INTFLAG_TXC;
irq_handler(serial_irq_ids[index], TxIrq);
}
/*if (interrupt_status & SERCOM_USART_INTFLAG_DRE) // for data ready for transmit
{
if (uart_data[index].count > 0){
usart->DATA.reg = uart_data[index].string[uart_data[index].count];
uart_data[index].count--;
}
if(uart_data[index].count == 0){
usart->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
usart->INTENSET.reg = SERCOM_USART_INTFLAG_TXC;
} else {
usart->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
}
}*/
if (interrupt_status & SERCOM_USART_INTFLAG_RXC) { // for receive complete
usart->INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
irq_handler(serial_irq_ids[index], RxIrq);
@ -523,6 +510,26 @@ void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
serial_irq_ids[serial_get_index(obj)] = id;
}
IRQn_Type get_serial_irq_num (serial_t *obj)
{
switch ((int)pUSART_S(obj)) {
case UART_0:
return SERCOM0_IRQn;
case UART_1:
return SERCOM1_IRQn;
case UART_2:
return SERCOM2_IRQn;
case UART_3:
return SERCOM3_IRQn;
case UART_4:
return SERCOM4_IRQn;
case UART_5:
return SERCOM5_IRQn;
default:
MBED_ASSERT(0);
}
}
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
{
IRQn_Type irq_n = (IRQn_Type)0;
@ -578,7 +585,6 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
}
NVIC_DisableIRQ(irq_n);
}
enable_usart(obj);
}
/******************************************************************************
@ -638,7 +644,11 @@ int serial_writable(serial_t *obj)
*/
void serial_tx_enable_event(serial_t *obj, int event, uint8_t enable)
{
if(enable) {
pSERIAL_S(obj)->events |= event;
} else {
pSERIAL_S(obj)->events &= ~ event;
}
}
/**
@ -648,7 +658,11 @@ void serial_tx_enable_event(serial_t *obj, int event, uint8_t enable)
*/
void serial_rx_enable_event(serial_t *obj, int event, uint8_t enable)
{
if(enable) {
pSERIAL_S(obj)->events |= event;
} else {
pSERIAL_S(obj)->events &= ~ event;
}
}
/** Configure the TX buffer for an asynchronous write serial transaction
@ -700,7 +714,9 @@ void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width)
*/
void serial_set_char_match(serial_t *obj, uint8_t char_match)
{
if (char_match != SERIAL_RESERVED_CHAR_MATCH) {
obj->char_match = char_match;
}
}
/************************************
@ -715,10 +731,27 @@ void serial_set_char_match(serial_t *obj, uint8_t char_match)
* @param hint A suggestion for how to use DMA with this transfer
* @return Returns number of data transfered, or 0 otherwise
*/
/*int serial_tx_asynch(serial_t *obj, void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint)
int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx_width, uint32_t handler, uint32_t event, DMAUsage hint)
{
MBED_ASSERT(tx != (void*)0);
if(tx_length == 0) return 0;
}*/
serial_tx_buffer_set(obj, (void *)tx, tx_length, tx_width);
serial_tx_enable_event(obj, event, true);
// if( hint == DMA_USAGE_NEVER) { //TODO: DMA to be implemented later
NVIC_ClearPendingIRQ(get_serial_irq_num(obj));
NVIC_DisableIRQ(get_serial_irq_num(obj));
NVIC_SetPriority(get_serial_irq_num(obj), 1);
NVIC_SetVector(get_serial_irq_num(obj), (uint32_t)handler);
NVIC_EnableIRQ(get_serial_irq_num(obj));
if (pUSART_S(obj)) {
_USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
_USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_DRE;
}
// }
}
/** Begin asynchronous RX transfer (enable interrupt for data collecting)
* The used buffer is specified in the serial object - rx_buff
@ -727,30 +760,45 @@ void serial_set_char_match(serial_t *obj, uint8_t char_match)
* @param cb The function to call when an event occurs
* @param hint A suggestion for how to use DMA with this transfer
*/
/*void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
{
MBED_ASSERT(rx != (void*)0);
}*/
serial_rx_enable_event(obj, SERIAL_EVENT_RX_ALL, false);
serial_rx_enable_event(obj, event, true);
serial_rx_buffer_set(obj, rx, rx_length, rx_width);
// if( hint == DMA_USAGE_NEVER) { //TODO: DMA to be implemented later
NVIC_ClearPendingIRQ(get_serial_irq_num(obj));
NVIC_SetVector(get_serial_irq_num(obj), (uint32_t)handler);
NVIC_EnableIRQ(get_serial_irq_num(obj));
if (pUSART_S(obj)) {
_USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
}
// }
}
/** Attempts to determine if the serial peripheral is already in use for TX
*
* @param obj The serial object
* @return Non-zero if the TX transaction is ongoing, 0 otherwise
*/
/*uint8_t serial_tx_active(serial_t *obj)
uint8_t serial_tx_active(serial_t *obj)
{
}*/
return ((_USART(obj).INTENSET.reg & SERCOM_USART_INTFLAG_DRE) ? true : false);
}
/** Attempts to determine if the serial peripheral is already in use for RX
*
* @param obj The serial object
* @return Non-zero if the RX transaction is ongoing, 0 otherwise
*/
/*uint8_t serial_rx_active(serial_t *obj)
uint8_t serial_rx_active(serial_t *obj)
{
}*/
return ((_USART(obj).INTENSET.reg & SERCOM_USART_INTFLAG_RXC) ? true : false);
}
/** The asynchronous TX handler. Writes to the TX FIFO and checks for events.
* If any TX event has occured, the TX abort function is called.
@ -758,10 +806,11 @@ void serial_set_char_match(serial_t *obj, uint8_t char_match)
* @param obj The serial object
* @return Returns event flags if a TX transfer termination condition was met or 0 otherwise
*/
/*int serial_tx_irq_handler_asynch(serial_t *obj)
int serial_tx_irq_handler_asynch(serial_t *obj)
{
}*/
_USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
}
/** The asynchronous RX handler. Reads from the RX FIFOF and checks for events.
* If any RX event has occured, the RX abort function is called.
@ -769,37 +818,125 @@ void serial_set_char_match(serial_t *obj, uint8_t char_match)
* @param obj The serial object
* @return Returns event flags if a RX transfer termination condition was met or 0 otherwise
*/
/*int serial_rx_irq_handler_asynch(serial_t *obj)
int serial_rx_irq_handler_asynch(serial_t *obj)
{
int event = 0;
/* This interrupt handler is called from USART irq */
uint8_t *buf = (uint8_t*)obj->rx_buff.buffer;
uint8_t error_code = 0;
uint16_t received_data = 0;
}*/
error_code = (uint8_t)(_USART(obj).STATUS.reg & SERCOM_USART_STATUS_MASK);
/* 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 */
_USART(obj).STATUS.reg |= SERCOM_USART_STATUS_FERR;
return SERIAL_EVENT_RX_FRAMING_ERROR;
} else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
/* Store the error code and clear flag by writing 1 to it */
_USART(obj).STATUS.reg |= SERCOM_USART_STATUS_BUFOVF;
return SERIAL_EVENT_RX_OVERFLOW;
} else if (error_code & SERCOM_USART_STATUS_PERR) {
/* Store the error code and clear flag by writing 1 to it */
_USART(obj).STATUS.reg |= SERCOM_USART_STATUS_PERR;
return SERIAL_EVENT_RX_PARITY_ERROR;
}
}
/* Read current packet from DATA register,
* increment buffer pointer and decrement buffer length */
received_data = (_USART(obj).DATA.reg & SERCOM_USART_DATA_MASK);
/* Read value will be at least 8-bits long */
buf[obj->rx_buff.pos] = received_data;
/* Increment 8-bit pointer */
obj->rx_buff.pos++;
/* Check if the last character have been received */
if(--(obj->rx_buff.length) == 0) {
event |= SERIAL_EVENT_RX_COMPLETE;
if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)){
event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
}
serial_rx_abort_asynch(obj);
return event & obj->serial.events;
}
/* Check for character match event */
if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
// event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
}
/* check for final char event */
if(obj->rx_buff.pos >= (obj->rx_buff.length)) {
// event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
}
}
/** Unified IRQ handler. Determines the appropriate handler to execute and returns the flags.
*
* WARNING: this code should be stateless, as re-entrancy is very possible in interrupt-based mode.
*/
/*int serial_irq_handler_asynch(serial_t *obj)
int serial_irq_handler_asynch(serial_t *obj)
{
//TODO: DMA to be implemented
uint16_t interrupt_status;
uint8_t *buf = obj->tx_buff.buffer;
}*/
interrupt_status = _USART(obj).INTFLAG.reg;
interrupt_status &= _USART(obj).INTENSET.reg;
if (pUSART_S(obj)) {
if (interrupt_status & SERCOM_USART_INTFLAG_DRE) {
/* Interrupt has another TX source */
if(obj->tx_buff.pos >= obj->tx_buff.length) {
/* Transfer complete. Switch off interrupt and return event. */
serial_tx_abort_asynch(obj);
return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
} else {
while((serial_writable(obj)) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) {
_USART(obj).DATA.reg = buf[obj->tx_buff.pos];
obj->tx_buff.pos++;
}
}
}
if (interrupt_status & SERCOM_USART_INTFLAG_TXC) {
serial_tx_irq_handler_asynch(obj);
}
if (interrupt_status & SERCOM_USART_INTFLAG_RXC) {
serial_rx_irq_handler_asynch(obj);
}
}
}
/** Abort the ongoing TX transaction. It disables the enabled interupt for TX and
* flush TX hardware buffer if TX FIFO is used
*
* @param obj The serial object
*/
/*void serial_tx_abort_asynch(serial_t *obj)
void serial_tx_abort_asynch(serial_t *obj)
{
}*/
//TODO: DMA to be implemented
_USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
_USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_TXC;
}
/** Abort the ongoing RX transaction It disables the enabled interrupt for RX and
* flush RX hardware buffer if RX FIFO is used
*
* @param obj The serial object
*/
/*void serial_rx_abort_asynch(serial_t *obj)
void serial_rx_abort_asynch(serial_t *obj)
{
}*/
//TODO: DMA to be implemented
_USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
}
#endif