mirror of
https://github.com/elua/elua.git
synced 2025-01-25 01:02:54 +08:00
timer interrupt support for AVR32
This commit is contained in:
parent
b79a1d4ead
commit
d4f03efb96
@ -173,10 +173,12 @@
|
||||
|
||||
// Interrupt list
|
||||
#define INT_UART_RX ELUA_INT_FIRST_ID
|
||||
#define INT_ELUA_LAST INT_UART_RX
|
||||
#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 1 )
|
||||
#define INT_ELUA_LAST INT_TMR_MATCH
|
||||
|
||||
#define PLATFORM_CPU_CONSTANTS\
|
||||
_C( INT_UART_RX )
|
||||
_C( INT_UART_RX ),\
|
||||
_C( INT_TMR_MATCH )
|
||||
|
||||
// *****************************************************************************
|
||||
// CPU constants that should be exposed to the eLua "cpu" module
|
||||
|
@ -128,10 +128,12 @@
|
||||
|
||||
// Interrupt list
|
||||
#define INT_UART_RX ELUA_INT_FIRST_ID
|
||||
#define INT_ELUA_LAST INT_UART_RX
|
||||
#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 1 )
|
||||
#define INT_ELUA_LAST INT_TMR_MATCH
|
||||
|
||||
#define PLATFORM_CPU_CONSTANTS\
|
||||
_C( INT_UART_RX )
|
||||
_C( INT_UART_RX ),\
|
||||
_C( INT_TMR_MATCH )
|
||||
|
||||
// *****************************************************************************
|
||||
// CPU constants that should be exposed to the eLua "cpu" module
|
||||
|
@ -228,10 +228,12 @@
|
||||
|
||||
// Interrupt list
|
||||
#define INT_UART_RX ELUA_INT_FIRST_ID
|
||||
#define INT_ELUA_LAST INT_UART_RX
|
||||
#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 1 )
|
||||
#define INT_ELUA_LAST INT_TMR_MATCH
|
||||
|
||||
#define PLATFORM_CPU_CONSTANTS\
|
||||
_C( INT_UART_RX )
|
||||
_C( INT_UART_RX ),\
|
||||
_C( INT_TMR_MATCH )
|
||||
|
||||
// *****************************************************************************
|
||||
// CPU constants that should be exposed to the eLua "cpu" module
|
||||
|
@ -119,28 +119,6 @@ static u32 platform_timer_set_clock( unsigned id, u32 clock );
|
||||
__attribute__((__interrupt__)) static void adc_int_handler();
|
||||
#endif
|
||||
|
||||
// Virtual timers support
|
||||
#if VTMR_NUM_TIMERS > 0
|
||||
#define VTMR_CH (2)
|
||||
|
||||
__attribute__((__interrupt__)) static void tmr_int_handler()
|
||||
{
|
||||
volatile avr32_tc_t *tc = &AVR32_TC;
|
||||
|
||||
tc_read_sr( tc, VTMR_CH );
|
||||
cmn_virtual_timer_cb();
|
||||
|
||||
#ifdef BUILD_UIP
|
||||
// Indicate that a SysTick interrupt has occurred.
|
||||
eth_timer_fired = 1;
|
||||
|
||||
// Generate a fake Ethernet interrupt. This will perform the actual work
|
||||
// of incrementing the timers and taking the appropriate actions.
|
||||
platform_eth_force_interrupt();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
const u32 uart_base_addr[ ] = {
|
||||
AVR32_USART0_ADDRESS,
|
||||
AVR32_USART1_ADDRESS,
|
||||
@ -220,37 +198,6 @@ int platform_init()
|
||||
#endif
|
||||
}
|
||||
|
||||
// Setup timer interrupt for the virtual timers if needed
|
||||
#if VTMR_NUM_TIMERS > 0
|
||||
INTC_register_interrupt( &tmr_int_handler, AVR32_TC_IRQ2, AVR32_INTC_INT0 );
|
||||
tmropt.waveform.wavsel = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER;
|
||||
tc_init_waveform( tc, VTMR_CH, &tmropt );
|
||||
tc_interrupt_t tmrint =
|
||||
{
|
||||
0, // External trigger interrupt.
|
||||
0, // RB load interrupt.
|
||||
0, // RA load interrupt.
|
||||
1, // RC compare interrupt.
|
||||
0, // RB compare interrupt.
|
||||
0, // RA compare interrupt.
|
||||
0, // Load overrun interrupt.
|
||||
0 // Counter overflow interrupt.
|
||||
};
|
||||
# ifdef FOSC32
|
||||
tc_write_rc( tc, VTMR_CH, FOSC32 / VTMR_FREQ_HZ );
|
||||
# else
|
||||
// Run VTMR from the slowest available PBA clock divisor
|
||||
{ u32 vt_clock_freq = platform_timer_set_clock( VTMR_CH, REQ_PBA_FREQ / 128 );
|
||||
u32 div = vt_clock_freq / VTMR_FREQ_HZ;
|
||||
if (div > 0xffff) div = 0xffff;
|
||||
tc_write_rc( tc, VTMR_CH, div );
|
||||
}
|
||||
# endif
|
||||
tc_configure_interrupts( tc, VTMR_CH, &tmrint );
|
||||
Enable_global_interrupt();
|
||||
tc_start( tc, VTMR_CH );
|
||||
#endif
|
||||
|
||||
// Setup spi controller(s) : up to 4 slave by controller.
|
||||
#if NUM_SPI > 0
|
||||
spi_master_options_t spiopt;
|
||||
@ -297,6 +244,13 @@ int platform_init()
|
||||
cmn_systimer_set_interrupt_freq( 1 );
|
||||
platform_systimer_init();
|
||||
|
||||
// Setup virtual timers if needed
|
||||
#if VTMR_NUM_TIMERS > 0
|
||||
#define VTMR_CH 2
|
||||
platform_cpu_set_interrupt( INT_TMR_MATCH, VTMR_CH, PLATFORM_CPU_ENABLE );
|
||||
platform_timer_set_match_int( VTMR_CH, 1000000 / VTMR_FREQ_HZ, PLATFORM_TIMER_INT_CYCLIC );
|
||||
#endif // #if VTMR_NUM_TIMERS > 0
|
||||
|
||||
cmn_platform_init();
|
||||
|
||||
// All done
|
||||
@ -539,6 +493,7 @@ int platform_s_uart_set_flow_control( unsigned id, int type )
|
||||
// Timer functions
|
||||
|
||||
static const u16 clkdivs[] = { 0xFFFF, 2, 8, 32, 128 };
|
||||
u8 avr32_timer_int_periodic_flag[ 3 ];
|
||||
|
||||
// Helper: get timer clock
|
||||
static u32 platform_timer_get_clock( unsigned id )
|
||||
@ -639,7 +594,25 @@ timer_data_type platform_s_timer_op( unsigned id, int op, timer_data_type data )
|
||||
|
||||
int platform_s_timer_set_match_int( unsigned id, timer_data_type period_us, int type )
|
||||
{
|
||||
return PLATFORM_TIMER_INT_INVALID_ID;
|
||||
volatile avr32_tc_t *tc = &AVR32_TC;
|
||||
u32 final;
|
||||
|
||||
if( period_us == 0 )
|
||||
{
|
||||
tc->channel[ id ].CMR.waveform.wavsel = TC_WAVEFORM_SEL_UP_MODE;
|
||||
return PLATFORM_TIMER_INT_OK;
|
||||
}
|
||||
final = ( u32 )( ( u64 )( platform_timer_get_clock( id ) * period_us ) / 1000000 );
|
||||
if( final == 0 )
|
||||
return PLATFORM_TIMER_INT_TOO_SHORT;
|
||||
if( final > 0xFFFF )
|
||||
return PLATFORM_TIMER_INT_TOO_LONG;
|
||||
tc_stop( tc, id );
|
||||
tc->channel[ id ].CMR.waveform.wavsel = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER;
|
||||
tc->channel[ id ].rc = final;
|
||||
avr32_timer_int_periodic_flag[ id ] = type;
|
||||
tc_start( tc, id );
|
||||
return PLATFORM_TIMER_INT_OK;
|
||||
}
|
||||
|
||||
u64 platform_timer_sys_raw_read()
|
||||
@ -1164,7 +1137,23 @@ u32 platform_eth_get_elapsed_time()
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
void platform_eth_timer_handler()
|
||||
{
|
||||
// Indicate that a SysTick interrupt has occurred.
|
||||
eth_timer_fired = 1;
|
||||
|
||||
// Generate a fake Ethernet interrupt. This will perform the actual work
|
||||
// of incrementing the timers and taking the appropriate actions.
|
||||
platform_eth_force_interrupt();
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_UIP
|
||||
|
||||
void platform_eth_timer_handler()
|
||||
{
|
||||
}
|
||||
|
||||
#endif // #ifdef BUILD_UIP
|
||||
|
||||
// ****************************************************************************
|
||||
// Platform specific modules go here
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <avr32/io.h>
|
||||
#include "usart.h"
|
||||
#include "intc.h"
|
||||
#include "tc.h"
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt handlers
|
||||
@ -56,6 +57,52 @@ __attribute__((__interrupt__)) static void uart3_rx_handler()
|
||||
uart_common_rx_handler( 3 );
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// TMR_MATCH interrupts
|
||||
|
||||
#ifndef VTMR_CH
|
||||
#if VTMR_NUM_TIMERS > 0
|
||||
#define VTMR_CH (2)
|
||||
#else // #if VTMR_NUM_TIMERS > 0
|
||||
#define VTMR_CH 0xFFFF
|
||||
#endif // #if VTMR_NUM_TIMERS > 0
|
||||
#endif // #ifndef VTMR_CH
|
||||
|
||||
extern void platform_eth_timer_handler();
|
||||
static const int tmr_irqs[] = { AVR32_TC_IRQ0, AVR32_TC_IRQ1, AVR32_TC_IRQ2 };
|
||||
extern u8 avr32_timer_int_periodic_flag[ 3 ];
|
||||
|
||||
static void tmr_match_common_handler( int id )
|
||||
{
|
||||
volatile avr32_tc_t *tc = &AVR32_TC;
|
||||
|
||||
tc_read_sr( tc, id ); // clear interrupt
|
||||
if( id == VTMR_CH )
|
||||
{
|
||||
cmn_virtual_timer_cb();
|
||||
platform_eth_timer_handler();
|
||||
}
|
||||
else
|
||||
cmn_int_handler( INT_TMR_MATCH, id );
|
||||
if( avr32_timer_int_periodic_flag[ id ] != PLATFORM_TIMER_INT_CYCLIC )
|
||||
tc->channel[ id ].CMR.waveform.wavsel = TC_WAVEFORM_SEL_UP_MODE;
|
||||
}
|
||||
|
||||
__attribute__((__interrupt__)) static void tmr0_int_handler()
|
||||
{
|
||||
tmr_match_common_handler( 0 );
|
||||
}
|
||||
|
||||
__attribute__((__interrupt__)) static void tmr1_int_handler()
|
||||
{
|
||||
tmr_match_common_handler( 1 );
|
||||
}
|
||||
|
||||
__attribute__((__interrupt__)) static void tmr2_int_handler()
|
||||
{
|
||||
tmr_match_common_handler( 2 );
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt: INT_UART_RX
|
||||
|
||||
@ -86,11 +133,42 @@ static int int_uart_rx_get_flag( elua_int_resnum resnum, int clear )
|
||||
return ( pusart->csr & AVR32_USART_CSR_RXRDY_MASK ) ? 1 : 0;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt: INT_TMR_MATCH
|
||||
|
||||
static int int_tmr_match_get_status( elua_int_resnum resnum )
|
||||
{
|
||||
volatile avr32_tc_channel_t *pch = AVR32_TC.channel + resnum;
|
||||
|
||||
return pch->IMR.cpcs;
|
||||
}
|
||||
|
||||
static int int_tmr_match_set_status( elua_int_resnum resnum, int status )
|
||||
{
|
||||
volatile avr32_tc_channel_t *pch = AVR32_TC.channel + resnum;
|
||||
int previous = pch->IMR.cpcs;
|
||||
|
||||
if( status == PLATFORM_CPU_ENABLE )
|
||||
pch->IER.cpcs = 1;
|
||||
else
|
||||
pch->IDR.cpcs = 1;
|
||||
return previous;
|
||||
}
|
||||
|
||||
static int int_tmr_match_get_flag( elua_int_resnum resnum, int clear )
|
||||
{
|
||||
volatile avr32_tc_channel_t *pch = AVR32_TC.channel + resnum;
|
||||
|
||||
( void )clear; // reading the status register will automatically clear the interrupt flag
|
||||
return pch->SR.cpcs;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Interrupt initialization
|
||||
|
||||
typedef void ( *phandler )();
|
||||
static const phandler phandlers[] = { uart0_rx_handler, uart1_rx_handler, uart2_rx_handler, uart3_rx_handler };
|
||||
static const phandler phandlers_usart[] = { uart0_rx_handler, uart1_rx_handler, uart2_rx_handler, uart3_rx_handler };
|
||||
static const phandler phandlers_tmr[] = { tmr0_int_handler, tmr1_int_handler, tmr2_int_handler };
|
||||
|
||||
void platform_int_init()
|
||||
{
|
||||
@ -98,7 +176,9 @@ void platform_int_init()
|
||||
|
||||
for( i = 0; i < NUM_UART; i ++ )
|
||||
if( usart_irqs[ i ] != -1 )
|
||||
INTC_register_interrupt( phandlers[ i ], usart_irqs[ i ], AVR32_INTC_INT0 );
|
||||
INTC_register_interrupt( phandlers_usart[ i ], usart_irqs[ i ], AVR32_INTC_INT0 );
|
||||
for( i = 0; i < sizeof( phandlers_tmr ) / sizeof( phandler ); i ++ )
|
||||
INTC_register_interrupt( phandlers_tmr[ i ], tmr_irqs[ i ], AVR32_INTC_INT0 );
|
||||
Enable_global_interrupt();
|
||||
}
|
||||
|
||||
@ -108,7 +188,9 @@ void platform_int_init()
|
||||
|
||||
const elua_int_descriptor elua_int_table[ INT_ELUA_LAST ] =
|
||||
{
|
||||
{ int_uart_rx_set_status, int_uart_rx_get_status, int_uart_rx_get_flag }
|
||||
{ int_uart_rx_set_status, int_uart_rx_get_status, int_uart_rx_get_flag },
|
||||
{ int_tmr_match_set_status, int_tmr_match_get_status, int_tmr_match_get_flag }
|
||||
};
|
||||
|
||||
#endif // #if defined( BUILD_C_INT_HANDLERS ) || defined( BUILD_LUA_INT_HANDLERS )
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user