1
0
mirror of https://github.com/elua/elua.git synced 2025-01-25 01:02:54 +08:00

Fairly large number of changes in here to make adc work with lua's provided

buf.c.

The smoothing buffer is still kept separate from the main buffering system,
but as samples come in via interrupt, they are placed into a "standard" elua
buf.  The size of this buf is configured according to whether one is grabbing
a bunch of samples rapidly (burst), or singly in order to accommodate the
expected number of incoming samples.  If smoothing is enabled, incoming
samples are claimed until the smoothing buffer is full, and then remaining
samples are left in the main buffer until they are collected.  This means that
whether one is collecting single samples or samples at burst rate, and
smoothing is enabled, the filter will only be providing samples that have
enough history.

Added a function to manually flush both smoothing and main buffers.
This would be useful if you know your state has changed and you only want
fresh samples that are going to be collected after a flush.

Also, a lot of functionality moved into elua_adc.c and common.c
(boundaries for what belongs where, might be evaluated), reducing the number
of platform.c specific functions dramatically.

Basic functionality seems to be working, but some more testing should be done.

Also, given that there's now a dynamic buffer behind everything, a shift in
the way sampling is handled could be done:
sample and burst functions could be made to be non-blocking, and to never
return anything except for errors.
a separate getsamples function could be used for removing samples collected by
either function from the buffer.
Suggestions are welcome as it would be nice to keep usage paradigms stable
after the 0.6 release.
This commit is contained in:
James Snyder 2009-02-16 00:53:00 +00:00
parent eafb837414
commit fbe307e12a
13 changed files with 444 additions and 313 deletions

View File

@ -155,7 +155,7 @@ cdefs = cdefs + " -DLUA_OPTIMIZE_MEMORY=%d" % ( optram != 0 and 2 or 0 )
local_libs = ''
# Application files
app_files = " src/main.c src/romfs.c src/xmodem.c src/shell.c src/term.c src/common.c src/buf.c src/dlmalloc.c "
app_files = " src/main.c src/romfs.c src/xmodem.c src/shell.c src/term.c src/common.c src/buf.c src/elua_adc.c src/dlmalloc.c "
# Newlib related files
newlib_files = " src/newlib/devman.c src/newlib/stubs.c src/newlib/genstd.c src/newlib/stdtcp.c"

View File

@ -31,7 +31,10 @@ typedef struct
enum
{
BUF_SIZE_NONE = 0,
BUF_SIZE_16 = 4,
BUF_SIZE_2,
BUF_SIZE_4,
BUF_SIZE_8,
BUF_SIZE_16,
BUF_SIZE_32,
BUF_SIZE_64,
BUF_SIZE_128,
@ -46,15 +49,13 @@ enum
};
// Buffer API
int buf_set(unsigned resid, unsigned resnum, u8 logsize, size_t dsize);
int buf_is_enabled( unsigned resid, unsigned resnum );
unsigned buf_get_size( unsigned resid, unsigned resnum );
unsigned buf_get_count( unsigned resid, unsigned resnum );
int buf_write( unsigned resid, unsigned resnum, t_buf_data *data, size_t dsize );
int buf_read( unsigned resid, unsigned resnum, t_buf_data *data, size_t dsize );
int buf_write( unsigned resid, unsigned resnum, t_buf_data *data );
int buf_read( unsigned resid, unsigned resnum, t_buf_data *data );
void buf_flush( unsigned resid, unsigned resnum );
#endif

34
inc/elua_adc.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef __ELUA_ADC_H__
#define __ELUA_ADC_H__
#include "type.h"
typedef struct
{
// Status Bit Flags
volatile u8 op_pending: 1, // Is there a pending conversion?
nonblocking: 1, // Are we in blocking or non-blocking mode? (0 - blocking, 1 - nonblocking)
burst: 1, // Acquiring in burst mode
smooth_ready: 1; // Has smoothing filter warmed up (i.e. smoothlen samples collected)
unsigned id, timer_id;
u8 logsmoothlen;
volatile u8 smoothidx;
volatile u32 smoothsum;
u16 *smoothbuf;
volatile u8 reqsamples;
} elua_adc_state;
void adc_smooth_data( unsigned id );
elua_adc_state *adc_get_ch_state( unsigned id );
u16 adc_get_processed_sample( unsigned id );
void adc_init_state( unsigned id );
int adc_update_smoothing( unsigned id, u8 len );
void adc_flush_smoothing( unsigned id );
u8 adc_samples_requested( unsigned id );
u8 adc_samples_ready( unsigned id );
#endif

View File

