コード例 #1
0
static __interrupt void prvUSCI_A1_ISR( void )
{
signed char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	while( ( UCA1IFG & UCRXIFG ) != 0 )
	{
		/* Get the character from the UART and post it on the queue of Rxed
		characters. */
		cChar = UCA1RXBUF;
		xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
	}
	
	/* If there is a Tx interrupt pending and the tx interrupts are enabled. */
	if( ( UCA1IFG & UCTXIFG ) != 0 )
	{
		/* The previous character has been transmitted.  See if there are any
		further characters waiting transmission. */
		if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
		{
			/* There was another character queued - transmit it now. */
			UCA1TXBUF = cChar;
		}
		else
		{
			/* There were no other characters to transmit - disable the Tx
			interrupt. */
			UCA1IE &= ~UCTXIE;
		}
	}

	__bic_SR_register_on_exit( SCG1 + SCG0 + OSCOFF + CPUOFF );
	
	/* If writing to a queue caused a task to unblock, and the unblocked task
	has a priority equal to or above the task that this interrupt interrupted,
	then lHigherPriorityTaskWoken will have been set to pdTRUE internally within
	xQueuesendFromISR(), and portEND_SWITCHING_ISR() will ensure that this
	interrupt returns directly to the higher priority unblocked task.
	
	THIS MUST BE THE LAST THING DONE IN THE ISR. */	
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
コード例 #2
0
ファイル: serial.c プロジェクト: Eclo/FreeRTOS
/* Serial port ISR.  This can cause a context switch so is not defined as a
standard ISR using the __irq keyword.  Instead a wrapper function is defined
within serialISR.s79 which in turn calls this function.  See the port
documentation on the FreeRTOS.org website for more information. */
__arm void vSerialISR( void )
{
unsigned short usStatus;
signed char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	/* What caused the interrupt? */
	usStatus = UART_FlagStatus( UART0 );

	if( usStatus & UART_TxHalfEmpty )
	{
		/* The interrupt was caused by the THR becoming empty.  Are there any
		more characters to transmit? */
		if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
		{
			/* A character was retrieved from the queue so can be sent to the
			THR now. */
			UART0->TxBUFR = cChar;
		}
		else
		{
			/* Queue empty, nothing to send so turn off the Tx interrupt. */
			serINTERRUPT_OFF();
		}		
	}

	if( usStatus & 	UART_RxBufFull )
	{
		/* The interrupt was caused by a character being received.  Grab the
		character from the RHR and place it in the queue of received
		characters. */
		cChar = UART0->RxBUFR;
		xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
	}

	/* If a task was woken by either a character being received or a character
	being transmitted then we may need to switch to another task. */
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

	/* End the interrupt in the EIC. */
	portCLEAR_EIC();
}
コード例 #3
0
ファイル: serial.c プロジェクト: aeste/freertos
/* Serial port ISR.  This can cause a context switch so is not defined as a
standard ISR using the __irq keyword.  Instead a wrapper function is defined
within serialISR.s79 which in turn calls this function.  See the port
documentation on the FreeRTOS.org website for more information. */
__arm void vSerialISR( void )
{
unsigned long ulStatus;
signed char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	/* What caused the interrupt? */
	ulStatus = serCOM0->US_CSR &= serCOM0->US_IMR;

	if( ulStatus & AT91C_US_TXRDY )
	{
		/* The interrupt was caused by the THR becoming empty.  Are there any
		more characters to transmit? */
		if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
		{
			/* A character was retrieved from the queue so can be sent to the
			THR now. */
			serCOM0->US_THR = cChar;
		}
		else
		{
			/* Queue empty, nothing to send so turn off the Tx interrupt. */
			vInterruptOff();
		}		
	}

	if( ulStatus & AT91C_US_RXRDY )
	{
		/* The interrupt was caused by a character being received.  Grab the
		character from the RHR and place it in the queue or received 
		characters. */
		cChar = serCOM0->US_RHR;
		xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
	}

	/* If a task was woken by either a character being received or a character 
	being transmitted then we may need to switch to another task. */
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

	/* End the interrupt in the AIC. */
	AT91C_BASE_AIC->AIC_EOICR = 0;
}
コード例 #4
0
ファイル: main.c プロジェクト: Lzyuan/STE-LPC1768-
void vSoftwareInterruptHandler( void )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
static unsigned long ulReceivedNumber;

/* The strings are declared static const to ensure they are not allocated to the
interrupt service routine stack, and exist even when the interrupt service routine
is not executing. */
static const char *pcStrings[] =
{
    "String 0\n",
    "String 1\n",
    "String 2\n",
    "String 3\n"
};

    /* Loop until the queue is empty. */
    while( xQueueReceiveFromISR( xIntegerQueue, &ulReceivedNumber, &xHigherPriorityTaskWoken ) != errQUEUE_EMPTY )
    {
        /* Truncate the received value to the last two bits (values 0 to 3 inc.), then
        send the string    that corresponds to the truncated value to the other
        queue. */
        ulReceivedNumber &= 0x03;
        xQueueSendToBackFromISR( xStringQueue, &pcStrings[ ulReceivedNumber ], &xHigherPriorityTaskWoken );
    }

    /* Clear the software interrupt bit using the interrupt controllers
    Clear Pending register. */
    mainCLEAR_INTERRUPT();

    /* xHigherPriorityTaskWoken was initialised to pdFALSE.  It will have then
    been set to pdTRUE only if reading from or writing to a queue caused a task
    of equal or greater priority than the currently executing task to leave the
    Blocked state.  When this is the case a context switch should be performed.
    In all other cases a context switch is not necessary.

    NOTE: The syntax for forcing a context switch within an ISR varies between
    FreeRTOS ports.  The portEND_SWITCHING_ISR() macro is provided as part of
    the Cortex M3 port layer for this purpose.  taskYIELD() must never be called
    from an ISR! */
    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
コード例 #5
0
ファイル: QueueSet.c プロジェクト: peterliu2/FreeRTOS
static void prvReceiveFromQueueInSetFromISR( void )
{
    QueueSetMemberHandle_t xActivatedQueue;
    uint32_t ulReceived;

    /* See if any of the queues in the set contain data. */
    xActivatedQueue = xQueueSelectFromSetFromISR( xQueueSet );

    if( xActivatedQueue != NULL ) {
        /* Reading from the queue for test purposes only. */
        if( xQueueReceiveFromISR( xActivatedQueue, &ulReceived, NULL ) != pdPASS ) {
            /* Data should have been available as the handle was returned from
            xQueueSelectFromSetFromISR(). */
            xQueueSetTasksStatus = pdFAIL;
        }

        /* Ensure the value received was the value expected. */
        prvCheckReceivedValue( ulReceived );
    }
}
コード例 #6
0
ファイル: serial.c プロジェクト: BuiChien/FreeRTOS-TM4C123GXL
/*
 * UART Tx interrupt service routine.
 */
__interrupt void UART0_TxISR( void )
{
signed char			cChar;
signed portBASE_TYPE	xTaskWoken = pdFALSE;

	/* The previous character has been transmitted.  See if there are any
	further characters waiting transmission. */
	if( xQueueReceiveFromISR(xCharsForTx, &cChar, &xTaskWoken) == pdTRUE )
	{
		/* There was another character queued - transmit it now. */
		TDR0 = cChar;
	}
	else
	{
		/* There were no other characters to transmit. */
		sTHREEmpty = pdTRUE;

		/* Disable transmit interrupts */
		SSR0_TIE = 0;
	}
}
コード例 #7
0
ファイル: can.c プロジェクト: Bento007/SJSU-Superway-2014
bool CAN_rx (can_t can, can_msg_t *pCanMsg, uint32_t timeout_ms)
{
    bool ok = false;

    if (CAN_VALID(can) && pCanMsg)
    {
        if (taskSCHEDULER_RUNNING == xTaskGetSchedulerState()) {
            ok = xQueueReceive(g_can_rx_qs[CAN_INDEX(can)], pCanMsg, OS_MS(timeout_ms));
        }
        else {
            uint64_t msg_timeout = sys_get_uptime_ms() + timeout_ms;
            while (! (ok = xQueueReceiveFromISR(g_can_rx_qs[CAN_INDEX(can)], pCanMsg, NULL))) {
                if (sys_get_uptime_ms() > msg_timeout) {
                    break;
                }
            }
        }
    }

    return ok;
}
コード例 #8
0
/*
 * This code has been adapted from the ST Microelectronics CDC
 * Example, which is covered under the V2 Liberty License:
 * http://www.st.com/software_license_agreement_liberty_v2
 */
static void usb_handle_transfer(void)
{
        portBASE_TYPE hpta = false;
        xQueueHandle queue = serial_get_tx_queue(usb_state.serial);
        uint8_t *buff = usb_state.USB_Tx_Buffer;
        size_t len = 0;

        for (; len < VIRTUAL_COM_PORT_DATA_SIZE; ++len)
                if (!xQueueReceiveFromISR(queue, buff + len, &hpta))
                        break;

        /* Check if we actually have something to send */
	if (len) {
                UserToPMABufferCopy(usb_state.USB_Tx_Buffer,
                                    ENDP1_TXADDR, len);
                SetEPTxCount(ENDP1, len);
                SetEPTxValid(ENDP1);
        }

        portEND_SWITCHING_ISR(hpta);
}
コード例 #9
0
// DMA interrupt handler. It is called each time a DMA block is finished processing.
static void dma_isr_handler(void)
{
    portBASE_TYPE task_awoken = pdFALSE;

    if (i2s_dma_is_eof_interrupt()) {
        dma_descriptor_t *descr = i2s_dma_get_eof_descriptor();

        if (xQueueIsQueueFullFromISR(dma_queue)) {
            // List of empty blocks is full. Sender don't send data fast enough.
            int dummy;
            underrun_counter++;
            // Discard top of the queue
            xQueueReceiveFromISR(dma_queue, &dummy, &task_awoken);
        }
        // Push the processed buffer to the queue so sender can refill it.
        xQueueSendFromISR(dma_queue, (void*)(&descr->buf_ptr), &task_awoken);
    }
    i2s_dma_clear_interrupt();

    portEND_SWITCHING_ISR(task_awoken);
}
コード例 #10
0
ファイル: serial.c プロジェクト: DuinOS/FreeRTOS
__arm void vSerialISR( void )
{
signed char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	do
	{
		if( UART0->MIS & UART_IT_Transmit )
		{
			/* The interrupt was caused by the THR becoming empty.  Are there any
			more characters to transmit? */
			if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
			{
				/* A character was retrieved from the queue so can be sent to the
				THR now. */
				UART0->DR = cChar;
			}
			else
			{
				xQueueEmpty = pdTRUE;		
			}		

			UART_ClearITPendingBit( UART0, UART_IT_Transmit );
		}
	
		if( UART0->MIS & UART_IT_Receive )
		{
			/* The interrupt was caused by a character being received.  Grab the
			character from the RHR and place it in the queue of received
			characters. */
			cChar = UART0->DR;
			xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
			UART_ClearITPendingBit( UART0, UART_IT_Receive );
		}
	} while( UART0->MIS );

	/* If a task was woken by either a character being received or a character
	being transmitted then we may need to switch to another task. */
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
コード例 #11
0
static portBASE_TYPE xComPortISR( xComPort * const pxPort )
{
unsigned short usStatusRegister;
char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	/* NOTE:  THIS IS NOT AN EFFICIENT ISR AS IT IS DESIGNED SOLELY TO TEST
	THE SCHEDULER FUNCTIONALITY.  REAL APPLICATIONS SHOULD NOT USE THIS
	FUNCTION. */

	usStatusRegister = portINPUT_WORD( pxPort->usStatusReg );

	if( usStatusRegister & serRX_READY )
	{
		cChar = ( char ) portINPUT_WORD( pxPort->usRxReg );
		xQueueSendFromISR( pxPort->xRxedChars, &cChar, &xHigherPriorityTaskWoken );

		/* Also release the semaphore - this does nothing interesting and is just a test. */
		xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
	}
	else if( pxPort->sTxInterruptOn && ( usStatusRegister & serTX_EMPTY ) )
	{
		if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
		{
			portOUTPUT_WORD( pxPort->usTxReg, ( unsigned short ) cChar );
		}
		else
		{
			/* Queue empty, nothing to send */
			vInterruptOff( pxPort, serTX_HOLD_EMPTY_INT );
		}
	}

    serRESET_PIC( pxPort->usIRQVector );

	/* If posting to the queue woke a task that was blocked on the queue we may
	want to switch to the woken task - depending on its priority relative to
	the task interrupted by this ISR. */
	return xHigherPriorityTaskWoken;
}
コード例 #12
0
/* This is too slow to use */
unsigned char* BPL_AllocMessageBufferFromISR(void)
{  
  unsigned char * pBuffer = NULL;

  signed portBASE_TYPE HigherPriorityTaskWoken;
  
  // params are: queue handle, ptr to the msg buffer, ticks to wait
  if( pdTRUE != xQueueReceiveFromISR(QueueHandles[FREE_QINDEX], 
                                     &pBuffer, 
                                     &HigherPriorityTaskWoken ))
  {
    PrintString2("@ Alloc Buf frm Isr", CR);
    SetBufferPoolFailureBit();
  }
  
  if ( HigherPriorityTaskWoken == pdTRUE )
  {
    portYIELD();
  }
  
  return pBuffer;
}
コード例 #13
0
ファイル: apc220.c プロジェクト: AlexFielding/luba
void USART1_IRQHandler(void) {

	static signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    if ( USART_GetITStatus(USART1, USART_IT_RXNE) ) {

		if ( xSemaphoreRx != NULL ) {
			if (xQueueReceiveFromISR( xSemaphoreRx, NULL, NULL)) {
				// The first rx buffer is available
				xSemaphoreGiveFromISR( xSemaphoreRx, &xHigherPriorityTaskWoken );
				rb_putc(&rx_buf1, USART1->DR);
			} else {
				// The first rx buffer is locked by the reader task
				// so we have to use the second buffer which is of course available
				rb_putc(&rx_buf2, USART1->DR);
				uart_stats.rx_buff1_busy++;
			}
		}

		uart_stats.rx_bytes++;
    }
}
コード例 #14
0
ファイル: cmsis_os.c プロジェクト: geliang201201/RTL_Ameba
/// Get a mail from a queue
/// \param[in]     queue_id      mail queue ID obtained with \ref osMailCreate.
/// \param[in]     millisec      timeout value or 0 in case of no time-out
/// \return event that contains mail information or error code.
/// \note MUST REMAIN UNCHANGED: \b osMailGet shall be consistent in every CMSIS-RTOS.
osEvent osMailGet (osMailQId queue_id, uint32_t millisec)
{
    portBASE_TYPE taskWoken;
    portTickType ticks;
    osEvent event;

    event.def.mail_id = queue_id;

    if (queue_id == NULL) {
        event.status = osErrorParameter;
        return event;
    }

    taskWoken = pdFALSE;

    ticks = millisec_to_ticks(millisec);

    if (inHandlerMode()) {
        if (xQueueReceiveFromISR(queue_id->handle, &event.value.p, &taskWoken) == pdTRUE) {
            /* We have mail */
            event.status = osEventMail;
        }
        else {
            event.status = osOK;
        }
        portEND_SWITCHING_ISR(taskWoken);
    }
    else {
        if (xQueueReceive(queue_id->handle, &event.value.p, ticks) == pdTRUE) {
            /* We have mail */
            event.status = osEventMail;
        }
        else {
            event.status = (ticks == 0) ? osOK : osEventTimeout;
        }
    }

    return event;
}
コード例 #15
0
ファイル: debug.c プロジェクト: yangk/FreeRTOS_BOARD_DEMO
//---------------------------------------------------------------------------------------------
void debug_port_interrupt_handler(void)
{
    char c;

    if (USART_GetITStatus(USART1, USART_IT_TXE) == SET)
    {
        if (xQueueReceiveFromISR(txchars_queue, &c, NULL) == pdPASS)
        {
            USART_SendData(USART1, c);
        }
        else
        {
            USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
        }
    }

    if (USART_GetITStatus(USART1, USART_IT_RXNE))
    {
        c = USART_ReceiveData(USART1);
        cmd_echo(c);
    }
}
コード例 #16
0
	/*
	 * UART Tx interrupt service routine.
	 */
	void vTxISR( void ) __interrupt[ UART1TX_VECTOR ]
	{
	signed char cChar;
	portBASE_TYPE xTaskWoken = pdFALSE;
	
		/* The previous character has been transmitted.  See if there are any
		further characters waiting transmission. */
	
		if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xTaskWoken ) == pdTRUE )
		{
			/* There was another character queued - transmit it now. */
			U1TXBUF = cChar;
		}
		else
		{
			/* There were no other characters to transmit. */
			sTHREEmpty = pdTRUE;
		}

        /* Make sure any low power mode bits are clear before leaving the ISR. */
        __bic_SR_register_on_exit( SCG1 + SCG0 + OSCOFF + CPUOFF );
	}
