1
0
mirror of https://github.com/elua/elua.git synced 2025-01-08 20:56:17 +08:00

- Changed interrupt support infrastructure. No docs yet (will be added later), but check src/platform/lpc24xx/platform_int.c for a quick glimpse of the concept.

- Added direct access to interrupt flags; an interrupt doesn't have to trigger a handler anymore, its flag(s) can be checked instead (platform_cpu_get_interrupt_flag).
- Added experimental C interrupt handlers support (NOT TESTED). It can be compiled and used separately from the Lua interrupt support implementation. Hint: src/elua_int.c, elua_int_set_c_handler and elua_int_get_c_handler, also BUILD_C_INT_HANDLERS (as opposed to BUILD_LUA_INT_HANDLERS).
- Added tmr.set_match_int function that sets a match interrupt on a timer (one-shot or cyclic). Also works on virtual timers. In fact, it currently works only on virtual timers, as none of the platforms have support for this operation with hardware timers.
-Added more interrupt support functions in the CPU module.

All of the above were implemented and tested on the ELUA-PUC board, and nothing else. As a side effect, THIS COMMIT BRAKES THE STR912 PORT! The port will be modified to take advantage of the new interrupt structure soon; until then, please don't update it.
This commit is contained in:
Bogdan Marinescu 2010-11-03 23:57:27 +00:00
parent 8885b719d7
commit 5978c7b680
17 changed files with 768 additions and 294 deletions

View File

@ -380,7 +380,8 @@ if not GetOption( 'help' ):
local_libs = ''
# Application files
app_files = " src/main.c src/romfs.c src/semifs.c src/xmodem.c src/shell.c src/term.c src/common.c src/buf.c src/elua_adc.c src/dlmalloc.c src/salloc.c src/luarpc_elua_uart.c src/elua_int.c "
app_files = """ src/main.c src/romfs.c src/semifs.c src/xmodem.c src/shell.c src/term.c src/common.c src/common_tmr.c src/buf.c src/elua_adc.c src/dlmalloc.c
src/salloc.c src/luarpc_elua_uart.c src/elua_int.c """
# Newlib related files
newlib_files = " src/newlib/devman.c src/newlib/stubs.c src/newlib/genstd.c src/newlib/stdtcp.c"

View File

@ -3,6 +3,8 @@
#ifndef __COMMON_H__
#define __COMMON_H__
#include "elua_int.h"
// Virtual timers data
#define VTMR_FIRST_ID ( 32 )
#define VTMR_GET_ID( x ) ( ( x ) - VTMR_FIRST_ID )
@ -11,7 +13,13 @@
// Functions exported by the common platform layer
void cmn_platform_init();
void cmn_virtual_timer_cb();
void cmn_int_handler( elua_int_id id, elua_int_resnum resnum );
// Timer-specific functions
int cmn_tmr_int_set_status( elua_int_resnum resnum, int status );
int cmn_tmr_int_get_status( elua_int_resnum resnum );
int cmn_tmr_int_get_flag( elua_int_resnum resnum, int clear );
unsigned int intlog2( unsigned int v );
#endif // #ifndef __COMMON_H__

View File

@ -14,6 +14,9 @@ typedef u16 elua_int_resnum;
#define ELUA_INT_FIRST_ID 1
#define ELUA_INT_INVALID_INTERRUPT 0xFF
// "Any resnum" value for "get flag" functions
#define ELUA_INT_RESNUM_ANY 0xFFFF
// This is what gets pushed in the interrupt queue
typedef struct
{
@ -21,6 +24,20 @@ typedef struct
elua_int_resnum resnum;
} elua_int_element;
// Interrupt functions and descriptor
typedef int ( *elua_int_p_set_status )( elua_int_resnum resnum, int state );
typedef int ( *elua_int_p_get_status )( elua_int_resnum resnum );
typedef int ( *elua_int_p_get_flag )( elua_int_resnum resnum, int clear );
typedef struct
{
elua_int_p_set_status int_set_status;
elua_int_p_get_status int_get_status;
elua_int_p_get_flag int_get_flag;
} elua_int_descriptor;
// C interrupt handlers
typedef void( *elua_int_c_handler )( elua_int_resnum resnum );
// Handler key in the registry
#define LUA_INT_HANDLER_KEY ( int )&elua_int_add
@ -33,7 +50,10 @@ int elua_int_add( elua_int_id inttype, elua_int_resnum resnum );
void elua_int_enable( elua_int_id inttype );
void elua_int_disable( elua_int_id inttype );
int elua_int_is_enabled( elua_int_id inttype );
void elua_int_cleanup();
void elua_int_disable_all();
elua_int_c_handler elua_int_set_c_handler( elua_int_id inttype, elua_int_c_handler phandler );
elua_int_c_handler elua_int_get_c_handler( elua_int_id inttype );
#endif

View File

@ -17,6 +17,7 @@ enum
// Platform initialization
int platform_init();
void platform_int_init();
// *****************************************************************************
// PIO subsection
@ -151,6 +152,16 @@ int platform_s_uart_recv( unsigned id, s32 timeout );
// Data types
typedef u32 timer_data_type;
// Interrupt types
#define PLATFORM_TIMER_INT_ONESHOT 1
#define PLATFORM_TIMER_INT_CYCLIC 2
// Match interrupt error codes
#define PLATFORM_TIMER_INT_OK 0
#define PLATFORM_TIMER_INT_TOO_SHORT 1
#define PLATFORM_TIMER_INT_INVALID_ID 2
#define PLATFORM_TIMER_INT_GENERIC_ERR 3
// Timer operations
enum
{
@ -159,8 +170,7 @@ enum
PLATFORM_TIMER_OP_SET_CLOCK,
PLATFORM_TIMER_OP_GET_CLOCK,
PLATFORM_TIMER_OP_GET_MAX_DELAY,
PLATFORM_TIMER_OP_GET_MIN_DELAY,
PLATFORM_TIMER_OP_SET_INT_TIMEOUT
PLATFORM_TIMER_OP_GET_MIN_DELAY
};
// The platform timer functions
@ -169,6 +179,8 @@ void platform_timer_delay( unsigned id, u32 delay_us );
void platform_s_timer_delay( unsigned id, u32 delay_us );
u32 platform_timer_op( unsigned id, int op, u32 data );
u32 platform_s_timer_op( unsigned id, int op, u32 data );
int platform_timer_set_match_int( unsigned id, u32 period_us, int type );
int platform_s_timer_set_match_int( unsigned id, u32 period_us, int type );
u32 platform_timer_get_diff_us( unsigned id, timer_data_type end, timer_data_type start );
// *****************************************************************************
@ -197,10 +209,18 @@ u32 platform_pwm_op( unsigned id, int op, u32 data );
#define PLATFORM_CPU_DISABLE 0
#define PLATFORM_CPU_ENABLE 1
// Interrupt functions return status
#define PLATFORM_INT_OK 0
#define PLATFORM_INT_GENERIC_ERROR ( -1 )
#define PLATFORM_INT_INVALID ( -2 )
#define PLATFORM_INT_NOT_HANDLED ( -3 )
#define PLATFORM_INT_NOT_ANY ( -4 )
int platform_cpu_set_global_interrupts( int status );
int platform_cpu_get_global_interrupts();
int platform_cpu_set_interrupt( elua_int_id id, elua_int_resnum resnum, int status );
int platform_cpu_get_interrupt( elua_int_id id, elua_int_resnum resnum );
int platform_cpu_get_interrupt_flag( elua_int_id id, elua_int_resnum resnum, int clear );
u32 platform_cpu_get_frequency();
// *****************************************************************************