@ -178,43 +178,23 @@ u32 platform_cpu_get_frequency();
// *****************************************************************************
// The platform ADC functions
int platform_adc_exists( unsigned id );
u32 platform_adc_op( unsigned id, int op, u32 data );
enum
{
PLATFORM_ADC_GET_MAXVAL,
PLATFORM_ADC_GET_SMOOTHING,
PLATFORM_ADC_SET_SMOOTHING
PLATFORM_ADC_SET_SMOOTHING,
PLATFORM_ADC_SET_NONBLOCKING,
PLATFORM_ADC_FLUSH,
};
u16 platform_adc_sample( unsigned id );
int platform_adc_is_done( unsigned id );
// Functions requiring platform-specific implementation
void platform_adc_sample( unsigned id );
void platform_adc_burst( unsigned id, u8 count, unsigned timer_id, u32 frequency );
void platform_adc_stop( unsigned id );
enum
{
PLATFORM_ADC_BLOCKING,
PLATFORM_ADC_NONBLOCKING
};
// Platform ADC state
struct platform_adc_state
{
volatile u8 op_pending: 1, // Is there a pending conversion?
nonblocking: 1, // Are we in blocking or non-blocking mode? (0 - blocking, 1 - nonblocking)
burst: 1, // Acquiring in burst mode
data_ready: 1, // Is data ready for this channel
smooth_ready: 1; // Has smoothing filter warmed up (i.e. smoothlen samples collected)
unsigned id, timer_id;
u8 burstlen, burstidx;
u8 smoothlen, smoothidx;
unsigned long smoothavg, smoothsum;
u16 sample, *burstbuf, *smoothbuf;
};
void platform_adc_set_mode( unsigned id, int mode );
void platform_adc_burst( unsigned id, u16* buf, unsigned count, unsigned timer_id, u32 frequency );
// ADC Common Functions
int platform_adc_exists( unsigned id );
u32 platform_adc_op( unsigned id, int op, u32 data );
// *****************************************************************************
// Ethernet specific functions
@ -234,5 +214,6 @@ void* platform_get_last_free_ram( unsigned id );
// Misc support
unsigned int intlog2( unsigned int v );
u32 rndpow2( u32 v);
#endif

View File

@ -5,8 +5,8 @@ disp.clear()
adc.setsmoothing(1,4)
adc.setsmoothing(1,16)
adc.setsmoothing(2,64)
adc.setsmoothing(3,128)
adc.setsmoothing(2,32)
adc.setsmoothing(3,64)
adcvals = {}
ctr = 0
@ -28,9 +28,9 @@ while ( true ) do
disp.stringdraw( outstring, 10, 10, 11 )
outstring = string.format("ADC1 (16): %04d",adcvals[1])
disp.stringdraw( outstring, 10, 20, 11 )
outstring = string.format("ADC2 (64): %04d",adcvals[2])
outstring = string.format("ADC2 (32): %04d",adcvals[2])
disp.stringdraw( outstring, 10, 30, 11 )
outstring = string.format("ADC3 (128): %04d",adcvals[3])
outstring = string.format("ADC3 (64): %04d",adcvals[3])
disp.stringdraw( outstring, 10, 40, 11 )
outstring = string.format("Tcyc: %06d (us)",dtime)
disp.stringdraw( outstring, 10, 50, 11 )

View File

