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:
parent
8885b719d7
commit
5978c7b680
@ -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"
|
||||
|
@ -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__
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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();
|
||||
|
||||
// *****************************************************************************
|
||||
|
@ -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
|
||||
|
||||
|
228
src/common.c
228
src/common.c
@ -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
289
src/common_tmr.c
Normal 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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)\
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 ) },
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
|
@ -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 ),\
|
||||
|
194
src/platform/lpc24xx/platform_int.c
Normal file
194
src/platform/lpc24xx/platform_int.c
Normal 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 }
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user