View File

@ -1,5 +1,6 @@
local vtmrid = tmr.VIRT0
local to = 1500000
local uartid = 0
local function handler( id, resnum )
print( string.format( "Got interrupt with id %d and resnum %d", id, resnum ) )
@ -7,18 +8,19 @@ local function handler( id, resnum )
local port, pin = pio.decode( resnum )
print( string.format( "Port is %d, pin is %d", port, pin ) )
elseif id == cpu.INT_TMR_MATCH then
print "Timer interrupt! Rearming ... "
tmr.setinttimeout( vtmrid, to )
print "Timer interrupt!"
end
end
cpu.set_int_handler( handler )
tmr.set_match_int( vtmrid, to, tmr.INT_CYCLIC )
cpu.sei( cpu.INT_GPIO_NEGEDGE, pio.P0_0 )
cpu.sei( cpu.INT_TMR_MATCH, vtmrid )
tmr.setinttimeout( vtmrid, to )
local tmrid = 0
while true do
print "Outside interrupt"
for i = 1, 1000 do tmr.delay( tmrid, 1000 ) end
if uart.getchar( uartid, 0 ) ~= "" then break end
end

View File

@ -15,6 +15,17 @@
#include "xmodem.h"
#include "elua_int.h"
#if defined( BUILD_LUA_INT_HANDLERS ) || defined( BUILD_C_INT_HANDLERS )
#define BUILD_INT_HANDLERS
#ifndef INT_TMR_MATCH
#define INT_TMR_MATCH ELUA_INT_INVALID_INTERRUPT
#endif
extern elua_int_descriptor elua_int_table[ INT_ELUA_LAST ];
#endif
// ****************************************************************************
// XMODEM support code
@ -125,6 +136,10 @@ static int uart_recv( s32 to )
void cmn_platform_init()
{
#ifdef BUILD_LUA_INT_HANDLERS
platform_int_init();
#endif
// Set the send/recv functions
std_set_send_func( uart_send );
std_set_get_func( uart_recv );
@ -226,161 +241,6 @@ int platform_uart_recv( unsigned id, unsigned timer_id, s32 timeout )
}
}
// ****************************************************************************
// Timers (and vtimers) functions
#if VTMR_NUM_TIMERS > 0
static volatile u32 vtmr_counters[ VTMR_NUM_TIMERS ];
static volatile s8 vtmr_reset_idx = -1;
#ifdef BUILD_LUA_INT_HANDLERS
static volatile u32 vtmr_period_limit[ VTMR_NUM_TIMERS ];
static volatile u8 vtmr_int_enabled[ ( VTMR_NUM_TIMERS + 7 ) >> 3 ];
#endif // #ifdef BUILD_LUA_INTERRUPT_HANDLERS
// This should be called from the platform's timer interrupt at VTMR_FREQ_HZ
void cmn_virtual_timer_cb()
{
unsigned i;
for( i = 0; i < VTMR_NUM_TIMERS; i ++ )
{
vtmr_counters[ i ] ++;
#ifdef BUILD_LUA_INT_HANDLERS
if( ( vtmr_int_enabled[ i >> 3 ] & ( 1 << ( i & 0x07 ) ) ) && ( vtmr_counters[ i ] == vtmr_period_limit[ i ] ) )
{
vtmr_int_enabled[ i >> 3 ] &= ( u8 )~( 1 << ( i & 0x07 ) );
elua_int_add( INT_TMR_MATCH, i + VTMR_FIRST_ID );
}
#endif // #ifdef BUILD_LUA_INT_HANDLERS
}
if( vtmr_reset_idx != -1 )
{
vtmr_counters[ vtmr_reset_idx ] = 0;
vtmr_reset_idx = -1;
}
}
static void vtmr_reset_timer( unsigned vid )
{
unsigned id = VTMR_GET_ID( vid );
vtmr_reset_idx = ( s8 )id;
while( vtmr_reset_idx != -1 );
}
static void vtmr_delay( unsigned vid, u32 delay_us )
{
timer_data_type final;
unsigned id = VTMR_GET_ID( vid );
final = ( ( u64 )delay_us * VTMR_FREQ_HZ ) / 1000000;
vtmr_reset_timer( vid );
while( vtmr_counters[ id ] < final );
}
#ifdef BUILD_LUA_INT_HANDLERS
static int vtmr_set_int_timeout( unsigned vid, u32 delay_us )
{
timer_data_type final;
unsigned id = VTMR_GET_ID( vid );
if( ( final = ( ( u64 )delay_us * VTMR_FREQ_HZ ) / 1000000 ) == 0 )
return 0;
vtmr_period_limit[ id ] = final;
vtmr_reset_timer( vid );
vtmr_int_enabled[ id >> 3 ] |= 1 << ( id & 0x07 );
return 1;
}
#else // #ifdef BUILD_LUA_INT_HANDLERS
static int vtmr_set_int_timeout( unsigned vid, u32 delay_us )
{
fprintf( stderr, "Timeouts with interrupts not available when Lua interrupt support is not enabled\n" );
return 0;
}
#endif // #ifdef BUILD_LUA_INT_HANDLERS
#else // #if VTMR_NUM_TIMERS > 0
void cmn_virtual_timer_cb()
{
}
#endif // #if VTMR_NUM_TIMERS > 0
int platform_timer_exists( unsigned id )
{
#if VTMR_NUM_TIMERS > 0
if( id >= VTMR_FIRST_ID )
return TIMER_IS_VIRTUAL( id );
else
#endif
return id < NUM_TIMER;
}
void platform_timer_delay( unsigned id, u32 delay_us )
{
#if VTMR_NUM_TIMERS > 0
if( TIMER_IS_VIRTUAL( id ) )
vtmr_delay( id, delay_us );
else
#endif
platform_s_timer_delay( id, delay_us );
}
u32 platform_timer_op( unsigned id, int op, u32 data )
{
u32 res = 0;
if( ( VTMR_NUM_TIMERS == 0 ) || ( !TIMER_IS_VIRTUAL( id ) ) )
return platform_s_timer_op( id, op, data );
#if VTMR_NUM_TIMERS > 0
switch( op )
{
case PLATFORM_TIMER_OP_START:
vtmr_reset_timer( id );
res = 0;
break;
case PLATFORM_TIMER_OP_READ:
res = vtmr_counters[ VTMR_GET_ID( id ) ];
break;
case PLATFORM_TIMER_OP_GET_MAX_DELAY:
res = platform_timer_get_diff_us( id, 0, 0xFFFFFFFF );
break;
case PLATFORM_TIMER_OP_GET_MIN_DELAY:
res = platform_timer_get_diff_us( id, 0, 1 );
break;
case PLATFORM_TIMER_OP_SET_CLOCK:
case PLATFORM_TIMER_OP_GET_CLOCK:
res = VTMR_FREQ_HZ;
break;
case PLATFORM_TIMER_OP_SET_INT_TIMEOUT:
res = vtmr_set_int_timeout( id, data );
break;
}
#endif
return res;
}
u32 platform_timer_get_diff_us( unsigned id, timer_data_type end, timer_data_type start )
{
timer_data_type temp;
u32 freq;
freq = platform_timer_op( id, PLATFORM_TIMER_OP_GET_CLOCK, 0 );
if( start < end )
{
temp = end;
end = start;
start = temp;
}
return ( ( u64 )( start - end ) * 1000000 ) / freq;
}
// ****************************************************************************
// CAN functions
@ -511,8 +371,66 @@ int platform_i2c_exists( unsigned id )
#endif
}
// ****************************************************************************
// Interrupt support
#ifdef BUILD_INT_HANDLERS
int platform_cpu_set_interrupt( elua_int_id id, elua_int_resnum resnum, int status )
{
elua_int_p_set_status ps;
if( id < ELUA_INT_FIRST_ID || id > INT_ELUA_LAST )
return PLATFORM_INT_INVALID;
if( ( ps = elua_int_table[ id - ELUA_INT_FIRST_ID ].int_set_status ) == NULL )
return PLATFORM_INT_NOT_HANDLED;
if( id == INT_TMR_MATCH )
return cmn_tmr_int_set_status( resnum, status );
return ps( resnum, status );
}
int platform_cpu_get_interrupt( elua_int_id id, elua_int_resnum resnum )
{
elua_int_p_get_status pg;
if( id < ELUA_INT_FIRST_ID || id > INT_ELUA_LAST )
return PLATFORM_INT_INVALID;
if( ( pg = elua_int_table[ id - ELUA_INT_FIRST_ID ].int_get_status ) == NULL )
return PLATFORM_INT_NOT_HANDLED;
if( id == INT_TMR_MATCH )
return cmn_tmr_int_get_status( resnum );
return pg( resnum );
}
int platform_cpu_get_interrupt_flag( elua_int_id id, elua_int_resnum resnum, int clear )
{
elua_int_p_get_flag pf;
if( id < ELUA_INT_FIRST_ID || id > INT_ELUA_LAST )
return PLATFORM_INT_INVALID;
if( ( pf = elua_int_table[ id - ELUA_INT_FIRST_ID ].int_get_flag ) == NULL )
return PLATFORM_INT_NOT_HANDLED;
if( id == INT_TMR_MATCH )
return cmn_tmr_int_get_flag( resnum, clear );
else
return pf( resnum, clear );
}
// Common interrupt handling
void cmn_int_handler( elua_int_id id, elua_int_resnum resnum )
{
elua_int_add( id, resnum );
#ifdef BUILD_C_INT_HANDLERS
elua_int_c_handler phnd = elua_int_get_c_handler( id );
if( phnd )
phnd( resnum );
#endif
}
#endif // #ifdef BUILD_INT_HANDLERS
// ****************************************************************************
// Misc support
unsigned int intlog2( unsigned int v )
{
unsigned r = 0;

289
src/common_tmr.c Normal file
View File

@ -0,0 +1,289 @@
// Common code, timer section
// Also implements virtual timers
#include "platform.h"
#include "platform_conf.h"
#include "type.h"
#include "common.h"
#include "elua_int.h"
#include <stdio.h>
// [TODO] when the new build system is ready, automatically add the
// code below in platform_conf.h
#if defined( BUILD_LUA_INT_HANDLERS ) || defined( BUILD_C_INT_HANDLERS )
#define BUILD_INT_HANDLERS
#ifndef INT_TMR_MATCH
#define INT_TMR_MATCH ELUA_INT_INVALID_INTERRUPT
#endif
extern elua_int_descriptor elua_int_table[ INT_ELUA_LAST ];
#endif
// ****************************************************************************
// Timers (and vtimers) functions
#if VTMR_NUM_TIMERS > 0
// ============================================================================
// VTMR functions
static volatile u32 vtmr_counters[ VTMR_NUM_TIMERS ];
static volatile s8 vtmr_reset_idx = -1;
#if defined( BUILD_INT_HANDLERS ) && ( INT_TMR_MATCH != ELUA_INT_INVALID_INTERRUPT )
#define CMN_TIMER_INT_SUPPORT
#endif // #if defined( BUILD_INT_HANDLERS ) && ( INT_TMR_MATCH != ELUA_INT_INVALID_INTERRUPT )
#ifdef CMN_TIMER_INT_SUPPORT
static volatile u32 vtmr_period_limit[ VTMR_NUM_TIMERS ];
static volatile u8 vtmr_int_periodic_flag[ ( VTMR_NUM_TIMERS + 7 ) >> 3 ];
static volatile u8 vtmr_int_enabled[ ( VTMR_NUM_TIMERS + 7 ) >> 3 ];
static volatile u8 vtmr_int_flag[ ( VTMR_NUM_TIMERS + 7 ) >> 3 ];
#endif // #ifdef CMN_TIMER_INT_SUPPORT
// This should be called from the platform's timer interrupt at VTMR_FREQ_HZ
void cmn_virtual_timer_cb()
{
unsigned i;
u8 msk;
for( i = 0; i < VTMR_NUM_TIMERS; i ++ )
{
vtmr_counters[ i ] ++;
#ifdef CMN_TIMER_INT_SUPPORT
msk = 1 << ( i & 0x07 );
if( vtmr_counters[ i ] >= vtmr_period_limit[ i ] )
{
vtmr_int_flag[ i >> 3 ] |= msk;
if( vtmr_int_enabled[ i >> 3 ] & msk )
elua_int_add( INT_TMR_MATCH, i + VTMR_FIRST_ID );
if( vtmr_int_periodic_flag[ i >> 3 ] & msk )
vtmr_counters[ i ] = 0;
else
vtmr_int_enabled[ i >> 3 ] &= ( u8 )~msk;
}
#endif // #ifdef CMN_TIMER_INT_SUPPORT
}
if( vtmr_reset_idx != -1 )
{
vtmr_counters[ vtmr_reset_idx ] = 0;
vtmr_reset_idx = -1;
}
}
static void vtmr_reset_timer( unsigned vid )
{
unsigned id = VTMR_GET_ID( vid );
vtmr_reset_idx = ( s8 )id;
while( vtmr_reset_idx != -1 );
}
static void vtmr_delay( unsigned vid, u32 delay_us )
{
timer_data_type final;
unsigned id = VTMR_GET_ID( vid );
final = ( ( u64 )delay_us * VTMR_FREQ_HZ ) / 1000000;
vtmr_reset_timer( vid );
while( vtmr_counters[ id ] < final );
}
#ifdef CMN_TIMER_INT_SUPPORT
static int vtmr_set_match_int( unsigned vid, u32 period_us, int type )
{
timer_data_type final;
unsigned id = VTMR_GET_ID( vid );
u8 msk = 1 << ( id & 0x07 );
if( period_us == 0 )
{
vtmr_int_enabled[ id >> 3 ] &= ( u8 )~msk;
vtmr_int_flag[ id >> 3 ] &= ( u8 )~msk;
return PLATFORM_TIMER_INT_OK;
}
if( ( final = ( ( u64 )period_us * VTMR_FREQ_HZ ) / 1000000 ) == 0 )
return PLATFORM_TIMER_INT_TOO_SHORT;
vtmr_period_limit[ id ] = final;
vtmr_reset_timer( vid );
if( type == PLATFORM_TIMER_INT_ONESHOT )
vtmr_int_periodic_flag[ id >> 3 ] &= ( u8 )~msk;
else
vtmr_int_periodic_flag[ id >> 3 ] |= msk;
vtmr_int_flag[ id >> 3 ] &= ( u8 )~msk;
vtmr_int_enabled[ id >> 3 ] |= msk;
return PLATFORM_TIMER_INT_OK;
}
static int vtmr_int_get_flag( elua_int_resnum resnum, int clear )
{
unsigned id = VTMR_GET_ID( resnum );
u8 msk = 1 << ( id & 0x07 );
int status = ( vtmr_int_flag[ id >> 3 ] & msk ) != 0;
if( clear )
vtmr_int_flag[ id >> 3 ] &= ( u8 )~msk;
return status;
}
static int vtmr_int_set_status( elua_int_resnum resnum, int status )
{
unsigned id = VTMR_GET_ID( resnum );
u8 msk = 1 << ( id & 0x07 );
int prev = ( vtmr_int_enabled[ id >> 3 ] & msk ) != 0;
if( status == PLATFORM_CPU_ENABLE )
vtmr_int_enabled[ id >> 3 ] |= msk;
else
vtmr_int_enabled[ id >> 3 ] &= ( u8 )~msk;
return prev;
}
static int vtmr_int_get_status( elua_int_resnum resnum )
{
unsigned id = VTMR_GET_ID( resnum );
u8 msk = 1 << ( id & 0x07 );
return ( vtmr_int_enabled[ id >> 3 ] & msk ) != 0;
}
#endif // #ifdef CMN_TIMER_INT_SUPPORT
#else // #if VTMR_NUM_TIMERS > 0
void cmn_virtual_timer_cb()
{
}
#endif // #if VTMR_NUM_TIMERS > 0
// ============================================================================
// Actual timer functions
int platform_timer_exists( unsigned id )
{
#if VTMR_NUM_TIMERS > 0
if( id >= VTMR_FIRST_ID )
return TIMER_IS_VIRTUAL( id );
else
#endif
return id < NUM_TIMER;
}
void platform_timer_delay( unsigned id, u32 delay_us )
{
#if VTMR_NUM_TIMERS > 0
if( TIMER_IS_VIRTUAL( id ) )
vtmr_delay( id, delay_us );
else
#endif
platform_s_timer_delay( id, delay_us );
}
u32 platform_timer_op( unsigned id, int op, u32 data )
{
u32 res = 0;
if( ( VTMR_NUM_TIMERS == 0 ) || ( !TIMER_IS_VIRTUAL( id ) ) )
return platform_s_timer_op( id, op, data );
#if VTMR_NUM_TIMERS > 0
switch( op )
{
case PLATFORM_TIMER_OP_START:
vtmr_reset_timer( id );
res = 0;
break;
case PLATFORM_TIMER_OP_READ:
res = vtmr_counters[ VTMR_GET_ID( id ) ];
break;
case PLATFORM_TIMER_OP_GET_MAX_DELAY:
res = platform_timer_get_diff_us( id, 0, 0xFFFFFFFF );
break;
case PLATFORM_TIMER_OP_GET_MIN_DELAY:
res = platform_timer_get_diff_us( id, 0, 1 );
break;
case PLATFORM_TIMER_OP_SET_CLOCK:
case PLATFORM_TIMER_OP_GET_CLOCK:
res = VTMR_FREQ_HZ;
break;
}
#endif
return res;
}
u32 platform_timer_get_diff_us( unsigned id, timer_data_type end, timer_data_type start )
{
timer_data_type temp;
u32 freq;
freq = platform_timer_op( id, PLATFORM_TIMER_OP_GET_CLOCK, 0 );
if( start < end )
{
temp = end;
end = start;
start = temp;
}
return ( ( u64 )( start - end ) * 1000000 ) / freq;
}
#ifdef CMN_TIMER_INT_SUPPORT
int platform_timer_set_match_int( unsigned id, u32 period_us, int type )
{
#if VTMR_NUM_TIMERS > 0
if( TIMER_IS_VIRTUAL( id ) )
return vtmr_set_match_int( id, period_us, type );
else
#endif
return platform_s_timer_set_match_int( id, period_us, type );
}
int cmn_tmr_int_set_status( elua_int_resnum resnum, int status )
{
#if VTMR_NUM_TIMERS > 0
if( TIMER_IS_VIRTUAL( resnum ) )
return vtmr_int_set_status( resnum, status );
#endif
elua_int_p_set_status ps;
if( ( ps = elua_int_table[ INT_TMR_MATCH - ELUA_INT_FIRST_ID ].int_set_status ) == NULL )
return PLATFORM_INT_NOT_HANDLED;
return ps( resnum, status );
}
int cmn_tmr_int_get_status( elua_int_resnum resnum )
{
#if VTMR_NUM_TIMERS > 0
if( TIMER_IS_VIRTUAL( resnum ) )
return vtmr_int_get_status( resnum );
#endif
elua_int_p_get_status pg;
if( ( pg = elua_int_table[ INT_TMR_MATCH - ELUA_INT_FIRST_ID ].int_get_status ) == NULL )
return PLATFORM_INT_NOT_HANDLED;
return pg( resnum );
}
int cmn_tmr_int_get_flag( elua_int_resnum resnum, int clear )
{
if( resnum == ELUA_INT_RESNUM_ANY )
return PLATFORM_INT_NOT_ANY;
#if VTMR_NUM_TIMERS > 0
if( TIMER_IS_VIRTUAL( resnum ) )
return vtmr_int_get_flag( resnum, clear );
#endif
elua_int_p_get_flag pf;
if( ( pf = elua_int_table[ INT_TMR_MATCH - ELUA_INT_FIRST_ID ].int_get_flag ) == NULL )
return PLATFORM_INT_NOT_HANDLED;
return pf( resnum, clear );
}
#else // #ifdef CMN_TIMER_INT_SUPPORT
int platform_timer_set_match_int( unsigned id, u32 period_us, int type )
{
fprintf( stderr, "Timer match interrupt not available when eLua interrupt support is not enabled.\n" );
return 0;
}
#endif // #ifdef CMN_TIMER_INT_SUPPORT

View File

@ -9,6 +9,9 @@
#include <stdio.h>
#include <string.h>
// ****************************************************************************
// Lua handlers
#ifdef BUILD_LUA_INT_HANDLERS
// Interrupt queue read and write indexes
@ -64,6 +67,9 @@ static void elua_int_hook( lua_State *L, lua_Debug *ar )
// Returns PLATFORM_OK or PLATFORM_ERR
int elua_int_add( elua_int_id inttype, elua_int_resnum resnum )
{
if( inttype < ELUA_INT_FIRST_ID || inttype > INT_ELUA_LAST )
return PLATFORM_ERR;
// If Lua is not running (no Lua state), or no Lua interrupt handler is set,
// or the interrupt is not enabled, don't do anything
if( lua_getstate() == NULL || !cpu_is_int_handler_active() || !elua_int_is_enabled( inttype ) )
@ -82,7 +88,6 @@ int elua_int_add( elua_int_id inttype, elua_int_resnum resnum )
elua_int_write_idx = ( elua_int_write_idx + 1 ) & INT_IDX_MASK;
// Set the Lua hook (it's OK to set it even if it's already set)
// [TODO] is it safe to call lua_sethook here ? If not, set a "trap" in lvm.c
lua_sethook( lua_getstate(), elua_int_hook, LUA_MASKCOUNT, 2 );
// All OK
@ -120,6 +125,14 @@ void elua_int_disable_all()
elua_int_flags[ i ] = 0;
}
// Called from lstate.c/lua_close
void elua_int_cleanup()
{
elua_int_disable_all();
elua_int_read_idx = elua_int_write_idx = 0;
memset( elua_int_queue, ELUA_INT_EMPTY_SLOT, sizeof( elua_int_queue ) );
}
#else // #ifdef BUILD_LUA_INT_HANDLERS
// This is needed by lua_close (lstate.c)
@ -127,6 +140,11 @@ void elua_int_disable_all()
{
}
// This too
void elua_int_cleanup()
{
}
void elua_int_enable( elua_int_id inttype )
{
}
@ -135,5 +153,50 @@ void elua_int_disable( elua_int_id inttype )
{
}
int elua_int_add( elua_int_id inttype, elua_int_resnum resnum )
{
return PLATFORM_ERR;
}
#endif // #ifdef BUILD_LUA_INT_HANDLERS
// ****************************************************************************
// C handlers
#ifdef BUILD_C_INT_HANDLERS
static elua_int_c_handler elua_int_c_handler_list[ INT_ELUA_LAST ];
elua_int_c_handler elua_int_set_c_handler( elua_int_id inttype, elua_int_c_handler phandler )
{
elua_int_c_handler crthandler;
if( inttype < ELUA_INT_FIRST_ID || inttype > INT_ELUA_LAST )
return NULL;
inttype -= ELUA_INT_FIRST_ID;
crthandler = elua_int_c_handler_list[ inttype ];
elua_int_c_handler_list[ inttype ] = phandler;
return crthandler;
}
elua_int_c_handler elua_int_get_c_handler( elua_int_id inttype )
{
if( inttype < ELUA_INT_FIRST_ID || inttype > INT_ELUA_LAST )
return NULL;
return elua_int_c_handler_list[ inttype - ELUA_INT_FIRST_ID ];
}
#else // #ifdef BUILD_C_INT_HANDLERS
elua_int_c_handler elua_int_set_c_handler( elua_int_id inttype, elua_int_c_handler phandler )
{
return NULL;
}
elua_int_c_handler elua_int_get_c_handler( elua_int_id inttype )
{
return NULL;
}
#endif // #ifdef BUILD_C_INT_HANDLERS

View File

@ -17,6 +17,7 @@
#define LNILKEY LRO_NILKEY
#define LFUNCVAL LRO_FUNCVAL
#define LNUMVAL LRO_NUMVAL
#define LBOOLVAL LRO_BOOLVAL
#define LROVAL LRO_ROVAL
#define LNILVAL LRO_NILVAL
#define LREGISTER(L, name, table)\

View File

@ -11,6 +11,7 @@
/* Macros one can use to define rotable entries */
#define LRO_FUNCVAL(v) {{.p = v}, LUA_TLIGHTFUNCTION}
#define LRO_NUMVAL(v) {{.n = v}, LUA_TNUMBER}
#define LRO_BOOLVAL(v) {{.n = v}, LUA_TBOOLEAN}
#define LRO_ROVAL(v) {{.p = ( void* )v}, LUA_TROTABLE}
#define LRO_NILVAL {{.p = NULL}, LUA_TNIL}

View File

@ -25,6 +25,7 @@
#include "platform_conf.h"
// BogdanM: modified for Lua interrupt support
#include "elua_int.h"
#include "platform.h"
#define state_size(x) (sizeof(x) + LUAI_EXTRASPACE)
#define fromstate(l) (cast(lu_byte *, (l)) - LUAI_EXTRASPACE)
@ -226,6 +227,13 @@ lua_State *lua_getstate(void) {
return lua_crtstate;
}
LUA_API void lua_close (lua_State *L) {
#ifndef LUA_CROSS_COMPILER
int oldstate = platform_cpu_set_global_interrupts( PLATFORM_CPU_DISABLE );
lua_sethook( L, NULL, 0, 0 );
lua_crtstate = NULL;
elua_int_cleanup();
platform_cpu_set_global_interrupts( oldstate );
#endif
L = G(L)->mainthread; /* only the main thread can be closed */
lua_lock(L);
luaF_close(L, L->stack); /* close all upvalues for this thread */
@ -240,9 +248,5 @@ LUA_API void lua_close (lua_State *L) {
luai_userstateclose(L);
close_state(L);
// BogdanM: modified for eLua interrupt support
#ifndef LUA_CROSS_COMPILER
lua_crtstate = NULL;
elua_int_disable_all();
#endif
}

View File

@ -90,6 +90,7 @@ static int cpu_cli( lua_State *L )
unsigned i;
elua_int_id id;
elua_int_resnum resnum;
int res;
if( lua_gettop( L ) > 0 )
{
@ -97,7 +98,11 @@ static int cpu_cli( lua_State *L )
for( i = 2; i <= lua_gettop( L ); i ++ )
{
resnum = ( elua_int_resnum )luaL_checkinteger( L, i );
platform_cpu_set_interrupt( id, resnum, PLATFORM_CPU_DISABLE );
res = platform_cpu_set_interrupt( id, resnum, PLATFORM_CPU_DISABLE );
if( res == PLATFORM_INT_INVALID )
return luaL_error( L, "%d is not a valid interrupt ID", ( int )id );
else if( res == PLATFORM_INT_NOT_HANDLED )
return luaL_error( L, "cli operation not implemented for interrupt %d with resnum %d", ( int )id, ( int )resnum );
}
elua_int_disable( id );
}
@ -119,6 +124,7 @@ static int cpu_sei( lua_State *L )
unsigned i;
elua_int_id id;
elua_int_resnum resnum;
int res;
if( lua_gettop( L ) > 0 )
{
@ -126,7 +132,11 @@ static int cpu_sei( lua_State *L )
for( i = 2; i <= lua_gettop( L ); i ++ )
{
resnum = ( elua_int_resnum )luaL_checkinteger( L, i );
platform_cpu_set_interrupt( id, resnum, PLATFORM_CPU_ENABLE );
res = platform_cpu_set_interrupt( id, resnum, PLATFORM_CPU_ENABLE );
if( res == PLATFORM_INT_INVALID )
return luaL_error( L, "%d is not a valid interrupt ID", ( int )id );
else if( res == PLATFORM_INT_NOT_HANDLED )
return luaL_error( L, "sei operation not implemented for interrupt %d with resnum %d", ( int )id, ( int )resnum );
}
elua_int_enable( id );
}
@ -201,7 +211,34 @@ static int cpu_set_int_handler( lua_State *L )
return luaL_error( L, "invalid argument (must be a function or nil)" );
return 0;
}
#endif
// Lua: flag = get_int_flag( id, resnum, [clear] )
// 'clear' default to true if not specified
static int cpu_get_int_flag( lua_State *L )
{
elua_int_id id;
elua_int_resnum resnum;
int clear = 1;
int res;
id = ( elua_int_id )luaL_checkinteger( L, 1 );
resnum = ( elua_int_resnum )luaL_checkinteger( L, 2 );
if( lua_gettop( L ) >= 3 )
{
if( lua_isboolean( L, 3 ) )
clear = lua_toboolean( L, 3 );
else
return luaL_error( L, "expected a bool as the 3rd argument of this function" );
}
res = platform_cpu_get_interrupt_flag( id, resnum, clear );
if( res == PLATFORM_INT_INVALID )
return luaL_error( L, "%d is not a valid interrupt ID", ( int )id );
else if( res == PLATFORM_INT_NOT_HANDLED )
return luaL_error( L, "get flag operation not implemented for interrupt %d with resnum %d", ( int )id, ( int )resnum );
lua_pushinteger( L, res );
return 1;
}
#endif // #ifdef BUILD_LUA_INT_HANDLERS
// Module function map
#define MIN_OPT_LEVEL 2
@ -219,6 +256,10 @@ const LUA_REG_TYPE cpu_map[] =
{ LSTRKEY( "clock" ), LFUNCVAL( cpu_clock ) },
#ifdef BUILD_LUA_INT_HANDLERS
{ LSTRKEY( "set_int_handler" ), LFUNCVAL( cpu_set_int_handler ) },
{ LSTRKEY( "get_int_flag" ), LFUNCVAL( cpu_get_int_flag) },
{ LSTRKEY( "ANY_RES" ), LNUMVAL( ELUA_INT_RESNUM_ANY ) },
{ LSTRKEY( "INT_FLAG_CLEAR" ), LBOOLVAL( 1 ) },
{ LSTRKEY( "INT_FLAG_KEEP" ), LBOOLVAL( 0 ) },
#endif
#if defined( PLATFORM_CPU_CONSTANTS ) && LUA_OPTIMIZE_MEMORY > 0
{ LSTRKEY( "__metatable" ), LROVAL( cpu_map ) },

View File

@ -120,22 +120,23 @@ static int tmr_getclock( lua_State* L )
return 1;
}
// Lua: setinttimeout( id, timeout )
static int tmr_setinttimeout( lua_State *L )
{
#ifdef BUILD_LUA_INT_HANDLERS
// Lua: set_match_int( id, timeout, type )
static int tmr_set_match_int( lua_State *L )
{
unsigned id;
u32 res;
id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( timer, id );
res = platform_timer_op( id, PLATFORM_TIMER_OP_SET_INT_TIMEOUT, ( u32 )luaL_checknumber( L, 2 ) );
lua_pushinteger( L, res );
return 1;
#else
return luaL_error( L, "setinttimeout not supported when Lua interrupt support is not compiled" );
#endif
res = platform_timer_set_match_int( id, ( u32 )luaL_checknumber( L, 2 ), ( int )luaL_checkinteger( L, 3 ) );
if( res == PLATFORM_TIMER_INT_TOO_SHORT )
return luaL_error( L, "timer interval too small" );
else if( res == PLATFORM_TIMER_INT_INVALID_ID )
return luaL_error( L, "mach interrupt cannot be set on this timer" );
return 0;
}
#endif // #ifdef BUILD_LUA_INT_HANDLERS
#if VTMR_NUM_TIMERS > 0
// __index metafunction for TMR
@ -173,13 +174,19 @@ const LUA_REG_TYPE tmr_map[] =
{ LSTRKEY( "getmaxdelay" ), LFUNCVAL( tmr_getmaxdelay ) },
{ LSTRKEY( "setclock" ), LFUNCVAL( tmr_setclock ) },
{ LSTRKEY( "getclock" ), LFUNCVAL( tmr_getclock ) },
{ LSTRKEY( "setinttimeout" ), LFUNCVAL( tmr_setinttimeout ) },
#ifdef BUILD_LUA_INT_HANDLERS
{ LSTRKEY( "set_match_int" ), LFUNCVAL( tmr_set_match_int ) },
#endif
#if LUA_OPTIMIZE_MEMORY > 0 && VTMR_NUM_TIMERS > 0
{ LSTRKEY( "__metatable" ), LROVAL( tmr_map ) },
#endif
#if VTMR_NUM_TIMERS > 0
{ LSTRKEY( "__index" ), LFUNCVAL( tmr_mt_index ) },
#endif
#if LUA_OPTIMIZE_MEMORY > 0 && defined( BUILD_LUA_INT_HANDLERS )
{ LSTRKEY( "INT_ONESHOT" ), LNUMVAL( PLATFORM_TIMER_INT_ONESHOT ) },
{ LSTRKEY( "INT_CYCLIC" ), LNUMVAL( PLATFORM_TIMER_INT_CYCLIC ) },
#endif
{ LNILKEY, LNILVAL }
};