@ -6,6 +6,10 @@
#define BUF_ENABLE
#endif
#if defined( BUF_ENABLE_ADC )
#define BUF_ENABLE
#endif
#ifdef BUF_ENABLE
#include "buf.h"
@ -33,7 +37,7 @@
static const buf_desc* buf_desc_array[ BUF_ID_TOTAL ] =
{
buf_desc_uart,
buf_desc_adc
buf_desc_adc,
};
// Helper macros
@ -58,13 +62,14 @@ static const buf_desc* buf_desc_array[ BUF_ID_TOTAL ] =
int buf_set( unsigned resid, unsigned resnum, u8 logsize, size_t dsize )
{
BUF_GETPTR( resid, resnum );
u8 prevlogsize = pbuf->logsize;
// Make sure dsize is a power of 2
if ( ( dsize = 0 ) || ( dsize & ( dsize - 1 ) ) )
return PLATFORM_ERR;
pbuf->logsize = logsize;
if ( dsize & ( dsize - 1 ) )
return PLATFORM_ERR;
pbuf->logdsize = intlog2( dsize );
pbuf->logsize = logsize + ( pbuf->logdsize );
if( ( pbuf->buf = ( t_buf_data* )realloc( pbuf->buf, BUF_BYTESIZE( pbuf ) ) ) == NULL )
{
@ -73,9 +78,21 @@ int buf_set( unsigned resid, unsigned resnum, u8 logsize, size_t dsize )
if( logsize != BUF_SIZE_NONE )
return PLATFORM_ERR;
}
if( prevlogsize > pbuf->logsize )
pbuf->rptr = pbuf->wptr = pbuf->count = 0;
return PLATFORM_OK;
}
// Marks buffer as empty
void buf_flush( unsigned resid, unsigned resnum )
{
BUF_GETPTR( resid, resnum );
pbuf->rptr = pbuf->wptr = pbuf->count = 0;
}
// Write to buffer
// resid - resource ID (BUF_ID_UART ...)
// resnum - resource number (0, 1, 2...)
@ -83,15 +100,11 @@ int buf_set( unsigned resid, unsigned resnum, u8 logsize, size_t dsize )
// dsize - length of data to get
// Returns PLATFORM_OK on success, PLATFORM_ERR on failure
// [TODO] maybe add a buffer overflow flag
int buf_write( unsigned resid, unsigned resnum, t_buf_data *data, size_t dsize )
int buf_write( unsigned resid, unsigned resnum, t_buf_data *data )
{
BUF_GETPTR( resid, resnum );
// Make sure we only add more of same type
if ( dsize != BUF_REALDSIZE( pbuf ) )
return PLATFORM_ERR;
memcpy( &pbuf->buf[ pbuf->wptr ], data, dsize );
memcpy( &pbuf->buf[ pbuf->wptr ], data, BUF_REALDSIZE( pbuf ) );
BUF_MOD_INCR( pbuf, wptr );
@ -136,19 +149,15 @@ unsigned buf_get_count( unsigned resid, unsigned resnum )
// dsize - length of data to get
// Returns PLATFORM_OK on success, PLATFORM_ERR on failure,
// PLATFORM_UNDERFLOW on buffer empty
int buf_read( unsigned resid, unsigned resnum, t_buf_data *data, size_t dsize )
int buf_read( unsigned resid, unsigned resnum, t_buf_data *data )
{
BUF_GETPTR( resid, resnum );
// Make sure buffer contains right type
if ( dsize != BUF_REALDSIZE( pbuf ) )
return PLATFORM_ERR;
if( READ16( pbuf->count ) == 0 )
return PLATFORM_UNDERFLOW;
memcpy( data, &pbuf->buf[ pbuf->rptr ], dsize );
memcpy( data, &pbuf->buf[ pbuf->rptr ], BUF_REALDSIZE( pbuf ) );
platform_cpu_disable_interrupts();
pbuf->count --;
BUF_MOD_INCR( pbuf, rptr );

View File

@ -7,6 +7,9 @@
#include "common.h"
#include "buf.h"
#include <stdio.h>
#include <stdlib.h>
#include "math.h"
#include "elua_adc.h"
// *****************************************************************************
// std functions and platform initialization
@ -76,12 +79,12 @@ static int cmn_recv_helper( unsigned id, s32 timeout )
{
if( timeout == 0 )
{
if ( ( buf_read( BUF_ID_UART, id, &data, sizeof( t_buf_data ) ) ) == PLATFORM_UNDERFLOW )
if ( ( buf_read( BUF_ID_UART, id, &data ) ) == PLATFORM_UNDERFLOW )
return -1;
}
else
{
while( ( buf_read( BUF_ID_UART, id, &data, sizeof( t_buf_data ) ) ) == PLATFORM_UNDERFLOW );
while( ( buf_read( BUF_ID_UART, id, &data ) ) == PLATFORM_UNDERFLOW );
}
return ( int )data;
}
@ -257,11 +260,48 @@ u32 platform_cpu_get_frequency()
// ****************************************************************************
// ADC functions
int platform_adc_exists( unsigned id )
{
return id < NUM_ADC;
}
#ifdef BUILD_ADC
u32 platform_adc_op( unsigned id, int op, u32 data )
{
elua_adc_state *s = adc_get_ch_state( id );
u32 res = 0;
switch( op )
{
case PLATFORM_ADC_GET_MAXVAL:
res = pow( 2, ADC_BIT_RESOLUTION ) - 1;
break;
case PLATFORM_ADC_GET_SMOOTHING:
res = (u16) 1 << s->logsmoothlen;
break;
case PLATFORM_ADC_SET_SMOOTHING:
adc_update_smoothing( id, ( u8 )data );
break;
case PLATFORM_ADC_SET_NONBLOCKING:
s->nonblocking = data;
break;
case PLATFORM_ADC_FLUSH:
adc_flush_smoothing( id );
buf_flush( BUF_ID_ADC, id );
break;
}
return res;
}
#endif
// ****************************************************************************
// Allocator support
@ -293,4 +333,17 @@ unsigned int intlog2( unsigned int v )
r++;
}
return r;
}
u32 rndpow2( u32 v )
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}

