1
0
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:
Bogdan Marinescu 2011-11-10 02:27:44 +02:00
parent b79a1d4ead
commit d4f03efb96
5 changed files with 141 additions and 64 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 )