View File

@ -2,7 +2,7 @@
cpumode = ARGUMENTS.get( 'cpumode', 'arm' ).lower()
specific_files = "startup.s irq.c target.c platform.c"
specific_files = "startup.s irq.c target.c platform.c platform_int.c"
if comp[ 'cpu' ] == 'LPC2468':
ldscript = "lpc2468.lds"
else:

View File

@ -27,40 +27,6 @@
extern void enable_ints();
extern void disable_ints();
// *****************************************************************************
// These interrupt handlers are the link to elua_int.c
static PREG const posedge_status[] = { ( PREG )&IO0_INT_STAT_R, ( PREG )&IO2_INT_STAT_R };
static PREG const negedge_status[] = { ( PREG )&IO0_INT_STAT_F, ( PREG )&IO2_INT_STAT_F };
static PREG const intclr_regs[] = { ( PREG )&IO0_INT_CLR, ( PREG )&IO2_INT_CLR };
static void int_handler_eint3()
{
elua_int_id id = ELUA_INT_INVALID_INTERRUPT;
pio_code resnum = 0;
int pidx, pin;
EXTINT |= 1 << 3; // clear interrupt
// Look for interrupt source
// In can only be GPIO0/GPIO2, as the EXT interrupts are not (yet) used
pidx = ( IO_INT_STAT & 1 ) ? 0 : 1;
if( *posedge_status[ pidx ] )
{
id = INT_GPIO_POSEDGE;
pin = intlog2( *posedge_status[ pidx ] );
}
else
{
id = INT_GPIO_NEGEDGE;
pin = intlog2( *negedge_status[ pidx ] );
}
resnum = PLATFORM_IO_ENCODE( pidx * 2, pin, PLATFORM_IO_ENC_PIN );
*intclr_regs[ pidx ] = 1 << pin;
// Queue interrupt
elua_int_add( id, resnum );
VICVectAddr = 0; // ACK interrupt
}
// ****************************************************************************
// Platform initialization
@ -96,12 +62,6 @@ static void platform_setup_cpu()
SCS |= 1;
}
// Setup all required interrupt handlers
static void platform_setup_interrupts()
{
install_irq( EINT3_INT, int_handler_eint3, HIGHEST_PRIORITY - 1 );
}
#define P2C(Period) (((Period<EMC_PERIOD)?0:(unsigned int)((float)Period/EMC_PERIOD)))
#define SDRAM_BASE_ADDR *(volatile unsigned int*)0xA0000000 //DYCS0
#define SDRAM_CS0_BASE (0xA0000000)
@ -179,9 +139,6 @@ int platform_init()
platform_setup_timers();
platform_setup_pwm();
// Setup interrupt handlers
platform_setup_interrupts();
// Initialize console UART
platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 );
@ -578,59 +535,9 @@ u32 platform_s_timer_op( unsigned id, int op, u32 data )
return res;
}
// ****************************************************************************
// CPU functions
static PREG const posedge_regs[] = { ( PREG )&IO0_INT_EN_R, NULL, ( PREG )&IO2_INT_EN_R };
static PREG const negedge_regs[] = { ( PREG )&IO0_INT_EN_F, NULL, ( PREG )&IO0_INT_EN_F };
// Helper: return the status of a specific interrupt (enabled/disabled)
static int platform_cpuh_get_int_status( elua_int_id id, elua_int_resnum resnum )
int platform_s_timer_set_match_int( unsigned id, u32 period_us, int type )
{
int port, pin;
if( id == INT_GPIO_POSEDGE || id == INT_GPIO_NEGEDGE )
{
port = PLATFORM_IO_GET_PORT( resnum );
pin = PLATFORM_IO_GET_PIN( resnum );
if( id == INT_GPIO_POSEDGE )
return *posedge_regs[ port ] & ( 1 << pin );
else
return *negedge_regs[ port ] & ( 1 << pin );
}
return 0;
}
int platform_cpu_set_interrupt( elua_int_id id, elua_int_resnum resnum, int status )
{
int crt_status = platform_cpuh_get_int_status( id, resnum );
int port, pin;
if( id == INT_GPIO_POSEDGE || id == INT_GPIO_NEGEDGE )
{
port = PLATFORM_IO_GET_PORT( resnum );
pin = PLATFORM_IO_GET_PIN( resnum );
if( id == INT_GPIO_POSEDGE )
{
if( status == PLATFORM_CPU_ENABLE )
*posedge_regs[ port ] |= 1 << pin;
else
*posedge_regs[ port ] &= ~( 1 << pin );
}
else
{
if( status == PLATFORM_CPU_ENABLE )
*negedge_regs[ port ] |= 1 << pin;
else
*negedge_regs[ port ] &= ~( 1 << pin );
}
}
return crt_status;
}
int platform_cpu_get_interrupt( elua_int_id id, elua_int_resnum resnum )
{
return platform_cpuh_get_int_status( id, resnum );
return PLATFORM_TIMER_INT_INVALID_ID;
}
// *****************************************************************************