149
src/elua_adc.c Normal file
View File

@ -0,0 +1,149 @@
#include "platform_conf.h"
#ifdef BUILD_ADC
#include "buf.h"
#include "type.h"
#include "elua_adc.h"
#include "platform.h"
#include <stdlib.h>
#define SMOOTH_REALSIZE( s ) ( ( u16 )1 << ( s->logsmoothlen ) )
// Primary set of pointers to channel states
elua_adc_state adc_state[ NUM_ADC ];
elua_adc_state *adc_get_ch_state( unsigned id )
{
return &adc_state[ id ];
}
// Initialize Configuration and Buffers
void adc_init_state( unsigned id )
{
elua_adc_state *s = adc_get_ch_state( id );
// Initialize Configuration
s->op_pending = 0;
s->nonblocking = 0;
s->burst = 0;
s->smooth_ready = 0;
s->reqsamples = 0;
s->id = id;
s->timer_id = 0;
s->logsmoothlen = 0;
s->smoothidx = 0;
// Data Configuration
s->smoothsum = 0;
// Buffer initialization
buf_set( BUF_ID_ADC, id, ADC_BUF_SIZE, sizeof( u16 ) );
}
int adc_update_smoothing( unsigned id, u8 len )
{
elua_adc_state *s = adc_get_ch_state( id );
if( len != s->logsmoothlen )
{
s->logsmoothlen = intlog2( len );
if ( len != 0 )
{
// Allocate and zero new smoothing buffer
if( ( s->smoothbuf = ( u16* )realloc( s->smoothbuf, ( SMOOTH_REALSIZE( s ) ) * sizeof( u16 ) ) ) == NULL )
{
return 1;
}
}
else
{
if ( s->smoothbuf != NULL )
free( s->smoothbuf );
}
// Zero out and mark as empty
adc_flush_smoothing( id );
}
return 0;
}
void adc_smooth_data( unsigned id )
{
elua_adc_state *s = adc_get_ch_state( id );
u16 sample;
if( s->smoothidx == SMOOTH_REALSIZE( s ) )
{
s->smoothidx = 0;
s->smooth_ready = 1;
}
// Subtract Oldest Value from Sum
s->smoothsum -= s->smoothbuf[ s->smoothidx ];
// Replace Oldest Value in Buffer
buf_read( BUF_ID_ADC, id, ( t_buf_data* )&sample );
s->smoothbuf[ s->smoothidx ] = sample;
// Add New Sample to Sum
s->smoothsum += s->smoothbuf[ s->smoothidx ];
s->smoothidx++;
}
u16 adc_get_processed_sample( unsigned id )
{
elua_adc_state *s = adc_get_ch_state( id );
u16 sample;
// If smoothing is enabled AND we already warmed up, or have enough to warm up
// smooth data and output latest sample
if ( ( s->logsmoothlen > 0) && ( s->smooth_ready ) )
{
adc_smooth_data( id );
return (u16) s->smoothsum >> s->logsmoothlen;
}
else if ( s->logsmoothlen == 0 && buf_get_count( BUF_ID_ADC, id ) > 0 )
{
buf_read( BUF_ID_ADC, id, ( t_buf_data* )&sample );
if ( s->reqsamples > 0)
s->reqsamples -- ;
return sample;
}
else
return 0;
}
void adc_flush_smoothing( unsigned id )
{
elua_adc_state *s = adc_get_ch_state( id );
u8 i;
s->smoothidx = 0;
s->smoothsum = 0;
s->smooth_ready = 0;
if ( s->logsmoothlen > 0 )
{
for( i = 0; i < ( SMOOTH_REALSIZE( s ) ); i ++ )
s->smoothbuf[ i ] = 0;
}
}
u8 adc_samples_requested( unsigned id )
{
elua_adc_state *s = adc_get_ch_state( id );
return s->reqsamples;
}
u8 adc_samples_ready( unsigned id )
{
return ( u8 ) buf_get_count( BUF_ID_ADC, id );
}
#endif

View File