コード例 #17
0
ファイル: serial.c プロジェクト: channgo2203/TinyROS
void vCOM_1_Tx_ISR( void )
{
	/* This can cause a context switch so this macro must be the first line
	in the function. */
	portENTER_SWITCHING_ISR();

	/* As this is a switching ISR the local variables must be declared as 
	static. */
	static char cTxByte;
	static signed portBASE_TYPE xTaskWokenByTx;

		/* This variable is static so must be explicitly reinitialised each
		time the function executes. */
		xTaskWokenByTx = pdFALSE;

		/* The interrupt was caused by the THR becoming empty.  Are there any
		more characters to transmit?  Note whether or not the Tx interrupt has
		woken a task. */
		if( xQueueReceiveFromISR( xCharsForTx, &cTxByte, &xTaskWokenByTx ) == pdTRUE )
		{
			/* A character was retrieved from the queue so can be sent to the
			THR now. */							
			TDR1 = cTxByte;

			/* Clear the interrupt. */
			SSR1 &= ~serTX_INTERRUPT;
		}
		else
		{
			/* Queue empty, nothing to send so turn off the Tx interrupt. */
			serTX_INTERRUPT_OFF();
		}		

	/* This must be the last line in the function.  We pass cTaskWokenByTx so 
	a context switch will occur if the Tx'ed character woke a task that has
	a priority higher than the task we interrupted. */
	portEXIT_SWITCHING_ISR( xTaskWokenByTx );
}
コード例 #18
0
ファイル: sSerial_test2.c プロジェクト: eloiz07/DPC_Touch
void USART1_IRQHandler(void)
{
	/*
	if(USART_GetITStatus(USART1, USART_IT_RXNE))
	{
		u8 RxData = (u8)USART_ReceiveData(USART1);
		test[testlen++] = RxData;
	}

	DisplayString(0, 0, (u8*)test);
	*/
	portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
	portCHAR cChar;

	if( USART_GetITStatus( USART1, USART_IT_TXE ) == SET )
	{
		/* The interrupt was caused by the THR becoming empty.  Are there any
		more characters to transmit? */
		if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
		{
			/* A character was retrieved from the queue so can be sent to the
			THR now. */
			USART_SendData( USART1, cChar );
		}
		else
		{
			USART_ITConfig( USART1, USART_IT_TXE, DISABLE );		
		}		
	}
	
	if( USART_GetITStatus( USART1, USART_IT_RXNE ) == SET )
	{
		cChar = USART_ReceiveData( USART1 );
		xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
	}	
	
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
コード例 #19
0
/* Tx interrupt handler.  This is called from the asm file wrapper. */
void vUARTTxISRHandler( void )
{
char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	/* Are there any more characters queue to transmit? */
	if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
	{
		/* Send the next character. */
		UD0TX = cChar;
	}
	else
	{
		/* The UART is no longer active. */
		ulTxInProgress = pdFALSE;
	}
	
	/* If reading a character from the Rx queue caused a task to unblock, and
	the unblocked task has a priority higher than the currently running task,
	then xHigherPriorityTaskWoken will have been set to true and a context
	switch should occur now. */
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
コード例 #20
0
ファイル: serial.c プロジェクト: anoopcdac/freertos-moo
static void prvTxHandler( void )
{
signed char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	/* The interrupt was caused by the transmit fifo having space for at least one
	character. Are there any more characters to transmit? */
	if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
	{
		/* A character was retrieved from the queue so can be sent to the uart now. */
		uart1->tx_data = cChar;
	}
	else
	{
		/* Queue empty, nothing to send so turn off the Tx interrupt. */
		uart1->tx_mask = 0;
	}

	/* If an event caused a task to unblock then we call "Yield from ISR" to
	ensure that the unblocked task is the task that executes when the interrupt
	completes if the unblocked task has a priority higher than the interrupted
	task. */
	portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
コード例 #21
0
ファイル: STM32_USART.c プロジェクト: peterliu2/FreeRTOS
void USART1_IRQHandler( void )
{
    long xHigherPriorityTaskWoken = pdFALSE;
    char cChar;

    if( USART_GetITStatus( USART1, USART_IT_TXE ) == SET ) {
        /* The interrupt was caused by the THR becoming empty.  Are there any
        more characters to transmit? */
        if( xQueueReceiveFromISR( xCharsForTx[ 0 ], &cChar, &xHigherPriorityTaskWoken ) ) {
            /* A character was retrieved from the buffer so can be sent to the
            THR now. */
            USART_SendData( USART1, cChar );
        } else {
            USART_ITConfig( USART1, USART_IT_TXE, DISABLE );
        }
    }

    if( USART_GetITStatus( USART1, USART_IT_RXNE ) == SET ) {
        cChar = USART_ReceiveData( USART1 );
        xQueueSendFromISR( xRxedChars[ 0 ], &cChar, &xHigherPriorityTaskWoken );
    }

    portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}
コード例 #22
0
ファイル: STM32_USART.c プロジェクト: lireric/ssn
void usart1_isr(void) {
	long xHigherPriorityTaskWoken = pdFALSE;
	char cChar;

	// ----- transmission complete:
	if (usart_get_flag(USART1, USART_SR_TC) == true) {
		gpio_clear(GPIOA, GPIO12); // clear RTS
		gpio_clear(GPIOA, GPIO_USART1_TX); // clear DI
		USART_SR(USART1) &= ~USART_SR_TC;	// reset flag TC
		usart_disable_tx_interrupt(USART1);
	}

	if (usart_get_flag(USART1, USART_SR_TXE) == true) {
		/* The interrupt was caused by the THR becoming empty.  Are there any
		 more characters to transmit? */
		if (xQueueReceiveFromISR(xCharsForTx[0], &cChar,
				&xHigherPriorityTaskWoken)) {
			/* A character was retrieved from the buffer so can be sent to the
			 THR now. */
			gpio_set(GPIOA, GPIO12); // set RTS
			usart_send(USART1, (uint8_t) cChar);
		} else {
//			gpio_clear(GPIOA, GPIO12); // clear RTS
//			usart_disable_tx_interrupt(USART1);
//			USART_SR(USART1) &= ~USART_SR_TXE;	// reset flag TXE
//			USART_CR1(USART1) |= USART_CR1_TCIE;
		}
	}

	if (usart_get_flag(USART1, USART_SR_RXNE) == true) {
		cChar = (char) usart_recv(USART1);
		xQueueSendFromISR(xRxedChars[0], &cChar, &xHigherPriorityTaskWoken);
	}

	portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
コード例 #23
0
ファイル: serialISR.c プロジェクト: smilingpaul/marhes-txt
/**
 @brief Serial ISR
 
 This ISR handles both UART0 and 1. The ISR handles data that wouldn't fit in 
 the ISR by writing the data written to the queue. The received data is put onto
 the queue. Error interrupts are not handled, the interrupts are just cleared.
 @note Use the wrapper function instead so the context gets saved.
*/
void vUART_ISR_Handler( void )
{
signed char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	/* What caused the interrupt? */
	switch( U0IIR & serINTERRUPT_SOURCE_MASK )
	{
		case serSOURCE_ERROR :	/* Not handling this, but clear the interrupt. */
								cChar = U0LSR;
								break;

		case serSOURCE_THRE	:	/* The THRE is empty.  If there is another
								character in the Tx queue, send it now. */
								if( xQueueReceiveFromISR( xCharsForTx[0], &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
								{
									U0THR = cChar;
								}
								else
								{
									/* There are no further characters 
									queued to send so we can indicate 
									that the THRE is available. */
									lTHREEmpty[0] = pdTRUE;
								}
								break;

		case serSOURCE_RX_TIMEOUT :
		case serSOURCE_RX	:	/* A character was received.  Place it in 
								the queue of received characters. */
								cChar = U0RBR;
								xQueueSendFromISR( xRxedChars[0], &cChar, &xHigherPriorityTaskWoken );
								break;

		default				:	/* There is nothing to do, leave the ISR. */
								break;
	}
	
  switch( U1IIR & serINTERRUPT_SOURCE_MASK )
	{
		case serSOURCE_ERROR :	/* Not handling this, but clear the interrupt. */
								cChar = U1LSR;
								break;

		case serSOURCE_THRE	:	/* The THRE is empty.  If there is another
								character in the Tx queue, send it now. */
								if( xQueueReceiveFromISR( xCharsForTx[1], &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
								{
									U1THR = cChar;
								}
								else
								{
									/* There are no further characters 
									queued to send so we can indicate 
									that the THRE is available. */
									lTHREEmpty[1] = pdTRUE;
								}
								break;

		case serSOURCE_RX_TIMEOUT :
		case serSOURCE_RX	:	/* A character was received.  Place it in 
								the queue of received characters. */
								cChar = U1RBR;
								xQueueSendFromISR( xRxedChars[1], &cChar, &xHigherPriorityTaskWoken );
								break;

		default				:	/* There is nothing to do, leave the ISR. */
								break;
	}

	if( xHigherPriorityTaskWoken )
	{
		portYIELD_FROM_ISR();
	}

	/* Clear the ISR in the VIC. */
	VICVectAddr = serCLEAR_VIC_INTERRUPT;
}
コード例 #24
0
ファイル: pca9665.c プロジェクト: lirihe/arm
/**
 * Interrupt service routine
 * Basically handles the entire protocol
 */
void __attribute__((noinline)) pca9665_dsr(portBASE_TYPE * task_woken) {

	static int handle, len;
	static uint8_t state;
	static uint8_t dest;

	/* Loop through number of devices */
	for (handle = 0; handle < pca9665_device_count; handle++) {

		/* Check for interrupt flag in device status register */
		if (!(pca9665_read_reg(handle, I2CCON) & CON_SI))
			continue;

		/* We have an interrupt, read the status register */
		state = pca9665_read_reg(handle, I2CSTA);

		/* The I2C driver is one _big_ state-machine */
		driver_debug(DEBUG_I2C, "I2C ISR %u %x\n\r", handle, state);
		switch (state) {

		/**
		 * MASTER IRQ's
		 */

		/* START: is the first ISR that appears for outgoing frames */
		case STA_M_REPEATED_START_SENDT:
		case STA_M_START_SENDT:

			/* Mark as busy, so start flag is not sent from task context while transmission is active */
			device[handle].is_busy = 1;

			/* If this is the beginning of a new frame, dequeue */
			if (device[handle].tx.frame == NULL && device[handle].rx.frame == NULL) {

				/* Try do dequeue element, if it fails, stop transmission */
				xQueueReceiveFromISR(device[handle].tx.queue, &device[handle].tx.frame, task_woken);
				if (device[handle].tx.frame == NULL) {
					pca9665_try_tx_from_isr(handle, task_woken);
					break;
				}

				/* If TX len > 0, go for master transmit */
				if (device[handle].tx.frame->len) {
					device[handle].mode = DEVICE_MODE_M_T;
					device[handle].tx.next_byte = 0;

				/* If TX len == 0 and RX len > 0, go for master receive */
				} else if (device[handle].tx.frame->len_rx) {
					device[handle].mode = DEVICE_MODE_M_R;
					device[handle].rx.frame = device[handle].tx.frame;
					device[handle].tx.frame = NULL;
					device[handle].rx.frame->len = device[handle].rx.frame->len_rx;
					device[handle].rx.next_byte = 0;

				/* Well, this should not happen */
				} else {
					csp_buffer_free_isr(device[handle].tx.frame);
					device[handle].tx.frame = NULL;
					pca9665_try_tx_from_isr(handle, task_woken);
					break;
				}

			}

			/* If mode is master receiver then set the read-bit in the address field */
			if (device[handle].mode == DEVICE_MODE_M_R) {

				dest = (device[handle].rx.frame->dest << 1) | 0x01;
				device[handle].rx.next_byte = 0;

				/* Do first part of frame here */
				if (device[handle].rx.frame->len > PCA9665_MAX_BUF) {
					pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);
				} else {
					pca9665_write_reg(handle, I2CCOUNT, device[handle].rx.frame->len | 0x80);
				}

				pca9665_write_data(handle, &dest, 1);

			} else {

				dest = device[handle].tx.frame->dest << 1;
				device[handle].tx.next_byte = 0;

				/* Do first part of frame here */
				if (device[handle].tx.frame->len + 1 > PCA9665_MAX_BUF) {
					pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);
					pca9665_write_data(handle, &dest, 1);
					pca9665_write_data(handle, &device[handle].tx.frame->data[device[handle].tx.next_byte],	PCA9665_MAX_BUF - 1);
					device[handle].tx.next_byte += PCA9665_MAX_BUF - 1;
				} else {
					pca9665_write_reg(handle, I2CCOUNT, device[handle].tx.frame->len + 1);
					pca9665_write_data(handle, &dest, 1);
					pca9665_write_data(handle, &device[handle].tx.frame->data[device[handle].tx.next_byte],	device[handle].tx.frame->len);
					device[handle].tx.next_byte += device[handle].tx.frame->len;
				}
			}

			/* Let the hardware continue */
			pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);
			break;

		/* WRITE ACK: A node is ready to be written to */
		case STA_M_SLAW_SENDT_ACKED:
		case STA_M_DATA_SENDT_ACKED:

			/* Safety first */
			if (device[handle].tx.frame == NULL)
				goto isr_error;

			/* Calculate remaining length */
			len = device[handle].tx.frame->len - device[handle].tx.next_byte;

			/* Transmit next chunk */
			if (len > 0) {

				if (len > PCA9665_MAX_BUF) {
					pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);
					pca9665_write_data(handle, &device[handle].tx.frame->data[device[handle].tx.next_byte],	PCA9665_MAX_BUF);
					device[handle].tx.next_byte += PCA9665_MAX_BUF;
				} else {
					pca9665_write_reg(handle, I2CCOUNT, len);
					pca9665_write_data(handle, &device[handle].tx.frame->data[device[handle].tx.next_byte],	len);
					device[handle].tx.next_byte += len;
				}

				pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);
				break;

			/* Or, Change from master transmit, to master read if wanted */
			} else if (device[handle].tx.frame->len_rx) {

				device[handle].mode = DEVICE_MODE_M_R;
				device[handle].rx.frame = device[handle].tx.frame;
				device[handle].tx.frame = NULL;
				device[handle].rx.frame->len = device[handle].rx.frame->len_rx;

				/* We need to send a repeated start now! */
				pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA | CON_STA);
				break;

			/* Or, We are done */
			} else {
				csp_buffer_free_isr(device[handle].tx.frame);
				device[handle].tx.frame = NULL;
				pca9665_try_tx_from_isr(handle, task_woken);
			}

			break;

		/* WRITE ERROR: A write has failed */
		case STA_M_SLAW_SENDT_NACKED:
		case STA_M_DATA_SENDT_LAST_NACKED:

			if (device[handle].tx.frame != NULL) {
				driver_debug(DEBUG_I2C, "I2C SLA+W NACK: 0x%02"PRIx8"\n\r", device[handle].tx.frame->dest);
				csp_buffer_free_isr(device[handle].tx.frame);
				device[handle].tx.frame = NULL;
			}

			pca9665_try_tx_from_isr(handle, task_woken);
			break;

		/* ARBITRATION LOST: Start condition failed */
		case STA_M_ARBITRATION_LOST:

			/* Restart transmission by resetting next_byte and preserving tx_frame pointer */
			device[handle].tx.next_byte = 0;
			pca9665_try_tx_from_isr(handle, task_woken);
			break;

		/* READ ACK: A node is ready to be read from */
		case STA_M_SLAR_SENT_ACKED:
		case STA_M_DATA_RECEIVED_ACKED:
		case STA_M_DATA_RECEIVED_NACKED:

			/* Safety first */
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			if (device[handle].rx.queue == NULL)
				goto isr_error;

			pca9665_read_data_to_buffer(handle);
			int remaining = device[handle].rx.frame->len - device[handle].rx.next_byte;
			driver_debug(DEBUG_I2C, "RX: Remaining %u\r\n", remaining);

			/* If no more to receive */
			if (remaining == 0) {
				if (xQueueSendToBackFromISR(device[handle].rx.queue, &device[handle].rx.frame, task_woken)	== pdFALSE) {
					driver_debug(DEBUG_I2C, "I2C rx queue full - freeing\n\r");
					csp_buffer_free_isr(device[handle].rx.frame);
				}
				device[handle].rx.frame = NULL;
				pca9665_try_tx_from_isr(handle, task_woken);
				break;
			}

			/* If more than a full PCA9665 buffer remains */
			if (remaining > PCA9665_MAX_BUF) {
				pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);

			/* Otherwise, this is the last bit, set NACK on final slave read */
			} else {
				pca9665_write_reg(handle, I2CCOUNT, remaining | 0x80);
			}

			pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);
			break;

		/* READ ERROR: A read has failed */
		case STA_M_SLAR_SENT_NACKED:

			/* Safety first */
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			driver_debug(DEBUG_I2C, "I2C SLA+R nacked\n\r");
			csp_buffer_free_isr(device[handle].rx.frame);
			device[handle].rx.frame = NULL;

			/* Start up again */
			pca9665_try_tx_from_isr(handle, task_woken);
			break;

		/**
		 * SLAVE RECEIVER BUFFERED MODE
		 */

		/* START: Lost the arbitration and is addressed as a slave receiver */
		case STA_S_ARB_LOST_SLAW_RECEIVED:
		case STA_S_ARB_LOST_GC_RECEIVED:

			/* Preserve TX frame active, so the START flag will be re-set when the
			 * reception is completed
			 */

			/* Deliberate Fallthrough */

		/* START: Addressed as a slave receiver */
		case STA_S_SLAW_RECEIVED_ACKED:
		case STA_S_GC_RECEIVED:

			/* Check if RX frame was started */
			if (device[handle].rx.frame != NULL)
				goto isr_error;

			/* Allocate new frame */
			device[handle].rx.frame = csp_buffer_get_isr(I2C_MTU);
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			device[handle].is_busy = 1;
			device[handle].rx.next_byte = 0;
			device[handle].rx.frame->len = 0;
			device[handle].rx.frame->dest = device[handle].slave_addr;
			pca9665_write_reg(handle, I2CCOUNT, PCA9665_MAX_BUF);
			pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);
			break;

		/* READ: Data received. */
		case STA_S_DATA_RECEIVED_SLA_ACKED:
		case STA_S_DATA_RECEIVED_GC_ACKED:

			/* Safety first */
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			/* Receive data, if any */
			pca9665_read_data_to_buffer(handle);

			/* Limit incoming bytes */
			pca9665_write_reg(handle, I2CCOUNT, (device[handle].rx.next_byte + PCA9665_MAX_BUF > I2C_MTU) ? (I2C_MTU - device[handle].rx.next_byte) | 0x80 : PCA9665_MAX_BUF);
			pca9665_write_reg(handle, I2CCON, CON_ENSIO | CON_MODE | CON_AA);

			break;

		/* STOP or NACK: No more data to receive */
		case STA_S_STOP_REP_RECEIVED:
		case STA_S_DATA_RECEIVED_SLA_NACKED:
		case STA_S_DATA_RECEIVED_GC_NACKED:

			/* Safety first */
			if (device[handle].rx.frame == NULL)
				goto isr_error;

			/* Receive data, if any */
			pca9665_read_data_to_buffer(handle);

			/* Queue up frame */
			device[handle].rx.frame->len = device[handle].rx.next_byte;
			if (device[handle].rx.queue != NULL) {
				if (xQueueSendToBackFromISR(device[handle].rx.queue, &device[handle].rx.frame, task_woken)	== pdFALSE) {
					driver_debug(DEBUG_I2C, "I2C RX queue full\n\r");
					csp_buffer_free_isr(device[handle].rx.frame);
				}
			} else if (device[handle].callback != NULL) {
				device[handle].callback(device[handle].rx.frame, task_woken);
			} else {
				csp_buffer_free_isr(device[handle].rx.frame);
			}

			/* The frame has been freed now */
			device[handle].rx.frame = NULL;

			/* Set back to master mode */
			pca9665_try_tx_from_isr(handle, task_woken);
			break;

		/**
		 * Other IRQ's, typically indicates a hardware or protcol error
		 * The IDLE status is considered an error if asserted at the same time as the Serial Interrupt flag
		 */
		case STA_IDLE:
		default:

isr_error:
			/* Soft reset the device */
			driver_debug(DEBUG_I2C, "I2C ERR 0x%02X\n\r", state);
			pca9665_init_registers(handle);

			/* Clean up RX */
			if (device[handle].rx.frame != NULL) {
				csp_buffer_free_isr(device[handle].rx.frame);
				device[handle].rx.frame = NULL;
			}

			/* Clean up TX */
			if (device[handle].tx.frame != NULL) {
				csp_buffer_free_isr(device[handle].tx.frame);
				device[handle].tx.frame = NULL;
			}

			/* Start up again */
			pca9665_try_tx_from_isr(handle, task_woken);

			break;
		}

	} /**< END Switch/Case */

}
コード例 #25
0
ファイル: spi_slave.c プロジェクト: jchunhua163/esp-idf-zh
//This is run in interrupt context and apart from initialization and destruction, this is the only code
//touching the host (=spihost[x]) variable. The rest of the data arrives in queues. That is why there are
//no muxes in this code.
static void IRAM_ATTR spi_intr(void *arg)
{
    BaseType_t r;
    BaseType_t do_yield = pdFALSE;
    spi_slave_transaction_t *trans = NULL;
    spi_slave_t *host = (spi_slave_t *)arg;

#ifdef DEBUG_SLAVE
    dumpregs(host->hw);
    if (host->dmadesc_rx) dumpll(&host->dmadesc_rx[0]);
#endif

    //Ignore all but the trans_done int.
    if (!host->hw->slave.trans_done) return;

    if (host->cur_trans) {
        if (host->dma_chan == 0 && host->cur_trans->rx_buffer) {
            //Copy result out
            uint32_t *data = host->cur_trans->rx_buffer;
            for (int x = 0; x < host->cur_trans->length; x += 32) {
                uint32_t word;
                int len = host->cur_trans->length - x;
                if (len > 32) len = 32;
                word = host->hw->data_buf[(x / 32)];
                memcpy(&data[x / 32], &word, (len + 7) / 8);
            }
        } else if (host->dma_chan != 0 && host->cur_trans->rx_buffer) {
            int i;
            //In case CS goes high too soon, the transfer is aborted while the DMA channel still thinks it's going. This
            //leads to issues later on, so in that case we need to reset the channel. The state can be detected because
            //the DMA system doesn't give back the offending descriptor; the owner is still set to DMA.
            for (i = 0; host->dmadesc_rx[i].eof == 0 && host->dmadesc_rx[i].owner == 0; i++) ;
            if (host->dmadesc_rx[i].owner) {
                spicommon_dmaworkaround_req_reset(host->dma_chan, spi_slave_restart_after_dmareset, host);
            }
        }
        if (host->cfg.post_trans_cb) host->cfg.post_trans_cb(host->cur_trans);
        //Okay, transaction is done.
        //Return transaction descriptor.
        xQueueSendFromISR(host->ret_queue, &host->cur_trans, &do_yield);
        host->cur_trans = NULL;
    }
    if (host->dma_chan != 0) {
        spicommon_dmaworkaround_idle(host->dma_chan);
        if (spicommon_dmaworkaround_reset_in_progress()) {
            //We need to wait for the reset to complete. Disable int (will be re-enabled on reset callback) and exit isr.
            esp_intr_disable(host->intr);
            if (do_yield) portYIELD_FROM_ISR();
            return;
        }
    }

    //Grab next transaction
    r = xQueueReceiveFromISR(host->trans_queue, &trans, &do_yield);
    if (!r) {
        //No packet waiting. Disable interrupt.
        esp_intr_disable(host->intr);
    } else {
        //We have a transaction. Send it.
        host->hw->slave.trans_done = 0; //clear int bit
        host->cur_trans = trans;

        if (host->dma_chan != 0) {
            spicommon_dmaworkaround_transfer_active(host->dma_chan);
            host->hw->dma_conf.val |= SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST;
            host->hw->dma_out_link.start = 0;
            host->hw->dma_in_link.start = 0;
            host->hw->dma_conf.val &= ~(SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
            host->hw->dma_conf.out_data_burst_en = 0;
            host->hw->dma_conf.indscr_burst_en = 0;
            host->hw->dma_conf.outdscr_burst_en = 0;

            //Fill DMA descriptors
            if (trans->rx_buffer) {
                host->hw->user.usr_miso_highpart = 0;
                spicommon_setup_dma_desc_links(host->dmadesc_rx, ((trans->length + 7) / 8), trans->rx_buffer, true);
                host->hw->dma_in_link.addr = (int)(&host->dmadesc_rx[0]) & 0xFFFFF;
                host->hw->dma_in_link.start = 1;
            }

            if (trans->tx_buffer) {
                spicommon_setup_dma_desc_links(host->dmadesc_tx, (trans->length + 7) / 8, trans->tx_buffer, false);
                host->hw->user.usr_mosi_highpart = 0;
                host->hw->dma_out_link.addr = (int)(&host->dmadesc_tx[0]) & 0xFFFFF;
                host->hw->dma_out_link.start = 1;
            }

            host->hw->slave.sync_reset = 1;
            host->hw->slave.sync_reset = 0;

        } else {
            //No DMA. Turn off SPI and copy data to transmit buffers.
            host->hw->cmd.usr = 0;
            host->hw->slave.sync_reset = 1;
            host->hw->slave.sync_reset = 0;

            host->hw->user.usr_miso_highpart = 0;
            host->hw->user.usr_mosi_highpart = 0;
            if (trans->tx_buffer) {
                const uint32_t *data = host->cur_trans->tx_buffer;
                for (int x = 0; x < trans->length; x += 32) {
                    uint32_t word;
                    memcpy(&word, &data[x / 32], 4);
                    host->hw->data_buf[(x / 32)] = word;
                }
            }
        }

        host->hw->slv_rd_bit.slv_rdata_bit = 0;
        host->hw->slv_wrbuf_dlen.bit_len = trans->length - 1;
        host->hw->slv_rdbuf_dlen.bit_len = trans->length - 1;
        host->hw->mosi_dlen.usr_mosi_dbitlen = trans->length - 1;
        host->hw->miso_dlen.usr_miso_dbitlen = trans->length - 1;
        host->hw->user.usr_mosi = (trans->tx_buffer == NULL) ? 0 : 1;
        host->hw->user.usr_miso = (trans->rx_buffer == NULL) ? 0 : 1;

        //Kick off transfer
        host->hw->cmd.usr = 1;
        if (host->cfg.post_setup_cb) host->cfg.post_setup_cb(trans);
    }
    if (do_yield) portYIELD_FROM_ISR();
}
コード例 #26
0
ファイル: i2cISR.c プロジェクト: vmandrews/CSDC-OBC-Software
void vI2C_ISR_Handler( void )
{
/* Holds the current transmission state. */							
static I2C_STATE eCurrentState = eSentStart;
static long lMessageIndex = -i2cBUFFER_ADDRESS_BYTES; /* There are two address bytes to send prior to the data. */
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
long lBytesLeft;

	/* The action taken for this interrupt depends on our current state. */
	switch( eCurrentState )
	{
		case eSentStart	:	

				/* We sent a start bit, if it was successful we can
				go on to send the slave address. */
				if( ( I2C_I2STAT == i2cSTATUS_START_TXED ) || ( I2C_I2STAT == i2cSTATUS_REP_START_TXED ) )
				{
					/* Send the slave address. */
					I2C_I2DAT = pxCurrentMessage->ucSlaveAddress;

					if( pxCurrentMessage->ucSlaveAddress & i2cREAD )
					{
						/* We are then going to read bytes back from the 
						slave. */
						eCurrentState = eSentAddressForRead;
						
						/* Initialise the buffer index so the first byte goes
						into the first buffer position. */
						lMessageIndex = 0;
					}
					else
					{
						/* We are then going to write some data to the slave. */
						eCurrentState = eSentAddressForWrite;

						/* When writing bytes we first have to send the two
						byte buffer address so lMessageIndex is set negative,
						when it reaches 0 it is time to send the actual data. */
						lMessageIndex = -i2cBUFFER_ADDRESS_BYTES;
					}
				}
				else
				{
					/* Could not send the start bit so give up. */
					i2cEND_TRANSMISSION( pdFAIL );					
				}

				I2C_I2CONCLR = i2cSTA_BIT;				

				break;

		case eSentAddressForWrite :

				/* We sent the address of the slave we are going to write to.
				If this was acknowledged we	can go on to send the data. */
				if( I2C_I2STAT == i2cSTATUS_TX_ADDR_ACKED )
				{
					/* Start the first byte transmitting which is the 
					first byte of the buffer address to which the data will 
					be sent. */
					I2C_I2DAT = pxCurrentMessage->ucBufferAddressHighByte;
					eCurrentState = eSentData;
				}
				else
				{
					/* Address was not acknowledged so give up. */
					i2cEND_TRANSMISSION( pdFAIL );					
				}					
				break;

		case eSentAddressForRead :

				/* We sent the address of the slave we are going to read from.
				If this was acknowledged we can go on to read the data. */
				if( I2C_I2STAT == i2cSTATUS_RX_ADDR_ACKED )
				{
					eCurrentState = eReceiveData;
					if( pxCurrentMessage->lMessageLength > i2cJUST_ONE_BYTE_TO_RX )
					{
						/* Don't ack the last byte of the message. */
						I2C_I2CONSET = i2cAA_BIT;
					}					
				}
				else
				{
					/* Something unexpected happened - give up. */
					i2cEND_TRANSMISSION( pdFAIL );					
				}
				break;

		case eReceiveData :
				
				/* We have just received a byte from the slave. */
				if( ( I2C_I2STAT == i2cSTATUS_DATA_RXED ) || ( I2C_I2STAT == i2cSTATUS_LAST_BYTE_RXED ) )
				{
					/* Buffer the byte just received then increment the index 
					so it points to the next free space. */
					pxCurrentMessage->pucBuffer[ lMessageIndex ] = I2C_I2DAT;
					lMessageIndex++;

					/* How many more bytes are we expecting to receive? */
					lBytesLeft = pxCurrentMessage->lMessageLength - lMessageIndex;
					if( lBytesLeft == ( unsigned long ) 0 )
					{
						/* This was the last byte in the message. */
						i2cEND_TRANSMISSION( pdPASS );

						/* If xMessageCompleteSemaphore is not null then there
						is a task waiting for this message to complete and we
						must 'give' the semaphore so the task is woken.*/
						if( pxCurrentMessage->xMessageCompleteSemaphore )
						{
							xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
						}

						/* Are there any other messages to transact? */
						if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
						{
							/* Start the next message - which was
							retrieved from the queue. */
							I2C_I2CONSET = i2cSTA_BIT;
						}
						else
						{
							/* No more messages were found to be waiting for
							transaction so the bus is free. */
							ulBusFree = ( unsigned long ) pdTRUE;			
						}						
					}
					else
					{
						/* There are more bytes to receive but don't ack the 
						last byte. */
						if( lBytesLeft <= i2cJUST_ONE_BYTE_TO_RX )
						{
							I2C_I2CONCLR = i2cAA_BIT;
						}							 
					}
				}
				else
				{
					/* Something unexpected happened - give up. */
					i2cEND_TRANSMISSION( pdFAIL );					
				}

				break;
				
		case eSentData	:	

				/* We sent a data byte, if successful send the	next byte in 
				the message. */
				if( I2C_I2STAT == i2cSTATUS_DATA_TXED )
				{
					/* Index to the next byte to send. */
					lMessageIndex++;
					if( lMessageIndex < 0 )
					{
						/* lMessage index is still negative so we have so far 
						only sent the first byte of the buffer address.  Send 
						the second byte now, then initialise the buffer index
						to zero so the next byte sent comes from the actual 
						data buffer. */
						I2C_I2DAT = pxCurrentMessage->ucBufferAddressLowByte;
					}
					else if( lMessageIndex < pxCurrentMessage->lMessageLength )
					{
						/* Simply send the next byte in the tx buffer. */
						I2C_I2DAT = pxCurrentMessage->pucBuffer[ lMessageIndex ];										
					}
					else
					{
						/* No more bytes in this message to be send.  Finished 
						sending message - send a stop bit. */
						i2cEND_TRANSMISSION( pdPASS );

						/* If xMessageCompleteSemaphore is not null then there
						is a task waiting for this message to be sent and the
						semaphore must be 'given' to wake the task. */
						if( pxCurrentMessage->xMessageCompleteSemaphore )
						{
							xSemaphoreGiveFromISR( pxCurrentMessage->xMessageCompleteSemaphore, &xHigherPriorityTaskWoken );
						}

						/* Are there any other messages to transact? */
						if( xQueueReceiveFromISR( xMessagesForTx, &pxCurrentMessage, &xHigherPriorityTaskWoken ) == pdTRUE )
						{
							/* Start the next message from the Tx queue. */
							I2C_I2CONSET = i2cSTA_BIT;
						}
						else
						{
							/* No more message were queues for transaction so 
							the bus is free. */
							ulBusFree = ( unsigned long ) pdTRUE;			
						}
					}
				}
				else
				{
					/* Something unexpected happened, give up. */
					i2cEND_TRANSMISSION( pdFAIL );					
				}
				break;

		default	:	
		
				/* Should never get here. */
				eCurrentState = eSentStart;
				break;
	}	

	/* Clear the interrupt. */
	I2C_I2CONCLR = i2cSI_BIT;
	VICVectAddr = i2cCLEAR_VIC_INTERRUPT;

	if( xHigherPriorityTaskWoken )
	{
		portYIELD_FROM_ISR();
	}
}
コード例 #27
0
ファイル: spi_master.c プロジェクト: altran-nl/esp-idf
//This is run in interrupt context and apart from initialization and destruction, this is the only code
//touching the host (=spihost[x]) variable. The rest of the data arrives in queues. That is why there are
//no muxes in this code.
static void IRAM_ATTR spi_intr(void *arg)
{
    int i;
    BaseType_t r;
    BaseType_t do_yield=pdFALSE;
    spi_trans_priv *trans_buf=NULL;
    spi_transaction_t *trans=NULL;
    spi_host_t *host=(spi_host_t*)arg;

    //Ignore all but the trans_done int.
    if (!host->hw->slave.trans_done) return;

    /*------------ deal with the in-flight transaction -----------------*/
    if (host->cur_cs != NO_CS) {
        spi_transaction_t *cur_trans = host->cur_trans_buf.trans;
        //Okay, transaction is done. 
        if (host->cur_trans_buf.buffer_to_rcv && host->dma_chan == 0 ) {
            //Need to copy from SPI regs to result buffer.
            for (int x=0; x < cur_trans->rxlength; x+=32) {
                //Do a memcpy to get around possible alignment issues in rx_buffer
                uint32_t word=host->hw->data_buf[x/32];
                int len=cur_trans->rxlength-x;
                if (len>32) len=32;
                memcpy(&host->cur_trans_buf.buffer_to_rcv[x/32], &word, (len+7)/8);
            }
        }
        //Call post-transaction callback, if any
        if (host->device[host->cur_cs]->cfg.post_cb) host->device[host->cur_cs]->cfg.post_cb(cur_trans);
        //Return transaction descriptor.
        xQueueSendFromISR(host->device[host->cur_cs]->ret_queue, &host->cur_trans_buf, &do_yield); 
        host->cur_cs = NO_CS;
    }
    //Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
    if (host->dma_chan) spicommon_dmaworkaround_idle(host->dma_chan);

    /*------------ new transaction starts here ------------------*/
    //ToDo: This is a stupidly simple low-cs-first priority scheme. Make this configurable somehow. - JD
    for (i=0; i<NO_CS; i++) {
        if (host->device[i]) {
            r=xQueueReceiveFromISR(host->device[i]->trans_queue, &host->cur_trans_buf, &do_yield);
            trans_buf = &host->cur_trans_buf;
            //Stop looking if we have a transaction to send.
            if (r) break;
        }
    }
    if (i==NO_CS) {
        //No packet waiting. Disable interrupt.
        esp_intr_disable(host->intr);
#ifdef CONFIG_PM_ENABLE
        //Release APB frequency lock
        esp_pm_lock_release(host->pm_lock);
#endif
    } else {
        host->hw->slave.trans_done=0; //clear int bit
        //We have a transaction. Send it.
        spi_device_t *dev=host->device[i];
        trans = trans_buf->trans;
        host->cur_cs=i;
        //We should be done with the transmission.
        assert(host->hw->cmd.usr == 0);
        
        //Reconfigure according to device settings, but only if we change CSses.
        if (i!=host->prev_cs) {
            int apbclk=APB_CLK_FREQ;
            int effclk=dev->clk_cfg.eff_clk;
            spi_set_clock(host->hw, dev->clk_cfg.reg);
            //Configure bit order
            host->hw->ctrl.rd_bit_order=(dev->cfg.flags & SPI_DEVICE_RXBIT_LSBFIRST)?1:0;
            host->hw->ctrl.wr_bit_order=(dev->cfg.flags & SPI_DEVICE_TXBIT_LSBFIRST)?1:0;
            
            //Configure polarity
            //SPI iface needs to be configured for a delay in some cases.
            int nodelay=0;
            int extra_dummy=0;
            if (host->no_gpio_matrix) {
                if (effclk >= apbclk/2) {
                    nodelay=1;
                }
            } else {
                if (effclk >= apbclk/2) {
                    nodelay=1;
                    extra_dummy=1;          //Note: This only works on half-duplex connections. spi_bus_add_device checks for this.
                } else if (effclk >= apbclk/4) {
                    nodelay=1;
                }
            }

            if (dev->cfg.mode==0) {
                host->hw->pin.ck_idle_edge=0;
                host->hw->user.ck_out_edge=0;
                host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
            } else if (dev->cfg.mode==1) {
                host->hw->pin.ck_idle_edge=0;
                host->hw->user.ck_out_edge=1;
                host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
            } else if (dev->cfg.mode==2) {
                host->hw->pin.ck_idle_edge=1;
                host->hw->user.ck_out_edge=1;
                host->hw->ctrl2.miso_delay_mode=nodelay?0:1;
            } else if (dev->cfg.mode==3) {
                host->hw->pin.ck_idle_edge=1;
                host->hw->user.ck_out_edge=0;
                host->hw->ctrl2.miso_delay_mode=nodelay?0:2;
            }

            //configure dummy bits
            host->hw->user.usr_dummy=(dev->cfg.dummy_bits+extra_dummy)?1:0;
            host->hw->user1.usr_dummy_cyclelen=dev->cfg.dummy_bits+extra_dummy-1;
            //Configure misc stuff
            host->hw->user.doutdin=(dev->cfg.flags & SPI_DEVICE_HALFDUPLEX)?0:1;
            host->hw->user.sio=(dev->cfg.flags & SPI_DEVICE_3WIRE)?1:0;

            host->hw->ctrl2.setup_time=dev->cfg.cs_ena_pretrans-1;
            host->hw->user.cs_setup=dev->cfg.cs_ena_pretrans?1:0;
            host->hw->ctrl2.hold_time=dev->cfg.cs_ena_posttrans-1;
            host->hw->user.cs_hold=(dev->cfg.cs_ena_posttrans)?1:0;

            //Configure CS pin
            host->hw->pin.cs0_dis=(i==0)?0:1;
            host->hw->pin.cs1_dis=(i==1)?0:1;
            host->hw->pin.cs2_dis=(i==2)?0:1;
        }
        host->prev_cs = i;
        //Reset SPI peripheral
        host->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
        host->hw->dma_out_link.start=0;
        host->hw->dma_in_link.start=0;
        host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
        host->hw->dma_conf.out_data_burst_en=1;
        //Set up QIO/DIO if needed
        host->hw->ctrl.val &= ~(SPI_FREAD_DUAL|SPI_FREAD_QUAD|SPI_FREAD_DIO|SPI_FREAD_QIO);
        host->hw->user.val &= ~(SPI_FWRITE_DUAL|SPI_FWRITE_QUAD|SPI_FWRITE_DIO|SPI_FWRITE_QIO);
        if (trans->flags & SPI_TRANS_MODE_DIO) {
            if (trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR) {
                host->hw->ctrl.fread_dio=1;
                host->hw->user.fwrite_dio=1;
            } else {
                host->hw->ctrl.fread_dual=1;
                host->hw->user.fwrite_dual=1;
            }
            host->hw->ctrl.fastrd_mode=1;
        } else if (trans->flags & SPI_TRANS_MODE_QIO) {
            if (trans->flags & SPI_TRANS_MODE_DIOQIO_ADDR) {
                host->hw->ctrl.fread_qio=1;
                host->hw->user.fwrite_qio=1;
            } else {
                host->hw->ctrl.fread_quad=1;
                host->hw->user.fwrite_quad=1;
            }
            host->hw->ctrl.fastrd_mode=1;
        }


        //Fill DMA descriptors
        if (trans_buf->buffer_to_rcv) {
            host->hw->user.usr_miso_highpart=0;
            if (host->dma_chan == 0) {
                //No need to setup anything; we'll copy the result out of the work registers directly later.
            } else {
                spicommon_dmaworkaround_transfer_active(host->dma_chan); //mark channel as active
                spicommon_setup_dma_desc_links(host->dmadesc_rx, ((trans->rxlength+7)/8), (uint8_t*)trans_buf->buffer_to_rcv, true);
                host->hw->dma_in_link.addr=(int)(&host->dmadesc_rx[0]) & 0xFFFFF;
                host->hw->dma_in_link.start=1;
            }
        } else {
            //DMA temporary workaround: let RX DMA work somehow to avoid the issue in ESP32 v0/v1 silicon 
            if (host->dma_chan != 0 ) {
                host->hw->dma_in_link.addr=0;
                host->hw->dma_in_link.start=1;
            }
        }

        if (trans_buf->buffer_to_send) {
            if (host->dma_chan == 0) {
                //Need to copy data to registers manually
                for (int x=0; x < trans->length; x+=32) {
                    //Use memcpy to get around alignment issues for txdata
                    uint32_t word;
                    memcpy(&word, &trans_buf->buffer_to_send[x/32], 4);
                    host->hw->data_buf[(x/32)+8]=word;
                }
                host->hw->user.usr_mosi_highpart=1;
            } else {
                spicommon_dmaworkaround_transfer_active(host->dma_chan); //mark channel as active
                spicommon_setup_dma_desc_links(host->dmadesc_tx, (trans->length+7)/8, (uint8_t*)trans_buf->buffer_to_send, false);
                host->hw->user.usr_mosi_highpart=0;
                host->hw->dma_out_link.addr=(int)(&host->dmadesc_tx[0]) & 0xFFFFF;
                host->hw->dma_out_link.start=1;
                host->hw->user.usr_mosi_highpart=0;
            }
        }

        host->hw->mosi_dlen.usr_mosi_dbitlen=trans->length-1;
        if ( dev->cfg.flags & SPI_DEVICE_HALFDUPLEX ) {
            host->hw->miso_dlen.usr_miso_dbitlen=trans->rxlength-1;
        } else {
            //rxlength is not used in full-duplex mode
            host->hw->miso_dlen.usr_miso_dbitlen=trans->length-1;
        }

        //Configure bit sizes, load addr and command
        int cmdlen;
        if ( trans->flags & SPI_TRANS_VARIABLE_CMD ) {
            cmdlen = ((spi_transaction_ext_t*)trans)->command_bits;
        } else {
            cmdlen = dev->cfg.command_bits;
        }
        int addrlen;
        if ( trans->flags & SPI_TRANS_VARIABLE_ADDR ) {
            addrlen = ((spi_transaction_ext_t*)trans)->address_bits;
        } else {
            addrlen = dev->cfg.address_bits;
        }
        host->hw->user1.usr_addr_bitlen=addrlen-1;
        host->hw->user2.usr_command_bitlen=cmdlen-1;
        host->hw->user.usr_addr=addrlen?1:0;
        host->hw->user.usr_command=cmdlen?1:0;

        // output command will be sent from bit 7 to 0 of command_value, and then bit 15 to 8 of the same register field.
        uint16_t command = trans->cmd << (16-cmdlen);    //shift to MSB
        host->hw->user2.usr_command_value = (command>>8)|(command<<8);  //swap the first and second byte
        // shift the address to MSB of addr (and maybe slv_wr_status) register. 
        // output address will be sent from MSB to LSB of addr register, then comes the MSB to LSB of slv_wr_status register. 
        if (addrlen>32) {
            host->hw->addr = trans->addr >> (addrlen- 32);
            host->hw->slv_wr_status = trans->addr << (64 - addrlen);
        } else {
コード例 #28
0
ファイル: csp_queue.c プロジェクト: YaoFei509/TRX_GOMSPACE
int csp_queue_dequeue_isr(csp_queue_handle_t handle, void * buf, CSP_BASE_TYPE * task_woken) {
	return xQueueReceiveFromISR(handle, buf, (signed CSP_BASE_TYPE *)task_woken);
}
コード例 #29
-1
ファイル: serial.c プロジェクト: kaizen8501/W7500_FreeRTOS
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, TickType_t xBlockTime )
{
signed portBASE_TYPE xReturn;
char cChar;
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

	if( xQueueSend( xCharsForTx, &cOutChar, xBlockTime ) == pdPASS )
	{
		xReturn = pdPASS;
		if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
		{
			/* A character was retrieved from the queue so can be sent to the
			THR now. */
            S_UART_SendData( cChar );
		}        
	}
	else
	{
		xReturn = pdFAIL;
	}

	return xReturn;
}
コード例 #30
-1
ファイル: serial.c プロジェクト: DanielKristofKiss/FreeRTOS
void USART3_IRQHandler( void )
{
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
char cChar;

	if( USART_GetITStatus( USART3, USART_IT_TXE ) == SET )
	{
		/* The interrupt was caused by the TX register becoming empty.  Are 
		there any more characters to transmit? */
		if( xQueueReceiveFromISR( xCharsForTx, &cChar, &xHigherPriorityTaskWoken ) == pdTRUE )
		{
			/* A character was retrieved from the queue so can be sent to the
			USART now. */
			USART_SendData( USART3, cChar );
		}
		else
		{
			USART_ITConfig( USART3, USART_IT_TXE, DISABLE );		
		}		
	}
	
	if( USART_GetITStatus( USART3, USART_IT_RXNE ) == SET )
	{
		/* A character has been received on the USART, send it to the Rx
		handler task. */
		cChar = USART_ReceiveData( USART3 );
		xQueueSendFromISR( xRxedChars, &cChar, &xHigherPriorityTaskWoken );
	}	

	/* If sending or receiving from a queue has caused a task to unblock, and
	the unblocked task has a priority equal to or higher than the currently 
	running task (the task this ISR interrupted), then xHigherPriorityTaskWoken 
	will have automatically been set to pdTRUE within the queue send or receive 
	function.  portEND_SWITCHING_ISR() will then ensure that this ISR returns 
	directly to the higher priority unblocked task. */
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
}