View File

@ -20,6 +20,7 @@
#define BUILD_ADC
#define BUILD_RPC
#define BUILD_LUA_INT_HANDLERS
#define BUILD_C_INT_HANDLERS
// *****************************************************************************
// UART/Timer IDs configuration data (used in main.c)
@ -137,27 +138,24 @@
// *****************************************************************************
// CPU constants that should be exposed to the eLua "cpu" module
#define PINSEL_BASE_ADDR 0xE002C000
#define IO_PINSEL0 ( PINSEL_BASE_ADDR + 0x00 )
#define IO_PINSEL1 ( PINSEL_BASE_ADDR + 0x04 )
#define IO_PINSEL2 ( PINSEL_BASE_ADDR + 0x08 )
#define IO_PINSEL3 ( PINSEL_BASE_ADDR + 0x0C )
#define IO_PINSEL4 ( PINSEL_BASE_ADDR + 0x10 )
#define IO_PINSEL5 ( PINSEL_BASE_ADDR + 0x14 )
#define IO_PINSEL6 ( PINSEL_BASE_ADDR + 0x18 )
#define IO_PINSEL7 ( PINSEL_BASE_ADDR + 0x1C )
#define IO_PINSEL8 ( PINSEL_BASE_ADDR + 0x20 )
#define IO_PINSEL9 ( PINSEL_BASE_ADDR + 0x24 )
#define IO_PINSEL10 ( PINSEL_BASE_ADDR + 0x28 )
#define PINSEL_BASE_ADDR 0xE002C000
#define IO_PINSEL0 ( PINSEL_BASE_ADDR + 0x00 )
#define IO_PINSEL1 ( PINSEL_BASE_ADDR + 0x04 )
#define IO_PINSEL2 ( PINSEL_BASE_ADDR + 0x08 )
#define IO_PINSEL3 ( PINSEL_BASE_ADDR + 0x0C )
#define IO_PINSEL4 ( PINSEL_BASE_ADDR + 0x10 )
#define IO_PINSEL5 ( PINSEL_BASE_ADDR + 0x14 )
#define IO_PINSEL6 ( PINSEL_BASE_ADDR + 0x18 )
#define IO_PINSEL7 ( PINSEL_BASE_ADDR + 0x1C )
#define IO_PINSEL8 ( PINSEL_BASE_ADDR + 0x20 )
#define IO_PINSEL9 ( PINSEL_BASE_ADDR + 0x24 )
#define IO_PINSEL10 ( PINSEL_BASE_ADDR + 0x28 )
// Interrupt list
enum
{
// Platform interrupts
INT_GPIO_POSEDGE = ELUA_INT_FIRST_ID,
INT_GPIO_NEGEDGE,
INT_TMR_MATCH
};
#define INT_GPIO_POSEDGE ELUA_INT_FIRST_ID
#define INT_GPIO_NEGEDGE ( ELUA_INT_FIRST_ID + 1 )
#define INT_TMR_MATCH ( ELUA_INT_FIRST_ID + 2 )
#define INT_ELUA_LAST INT_TMR_MATCH
#define PLATFORM_CPU_CONSTANTS\
_C( IO_PINSEL0 ),\