@ -7,19 +7,24 @@
#include "auxmods.h"
#include "lrotable.h"
#include "platform_conf.h"
#include <stdlib.h> // needed for malloc
#include "elua_adc.h"
#ifdef BUILD_ADC
// Lua: sample( id )
static int adc_sample( lua_State* L )
{
unsigned id;
u16 res;
id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( adc, id );
res = platform_adc_sample( id );
lua_pushinteger( L, res );
return 1;
platform_adc_sample( id );
if ( adc_samples_ready( id ) >= 1 )
{
lua_pushinteger( L, adc_get_processed_sample( id ) );
return 1;
}
return 0;
}
// Lua: maxval( id )
@ -36,15 +41,20 @@ static int adc_maxval( lua_State* L )
}
// Lua: isdone( id )
static int adc_is_done( lua_State* L )
static int adc_data_ready( lua_State* L )
{
unsigned id;
int res;
u8 asamp, rsamp;
id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( adc, id );
res = platform_adc_is_done( id );
lua_pushinteger( L, res );
asamp = adc_samples_ready( id );
rsamp = adc_samples_requested( id );
if ( rsamp > 0 && asamp >= rsamp )
lua_pushinteger( L, 1 );
else
lua_pushinteger( L, 0 );
return 1;
}
@ -56,7 +66,7 @@ static int adc_set_mode( lua_State* L )
id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( adc, id );
mode = luaL_checkinteger( L, 2 );
platform_adc_set_mode( id, mode );
platform_adc_op( id, PLATFORM_ADC_SET_NONBLOCKING, mode );
return 0;
}
@ -64,15 +74,21 @@ static int adc_set_mode( lua_State* L )
static int adc_set_smoothing( lua_State* L )
{
unsigned id, length, res;
id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( adc, id );
length = luaL_checkinteger( L, 2 );
res = platform_adc_op( id, PLATFORM_ADC_SET_SMOOTHING, length );
if ( res )
return luaL_error( L, "Buffer allocation failed." );
if ( !( length & ( length - 1 ) ) )
{
res = platform_adc_op( id, PLATFORM_ADC_SET_SMOOTHING, length );
if ( res )
return luaL_error( L, "Buffer allocation failed." );
else
return 0;
}
else
return 0;
return luaL_error( L, "Smoothing length must be power of 2" );
}
// Lua: getsmoothing( id )
@ -88,12 +104,25 @@ static int adc_get_smoothing( lua_State* L )
return 1;
}
// Lua: flush( id )
static int adc_flush( lua_State* L )
{
unsigned id;
u32 res;
id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( adc, id );
res = platform_adc_op( id, PLATFORM_ADC_FLUSH, 0 );
lua_pushinteger( L, res );
return 1;
}
// Lua: burst( id, count, timer_id, frequency )
static int adc_burst( lua_State* L )
{
unsigned i, id, count, timer_id;
unsigned id, timer_id, i;
u8 count;
u32 frequency;
u16 *buf;
id = luaL_checkinteger( L, 1 );
MOD_CHECK_ID( adc, id );
@ -101,28 +130,45 @@ static int adc_burst( lua_State* L )
timer_id = luaL_checkinteger( L, 3 );
MOD_CHECK_ID( timer, timer_id );
frequency = luaL_checkinteger( L, 4 );
// Allocate buffer to contain returned samples
if( ( buf = malloc( count * sizeof( u16 ) ) ) == NULL )
return luaL_error( L, "Buffer allocation failed." );
for( i = 0; i < count; i ++ )
buf[ i ] = 0;
platform_adc_burst( id, buf, count, timer_id, frequency );
// Push data back to Lua
lua_createtable( L, count, 0 );
for( i = 0; i < count; i ++ )
if ( count == 0 )
return 0;
if ( count & ( count - 1 ) )
return luaL_error( L, "count must be power of 2" );
// If we already have enough data, return it and start next burst
if( adc_samples_ready( id ) >= count )
{
lua_pushinteger( L, buf[ i ] );
lua_rawseti( L, -2, i+1 );
// Push data back to Lua
lua_createtable( L, count, 0 );
for( i = 0; i < count; i ++ )
{
lua_pushinteger( L, adc_get_processed_sample( id ) );
lua_rawseti( L, -2, i+1 );
}
platform_adc_burst( id, count, timer_id, frequency );
return 1;
}
// Free buffer
free( buf );
return 1;
else // If no data is available, kick off burst, return data if we have some afterwards
{
platform_adc_burst( id, count, timer_id, frequency );
if( adc_samples_ready( id ) >= count )
{
// Push data back to Lua
lua_createtable( L, count, 0 );
for( i = 0; i < count; i ++ )
{
lua_pushinteger( L, adc_get_processed_sample( id ) );
lua_rawseti( L, -2, i+1 );
}
return 1;
}
}
return 0;
}
// Module function map
@ -132,11 +178,12 @@ const LUA_REG_TYPE adc_map[] =
{
{ LSTRKEY( "sample" ), LFUNCVAL( adc_sample ) },
{ LSTRKEY( "maxval" ), LFUNCVAL( adc_maxval ) },
{ LSTRKEY( "isdone" ), LFUNCVAL( adc_is_done ) },
{ LSTRKEY( "dataready" ), LFUNCVAL( adc_data_ready ) },
{ LSTRKEY( "setmode" ), LFUNCVAL( adc_set_mode ) },
{ LSTRKEY( "setsmoothing" ), LFUNCVAL( adc_set_smoothing ) },
{ LSTRKEY( "getsmoothing" ), LFUNCVAL( adc_get_smoothing ) },
{ LSTRKEY( "burst" ), LFUNCVAL( adc_burst ) },
{ LSTRKEY( "flush" ), LFUNCVAL( adc_flush ) },
{ LNILKEY, LNILVAL }
};
@ -144,3 +191,5 @@ LUALIB_API int luaopen_adc( lua_State *L )
{
LREGISTER( L, AUXLIB_ADC, adc_map );
}
#endif

