From b3f6110150f9f671d3ff479af27487acf2ae69e8 Mon Sep 17 00:00:00 2001 From: James Snyder Date: Mon, 16 Feb 2009 23:01:32 +0000 Subject: [PATCH] ADC bugfixes, and change to sample and burst being non-blocking. Samples are acquired with getsamples. --- inc/buf.h | 10 +++- inc/elua_adc.h | 5 +- romfs/adcscope.lua | 64 ++++++++++++--------- src/buf.c | 14 ++--- src/elua_adc.c | 19 +++++-- src/modules/adc.c | 93 ++++++++++++++++--------------- src/platform/at91sam7x/platform.c | 2 +- src/platform/avr32/platform.c | 2 +- src/platform/lm3s/platform.c | 70 +++++++++++------------ 9 files changed, 152 insertions(+), 127 deletions(-) diff --git a/inc/buf.h b/inc/buf.h index 545f71c1..d3a3f9a1 100644 --- a/inc/buf.h +++ b/inc/buf.h @@ -48,9 +48,17 @@ enum BUF_SIZE_32768 }; +enum +{ + BUF_DSIZE_U8 = 0, + BUF_DSIZE_U16, + BUF_DSIZE_U32 +}; + + // Buffer API -int buf_set(unsigned resid, unsigned resnum, u8 logsize, size_t dsize); +int buf_set(unsigned resid, unsigned resnum, u8 logsize, u8 logdsize); int buf_is_enabled( unsigned resid, unsigned resnum ); unsigned buf_get_size( unsigned resid, unsigned resnum ); unsigned buf_get_count( unsigned resid, unsigned resnum ); diff --git a/inc/elua_adc.h b/inc/elua_adc.h index ae4a09dd..034a498e 100644 --- a/inc/elua_adc.h +++ b/inc/elua_adc.h @@ -28,7 +28,8 @@ u16 adc_get_processed_sample( unsigned id ); void adc_init_state( unsigned id ); int adc_update_smoothing( unsigned id, u8 loglen ); void adc_flush_smoothing( unsigned id ); -u8 adc_samples_requested( unsigned id ); -u8 adc_samples_ready( unsigned id ); +u16 adc_samples_requested( unsigned id ); +u16 adc_samples_available( unsigned id ); +void adc_wait_pending( unsigned id ); #endif \ No newline at end of file diff --git a/romfs/adcscope.lua b/romfs/adcscope.lua index d618db3c..eacffb9b 100644 --- a/romfs/adcscope.lua +++ b/romfs/adcscope.lua @@ -1,40 +1,52 @@ -require("LM3S") -disp.init(1000000) -disp.clear() +adcchannels = {0, 1, 2, 3} +adcsmoothing = {4, 16, 32, 64} -adc.setsmoothing(0,4) -adc.setsmoothing(1,16) -adc.setsmoothing(2,32) -adc.setsmoothing(3,64) +for i, v in ipairs(adcchannels) do + adc.setmode(v,0) + adc.setsmoothing(v,adcsmoothing[i]) +end -disp.stringdraw( "ADC Scope", 10, 10, 11 ) +term.clrscr() -adcvals = {} -ctr = 0 +term.gotoxy(1,1) +term.putstr("ADC Status:") +term.gotoxy(1,3) +term.putstr(" CH SLEN RES") +term.gotoxy(1,#adcchannels+6) +term.putstr("Press ESC to exit.") -while ( true ) do +local adcvals = {} +local ctr = 0 + +while true do + local key, stime, etime, dtime + local sample = adc.sample + local getsamples = adc.getsamples ctr = ctr + 1 stime = tmr.start(0) - adcvals[0] = adc.sample(0) - adcvals[1] = adc.sample(1) - adcvals[2] = adc.sample(2) - adcvals[3] = adc.sample(3) + for i, v in ipairs(adcchannels) do + sample(v) + adcvals[i] = getsamples(v,1) + end etime = tmr.read(0) dtime = tmr.diff(0,etime,stime) if ( ctr == 100 ) then ctr = 0 - outstring = string.format("ADC0 (4): %04d",adcvals[0]) - disp.stringdraw( outstring, 10, 10, 11 ) - outstring = string.format("ADC1 (16): %04d",adcvals[1]) - disp.stringdraw( outstring, 10, 20, 11 ) - outstring = string.format("ADC2 (32): %04d",adcvals[2]) - disp.stringdraw( outstring, 10, 30, 11 ) - 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 ) + term.gotoxy(1,4) + for i, v in ipairs(adcchannels) do + term.putstr(string.format("ADC%d (%03d): %04d\n",v,adcsmoothing[i],adcvals[i])) + term.gotoxy(1,i+4) + end + term.putstr(string.format("Tcyc: %06d (us)\n",dtime)) + + key = term.getch( term.NOWAIT ) + if key == term.KC_ESC then break end end -end \ No newline at end of file + if key == term.KC_ESC then break end +end + +term.clrscr() +term.gotoxy( 1 , 1 ) \ No newline at end of file diff --git a/src/buf.c b/src/buf.c index 5ab142ef..4eab0e5e 100644 --- a/src/buf.c +++ b/src/buf.c @@ -52,20 +52,15 @@ static const buf_desc* buf_desc_array[ BUF_ID_TOTAL ] = // resid - resource ID (BUF_ID_UART ...) // resnum - resource number (0, 1, 2...) // bufsize - new size of the buffer (one of the BUF_SIZE_xxx constants from -// dsize - number of bytes held by each element (must be a power of 2) // buf.h, or BUF_SIZE_NONE to disable buffering +// logdsize - log2(bytes) size of elements (from BUF_DSIZE_xxx constants) // Returns 1 on success, 0 on failure -int buf_set( unsigned resid, unsigned resnum, u8 logsize, size_t dsize ) +int buf_set( unsigned resid, unsigned resnum, u8 logsize, u8 logdsize ) { BUF_GETPTR( resid, resnum ); - u8 prevlogsize = pbuf->logsize; - // Make sure dsize is a power of 2 - if ( dsize & ( dsize - 1 ) ) - return PLATFORM_ERR; - - pbuf->logdsize = intlog2( dsize ); - pbuf->logsize = logsize + ( pbuf->logdsize ); + pbuf->logdsize = logdsize; + pbuf->logsize = logsize + logdsize; if( ( pbuf->buf = ( t_buf_data* )realloc( pbuf->buf, BUF_BYTESIZE( pbuf ) ) ) == NULL ) { @@ -90,7 +85,6 @@ void buf_flush( unsigned resid, unsigned resnum ) // resid - resource ID (BUF_ID_UART ...) // resnum - resource number (0, 1, 2...) // data - pointer for where data will come from -// 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 ) diff --git a/src/elua_adc.c b/src/elua_adc.c index 61c9a280..da7cdd90 100644 --- a/src/elua_adc.c +++ b/src/elua_adc.c @@ -38,7 +38,7 @@ void adc_init_state( unsigned id ) s->smoothsum = 0; // Buffer initialization - buf_set( BUF_ID_ADC, id, ADC_BUF_SIZE, sizeof( u16 ) ); + buf_set( BUF_ID_ADC, id, ADC_BUF_SIZE, BUF_DSIZE_U16 ); } int adc_update_smoothing( unsigned id, u8 loglen ) @@ -135,15 +135,26 @@ void adc_flush_smoothing( unsigned id ) } } -u8 adc_samples_requested( unsigned id ) +u16 adc_samples_requested( unsigned id ) { elua_adc_state *s = adc_get_ch_state( id ); return s->reqsamples; } -u8 adc_samples_ready( unsigned id ) +u16 adc_samples_available( unsigned id ) { - return ( u8 ) buf_get_count( BUF_ID_ADC, id ); + return ( u16 ) buf_get_count( BUF_ID_ADC, id ); } +void adc_wait_pending( unsigned id ) +{ + elua_adc_state *s = adc_get_ch_state( id ); + + if ( s->nonblocking == 0 && s->op_pending == 1 ) + { + while ( s->op_pending == 1 ) { ; } + } +} + + #endif \ No newline at end of file diff --git a/src/modules/adc.c b/src/modules/adc.c index 4240c881..82f1c504 100644 --- a/src/modules/adc.c +++ b/src/modules/adc.c @@ -15,15 +15,15 @@ static int adc_sample( lua_State* L ) { unsigned id; + int res; id = luaL_checkinteger( L, 1 ); MOD_CHECK_ID( adc, id ); - platform_adc_sample( id ); - if ( adc_samples_ready( id ) >= 1 ) - { - lua_pushinteger( L, adc_get_processed_sample( id ) ); - return 1; - } + res = platform_adc_sample( id ); + + if ( res != PLATFORM_OK ) + return luaL_error( L, "burst failed" ); + return 0; } @@ -40,21 +40,14 @@ static int adc_maxval( lua_State* L ) return 1; } -// Lua: isdone( id ) -static int adc_data_ready( lua_State* L ) +// Lua: samplesready( id ) +static int adc_samples_ready( lua_State* L ) { unsigned id; - u8 asamp, rsamp; - + id = luaL_checkinteger( L, 1 ); MOD_CHECK_ID( adc, id ); - asamp = adc_samples_ready( id ); - rsamp = adc_samples_requested( id ); - if ( rsamp > 0 && asamp >= rsamp ) - lua_pushinteger( L, 1 ); - else - lua_pushinteger( L, 0 ); - + lua_pushinteger( L, adc_samples_available( id ) ); return 1; } @@ -122,7 +115,7 @@ static int adc_flush( lua_State* L ) // Lua: burst( id, count, timer_id, frequency ) static int adc_burst( lua_State* L ) { - unsigned id, timer_id, i, count; + unsigned id, timer_id, count; u32 frequency; int res; @@ -132,52 +125,59 @@ static int adc_burst( lua_State* L ) timer_id = luaL_checkinteger( L, 3 ); MOD_CHECK_ID( timer, timer_id ); frequency = luaL_checkinteger( L, 4 ); + + if ( ( count == 0 ) || count & ( count - 1 ) ) + return luaL_error( L, "count must be power of 2 and > 0" ); + + res = platform_adc_burst( id, intlog2( count ), timer_id, frequency ); + if ( res != PLATFORM_OK ) + return luaL_error( L, "burst failed" ); + + return 0; +} - if ( count == 0 ) - return 0; + +// Lua: getsamples( id, count ) +static int adc_get_samples( lua_State* L ) +{ + unsigned id, i, count; + int total = lua_gettop( L ); + u16 nsamps; - if ( count & ( count - 1 ) ) - return luaL_error( L, "count must be power of 2" ); + id = luaL_checkinteger( L, 1 ); + MOD_CHECK_ID( adc, id ); + nsamps = adc_samples_available( id ); - // If we already have enough data, return it and start next burst - if( adc_samples_ready( id ) >= count ) + if ( total == 2 ) + count = luaL_checkinteger( L, 2 ); + else + count = nsamps; + + if ( count == 0 ) { count = nsamps; } // count = 0 means grab all samples + + adc_wait_pending( id ); + + if ( nsamps > 0 && nsamps >= count ) { - // Push data back to Lua - lua_createtable( L, count, 0 ); - for( i = 0; i < count; i ++ ) + if ( nsamps == 1 || count == 1 ) { lua_pushinteger( L, adc_get_processed_sample( id ) ); - lua_rawseti( L, -2, i+1 ); } - - res = platform_adc_burst( id, intlog2( count ), timer_id, frequency ); - if ( res != PLATFORM_OK ) - return luaL_error( L, "burst failed" ); - - - return 1; - } - else // If no data is available, kick off burst, return data if we have some afterwards - { - res = platform_adc_burst( id, intlog2( count ), timer_id, frequency ); - if ( res != PLATFORM_OK ) - return luaL_error( L, "burst failed" ); - - if( adc_samples_ready( id ) >= count ) + else { - // 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 1; } return 0; } + // Module function map #define MIN_OPT_LEVEL 2 #include "lrodefs.h" @@ -185,12 +185,13 @@ const LUA_REG_TYPE adc_map[] = { { LSTRKEY( "sample" ), LFUNCVAL( adc_sample ) }, { LSTRKEY( "maxval" ), LFUNCVAL( adc_maxval ) }, - { LSTRKEY( "dataready" ), LFUNCVAL( adc_data_ready ) }, + { LSTRKEY( "samplesready" ), LFUNCVAL( adc_samples_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 ) }, + { LSTRKEY( "getsamples" ), LFUNCVAL( adc_get_samples ) }, { LNILKEY, LNILVAL } }; diff --git a/src/platform/at91sam7x/platform.c b/src/platform/at91sam7x/platform.c index a109c790..abad70fa 100644 --- a/src/platform/at91sam7x/platform.c +++ b/src/platform/at91sam7x/platform.c @@ -83,7 +83,7 @@ int platform_init() USART_SetReceiverEnabled( pusart, 1 ); #if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE ) // Enable buffering on the console UART - buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, sizeof ( char ) ); + buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, BUF_DSIZE_U8 ); // Set interrupt handler and interrupt flag on UART unsigned uart_id = CON_UART_ID == 0 ? AT91C_ID_US0 : AT91C_ID_US1; AIC_DisableIT( uart_id ); diff --git a/src/platform/avr32/platform.c b/src/platform/avr32/platform.c index 27b7b8e7..023b42b7 100644 --- a/src/platform/avr32/platform.c +++ b/src/platform/avr32/platform.c @@ -118,7 +118,7 @@ int platform_init() platform_uart_setup( CON_UART_ID, CON_UART_SPEED, 8, PLATFORM_UART_PARITY_NONE, PLATFORM_UART_STOPBITS_1 ); #if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE ) // Enable buffering on the console UART - buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, sizeof ( char ) ); + buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, BUF_DSIZE_U8 ); // Set interrupt handler and interrupt flag on UART INTC_register_interrupt( &uart_rx_handler, CON_UART_IRQ, AVR32_INTC_INT0 ); volatile avr32_usart_t *pusart = ( volatile avr32_usart_t* )uart_base_addr[ CON_UART_ID ]; diff --git a/src/platform/lm3s/platform.c b/src/platform/lm3s/platform.c index b18bd2dc..f6e1ead6 100644 --- a/src/platform/lm3s/platform.c +++ b/src/platform/lm3s/platform.c @@ -277,7 +277,7 @@ static void uarts_init() #if defined( BUF_ENABLE_UART ) && defined( CON_BUF_SIZE ) // Enable buffering on the console UART - buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, sizeof ( t_buf_data ) ); + buf_set( BUF_ID_UART, CON_UART_ID, CON_BUF_SIZE, BUF_DSIZE_U8 ); // Set interrupt handler and interrupt flag on UART IntEnable(INT_UART0); @@ -533,9 +533,7 @@ 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 ++ ) { @@ -559,10 +557,13 @@ void ADCIntHandler( void ) platform_adc_stop( id ); } else if ( s->burst == 0 ) + { + // Need to manually fire off sample request in single sample mode ADCProcessorTrigger( ADC_BASE, id ); + } + } } - platform_cpu_enable_interrupts(); } static void adcs_init() @@ -599,19 +600,22 @@ int platform_adc_sample( unsigned id ) elua_adc_state *s = adc_get_ch_state( id ); int res; - res = buf_set( BUF_ID_ADC, id, ADC_BUF_SIZE , sizeof( u16 ) ); - if ( res != PLATFORM_OK ) - return res; - - // Need more general buf resizing... for now flush each time - buf_flush( BUF_ID_ADC, id ); - - s->burst = 0; - s->op_pending = 1; - s->reqsamples = 1; - // Make sure sequencer is disabled before making changes ADCSequenceDisable( ADC_BASE, id ); + + // If switching from burst, resize & flush buffer + if ( s->burst == 1 ) + { + buf_flush( BUF_ID_ADC, id ); + res = buf_set( BUF_ID_ADC, id, ADC_BUF_SIZE , BUF_DSIZE_U16 ); + if ( res != PLATFORM_OK ) + return res; + s->burst = 0; + s->reqsamples = 0; + } + + s->op_pending = 1; + s->reqsamples += 1; // Conversion will run back-to-back until required samples are acquired ADCSequenceConfigure( ADC_BASE, id, ADC_TRIGGER_PROCESSOR, id ) ; @@ -620,11 +624,6 @@ int platform_adc_sample( unsigned id ) ADCSequenceEnable( ADC_BASE, id ); ADCProcessorTrigger( ADC_BASE, id ); - // If in blocking mode and sample is pending, wait for ready flag - if ( s->nonblocking == 0 && s->op_pending == 1 ) - { - while ( s->op_pending == 1 ) { ; } - } return PLATFORM_OK; } @@ -633,21 +632,25 @@ int platform_adc_burst( unsigned id, u8 logcount, unsigned timer_id, u32 frequen elua_adc_state *s = adc_get_ch_state( id ); int res; - res = buf_set( BUF_ID_ADC, id, logcount , sizeof( u16 ) ); - if ( res != PLATFORM_OK ) - return res; + // Make sure sequencer is disabled before making changes + ADCSequenceDisable( ADC_BASE, id ); + + // If switching from non-burst, resize & flush buffer + if (s->burst == 0 || ( (u16) 1 << logcount ) != buf_get_count( BUF_ID_ADC, id ) ) + { + res = buf_set( BUF_ID_ADC, id, logcount, BUF_DSIZE_U16 ); + if ( res != PLATFORM_OK ) + return res; + // Need more general buf resizing... for now flush each time + buf_flush( BUF_ID_ADC, id ); + s->burst = 1; + s->reqsamples = 0; + } - // Need more general buf resizing... for now flush each time - buf_flush( BUF_ID_ADC, id ); - - s->burst = 1; s->timer_id = timer_id; s->op_pending = 1; s->reqsamples = (u16) 1 << logcount; - // Make sure sequencer is disabled before making changes - ADCSequenceDisable( ADC_BASE, id ); - // Set sequence id to be triggered repeatedly, with priority id ADCSequenceConfigure( ADC_BASE, id, ADC_TRIGGER_TIMER, id ); @@ -660,11 +663,6 @@ int platform_adc_burst( unsigned id, u8 logcount, unsigned timer_id, u32 frequen TimerControlTrigger(timer_base[timer_id], TIMER_A, true); TimerEnable(timer_base[timer_id], TIMER_A); - // If in blocking mode and sampling task is pending, wait until buffer fills - if ( s->nonblocking == 0 && s->op_pending == 1 ) - { - while ( s->op_pending == 1 ) { ; } - } return PLATFORM_OK; }