View File

@ -0,0 +1,194 @@
// LPC24xx interrupt support
// Generic headers
#include "platform.h"
#include "platform_conf.h"
#include "elua_int.h"
#include "common.h"
// Platform-specific headers
#include "irq.h"
#include "LPC23xx.h"
#include "target.h"
// ****************************************************************************
// Interrupt handlers
static PREG const posedge_status[] = { ( PREG )&IO0_INT_STAT_R, ( PREG )&IO2_INT_STAT_R };
static PREG const negedge_status[] = { ( PREG )&IO0_INT_STAT_F, ( PREG )&IO2_INT_STAT_F };
static PREG const intclr_regs[] = { ( PREG )&IO0_INT_CLR, ( PREG )&IO2_INT_CLR };
#define EINT3_BIT 3
// EINT3 (INT_GPIO) interrupt handler
static void int_handler_eint3()
{
elua_int_id id = ELUA_INT_INVALID_INTERRUPT;
pio_code resnum = 0;
int pidx, pin;
EXTINT |= 1 << EINT3_BIT; // clear interrupt
// Look for interrupt source
// In can only be GPIO0/GPIO2, as the EXT interrupts are not (yet) used
pidx = ( IO_INT_STAT & 1 ) ? 0 : 1;
if( *posedge_status[ pidx ] )
{
id = INT_GPIO_POSEDGE;
pin = intlog2( *posedge_status[ pidx ] );
}
else
{
id = INT_GPIO_NEGEDGE;
pin = intlog2( *negedge_status[ pidx ] );
}
resnum = PLATFORM_IO_ENCODE( pidx * 2, pin, PLATFORM_IO_ENC_PIN );
*intclr_regs[ pidx ] = 1 << pin;
// Run the interrupt through eLua
cmn_int_handler( id, resnum );
VICVectAddr = 0; // ACK interrupt
}
// ****************************************************************************
// GPIO helper functions
static PREG const posedge_regs[] = { ( PREG )&IO0_INT_EN_R, NULL, ( PREG )&IO2_INT_EN_R };
static PREG const negedge_regs[] = { ( PREG )&IO0_INT_EN_F, NULL, ( PREG )&IO0_INT_EN_F };
static int gpioh_get_int_status( elua_int_id id, elua_int_resnum resnum )
{
int port, pin;
port = PLATFORM_IO_GET_PORT( resnum );
pin = PLATFORM_IO_GET_PIN( resnum );
if( id == INT_GPIO_POSEDGE )
return *posedge_regs[ port ] & ( 1 << pin );
else
return *negedge_regs[ port ] & ( 1 << pin );
return 0;
}
static int gpioh_set_int_status( elua_int_id id, elua_int_resnum resnum, int status )
{
int crt_status = gpioh_get_int_status( id, resnum );
int port, pin;
port = PLATFORM_IO_GET_PORT( resnum );
pin = PLATFORM_IO_GET_PIN( resnum );
if( id == INT_GPIO_POSEDGE )
{
if( status == PLATFORM_CPU_ENABLE )
*posedge_regs[ port ] |= 1 << pin;
else
*posedge_regs[ port ] &= ~( 1 << pin );
}
else
{
if( status == PLATFORM_CPU_ENABLE )
*negedge_regs[ port ] |= 1 << pin;
else
*negedge_regs[ port ] &= ~( 1 << pin );
}
EXTINT |= 1 << EINT3_BIT;
return crt_status;
}
static int gpioh_get_flag( elua_int_id id, elua_int_resnum resnum, int clear )
{
int pidx;
int flag = 0;
// Look for interrupt source
// In can only be GPIO0/GPIO2, as the EXT interrupts are not (yet) used
pidx = ( IO_INT_STAT & 1 ) ? 0 : 1;
if( resnum == ELUA_INT_RESNUM_ANY )
{
if( id == INT_GPIO_POSEDGE && *posedge_status[ pidx ] )
resnum = intlog2( *posedge_status[ pidx ] );
else if( id == INT_GPIO_NEGEDGE && *negedge_status[ pidx ] )
resnum = intlog2( *negedge_status[ pidx ] );
else
return 0;
}
if( id == INT_GPIO_POSEDGE && ( *posedge_status[ pidx ] && ( 1 << resnum ) ) )
flag = 1;
else if( id == INT_GPIO_NEGEDGE && ( *negedge_status[ pidx ] && ( 1 << resnum ) ) )
flag = 1;
if( flag && clear )
*intclr_regs[ pidx ] = 1 << resnum;
return flag;
}
// ****************************************************************************
// Interrupt: INT_GPIO_POSEDGE
static int int_gpio_posedge_set_status( elua_int_resnum resnum, int status )
{
return gpioh_set_int_status( INT_GPIO_POSEDGE, resnum, status );
}
static int int_gpio_posedge_get_status( elua_int_resnum resnum )
{
return gpioh_get_int_status( INT_GPIO_POSEDGE, resnum );
}
static int int_gpio_posedge_get_flag( elua_int_resnum resnum, int clear )
{
return gpioh_get_flag( INT_GPIO_POSEDGE, resnum, clear );
}
// ****************************************************************************
// Interrupt: INT_GPIO_NEGEDGE
static int int_gpio_negedge_set_status( elua_int_resnum resnum, int status )
{
return gpioh_set_int_status( INT_GPIO_NEGEDGE, resnum, status );
}
static int int_gpio_negedge_get_status( elua_int_resnum resnum )
{
return gpioh_get_int_status( INT_GPIO_NEGEDGE, resnum );
}
static int int_gpio_negedge_get_flag( elua_int_resnum resnum, int clear )
{
return gpioh_get_flag( INT_GPIO_NEGEDGE, resnum, clear );
}
// ****************************************************************************
// Interrupt: INT_TMR_MATCH
static int int_tmr_match_set_status( elua_int_resnum resnum, int status )
{
return PLATFORM_INT_NOT_HANDLED;
}
static int int_tmr_match_get_status( elua_int_resnum resnum )
{
return PLATFORM_INT_NOT_HANDLED;
}
static int int_tmr_match_get_flag( elua_int_resnum resnum, int clear )
{
return PLATFORM_INT_NOT_HANDLED;
}
// ****************************************************************************
// Interrupt initialization
void platform_int_init()
{
install_irq( EINT3_INT, int_handler_eint3, HIGHEST_PRIORITY - 1 );
}
// ****************************************************************************
// Interrupt table
// Must have a 1-to-1 correspondence with the interrupt enum in platform_conf.h!
elua_int_descriptor elua_int_table[ INT_ELUA_LAST ] =
{
{ int_gpio_posedge_set_status, int_gpio_posedge_get_status, int_gpio_posedge_get_flag },
{ int_gpio_negedge_set_status, int_gpio_negedge_get_status, int_gpio_negedge_get_flag },
{ int_tmr_match_set_status, int_tmr_match_get_status, int_tmr_match_get_flag }
};