View File

@ -50,7 +50,7 @@ static void uart_rx_handler()
{
c = pbase->US_CSR;
c = pbase->US_RHR;
buf_write( BUF_ID_UART, CON_UART_ID, ( t_buf_data* )&c, sizeof ( char ) );
buf_write( BUF_ID_UART, CON_UART_ID, ( t_buf_data* )&c );
asm( "pop {r0}":: );
asm( "bx r0":: );
}

View File

@ -57,7 +57,7 @@ __attribute__((__interrupt__)) static void uart_rx_handler()
usart_read_char( pusart, &c );
temp = ( t_buf_data )c;
buf_write( BUF_ID_UART, CON_UART_ID, &temp, sizeof ( char ) );
buf_write( BUF_ID_UART, CON_UART_ID, &temp );
}
#endif

View File

@ -9,9 +9,9 @@
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "uip_arp.h"
#include "elua_uip.h"
#include "elua_adc.h"
#include "uip-conf.h"
#include "platform_conf.h"
#include "common.h"
@ -254,7 +254,7 @@ void UARTIntHandler()
while( UARTCharsAvail( uart_base[ CON_UART_ID ] ) )
{
c = UARTCharGetNonBlocking( uart_base[ CON_UART_ID ] );
buf_write( BUF_ID_UART, CON_UART_ID, ( t_buf_data* )&c, sizeof ( t_buf_data ) );
buf_write( BUF_ID_UART, CON_UART_ID, ( t_buf_data* )&c );
}
}
#endif
@ -509,125 +509,22 @@ void platform_cpu_disable_interrupts()
// *****************************************************************************
// ADC specific functions and variables
// NOTES: HWREGBITW should be replaced with some similar function that will work for other platforms
const static u32 adc_ctls[] = { ADC_CTL_CH0, ADC_CTL_CH1, ADC_CTL_CH2, ADC_CTL_CH3 };
const static u32 adc_ints[] = { INT_ADC0, INT_ADC1, INT_ADC2, INT_ADC3 };
struct platform_adc_state adc_state[ NUM_ADC ];
void platform_adc_stop_burst( struct platform_adc_state *s )
void platform_adc_stop( unsigned id )
{
elua_adc_state *s = adc_get_ch_state( id );
ADCSequenceDisable( ADC_BASE, s->id );
TimerControlTrigger( timer_base[s->timer_id], TIMER_A, false );
}
// Initialize Configuration and Buffers
void adc_init_state( struct platform_adc_state *s, unsigned id )
{
// Initialize Configuration
s->op_pending = 0;
s->nonblocking = 0;
s->burst = 0;
s->data_ready = 0;
s->smooth_ready = 0;
s->id = id;
s->timer_id = 0;
s->burstlen = 1;
s->burstidx = 0;
s->smoothlen = 1;
s->smoothidx = 0;
s->sample = 0;
// Data Configuration
s->smoothavg = 0;
s->smoothsum = 0;
// Buffer initialization
s->smoothbuf = malloc( s->smoothlen * sizeof( u16 ) );
}
int adc_update_smoothing(struct platform_adc_state *s, u8 len)
{
u8 i;
if( len != s->smoothlen )
if ( s->burst )
{
s->smoothlen = len;
// Free old buffer space
if ( s->smoothbuf != NULL )
free( s->smoothbuf );
// Reset sum, avg, index location
s->smoothidx = 0;
s->smoothavg = 0;
s->smoothsum = 0;
s->smooth_ready = 0;
// Allocate and zero new smoothing buffer
if( ( s->smoothbuf = malloc( s->smoothlen * sizeof( u16 ) ) ) == NULL )
{
return 1;
}
for( i = 0; i < s->smoothlen; i ++ )
s->smoothbuf[ i ] = 0;
}
return 0;
}
void adc_process_data( struct platform_adc_state *s, u16 samplevalue )
{
// Take just acquired sample and do smoothing / burst buffering
if ( s->smoothlen > 1 )
{
if( s->smoothidx == s->smoothlen )
{
s->smoothidx = 0;
s->smooth_ready = 1;
}
// Subtract Oldest Value from Sum
s->smoothsum -= s->smoothbuf[ s->smoothidx ];
// Replace Oldest Value in Buffer
s->smoothbuf[ s->smoothidx ] = ( u16 ) samplevalue;
// Add New Sample to Sum
s->smoothsum += s->smoothbuf[ s->smoothidx ];
s->smoothidx++;
// Calculate Average
if ( ( s->smoothlen != 0 ) && !( s->smoothlen & ( s->smoothlen - 1 ) ) )
s->smoothavg = s->smoothsum >> intlog2( s->smoothlen );
else
s->smoothavg = s->smoothsum / s->smoothlen;
s->sample = ( u16 ) s->smoothavg;
}
else
s->sample = samplevalue;
// Increment buffer position, unless we're waiting on the smoothing filter to warm up
if ( ( ( s->smooth_ready == 1 && s->smoothlen > 1 ) || s->smoothlen == 1 ) && ( s->burst == 1 ) )
s->burstbuf[ s->burstidx++ ] = s->sample;
// If we have enough samples, clean up / finish
if ( s->burstidx == s->burstlen || s->burst == 0 )
{
s->data_ready = 1;
s->op_pending = 0;
if ( s->burst == 1 )
{
// Disable Burst Mode
platform_adc_stop_burst( s );
s->burst = 0;
}
TimerControlTrigger( timer_base[s->timer_id], TIMER_A, false );
}
}
@ -637,19 +534,35 @@ void ADCIntHandler( void )
unsigned long rawSample;
unsigned id;
platform_cpu_disable_interrupts();
// Check each sequence for a pending sample
for( id = 0; id < NUM_ADC; id ++ )
{
if( ADCIntStatus(ADC_BASE, id, false) )
{
{
elua_adc_state *s = adc_get_ch_state( id );
// Clear Interrupt & Get Sample
ADCIntClear(ADC_BASE, id);
ADCSequenceDataGet(ADC_BASE, id, &rawSample);
// Process Received Sample
adc_process_data(&adc_state[ id ], (u16) rawSample);
buf_write( BUF_ID_ADC, id, ( t_buf_data* )&rawSample);
// Fill in smoothing buffer until warmed up
if ( s->logsmoothlen > 0 && s->smooth_ready == 0)
adc_smooth_data( id );
// If we have the number of requested samples, stop sampling
if ( buf_get_count( BUF_ID_ADC, id ) >= s->reqsamples )
{
platform_adc_stop( id );
}
else if ( s->burst == 0 )
ADCProcessorTrigger( ADC_BASE, id );
}
}
platform_cpu_enable_interrupts();
}
static void adcs_init()
@ -661,7 +574,7 @@ static void adcs_init()
for( id = 0; id < NUM_ADC; id ++ )
{
// Init ADC State Struct
adc_init_state( &adc_state[ id ], id );
adc_init_state( id );
// Make sure sequencer is disabled before making changes
ADCSequenceDisable( ADC_BASE, id );
@ -680,124 +593,63 @@ static void adcs_init()
}
}
u32 platform_adc_op( unsigned id, int op, u32 data ) // Move to common?
{
// Do we really need 32-bit in and out?
u32 res = 0;
switch( op )
{
case PLATFORM_ADC_GET_MAXVAL:
res = pow( 2,ADC_BIT_RESOLUTION ) - 1;
break;
case PLATFORM_ADC_GET_SMOOTHING:
res = adc_state[ id ].smoothlen;
break;
case PLATFORM_ADC_SET_SMOOTHING:
// If buffer length changes, alloc new buffer, and reset position
adc_update_smoothing( &adc_state[ id ], ( u8 )data );
break;
}
return res;
}
// Get a single sample from the specified ADC channel
u16 platform_adc_sample( unsigned id )
void platform_adc_sample( unsigned id )
{
// If no sample is pending or if were configured for burst, set to single-shot
if ( adc_state[ id ].op_pending == 0 || adc_state[ id ].burst == 1)
{
// Make sure sequencer is disabled before making changes
ADCSequenceDisable( ADC_BASE, id );
elua_adc_state *s = adc_get_ch_state( id );
// Conversion initiated on processor trigger
ADCSequenceConfigure( ADC_BASE, id, ADC_TRIGGER_PROCESSOR, id ) ;
s->op_pending = 1;
s->burst = 0;
s->reqsamples = 1;
// Make sure sequencer is disabled before making changes
ADCSequenceDisable( ADC_BASE, id );
// Restart Sequencer
ADCSequenceEnable( ADC_BASE, id);
adc_state[ id ].burst = 0;
}
// Conversion will run back-to-back until required samples are acquired
ADCSequenceConfigure( ADC_BASE, id, ADC_TRIGGER_PROCESSOR, id ) ;
// Fire Trigger to start sample conversion
adc_state[ id ].op_pending = 1;
// Start Sequencer
ADCSequenceEnable( ADC_BASE, id );
ADCProcessorTrigger( ADC_BASE, id );
// If in blocking mode and sample is pending, wait for ready flag
if ( adc_state[ id ].nonblocking == 0 && adc_state[ id ].op_pending == 1 )
if ( s->nonblocking == 0 && s->op_pending == 1 )
{
while ( adc_state[ id ].data_ready == 0 ) { ; }
}
// Return last sample and mark used
adc_state[ id ].data_ready = 0;
return adc_state[ id ].sample;
}
// returns 1 if the conversion on the specified channel ended, 0 otherwise
int platform_adc_is_done( unsigned id )
{
return adc_state[ id ].data_ready;
}
// sets the mode on the specified ADC channel to either blocking (0) or non-blocking (1)
void platform_adc_set_mode( unsigned id, int mode )
{
switch( mode )
{
case PLATFORM_ADC_BLOCKING:
adc_state[ id ].nonblocking = 0;
break;
case PLATFORM_ADC_NONBLOCKING:
adc_state[ id ].nonblocking = 1;
break;
while ( s->op_pending == 1 ) { ; }
}
}
void platform_adc_burst( unsigned id, u16* buf, unsigned count, unsigned timer_id, u32 frequency )
void platform_adc_burst( unsigned id, u8 count, unsigned timer_id, u32 frequency )
{
if( adc_state[ id ].burst == 0 )
{
// Make sure sequencer is disabled before making changes
ADCSequenceDisable( ADC_BASE, id );
elua_adc_state *s = adc_get_ch_state( id );
// Set sequence id to be triggered repeatedly, with priority id
ADCSequenceConfigure( ADC_BASE, id, ADC_TRIGGER_TIMER, id );
s->burst = 1;
s->timer_id = timer_id;
s->op_pending = 1;
s->reqsamples = count;
// Restart Sequencer
ADCSequenceEnable( ADC_BASE, id );
adc_state[ id ].burst = 1;
}
// If we have a new buffer, replace the old one
// - same buffer a way to get previously requested non-blocking data?
//if (adc_state[ id ].burstbuf != buf)
//{
adc_state[ id ].burstbuf = buf;
adc_state[ id ].burstlen = count;
adc_state[ id ].burstidx = 0;
//}
// Make sure sequencer is disabled before making changes
ADCSequenceDisable( ADC_BASE, id );
adc_state[ id ].timer_id = timer_id;
adc_state[ id ].op_pending = 1;
// Set sequence id to be triggered repeatedly, with priority id
ADCSequenceConfigure( ADC_BASE, id, ADC_TRIGGER_TIMER, id );
// Restart Sequencer
ADCSequenceEnable( ADC_BASE, id );
buf_set( BUF_ID_ADC, id, intlog2( count ) , sizeof( u16 ) );
// Setup timer and go
TimerConfigure(timer_base[timer_id], TIMER_CFG_32_BIT_PER);
TimerLoadSet(timer_base[timer_id], TIMER_A, SysCtlClockGet() / frequency);
TimerControlTrigger(timer_base[timer_id], TIMER_A, true);
TimerEnable(timer_base[timer_id], TIMER_A);
TimerEnable(timer_base[timer_id], TIMER_A);
// If in blocking mode and sampling task is pending, wait until buffer fills
//if ( adc_state[ id ].nonblocking == 0 && adc_state[ id ].op_pending == 1 )
//{
while ( adc_state[ id ].data_ready == 0 ) { ; }
// Mark data as used
adc_state[ id ].data_ready = 0;
//}
if ( s->nonblocking == 0 && s->op_pending == 1 )
{
while ( s->op_pending == 1 ) { ; }
}
}
// ****************************************************************************

View File

@ -20,6 +20,7 @@
#define BUILD_DHCPC
#define BUILD_DNS
#define BUILD_CON_GENERIC
#define BUILD_ADC
//#define BUILD_CON_TCP
// *****************************************************************************
@ -104,6 +105,8 @@ LUALIB_API int ( luaopen_disp )( lua_State* L );
// ADC Bit Depth for Built-in ADCs
#define ADC_BIT_RESOLUTION 10
#define BUF_ENABLE_ADC
#define ADC_BUF_SIZE BUF_SIZE_2
// CPU frequency (needed by the CPU module, 0 if not used)
#define CPU_FREQUENCY SysCtlClockGet()